/*  _______         ____    __         ___    ___
 * \    _  \       \    /  \  /       \   \  /   /       '   '  '
 *  |  | \  \       |  |    ||         |   \/   |         .      .
 *  |  |  |  |      |  |    ||         ||\  /|  |
 *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
 *  |  |  |  |      |  |    ||         ||    |  |         .      .
 *  |  |_/  /        \  \__//          ||    |  |
 * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
 *                                                      /  \
 *                                                     / .  \
 * dumb.txt - DUMB library reference.                 / / \  \
 *                                                   | <  /   \_
 * See readme.txt for general information on         |  \/ /\   /
 * DUMB and how to set it up.                         \_  /  > /
 *                                                      | \ / /
 * If you are new to DUMB, see howto.txt.               |  ' /
 *                                                       \__/
 */


***********************************
*** Include Files and Libraries ***
***********************************


dumb.h

   Include this if you only want the core DUMB library functions. You will
   be able to load music files and render them into memory buffers at your
   own pace. The core library is completely portable, and as such does not
   access hardware; you must relay the sound data to the sound card yourself.
   A stdio file input module is available, but you must actively register it
   if you wish to use it (see dumb_register_stdfiles()); if you do not
   register it, it will not be linked into your executable. You must register
   it, or a DUMBFILE module of your own, in order to load stand-alone music
   files.

   Optimised: -ldumb   or  /link dumb.lib
   Debugging: -ldumbd  or  /link dumbd.lib


aldumb.h

   Include this if you wish to use DUMB with Allegro. This will provide you
   with functions to play DUHs back through Allegro's audio streams and embed
   music files in Allegro datafiles. A file input module using Allegro's
   packfiles is provided; you have a choice between this and the stdio
   module (or provide one of your own). You will be able to load datafiles
   containing music files no matter which file input module you register, or
   even if you register no file input module. However, you must register a
   file input module in order to load stand-alone files.

   Optimised: -laldmb -ldumb -lalleg  or  /link aldmb.lib alleg.lib dumb.lib
   Debugging: -laldmd -ldumbd -lalld  or  /link aldmd.lib alld.lib dumbd.lib

   aldmb or aldmd must be linked in first, so the symbols can be resolved
   when linking in the other two libraries.


***************************
*** Version Information ***
***************************


#define DUMB_MAJOR_VERSION
#define DUMB_MINOR_VERSION
#define DUMB_REVISION_VERSION

   Numeric constants representing this version of DUMB. If this were version
   1.0, DUMB_MAJOR_VERSION would be 1 and DUMB_MINOR_VERSION would be 0.
   DUMB_REVISION_VERSION will be 0 on any significant releases, and will be
   incremented as releases with bugfixes and minor features are made.

   Typical usage:

      #if DUMB_MAJOR_VERSION < 1
      #error This add-on requires DUMB v1.0 or higher. Please upgrade.
      #endif


#define DUMB_VERSION

   A numeric constant which appears in the format MMmmrr when displayed in
   decimal (M for major, m for minor, r for revision). This is most useful
   for comparing version numbers; it has little other practical use.

   Typical usage:

      #if DUMB_VERSION < 801
      #error This game requires DUMB v0.8.1 or higher. Please upgrade.
      #endif

      #if DUMB_VERSION < 10002
      #error This game requires DUMB v1.0.2 or higher. Please upgrade.
      #endif


#define DUMB_VERSION_STR

   String constant representing this version of DUMB. If this were Version
   1.0, DUMB_VERSION_STR would be "1.0". DUMB_REVISION_VERSION will only
   appear on the end if it is nonzero; then DUMB_VERSION_STR might be
   "1.0.1".


#define DUMB_NAME

   A string identifying DUMB and its version. If this were Version 1.0,
   DUMB_NAME might be "DUMB v1.0". This constant is suitable for use in your
   Credits screen if you wish to acknowledge the use of DUMB there.


#define DUMB_YEAR
#define DUMB_MONTH
#define DUMB_DAY

   Numeric constants representing the year, month and day of this release of
   DUMB. All four digits are included in the year. Please note that
   DUMB_MONTH and DUMB_DAY were inadvertently swapped in the v0.8 release.


#define DUMB_YEAR_STR4
#define DUMB_YEAR_STR2
#define DUMB_MONTH_STR2
#define DUMB_MONTH_STR1
#define DUMB_DAY_STR2
#define DUMB_DAY_STR1

   String constants representing the year, month and day of this release of
   DUMB. DUMB_MONTH_STR2 and DUMB_DAY_STR2 include a leading zero if the
   month or day respectively are less than ten; the STR1 variations do not.
   DUMB_YEAR_STR2 contains only the two rightmost digits of the year, while
   DUMB_YEAR_STR4 contains all four. I recommend using DUMB_YEAR_STR4,
   especially so soon after the turn of the century (indeed the millennium).
   However, it is a matter of personal preference which you use.

   Please note that the month and day were inadvertently swapped in the v0.8
   release.


#define DUMB_DATE

   A numeric constant that appears in the form yyyymmdd when displayed in
   decimal. This is most useful for comparing release dates; it has little
   other practical use.

   WARNING: The month and day were inadvertently swapped in the v0.8 release.
            Please do not compare this constant against any date in 2002. In
            any case, DUMB_VERSION is probably more useful for this purpose.


#define DUMB_DATE_STR

   The date as a string. The format is "d.m.yyyy", with dots used as
   separators, the day written first, four digits for the year, and no
   leading zeros on the day or month. This is my preferred format. If you
   don't like it, you can construct your own format using the other
   constants. For example, "mm/dd/yy" could be constructed as follows:

      DUMB_MONTH_STR2 "/" DUMB_DAY_STR2 "/" DUMB_YEAR_STR2

   Please note that the month and day were inadvertently swapped in the v0.8
   release.


*************************
*** Basic Sample Type ***
*************************


typedef int sample_t;

   DUMB works internally with 32-bit integer samples, with a 'normal range'
   from -0x800000 to 0x7FFFFF (as of DUMB v0.9.2; previously they ranged from
   -0x8000 to 0x7FFF). Any samples that exceed this range will eventually be
   clipped, and could cause integer overflow in extreme cases.


***********************************
*** Library Clean-up Management ***
***********************************


int dumb_atexit(void (*proc)(void));

   Registers a function to be called at the end of your program. You can
   register multiple functions to be called, and the one you register last
   will be called first. If you try to register the same function twice, the
   second attempt will have no effect.

   See fnptr.txt for help with function pointers.

   You must call dumb_exit() before exiting your program for this to work
   properly. The library itself registers functions with dumb_atexit(), so it
   is important to call dumb_exit() even if you do not use dumb_atexit()
   yourself.

   This function will return zero on success. It will return zero when
   trying to install the same function twice. If it fails through lack of
   memory, it will return nonzero. Generally you can ignore the return code;
   in the worst case some memory will not be freed at the end. If it is
   crucial that your function be called (e.g. to shut down some hardware or
   save critical data), then you should call your function manually at the
   end of the program instead of registering it here - or use the stdlib
   function atexit(), guaranteed under ANSI C to succeed for at least 32
   functions.


void dumb_exit(void);

   You should call this before exiting your program if you have used any part
   of DUMB in the program. Some parts of DUMB will allocate memory, and this
   function will free it all up.

   More specifically, this function will call any functions that have been
   registered with dumb_atexit(). If a part of DUMB needs shutting down, the
   shutdown procedure will have been registered in this way.

   dumb_exit() will, of course, also call any functions you registered with
   dumb_atexit() yourself.

   After a call to dumb_exit(), the list of functions is erased. If you are
   not ready to exit your program, you can start using DUMB anew as if your
   program had just started. (Note that not everything will be reset in
   practice - dumb_resampling_quality will retain whatever you set it to, for
   example, though you should not assume it will.)

   If you only need to call dumb_exit() once at the end of the program, you
   can use the following to register dumb_exit() with stdlib.h atexit():

      #include <stdlib.h>

      atexit(&dumb_exit);

   Then dumb_exit() will be called for you when your program exits. This is
   the recommended method, since it will ensure clean-up even if your program
   aborts. You should only call dumb_exit() manually if you need to shut DUMB
   down prematurely, or if atexit() is unavailable for one reason or another.


*****************************
*** Sequential File Input ***
*****************************


   DUMB provides a strictly sequential file input system which uses the
   DUMBFILE struct. "Strictly sequential" means you cannot seek backwards.
   However, the system will keep track of how many bytes you have read,
   enabling you to seek forwards. DUMBFILEs provide a convenient error
   detection system, so you do not have to check the return value from every
   function call in the way you do with the ANSI C functions.

   Note that DUMBFILEs cannot be used for output, nor can they be used
   portably for text files.

   If an error occurs when reading data from a DUMBFILE, the DUMBFILE will
   become inoperative. All subsequent activities on the DUMBFILE will return
   error codes without attempting to read from the file. The position in the
   file will also be forgotten. You can find out if this has happened at any
   stage with the dumbfile_error() function. You are still required to close
   the DUMBFILE, and the return value from dumbfile_close() will tell you if
   an error has occurred.

   This system allows you to input large chunks of your file, neither
   checking every return value nor wasting time accessing a file that has
   already experienced an error. However, before you allocate an amount of
   memory or read in a quantity of data depending on previous input from the
   file, you should always check that such input was valid. In particular you
   should avoid passing zero or negative numbers to malloc(), and avoid
   passing negative numbers to dumbfile_skip() and dumbfile_getnc().

   DUMBFILEs can be hooked. In other words, you can specify your own
   functions to do the work of reading from a file. While DUMB contains two
   modules for this purpose, it does not set them up for you automatically.
   In most cases you must register one of these modules yourself, or provide
   your own module. See register_dumbfile_system(), dumb_register_stdfiles()
   and dumb_register_packfiles().


void register_dumbfile_system(DUMBFILE_SYSTEM *dfs);

   Use this function to register a set of functions for use by the DUMBFILEs
   (a DUMBFILE system). The DUMBFILE_SYSTEM struct contains the following
   fields:

      void *(*open)(const char *filename);
      int (*skip)(void *f, long n);
      int (*getc)(void *f);
      long (*getnc)(char *ptr, long n, void *f);
      void (*close)(void *f);

   See fnptr.txt for help with function pointers such as these.

   Your 'open' function should open the file specified and return a pointer
   to a struct representing the open file. This pointer will be passed to
   your other functions as 'f'. Your 'close' function should close the file
   and free all memory pointed to by 'f'. Note that the 'close' operation
   should never be able to fail; if you are calling a function with a return
   value, you can generally ignore it.

   Your 'getc' function should read one byte from the file and return its
   value in the range 0 to 255. If an error occurs, you should return -1. Do
   not worry about remembering that an error has occurred; DUMB will do that
   for you.

   'skip' is for skipping parts of the file, and should skip n bytes,
   returning 0 on success or any other number on failure. 'getnc' should read
   n bytes from the file, store them at 'ptr', and return the number of bytes
   read (n on success, fewer on failure). However, these two functions are
   optional, and you should only provide them if the operations can be done
   more efficiently than with repeated calls to your 'getc' function. If this
   is not the case, specify NULL for 'skip', 'getnc' or both, and DUMB will
   use your 'getc' function to do the work.

   Once you have written all your functions, you need to create a
   DUMBFILE_SYSTEM struct to hold them, and pass its pointer to
   register_dumbfile_system().

   The DUMBFILE_SYSTEM struct must be permanent. In other words, it must be
   either global or static, and you should not modify it later. DUMB will not
   make its own copy.

   You will most likely create your own struct to represent the open file,
   but do not be tempted to specify that struct in the function prototypes
   and pacify the compiler warnings by casting your function pointers. There
   exist computer systems where a (void *) pointer and a (MY_STRUCT *)
   pointer are represented differently in memory, and a cast of such a
   pointer causes a tangible conversion to take place. If you cast the
   function pointers, the computer cannot know when such a conversion is
   necessary. Instead, use the following structure:

      int myskip(void *f, long n)
      {
         FILE *file = f;
         /* Do some stuff with 'file' */
         return something;
      }

   If you need examples, have a look at the two existing DUMBFILE systems in
   dumb/src/core/stdfile.c and dumb/src/allegro/packfile.c.


DUMBFILE *dumbfile_open(const char *filename);

   Open the specified file for input. You must pass the DUMBFILE pointer
   whenever you wish to operate on this file. When you have finished with the
   file, you must pass it to dumbfile_close().

   Before you use this function, make sure you have registered a DUMBFILE
   system. See register_dumbfile_system(), dumb_register_stdfiles() and
   dumb_register_packfiles().

   You must check the return value from this function. If it is NULL, the
   file could not be opened, and you must not pass the DUMBFILE to any other
   function. The debugging library will abort if you get this wrong; the
   optimised library will act weird.


DUMBFILE *dumbfile_open_ex(void *file, DUMBFILE_SYSTEM *dfs);

   This function is provided for more specialised use. You should create a
   DUMBFILE_SYSTEM specially for the purpose. Its 'open' field is irrelevant;
   for neatness, set it to NULL, unless you are using this DUMBFILE_SYSTEM
   with register_dumbfile_system() as well.

   When you have called this function, the DUMBFILE struct it returned can be
   used as normal. The specified DUMBFILE_SYSTEM will be used for all input,
   with 'file' passed to your 'skip', 'getc' and 'getnc' functions as 'f'.
   This can be used, for example, to read from an already open file.

   Note that the position will always be initialised to 0 for this DUMBFILE.
   This means for example that offsets in the file do not need adjusting when
   embedding data in a larger file.

   There are two ways to use this function. If you want 'file' to persist
   after using a DUMBFILE returned by this function, you should make sure the
   'close' field in the DUMBFILE is set to NULL. When the DUMBFILE is closed,
   'file' will be left alone, and you can and should deal with it yourself
   when the DUMBFILE has been closed.

   Alternatively, you can provide a 'close' function to get rid of 'file' for
   you when the DUMBFILE is closed. If you do this, you should not otherwise
   use 'file' after a call to this function.

   If dumbfile_open_ex() has to return NULL, owing to lack of memory, then
   your 'close' function will be called if provided. In other words, if you
   have provided a 'close' function, then you no longer need to worry about
   'file' whether this function succeeds or not.

   See dumb/src/helpers/stdfile.c and dumb/src/allegro/packfile.c for
   examples of how to use this function. Neither provides a 'close' function,
   so I hope my explanation here will suffice. If not, please feel free to
   contact me so I can make the explanation clearer and help you do what you
   want to do. Contact details are at the end of this file.


long dumbfile_pos(DUMBFILE *f);

   Returns the number of bytes read from the DUMBFILE (or skipped) since it
   was opened, or -1 if an error has occurred while reading.


int dumbfile_skip(DUMBFILE *f, long n);

   Skips n bytes of the specified DUMBFILE. Returns zero on success.


int dumbfile_getc(DUMBFILE *f);

   Reads one byte from the DUMBFILE and returns it in unsigned format (from 0
   to 255). If an error occurs, or occurred before, this function returns -1.


int dumbfile_igetw(DUMBFILE *f);

   Reads two bytes from the DUMBFILE and combines them into a word ranging
   from 0 to 65535. The first byte read is the least significant byte, as
   with Intel processors. This function returns -1 on error.


int dumbfile_mgetw(DUMBFILE *f);

   Reads two bytes from the DUMBFILE and combines them into a word ranging
   from 0 to 65535. The first byte read is the most significant byte, as
   with the Apple Macintosh. This function returns -1 on error.


long dumbfile_igetl(DUMBFILE *f);

   Reads four bytes from the DUMBFILE and combines them into a long integer
   ranging from -2147483648 to 2147483647. The first byte read is the least
   significant byte, as with Intel processors. This function returns -1 on
   error, but -1 is also a valid return value. After a call to this function,
   you can use dumbfile_error() to find out if an error occurred.


long dumbfile_mgetl(DUMBFILE *f);

   Reads four bytes from the DUMBFILE and combines them into a long integer
   ranging from -2147483648 to 2147483647. The first byte read is the most
   significant byte, as with the Apple Macintosh. This function returns -1 on
   error, but -1 is also a valid return value. After a call to this function,
   you can use dumbfile_error() to find out if an error occurred.


unsigned long dumbfile_cgetul(DUMBFILE *f);

   Reads an unsigned (nonnegative) integer from the DUMBFILE. The integer is
   stored in a condensed format where smaller numbers use less space:

           0 to 127         1 byte
         128 to 16383       2 bytes
       16384 to 2097151     3 bytes
     2097152 to 268435455   4 bytes
   268435456 to 4294967295  5 bytes

   This format is the same as that used for the times between notes in MIDI
   files.

   If an error occurs, this function returns (unsigned long)(-1), but that
   may be a valid return value. After a call to this function, you can use
   dumbfile_error() to find out if an error occurred.


signed long dumbfile_cgetsl(DUMBFILE *f);

   Reads a signed integer from the DUMBFILE. The integer is stored in a
   condensed format where numbers closer to zero use less space:

           -64 to 63          1 byte
         -8192 to 8191        2 bytes
      -1048576 to 1048575     3 bytes
    -134217728 to 134217727   4 bytes
   -2147483648 to 2147483647  5 bytes

   If an error occurs, this function returns -1, but -1 is also a valid
   return value. After a call to this function, you can use dumbfile_error()
   to find out if an error occurred.


long dumbfile_getnc(char *ptr, long n, DUMBFILE *f);

   Reads n bytes from the DUMBFILE and stores them at 'ptr'. Note that the
   pointer is to a series of chars. You may also use this function to read in
   a series of signed chars or unsigned chars (which are both officially
   distinct types from char), but do not use this to read ints, structs or
   any other data type from the file. Integers must be read one at a time
   using dumbfile_igetl(), dumbfile_cgetul(), etc. To load a struct in, you
   must read each field separately using an appropriate function for each
   one. For complicated data types, you can simplify this process by writing
   a function for each struct.

   dumbfile_getnc() returns the number of bytes successfully read, which will
   be less than n if an error occurs, and may be as low as zero. If
   dumbfile_getnc() returns -1, that means an error occurred on this DUMBFILE
   earlier, before this function was called.


int dumbfile_error(DUMBFILE *f);

   This function returns -1 if an error has occurred with the specified
   DUMBFILE, or 0 if all is well.


int dumbfile_close(DUMBFILE *f);

   This function closes the DUMBFILE, after which the pointer will be
   invalid. dumbfile_close() returns the value that dumbfile_error() would
   have returned, which is -1 if an error occurred while reading or 0
   otherwise. Regardless of the return value, the file will always be closed
   properly.


*******************************
*** stdio File Input Module ***
*******************************


void dumb_register_stdfiles(void);

   This function registers the stdio file input module for use by DUMBFILEs.
   FILE structs and their corresponding functions, as defined by the ANSI C
   header stdio.h, will be used internally for all DUMBFILE input (unless
   opened with dumbfile_open_ex()).

   This must be called before dumbfile_open() is used, or else an alternative
   system must be registered (see register_dumbfile_system() and
   dumb_register_packfiles()).


DUMBFILE *dumbfile_open_stdfile(FILE *p);

   If you have a stdio FILE struct representing an open file, you can call
   this if you wish to read from it using a DUMBFILE. This is useful when you
   need to pass a DUMBFILE struct to a library function, to read an embedded
   music file for example. When you close the DUMBFILE, you can continue
   using the FILE struct to read what follows the embedded data.


********************************
*** Memory File Input Module ***
********************************


DUMBFILE *dumbfile_open_memory(const char *data, long size);

   This function is useful if you have an image of a music file in memory.
   You might have such an image if you use dat2s to encode a datafile
   directly into the executable. Pass a pointer to the start of the memory,
   and the size of the image to make sure DUMB doesn't overrun the buffer.
   The resulting DUMBFILE will feed the contents of the image to you.

   Note that the pointer is of type 'char *'. Files are series of chars, and
   interpreting them directly as anything else isn't portable.


**********************
*** DUH Management ***
**********************


void unload_duh(DUH *duh);

   Removes a DUH from memory. You must call this for all DUHs you load,
   making sure they're not playing at the time.


long duh_get_length(DUH *duh);

   Returns the length of a DUH; 65536 represents one second. This value is
   calculated when the DUH is created, and this function simply lifts it from
   the struct. It may not truly correspond to the time for which the DUH will
   generate sound. For module files, it will represent the point at which the
   module first loops (or, in the case of some XM and MOD files, freezes).
   Any add-ons to DUMB will provide their own code for calculating this.

   The algorithm for calculating the length of a module file can be fooled,
   but only by very deliberate methods. In the early days, when modules could
   only be played by their editors and had to be exported to .wav or similar
   in order to be used elsewhere, musicians would sometimes make the player
   think it was looping when it wasn't in order to prevent their music from
   being exported properly. If the length of a module seems a lot less than
   it should be, the module is probably protected in this way.

   Getting around this protection reliably would be extremely difficult, but
   after considering it for a while I decided it would be better not to. The
   musician has a right to protect his or her music in this way, and I have
   no interest in actively breaking that protection.

   (On the other hand, some musicians were just showing off!)


***********************************
*** IT, XM, S3M and MOD Support ***
***********************************


int dumb_it_max_to_mix;

   Specifies the maximum number of samples DUMB will mix at any one time. The
   default number is 64. Regardless of this value, all samples will continue
   to be processed up to an internal maximum of 256 (roughly speaking; in
   fact it will process one sample for each channel plus up to 192 extra
   samples that are continuing to play owing to Impulse Tracker's New Note
   Actions), and samples that have been cut will sound again as soon as the
   congestion clears. Samples are given priority according to their final
   volume after all factors affecting the volume of a sample have been
   considered.

   If you play two or more modules at once, this value represents the
   maximum number of samples for each one. You will have to reduce it further
   if your computer cannot keep up.

   Despite the name, this variable controls XM, S3M and MOD files as well as
   IT files.


DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh);

   This function attempts to retrieve the DUMB_IT_SIGDATA struct from a DUH.
   This struct will exist for any IT, XM, S3M or MOD file, and you can use it
   to obtain or override module-specific information. If 'duh' is NULL, or if
   the DUH you pass contains something other than a music module, then this
   function will return NULL (which can safely be passed to any other
   function).


DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer);

   This function attempts to retrieve the DUMB_IT_SIGRENDERER struct from a
   DUH_SIGRENDERER. This struct will exist for any currently playing IT, XM,
   S3M or MOD file, and you can use it to obtain or override information
   specific to module playback. If 'sigrenderer' is NULL, or if the
   DUH_SIGRENDERER you pass is rendering something other than a music module,
   then this function will return NULL (which can safely be passed to any
   other function).


DUH_SIGRENDERER *dumb_it_start_at_order
                                  (DUH *duh, int n_channels, int startorder);

   This function, given a DUH containing an IT, XM, S3M or MOD file, will
   start playing it at the specified order. If the DUH does not contain a
   module, this function will fail and return NULL.

   Note that starting at an arbitrary order may result in missing notes or
   other playback oddities. It should be used primarily for modules that
   contain multiple songs that start on different orders. If you wish just to
   start some music in the middle, consider using duh_start_sigrenderer() or
   al_start_duh() with the pos parameter set appropriately.


void dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer,
                               int (*callback)(void *data), void *data);

   Installs a callback which will be called every time the module loops. You
   can pass any data pointer you like, and it will be passed to the callback
   for you. DUMB considers a file to loop when it reaches the end, or when a
   'Jump to order' effect (Bxx in both IT/S3M and XM/MOD) jumps to the same
   order or a preceding order. This can result in the loop callback being
   called when the module isn't really looping, but this only happens if the
   module has a very deliberate design. See duh_get_length() for further
   musings on this subject.

   If your callback returns nonzero, the music will stop abruptly. Samples
   will be cut, and the main program will be notified that the
   DUH_SIGRENDERER has ended.

   Alternatively, if you pass the DUMB_IT_SIGRENDERER for 'data', or
   otherwise arrange for it to be available to the callback, then you can
   call:

      dumb_it_sr_set_speed(sigrenderer, 0);

   from inside the callback, and this will cause the music to freeze but
   samples will be able to continue playing. The xm_speed_zero callback will
   NOT be called in this case (see below for information on this callback).
   Note also that setting the speed in this way will work equally for IT and
   S3M files, even though a 'speed zero' effect can only exist in XM and MOD
   files. Beware when using this method; samples might not fade at all!

   A helper callback, dumb_it_callback_terminate(), is provided; installing
   this will cause the music to terminate when it tries to loop for the first
   time.

   Pass NULL to remove the callback function; the module will then loop as
   normal.


void dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer,
                                    int (*callback)(void *data), void *data);

   Installs a callback which is in many ways similar to the loop callback
   (see dumb_it_set_loop_callback()). This callback will be called whenever
   an F00 effect is encountered in a MOD or XM file, setting the speed to
   zero. If the callback returns nonzero, the music will terminate. If not,
   any currently playing samples will continue to play. You can pass any data
   pointer you like to this function, and it will be passed to your callback
   for you.

   The helper callback, dumb_it_callback_terminate(), will also work here;
   installing it will cause the music to terminate as soon as an F00 effect
   is encountered.

   Pass NULL to remove the callback function.


void dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer,
                int (*callback)(void *data, int channel, unsigned char byte),
                void *data);

   Installs a callback function which will be called whenever MIDI data are
   generated by an IT file. (No other module formats are capable of
   generating MIDI data, so your callback will never be called.)

   Zxx macros will generate MIDI data. These are most often used to set the
   parameters for IT's low-pass resonant filters, and DUMB will handle these
   messages by itself by default. See Impulse Tracker's documentation for
   the MIDI messages that control filters. However, Zxx macros can be used
   to send any kind of MIDI data.

   If you wish to interpret MIDI messages yourself, you can use this
   callback. Note that the only MIDI messages generated by DUMB at present
   are from Zxx macros; there are no messages for note start, stop, or
   anything else.

   If you return 1 from this callback, DUMB will subsequently ignore the byte
   of MIDI data. You can use this to prevent Zxx macros from controlling the
   filters, useful if they were intended to do something else. Note that this
   is NOT an effective way to disable filters, since instruments can have
   filter envelopes and initial filter parameters. DUMB provides no means to
   disable filters, as any IT file that uses them will sound wrong without
   them. If you want lower processor consumption, use a different piece of
   music.

   A helper callback, dumb_it_callback_midi_block(), is provided for blocking
   all MIDI messages and making Zxx macros do nothing.

   Pass NULL to remove the callback.


int dumb_it_callback_terminate(void *data);

   This is a helper callback that can be installed with both
   dumb_it_set_loop_callback() and dumb_it_set_xm_speed_zero_callback(). In
   each case it will cause the music to terminate abruptly.


int dumb_it_callback_midi_block(void *data, int channel, unsigned char byte);

   This helper callback, for use with dumb_it_set_midi_callback(), will
   absorb all MIDI messages, returning 1 to prevent DUMB from interpreting
   them itself.


DUH *dumb_load_it(const char *filename);

   Loads the specified Impulse Tracker file, encapsulating it in a DUH
   struct. Once the file is loaded, it can be treated exactly the same as any
   other DUH in memory. If this fails it will return NULL, but you can safely
   pass this NULL value to DUMB's other functions, so you do not need to
   check the return value explicitly.


DUH *dumb_read_it(DUMBFILE *f);

   Reads an Impulse Tracker file from an already open DUMBFILE. This leaves
   the DUMBFILE open, but the DUMBFILE may not be positioned at the end of
   the IT data. If you are embedding an IT in another file, you are advised
   to store the size of the IT file and make up for it at the end using
   dumbfile_pos().

   Otherwise, this function is identical to dumb_load_it().

   WARNING: The behaviour of this function is undefined if you pass a
            DUMBFILE from which data have already been read; it is likely not
            to work. This oversight will be fixed in future releases.


DUH *dumb_load_xm(const char *filename);

   Loads the specified Fast Tracker II file, encapsulating it in a DUH
   struct. Once the file is loaded, it can be treated exactly the same as any
   other DUH in memory. If this fails it will return NULL, but you can safely
   pass this NULL value to DUMB's other functions, so you do not need to
   check the return value explicitly.


DUH *dumb_read_xm(DUMBFILE *f);

   Reads a Fast Tracker II file from an already open DUMBFILE. This leaves
   the DUMBFILE open, but the DUMBFILE may not be positioned at the end of
   the XM data. If you are embedding an XM in another file, you are advised
   to store the size of the XM file and make up for it at the end using
   dumbfile_pos().

   Otherwise, this function is identical to dumb_load_xm().

   WARNING: The behaviour of this function is undefined if you pass a
            DUMBFILE from which data have already been read; it is likely not
            to work. This oversight will be fixed in future releases.


DUH *dumb_load_s3m(const char *filename);

   Loads the specified Scream Tracker 3 file, encapsulating it in a DUH
   struct. Once the file is loaded, it can be treated exactly the same as any
   other DUH in memory. If this fails it will return NULL, but you can safely
   pass this NULL value to DUMB's other functions, so you do not need to
   check the return value explicitly.


DUH *dumb_read_s3m(DUMBFILE *f);

   Reads a Scream Tracker 3 file from an already open DUMBFILE. This leaves
   the DUMBFILE open, but the DUMBFILE may not be positioned at the end of
   the S3M data. If you are embedding an S3M in another file, you are advised
   to store the size of the S3M file and make up for it at the end using
   dumbfile_pos().

   Otherwise, this function is identical to dumb_load_s3m().

   WARNING: The behaviour of this function is undefined if you pass a
            DUMBFILE from which data have already been read; it is likely not
            to work. This oversight will be fixed in future releases.


DUH *dumb_load_mod(const char *filename);

   Loads the specified Amiga module file, encapsulating it in a DUH struct.
   Once the file is loaded, it can be treated exactly the same as any other
   DUH in memory. If this fails it will return NULL, but you can safely pass
   this NULL value to DUMB's other functions, so you do not need to check the
   return value explicitly.


DUH *dumb_read_mod(DUMBFILE *f);

   Reads an Amiga module file from an already open DUMBFILE. This leaves the
   DUMBFILE open, but the DUMBFILE may not be positioned at the end of the
   MOD data. If you are embedding a MOD in another file, you are advised to
   store the size of the MOD file and make up for it at the end using
   dumbfile_pos().

   Otherwise, this function is identical to dumb_load_mod().

   WARNING: The behaviour of this function is undefined if you pass a
            DUMBFILE from which data have already been read; it is likely not
            to work. This oversight will be fixed in future releases.


int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd);

   This function returns the number of orders in the module.


int dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd);
void dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv);

   These functions obtain and set the initial global volume for the module.
   This value ranges from 0 to 128 inclusive. The module can set the global
   volume itself during playback, so your change may not last throughout the
   playback.


int dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd);
void dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv);

   These functions obtain and set the mixing volume for the module. This
   value ranges from 0 to 128 inclusive, and does not change during playback.
   IT files have the mixing volume stored in them; for other formats it is
   set to 48 on loading.


int dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd);
void dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed);
int dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd);
void dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo);

   These functions obtain and set the initial speed and tempo for the module.
   During module playback, everything happens on a tick. If a beat is 24
   ticks, then the tempo is measured in beats per second. The speed is then
   the number of ticks per row. With a speed of 6, a beat is then four rows.

   Modules can set these values during playback, so your change may not last
   throughout the playback. MOD files have to set the speed and tempo on the
   first row if they want anything other than the default 6/125, so your
   change may not be noticed at all!


int dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel);
void dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel,
                                                                 int volume);

   These functions obtain and set the initial volume for the specified
   channel. The channel parameter is 0-based (contrary to the display in most
   trackers so be careful), and can range from 0 to DUMB_IT_N_CHANNELS - 1,
   i.e. from 0 to 63.

   Modules can set their channel volumes during playback, so your changes may
   not last throughout the playback.


int dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr);
int dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr);

   These functions return the current order and row of playback. Both are
   0-based. If the DUMB_IT_SIGRENDERER is invalid, or has been terminated
   by a callback (see dumb_it_set_loop_callback() and
   dumb_it_set_xm_speed_zero_callback()), these functions will both return
   -1.


int dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr);
void dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv);

   These functions obtain and set the current global volume for the module.
   This value ranges from 0 to 128 inclusive. The module can set the global
   volume itself during playback, so your change may not last.


int dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr);
void dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo);
int dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr);
void dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed);

   These functions obtain and set the current speed and tempo of the module.
   See the dumb_it_sd_*() equivalents of these functions for details on what
   the speed and tempo mean.

   Modules can set these values during playback, so your change may not last.


int dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel);
void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel,
                                                                 int volume);

   These functions obtain and set the current volume for the specified
   channel. The channel parameter is 0-based (contrary to the display in most
   trackers so be careful), and can range from 0 to DUMB_IT_N_CHANNELS - 1,
   i.e. from 0 to 63.

   Modules can set their channel volumes during playback, so your changes may
   not last.


void dumb_it_sr_get_channel_state(DUMB_IT_SIGRENDERER *sr, int channel,
                                               DUMB_IT_CHANNEL_STATE *state);

   Returns the current playback state of the given channel. If you pass a
   channel in the range 0 to DUMB_IT_N_CHANNELS-1 (0 to 63), you will get the
   state of the most recently played note on that physical channel, if it is
   still playing. For MOD, S3M and XM files, that's all there is to it.

   IT files can have more than one note playing on a single channel, courtesy
   of New Note Actions. This function also lets you query all the notes that
   have been forced into the background and are still playing. For this, set
   'channel' to a value from DUMB_IT_N_CHANNELS to DUMB_IT_TOTAL_CHANNELS-1.
   DUMB_IT_TOTAL_CHANNELS is defined as follows:

      #define DUMB_IT_TOTAL_CHANNELS \
                                (DUMB_IT_N_CHANNELS + DUMB_IT_N_NNA_CHANNELS)

   Querying these background channels for MOD, S3M and XM files will not do
   any harm; the function will report that these channels are inactive. For
   all files, be sure not to query any channel numbers greater than or equal
   to DUMB_IT_TOTAL_CHANNELS.

   You must provide a pointer to a preallocated DUMB_IT_CHANNEL_STATE struct.
   The easiest way to do this is as follows:

      DUMB_IT_CHANNEL_STATE state;
      dumb_it_sr_get_channel_state(sr, channel, &state);

   or:

      DUMB_IT_CHANNEL_STATE state[IT_TOTAL_CHANNELS];
      dumb_it_sr_get_channel_state(sr, channel, &state[channel]);

   This struct contains the following fields:

          int channel;
          int sample;
          int freq;
          float volume;
          unsigned char pan;
          signed char subpan;
          unsigned char filter_cutoff;
          unsigned char filter_subcutoff;
          unsigned char filter_resonance;

   The first field to check is 'sample'; if this is 0, then the channel is
   inactive and the other fields are undefined. Otherwise, it is the index of
   the currently playing sample, and is 1-based.

   The channel number is returned, 0-based. This will be the same as the
   channel number you passed, unless you are querying a background channel in
   which case it will represent the channel the note originated on.

   The freq field is the current playback frequency, taking into account all
   phenomena such as slides, vibrato and arpeggio.

   The volume field ranges from 0.0f to 1.0f. In practical terms, it will
   rarely reach 1.0f; if it does, the module is probably clipping a lot. This
   takes mixing volume into account, along with all the other volume
   phenomena in the IT file. The only one it doesn't take into account is the
   one you pass to duh_render() or duh_sigrenderer_get_samples(), or the one
   you passed to al_start_duh() (these are in fact the same thing).

   The pan field ranges from 0 to 64 for a normally panned sample, but will
   be 100 if the sample is playing using IT's surround mode where the right-
   hand channel is inverted. If you want a more accurate pan reading, use one
   of the following to get one:

      int scaled_pan = ((int)state.pan << 8) + state.subpan;
      float float_pan = state.pan + state.subpan / 256.0f;

   The first will give a scaled value ranging (strictly) from 0 to 64*256.
   The second will give a floating-point value whose scale corresponds to
   that of the pan field. These results will only be valid if surround mode
   is off, so you should check that pan <= 64 before using the above
   expressions. At the time of writing, pitch-pan separation and panning
   envelopes take advantage of the extra accuracy offered by subpan.

   Note that subpan is signed. This means applications that only look at the
   pan field will get an unbiased reading.

   The filter cut-off and resonance both range from 0 to 127. If the cut-off
   is 127 and the resonance is 0, then no filters are applied. These
   parameters only ever change from the default values for IT files.

   While IT allows you to set 127 different filter cut-off levels in the
   patterns and as a default value per instrument, it also allows you to
   create a filter envelope, which will result in an actual cut-off somewhere
   between 0 and the first-mentioned value. By the time this has been
   calculated, the actual cut-off may lie in between two levels on the
   original scale. If this is the case, filter_subcutoff will be nonzero and
   you can combine it with filter_cutoff. Typically you will want to use one
   of the following:

      int scaled_cutoff = ((int)state.filter_cutoff << 8) +
                                state.filter_subcutoff;

      float float_cutoff = state.filter_cutoff +
                           state.filter_subcutoff / 256.0f;

   The first will give you a scaled value whose maximum is 127*256. The
   second will give you a floating-point value whose scale corresponds to the
   scale used by filter_cutoff. These match the expressions given further up
   for pan and subpan, but in this case, filter_subcutoff is unsigned.

   Note that filter_subcutoff will always be zero if filter_cutoff is 127, so
   you need not check it if you simply wish to determine whether filters are
   being applied.


*******************************
*** DUH Rendering Functions ***
*******************************


   Use these functions to generate samples from a DUH. First you call
   duh_start_sigrenderer() with the DUH, the number of channels you want and
   the position at which you want to start. Then you use duh_render() or
   duh_sigrenderer_get_samples() to generate the samples. You can call these
   functions as many times as you like, and they will generate as many or as
   few samples as you require. When you have finished, call
   duh_end_sigrenderer().


DUH_SIGRENDERER *duh_start_sigrenderer
                               (DUH *duh, int sig, int n_channels, long pos);

   Starts a DUH_SIGRENDERER off. This is the struct you can use to get
   samples from a DUH. This function does not generate any samples; you must
   pass the struct to duh_render() or duh_sigrenderer_get_samples() for that.
   When you have finished with it, you must pass it to duh_end_sigrenderer().
   You can use as many DUH_SIGRENDERER structs as you like at the same time.

   Set sig to 0 for now. Currently, n_channels can only be 1 or 2, for
   monaural and stereo sound respectively. The debugging library will cause
   your program to abort if you pass anything else. Future versions will be
   enhanced to support more channels as soon as someone needs them.

   When specifying the position, 0 represents the start of the DUH, and 65536
   represents one second. Unlike most other music systems, DUMB will always
   make sure every note is there right from the start (assuming you aren't
   using any broken add-ons). In other words, you can start a DUH at a point
   halfway through a long note, and you will still hear the long note.


void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer,
                     DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data);

   Installs a callback function which will be called every time the given
   sigrenderer is used to generate some samples. This can be used to create
   an oscilloscope or spectrum analyser. DUH_SIGRENDERER_ANALYSER_CALLBACK is
   defined as follows:

      typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data,
                const sample_t *const *samples, int n_channels, long length);

   If the above confuses you, see fnptr.txt. As for the 'samples' parameter,
   the first 'const' says that the samples are read-only; the second says
   that each channel's sample pointer is also read-only. If you don't
   understand this, don't worry about it.

   Beware: your callback function may occasionally be called with
   samples == NULL. This means the main program has decided to skip through
   the music without generating any data (see duh_sigrenderer_get_samples()).
   You should handle this case elegantly, typically by returning immediately,
   but you may wish to make a note of the fact that the music is being
   skipped, for whatever reason.

   Beware again: if the main program ever calls duh_sigrenderer_get_samples()
   on a buffer that isn't all silence, this callback function will be passed
   the existing buffer after mixing, and thus it will include the original
   data. This will not be an issue if you stick to duh_render(), which always
   starts with a buffer filled with silence.

   The samples array is two-dimensional. Refer to it as follows:

      samples[channel_number][sample_position]

   where 0 <= channel_number < n_channels,
     and 0 <= sample_position < length.

   In addition you can pass any 'data' pointer you like to
   duh_sigrenderer_set_analyser_callback(), and this pointer will be relayed
   to your callback function each time.

   To remove the callback function, pass NULL to
   duh_sigrenderer_set_analyser_callback().


int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer);

   Tells you how many channels a DUH_SIGRENDERER is set up to generate, or 0
   if it is invalid (perhaps owing to lack of memory). This will be 1 for
   monaural sound or 2 for stereo, in this release.


long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer);

   Tells you what position a DUH_SIGRENDERER is up to, or -1 if it is invalid
   (perhaps owing to lack of memory). As usual, 65536 is one second.


long duh_sigrenderer_get_samples(DUH_SIGRENDERER *sigrenderer,
                                 float volume, float delta,
                                 long size, sample_t **samples);

   Generates some samples in DUMB's internal 32-bit format (see sample_t; see
   also duh_render()). The samples buffer is a two-dimensional array, and can
   be allocated with create_sample_buffer(); see
   duh_sigrenderer_set_analyser_callback() for details.
   duh_sigrenderer_get_samples() mixes sample data with what's already in the
   buffer, so you have to call dumb_silence() first.

   The volume is a float. 1.0f is the pseudo-maximum. If you pass 1.0f, any
   properly designed DUH will play nice and loud, but will not clip. You can
   pass a greater volume if you like, but be prepared for the possibility of
   distortion due to integer overflow. Of course you can pass smaller values
   to play the DUH more quietly, and this will also resolve clipping issues
   in badly designed DUHs.

   Use delta to control the speed of the output signal. If you pass 1.0f, the
   resultant signal will be suitable for a 65536-Hz sampling rate (which
   isn't a commonly used rate). The most common sampling rates are 11025 Hz,
   22050 Hz, 44100 Hz and 48000 Hz. You can work out the required delta value
   as follows:

      delta = 65536.0f / sampling_rate;

   If you then increase this value, the DUH will speed up and increase in
   pitch. If you decrease it, the DUH will slow down and decrease in pitch.

   This function will attempt to render 'size' samples. In most cases it will
   succeed. However, if the end of the DUH is reached, it may render fewer.
   The number of samples rendered will be returned. Therefore, if the return
   value is less than the value of 'size' passed, you know the DUH has
   finished. It is safe to continue calling duh_sigrenderer_get_samples() if
   you wish, and it will continually return 0.

   If the DUH_SIGRENDERER is a null pointer, this function will generate
   precisely 0 samples. If you pass NULL for 'samples', the function will
   behave exactly the same as if you provided a sample buffer, except the
   samples won't be stored anywhere and the function will execute very
   quickly. This can be used to skip ahead in the audio.


long duh_render(DUH_SIGRENDERER *sigrenderer,
                int bits, int unsign,
                float volume, float delta,
                long size, void *sptr);

   Generates some samples and converts them to an 8-bit or 16-bit format (see
   also duh_sigrenderer_get_samples()). Pass the DUH_SIGRENDERER as returned
   by duh_start_sigrenderer(). Pass the number of bits, which should be 8 or
   16. If unsign is nonzero, the samples will be unsigned (centred on 0x80 or
   0x8000 for 8 bits and 16 bits respectively). If unsign is zero, the
   samples will be signed.

   Allegro's audio streams always take unsigned samples. 8-bit .wav files
   always take unsigned samples. 16-bit .wav files always take signed
   samples.

   The volume and delta parameters work the same as for
   duh_sigrenderer_get_samples().

   This function will attempt to render 'size' samples. In most cases it will
   succeed. However, if the end of the DUH is reached, it may render fewer.
   The number of samples rendered will be returned. Therefore, if the return
   value is less than the value of 'size' passed, you know the DUH has
   finished. It is safe to continue calling duh_render() if you wish, and it
   will continually return 0. However, if you wish to do this, you will
   probably have to fill the rest of the buffer with silence, which is 0 for
   signed, 0x80 for 8-bit unsigned or 0x8000 for 16-bit unsigned.

   The samples will be placed at sptr. Use an array of chars for 8 bits or an
   array of shorts for 16 bits. Stereo samples will be interleaved, left
   first. Your array should contain at least (size * n_channels) elements of
   the appropriate bit resolution.

   From an aesthetic standpoint if nothing else, it is wise to use the C
   qualifiers 'signed' or 'unsigned' depending on whether the samples are
   signed or unsigned. This is also convenient if you wish to process the
   samples further yourself.

   If the DUH_SIGRENDERER is a null pointer, this function will generate
   precisely 0 samples. Unlike with duh_sigrenderer_get_samples(), you must
   specify a sample buffer.


void duh_end_sigrenderer(DUH_SIGRENDERER *dr);

   Terminates a DUH_SIGRENDERER. Be sure to call this when you've finished
   with one. You can safely pass a null pointer.


********************************
*** Allegro Packfile Support ***
********************************


void dumb_register_packfiles(void);

   This function registers the Allegro PACKFILE input module for use by
   DUMBFILEs. PACKFILE structs and their corresponding functions, as defined
   by Allegro's header file allegro.h, will be used internally for all
   DUMBFILE input (unless opened with dumbfile_open_ex()).

   This must be called before dumbfile_open() is used, or else an alternative
   system must be registered (see register_dumbfile_system() and
   dumb_register_stdfiles()). Note that you don't have to call this function
   in order to load datafiles that contain music.


DUMBFILE *dumbfile_open_packfile(PACKFILE *p);

   If you have an Allegro PACKFILE struct representing an open file, you can
   call this if you wish to read from it using a DUMBFILE. This is useful
   when you need to pass a DUMBFILE struct to a library function, to read an
   embedded music file for example. When you close the DUMBFILE, you can
   continue using the PACKFILE struct to read what follows the embedded data.


DUMBFILE *dumbfile_from_packfile(PACKFILE *p);

   This function is the same as dumbfile_open_packfile(), except it will
   check if p is NULL, and arrange for pack_fclose() to be called on the
   PACKFILE when you close the DUMBFILE. It can be seen as a function for
   converting a PACKFILE to a DUMBFILE, but it will only work for a PACKFILE
   you obtained with pack_fopen(), not pack_fopen_chunk(). If this function
   fails, which may happen if memory is short, then the PACKFILE will be
   closed immediately, so you need not worry about potential memory leaks or
   files being left open when this happens.

   The following is typical usage, and will open the compressed file foo.bin:

      DUMBFILE *f = dumbfile_from_packfile(pack_fopen("foo.bin",
                                                      F_READ_PACKED));

   This differs from calling dumb_register_packfiles() and dumbfile_open() in
   that the latter will only read uncompressed files (and is thus a method
   suitable for reading music modules).


***********************************************
*** Allegro Datafile Registration Functions ***
***********************************************


void dumb_register_dat_it(long type);

   If you wish to embed an IT file in an Allegro datafile, it is recommended
   that you use "IT  " for the type. The grabber will have a box for the type
   when you insert a new object. The grabber will treat the IT file as binary
   data, which means the datafile will contain an exact copy of the IT file
   on disk.

   You must then call dumb_register_dat_it(DUMB_DAT_IT) in your program
   before you load the datafile. Once you've done this, you'll be able to
   access the DUH using the usual datafile[n].dat notation. You do not need
   to call unload_duh() on this DUH; unload_datafile() will do that for you.

   If you are using a different type for whatever reason, you can use
   Allegro's DAT_ID() macro for encoding it and passing it to this function.
   For example:

      dumb_register_dat_it(DAT_ID('B','L','A','H'));

   Assuming you used the recommended type, the following example iterates
   through all the ITs in disan.dat:

      DATAFILE *dat;
      int n;

      dumb_register_dat_it();
      dat = load_datafile("disan.dat");

      for (n = 0; dat[n].type != DAT_END; n++) {
         if (dat[n].type == DUMB_DAT_IT) {
            DUH *duh = dat[n].dat;
            /* Insert code here to play 'duh' or whatever you want to do. */
         }
      }

      unload_datafile(dat);


void dumb_register_dat_xm(long type);

   Inserting an XM file in an Allegro datafile is the same as inserting an IT
   file, except that the recommended type is "XM  ", the registration
   function is dumb_register_dat_xm(), and the macro DUMB_DAT_XM is provided
   for the type. The intuitive process of substituting XM for IT in the above
   method will work.


void dumb_register_dat_s3m(long type);

   Inserting an S3M file in an Allegro datafile is the same as inserting an
   IT file, except that the recommended type is "S3M ", the registration
   function is dumb_register_dat_s3m(), and the macro DUMB_DAT_S3M is
   provided for the type. The intuitive process of substituting S3M for IT in
   the above method will work.


void dumb_register_dat_mod(long type);

   Inserting a MOD file in an Allegro datafile is the same as inserting an IT
   file, except that the recommended type is "MOD ", the registration
   function is dumb_register_dat_mod(), and the macro DUMB_DAT_MOD is
   provided for the type. The intuitive process of substituting MOD for IT in
   the above method will work.


****************************************
*** Sample Buffer Allocation Helpers ***
****************************************


   Many parts of DUMB require sample buffers allocated in a special way. A
   pointer to one looks like this:

      sample_t **samples;

   and it can be indexed as follows:

      samples[channel_number][sample_position]

   where 0 <= channel_number < n_channels
     and 0 <= sample_position < length.

   The following helpers will allocate and deallocate such buffers for you.
   They will not initialise them, and DUMB always writes into these buffers
   by adding to what's already there, so you will generally have to call
   dumb_silence() too.


sample_t **create_sample_buffer(int n_channels, long length);

   This will allocate a sample buffer to hold the specified number of samples
   for the specified number of channels. Don't forget to check the return
   value!

   You will generally have to initialise the buffer by calling
   dumb_silence(); the channels will be stored consecutively in memory, so
   the following technique is officially supported:

      dumb_silence(samples[0], n_channels * length);

   See dumb_silence() for general information on what this function does.


void destroy_sample_buffer(sample_t **samples);

   This function does the obvious: it frees up a sample buffer when you've
   finished with it. It is safe to pass a null pointer to this function.


************************
*** Silencing Helper ***
************************


void dumb_silence(sample_t *samples, long length);

   This function simply stores 'length' samples' worth of silence in the
   array. It is typically used straight after allocating a sample buffer with
   create_sample_buffer().


**************************
*** Resampling Helpers ***
**************************


   Please forgive the odd section name; it has to do with DUMB's internal
   structure and the fact that the resampling algorithm is there not just for
   use in rendering module files but for use anywhere that a waveform needs
   resampling. Unfortunately DUMB's resampling algorithm is not ready to be
   documented and used yet. However, one thing can be documented, and that's
   the global variable controlling the resampling quality.

   (Ironically, even this variable has changed! See deprec.txt for
   information on what it used to do.)


int dumb_resampling_quality;

   Allows you to control the quality of all resampling that takes place. This
   may be set to any DUMB_RQ_* constant (except DUMB_RQ_N_LEVELS). Higher
   values will sound better, but lower values will use up less processor
   time. You may compare any two DUMB_RQ_* constants or values using the
   integer inequalities <, <=, > and >=; higher numbers represent higher-
   quality algorithms.

   #define DUMB_RQ_ALIASING

      |     --___         'Aliasing' has very noticeable and usually unwanted
      |__---     __       overtones. It will occasionally produce acceptable
      |            ___--  results for noisy (impure) samples (or for cheap
                          speakers!), but usually you will want to pay for
      the extra processor time, which isn't much, and go for linear
      interpolation.

   #define DUMB_RQ_LINEAR

      |  __          Linear interpolation is a pretty good algorithm in most
      | /  \  /\     cases. When resampling down a few octaves, however, you
      |/    \/  \__  may begin to notice unwanted high frequencies. You can
                     reduce these by switching to cubic interpolation, but it
      will cost you some processor time.

   #define DUMB_RQ_CUBIC

      Cubic interpolation looks like a smooth curve to the eye, and will
      produce good results in most cases. At present this is the highest
      quality offered by DUMB, and also the default. While this may seem
      extravagant, GCC 3.x and an AthlonXP handle it quite well - and the
      general trend is for processors to get better!

   #define DUMB_RQ_N_LEVELS

      This represents the number of resampling quality levels DUMB provides.
      Values of dumb_resampling_quality from 0 to DUMB_RQ_N_LEVELS - 1 are
      valid. You can use this constant if you wish to offer the resampling
      quality as an option for the user.


*************************************
*** Allegro DUH Playing Functions ***
*************************************


   The functions in this section allow you to play back a DUH through
   Allegro's sound system. You must call Allegro's install_sound() function
   before you use them.


AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos,
                            float volume, long bufsize, int freq);

   Starts playing the specified DUH.

   An AL_DUH_PLAYER represents one instance of the DUH playing. If you wish,
   you can have two or more AL_DUH_PLAYERs going at the same time, for the
   same DUH or for different ones. Each uses one of Allegro's audio streams
   and hence one voice. The voice will be given priority 255 initially, so a
   build-up of sound effects will not cause your music streams to cut off (as
   long as you don't give all your sound effects priority 255!). You can
   change the priority of a stream with al_duh_set_priority(). See Allegro's
   documentation for more information on how voice priorities work.

   At present, n_channels can either be 1 or 2 for monaural or stereo
   respectively. If you use the debugging library, your program will abort if
   other values are passed; otherwise weird things will happen.

   The DUH will start playing from position 'pos'. 0 represents the start of
   the DUH, and 65536 represents one second. Unlike other music systems, DUMB
   will always make sure every note is there right from the start. In other
   words, you can start a DUH at a point halfway through a long note, and you
   will still hear the long note.

   The volume is a float. 1.0f is the pseudo-maximum. If you pass 1.0f, any
   properly designed DUH file will play nice and loud, but will not clip. You
   can pass a greater volume if you like, but be prepared for clipping to
   occur. Of course you can pass smaller values to play the DUH more quietly,
   and this will also resolve clipping issues in badly designed DUH files.

   You will need to pass the AL_DUH_PLAYER to other functions when you need
   to stop or pause the DUH, change its volume, or otherwise modify the way
   it is playing. You will also need to pass it to al_poll_duh() at regular
   intervals; if the sound is choppy, try calling al_poll_duh() more often.

   'bufsize' is the number of samples that will be rendered at once. 1024 is
   a suitable value for most purposes. The greater this is, the less often
   you will have to call al_poll_duh() - but when al_poll_duh() decides to
   fill the buffer, it will take longer doing so. If your game exhibits
   regular brief freezes, try reducing the buffer size. If the sound is
   choppy, however, you may have to increase it.

   'freq' specifies the sampling frequency at which the DUH should be
   rendered. At present there is no (official and portable) way of knowing
   the frequency at which Allegro is mixing - but if you do know that
   frequency, passing it here will give the highest quality sound. If you
   reduce it, the DUH will sound less crisp but use less processor time.

   When you have finished, you must pass the AL_DUH_PLAYER to al_stop_duh()
   to free up memory. Do not destroy the DUH beforehand.

   There is no real need to check the return value from this function. The
   other functions can be called safely with null pointers, so if there is a
   problem, your music will simply not play.


void al_stop_duh(AL_DUH_PLAYER *dp);

   This will stop an AL_DUH_PLAYER. You must call this when you have finished
   with it, before destroying the DUH. The pointer will no longer be valid on
   return from this function.


void al_pause_duh(AL_DUH_PLAYER *dp);

   This will pause an AL_DUH_PLAYER. Use al_resume_duh() when you want it to
   continue. You can safely call al_poll_duh() while the music is paused, and
   it will do nothing.


void al_resume_duh(AL_DUH_PLAYER *dp);

   Causes a paused AL_DUH_PLAYER to resume playing (see al_pause_duh()).


void al_duh_set_priority(AL_DUH_PLAYER *dp, int priority);

   This will set the priority of the audio stream underlying an
   AL_DUH_PLAYER. The priority is an integer ranging from 0 to 255. When
   too many samples play at the same time, those with lower priorities will
   be cut. 128 is the usual default with Allegro, but DUMB overrides the
   default for all AL_DUH_PLAYER structs: they will be set up initially with
   priority 255, so your music won't be cut (unless you play too many other
   streams or samples with priority 255). See Allegro's documentation for
   more information on priorities.


void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume);

   This will set the volume of an AL_DUH_PLAYER. See al_start_duh() for
   details on the volume parameter.


int al_poll_duh(AL_DUH_PLAYER *dp);

   An AL_DUH_PLAYER is not interrupt-driven. That means it will not play by
   itself. You must keep it alive from your main program. Call this function
   at regular intervals. If the sound crackles, try calling it more often.
   (There is nothing you can do if Windows decides to play with the hard
   disk; that will make your sound crackle no matter what you do.)

   Normally this function will return zero. However, if it returns nonzero,
   that means the AL_DUH_PLAYER will not generate any more sound. Indeed the
   underlying audio stream and DUH_SIGRENDERER have been destroyed. When this
   happens, you can call al_stop_duh() whenever you wish - but you do not
   have to. Note that this function will wait two buffers' worth of samples
   before taking this action, allowing Allegro to mix the trailing sound
   before the audio stream is destroyed. This is an attempt to make sure your
   music does not get cut off prematurely, and it should work when using
   Allegro's mixer (the only option on DOS, the default on Linux as far as I
   know, but not the default on Windows). That said, if you immediately call
   Allegro's remove_sound() or exit your program, the music may get cut off.
   If you are using another mixer and experience problems, let me know (but I
   don't guarantee to be able to come up with an elegant solution, i.e. it
   might not get fixed).

   In case you were wondering, it is not safe on all platforms to call
   al_poll_duh() from an interrupt context (that means an Allegro timer
   handler). Not only is no part of DUMB locked in memory, but many parts of
   DUMB allocate and free their memory on a call-by-call basis! Remember that
   any disk access that occurs in interrupt context is likely to crash the
   machine; this is explained more fully in howto.txt. This limitation only
   applies to DOS at present, and is due to the fact that the DOS file access
   functions are not re-entrant.

   Multitasking systems are generally safe. If you are sure you don't want to
   target DOS, you can call al_poll_duh() from inside a timer handler, but I
   recommend including a construction like the following!

      #ifdef ALLEGRO_DOS
      #error calling al_poll_duh() from a timer handler will not work in DOS!
      #endif

   Furthermore, if you call al_poll_duh() from inside a timer handler, you
   must use a semaphore or other threading mechanism to make sure it is not
   executing when you call al_stop_duh(). If you don't know what a semaphore
   is, for Heaven's sake follow my advice and call al_poll_duh() from your
   main loop!


long al_duh_get_position(AL_DUH_PLAYER *dp);

   Tells you what position an AL_DUH_PLAYER is up to, or -1 if it is invalid
   (perhaps owing to lack of memory). As usual, 65536 is one second. Note
   that this is a whole number, whereas a fractional part is stored
   internally; the sample will not be continuous if you terminate the
   AL_DUH_PLAYER and then reinitiate it with the same position. Furthermore,
   note that Allegro will not have mixed in all the sound up to this point;
   if you wait for this to reach a certain position and then terminate the
   AL_DUH_PLAYER, the sound will cut off too early. Please contact me if you
   need to get around this.


AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer
        (DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq);

   If you have a DUH_SIGRENDERER, and would like to start playing music from
   it through an Allegro audio stream, use this function. Beware that it may
   return NULL, in which case you will have to call duh_end_sigrenderer()
   yourself instead of relying on the encapsulating AL_DUH_PLAYER to do it
   for you.


DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp);

   This returns the DUH_SIGRENDERER contained in an AL_DUH_PLAYER, useful for
   controlling playback, installing callbacks, etc.


DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp);

   This destroys an AL_DUH_PLAYER, but preserves the DUH_SIGRENDERER it
   contains, and returns it to you. You can then continue rendering samples
   from the DUH_SIGRENDERER and do whatever you like with them.


*********************
*** Thread Safety ***
*********************


The following points should pretty much sum up the essence of DUMB's thread
safety. If I haven't covered the one thing you'd like to do, please don't
hesitate to ask about it.

DOs:

- You may load and use multiple DUHs in separate threads.

- You may change dumb_resampling_quality and dumb_it_max_to_mix while another
  thread is generating samples.

DON'Ts:

- You may not generate samples from the same DUH in multiple threads, even if
  you are using separate DUH_RENDERERs (separate AL_DUH_PLAYERS).


******************
*** Conclusion ***
******************


"DUMB is the bestest music player in the world because ..."

Complete this sentence in fifteen words or fewer and receive a free copy of
DUMB! (Your Internet Service Provider may issue charges for your connection,
required for download of the Product. Your electricity supplier may issue
charges for the electricity consumed in writing the Product to a Permanent
Storage Device. You may have been charged for a Permanent Storage Device on
which to store the Product.)


Ben Davis
entheh@users.sf.net
IRC EFnet #dumb
See readme.txt for details on using IRC.