diff options
author | Alexey Yakovenko <wakeroid@gmail.com> | 2009-07-19 11:59:24 +0200 |
---|---|---|
committer | Alexey Yakovenko <wakeroid@gmail.com> | 2009-07-19 11:59:24 +0200 |
commit | b41446ad033a52ed24176f9ba01362e3648e97ee (patch) | |
tree | a16163dabd4af0434706f5abe2c2da4079c1b2c0 /dumb/dumb-0.9.3/docs | |
parent | 051a79c282355c72ea08c7598b7f4c1b58526e30 (diff) |
removed vanilla DUMB tree
Diffstat (limited to 'dumb/dumb-0.9.3/docs')
-rw-r--r-- | dumb/dumb-0.9.3/docs/deprec.txt | 311 | ||||
-rw-r--r-- | dumb/dumb-0.9.3/docs/dumb.txt | 1839 | ||||
-rw-r--r-- | dumb/dumb-0.9.3/docs/faq.txt | 286 | ||||
-rw-r--r-- | dumb/dumb-0.9.3/docs/fnptr.txt | 111 | ||||
-rw-r--r-- | dumb/dumb-0.9.3/docs/howto.txt | 864 | ||||
-rw-r--r-- | dumb/dumb-0.9.3/docs/modplug.txt | 155 | ||||
-rw-r--r-- | dumb/dumb-0.9.3/docs/ptr.txt | 127 |
7 files changed, 0 insertions, 3693 deletions
diff --git a/dumb/dumb-0.9.3/docs/deprec.txt b/dumb/dumb-0.9.3/docs/deprec.txt deleted file mode 100644 index 98961156..00000000 --- a/dumb/dumb-0.9.3/docs/deprec.txt +++ /dev/null @@ -1,311 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * deprec.txt - Deprecated functions, why they / / \ \ - * were deprecated, and what to do | < / \_ - * instead. | \/ /\ / - * \_ / > / - * | \ / / - * | ' / - * \__/ - */ - - -********************************************** -*** How the functions have been deprecated *** -********************************************** - - - GCC 3.1 and later provide a very useful attribute. The following: - - __attribute__((__deprecated__)) - - when written alongside a function prototype, variable declaration or type - definition, will result in a warning from GCC if any such part of the API - is used. The warning will even tell you where the declaration is, and I - have inserted comments by all the deprecated declarations, telling you - what to do. - - Unfortunately, GCC 2.x and 3.0.x and MSVC do not have any means to - deprecate things. The approach I have taken with these compilers is to - avoid prototyping the deprecated parts of the API. This means you will get - warnings and errors, and they won't be very helpful. If your program - compiles, you may get strange crashes when you run it, since the compiler - needs the declarations in order to make sure function calls are carried - out correctly. - - If you would like the deprecated parts of the API to be declared, you can - compile with the -DDUMB_DECLARE_DEPRECATED switch for GCC, or the - -D"DUMB_DECLARE_DEPRECATED" switch for MSVC. This will be accepted by - GCC 3.x but is unnecessary. Use this switch with other people's projects - if necessary, but please make the effort to update your own projects to - use the new API, as the deprecated parts may be removed in the future. - - The rest of this file explains why some parts of the API were deprecated, - and how to adapt your code. - - -************************************** -*** What happened to DUH_RENDERER? *** -************************************** - - - The DUH_RENDERER struct was designed for rendering audio to an end-user - format - 8-bit or 16-bit, signed or unsigned, with stereo samples - interleaved. In order for it to do this, it was built on top of the - hitherto undocumented DUH_SIGRENDERER struct, which rendered audio in - DUMB's internal 32-bit signed format with channels (left/right) stored - separately. The DUH_RENDERER struct contained a pointer to a - DUH_SIGRENDERER struct, along with some other data like the position and - number of channels. - - There were then some developments in the API. The DUH_SIGRENDERER struct - also stored the position and the number of channels, so I decided to write - functions for returning these. Suddenly there was no need to store them in - the DUH_RENDERER struct. Before long, the DUH_RENDERER struct contained - nothing but a pointer to a DUH_SIGRENDERER. - - I decided it would be a good idea to unify the structs. After all, there - really is no difference between the data stored in each, and it would be - easy to make duh_render(DUH_RENDERER *dr, ...) and - duh_render_signal(DUH_SIGRENDERER *sr, ...) work on the same type of - struct. (Note that duh_render_signal() is now deprecated too; see the next - section.) It took some deliberation, but I decided I didn't want functions - to be #defined (it prevents you from using these names for member - functions in C++ classes), and that meant they had to be defined - somewhere. Defining redundant functions is a source of bloat, inefficiency - and general inelegance. After weighing things up, I decided it was better - to deprecate the redundant functions and have people begin to use the more - efficient versions, and eventually the redundant functions will be able to - be removed. - - So why did I choose to keep the more complicated name, DUH_SIGRENDERER? - The reason has to do with what DUMB will become in the future. Signals are - an inherent part of the DUH struct and how .duh files will be constructed. - It will be possible to have multiple signals in a single DUH struct, and - you will be able to choose which one you want to play (this is the 'sig' - parameter passed to duh_start_sigrenderer()). But don't hold your breath; - we still have a long way to go before .duh files will start to appear... - - -typedef DUH_SIGRENDERER DUH_RENDERER; - - Wherever you are using DUH_RENDERER in your program, simply replace it - with DUH_SIGRENDERER. An automated (case-sensitive!) search and replace - operation should get this done. - - -DUH_RENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos); - - Use duh_start_sigrenderer() instead. It takes an extra parameter, 'sig', - which comes after 'duh' and before 'n_channels'; pass 0 for this. So an - example would be, replace: - - sr = duh_start_renderer(duh, 2, 0); - - with: - - sr = duh_start_sigrenderer(duh, 0, 2, 0); - - -int duh_renderer_get_n_channels(DUH_RENDERER *dr); -long duh_renderer_get_position(DUH_RENDERER *dr); -void duh_end_renderer(DUH_RENDERER *dr); - - These are easy enough to fix; all you have to do is replace 'renderer' - with 'sigrenderer'. So the new functions are: - - int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer); - long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer); - void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer); - - -Note that duh_render() has NOT been deprecated. It now uses DUH_SIGRENDERER -instead of DUH_RENDERER, but its functionality is unchanged. You do not have -to change calls to this function in any way. - - -DUH_RENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sr); -DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_RENDERER *dr); -DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_RENDERER *dr); - - These functions did not exist in the last release of DUMB, so you are - probably not using them, but they are included here for completeness. All - you have to do here is unwrap the function, since the structs have been - unified. So, for instance, replace: - - duh_renderer_encapsulate_sigrenderer(my_sigrenderer) - - with: - - my_sigrenderer - - Simple! - - -AL_DUH_PLAYER *al_duh_encapsulate_renderer(DUH_RENDERER *dr, - float volume, long bufsize, int freq); -DUH_RENDERER *al_duh_get_renderer(AL_DUH_PLAYER *dp); -DUH_RENDERER *al_duh_decompose_to_renderer(AL_DUH_PLAYER *dp); - - Again, these functions were not in the last release, so you probably - aren't using them. Nevertheless, the fix is simple as always: simply - replace 'renderer' with 'sigrenderer'. So the new functions are: - - AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer(DUH_SIGRENDERER *sr, - float volume, long bufsize, int freq); - DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp); - DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp); - - -********************* -*** Miscellaneous *** -********************* - - -sample_t **create_sample_buffer(int n_channels, long length); - -long duh_render_signal(DUH_SIGRENDERER *sigrenderer, - float volume, float delta, - long size, sample_t **samples); - -long duh_sigrenderer_get_samples(DUH_SIGRENDERER *sigrenderer, - float volume, float delta, - long size, sample_t **samples); - - These functions dealt with samples in DUMB's internal format, which - consists of 32-bit integers. For duh_render_signal(), the older of the two - rendering functions, the integers had a 'normal range' of -0x8000 to - 0x7FFF: any samples outside this range would have to be clipped when sent - to the sound card. For duh_sigrenderer_get_samples(), the range had - increased to -0x800000 to 0x7FFFFF, hence the new function was created and - the old turned into an inefficient wrapper and deprecated. - - Since then, another change has taken place: DUMB now interleaves left and - right samples when processing stereo data. This meant - create_sample_buffer() and duh_sigrenderer_get_samples() both had to be - deprecated, because if you were using them yourself, you were probably - processing the sample data. The functions still exist and will convert the - data into the right form for you, but they are inefficient. - - To update your code, first call allocate_sample_buffer() instead of - create_sample_buffer(), and then call duh_sigrenderer_generate_samples() - with the same arguments as whichever renderer function you were using - before. Be aware first that the range is -0x800000 to 0x7FFFFF, so you - will need to account for this if you were using duh_render_signal(). Then - change the way you index the samples. Whereas before you had to write - samples[channel][position], you now have to write - - samples[0][position] for mono (no change); - samples[0][position*2+channel] for stereo. - - The [0] is still there in anticipation of surround sound support: samples - will only ever be interleaved in twos, because each new interleaving - pattern results in more code duplication. - - destroy_sample_buffer() has not been deprecated, since it is compatible - with both the old and the new allocation functions. - - -typedef void (*DUH_SIGRENDERER_CALLBACK)(void *data, sample_t **samples, - int n_channels, long length); - -void duh_sigrenderer_set_callback(DUH_SIGRENDERER *sigrenderer, - DUH_SIGRENDERER_CALLBACK callback, void *data); - -typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK) - (void *data, sample_t **samples, - int n_channels, long length); - -void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer, - DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data); - - For the same reasons as explained above for create_sample_buffer() and - friends, these two functions (and corresponding typedefs) have had to be - deprecated. - - If you were using duh_sigrenderer_set_callback(), then be aware that it - was only intended to allow you to analyse the output, not modify it. For - this reason, the names were changed to DUH_SIGRENDERER_ANALYSER_CALLBACK - and duh_sigrenderer_set_analyser_callback(), and the 'samples' parameter - to your callback needed to be specified as follows: - - const sample_t *const *samples - - The first 'const' indicates that you must not modify the samples. The - second indicates that you must not modify the pointers to each channel. - - If you wanted to use this callback to apply a DSP effect, don't worry; - there is a better way of doing this. It is undocumented, so contact me - and I shall try to help. Contact details are at the bottom of this file. - - Having corrected that, follow the instructions under - create_sample_buffer() to update your code to handle the new sample - format. Then call duh_sigrenderer_set_sample_analyser_callback() instead - (note the addition of 'sample' to the name). - - If you try to call one of the old functions, it will print a message to - stderr directing you to this file, and it will not install the callback. - You shouldn't be able to get this far without a compiler warning (or, if - you don't have GCC 3.1 or later, some compiler errors). - - For reference, here are the new definitions: - - typedef void (*DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK)(void *data, - const sample_t *const *samples, int n_channels, long length); - - void duh_sigrenderer_set_sample_analyser_callback( - DUH_SIGRENDERER *sigrenderer, - DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data); - - -int dumb_resampling_quality; - - This variable has changed meaning. It used to hold a value from 0 to 4, - whose meaning was as follows: - - 0 - aliasing - 1,2 - linear interpolation - 3 - quadratic interpolation - 4 - cubic interpolation - - 0,1 - always use a straightforward interpolation algorithm - 2,3,4 - when decimating (increasing the pitch), use a linear average - algorithm designed to reduce frequencies that would otherwise - reflect off the Nyquist - - Now the variable only holds values from 0 to 2, and these values have - preprocessor constants associated with them. The somewhat inappropriate - quadratic interpolation has been removed. The linear average algorithm has - also been removed, and may or may not come back; there are probably more - efficient ways of achieving the same effect, which I shall be - investigating in the future. - - This change will have hardly any noticeable effect on existing programs. - Levels 2, 3 and 4 used considerably more processor time because of the - linear average algorithm. Likewise, Level 2 in the new scheme (cubic) uses - considerably more processor time than Levels 1 and 0, and Levels 3 and 4 - will behave identically to Level 2. - - -****************** -*** Conclusion *** -****************** - - -"I conclude that... DUMB is the bestest music player in the world because... -Complete this sentence in fifteen words or fewer... D'OH!" - -The preceding conclusion formerly appeared in dumb.txt, and is deprecated -because it's lame. - - -Ben Davis -entheh@users.sf.net diff --git a/dumb/dumb-0.9.3/docs/dumb.txt b/dumb/dumb-0.9.3/docs/dumb.txt deleted file mode 100644 index c8eda9b2..00000000 --- a/dumb/dumb-0.9.3/docs/dumb.txt +++ /dev/null @@ -1,1839 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/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". - - This was broken in DUMB v0.9 and earlier. - - -#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. - - This was broken in DUMB v0.9 and earlier, since it depends on - DUMB_VERSION_STR. - - -#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, and the STR4 and STR1 constants were broken in v0.9 and earlier. - - -#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 personal preference. 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, and this was broken anyway in v0.9 and earlier. - - -************************* -*** 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!) - - -const char *duh_get_tag(DUH *duh, const char *key); - - DUH structs can contain a number of 'tags'. You can retrieve a tag by - giving its key. At present, module files are set up with a single tag, - which you can retrieve by setting key to "TITLE" (case matters). The value - returned is the title of the module. - - You can retrieve other author information from the module by calling - duh_get_it_sigdata() and then using the dumb_it_sd_*() functions. See the - descriptions of the relevant functions for the maximum length of the title - for each format and some comments on non-ASCII characters. - - -*********************************** -*** 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); - - Module files contain a set of patterns, numbered from zero, but they are - not necessarily played in order. Some patterns may be repeated, and some - may be left out altogether. When a module is played, the player runs - through a sequence of pattern numbers stored in the file, playing the - corresponding pattern for each number. Each entry in the sequence is - called an 'order', and the orders are numbered from from zero. - - 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 to seek - to a specific time in the music, as if you have recorded it and are - starting playback in the middle, then use 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); -DUH *dumb_load_xm(const char *filename); -DUH *dumb_load_s3m(const char *filename); -DUH *dumb_load_mod(const char *filename); - - These load the specified Impulse Tracker, Fast Tracker II, Scream Tracker - 3 or 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. - - These functions call dumb_it_do_initial_runthrough(), which takes time and - memory but means the playback time is known and fast seeking is possible. - See dumb_it_do_initial_runthrough() for more information. If you do not - need this functionality, consider calling the *_quick() equivalents of - these functions instead. - - -DUH *dumb_read_it(DUMBFILE *f); -DUH *dumb_read_xm(DUMBFILE *f); -DUH *dumb_read_s3m(DUMBFILE *f); -DUH *dumb_read_mod(DUMBFILE *f); - - These read an Impulse Tracker, Fast Tracker II, Scream Tracker 3 or Amiga - module file from an already open DUMBFILE. They leave the DUMBFILE open, - but the DUMBFILE may not be positioned at the end of the data. If you are - embedding a module in another file, you are advised to store the size of - the module file and make up for it at the end using dumbfile_pos(). - - Otherwise, these functions are identical to dumb_load_*(), and have - *_quick() equivalents. - - WARNING: The behaviour of these functions are undefined if you pass a - DUMBFILE from which data have already been read; they are likely - not to work. This oversight will be fixed in future releases. - - -DUH *dumb_load_it_quick(const char *filename); -DUH *dumb_load_xm_quick(const char *filename); -DUH *dumb_load_s3m_quick(const char *filename); -DUH *dumb_load_mod_quick(const char *filename); -DUH *dumb_read_it_quick(DUMBFILE *f); -DUH *dumb_read_xm_quick(DUMBFILE *f); -DUH *dumb_read_s3m_quick(DUMBFILE *f); -DUH *dumb_read_mod_quick(DUMBFILE *f); - - These functions are identical to the versions without the _quick suffix, - except they omit the initial run-through. They execute faster and the - resultant DUH structs use less memory. However, seeking by time is slower - (seeking with dumb_it_start_at_order() is unaffected), and the length is - unknown and returned as -1. - - -void dumb_it_do_initial_runthrough(DUH *duh); - - This runs through the module represented by the DUH and stores a copy of - the playback state at 30-second intervals. It stops when it first - encounters a jump to an earlier pattern or a MOD/XM speed zero effect, at - which point it adds to the DUH struct the length of time for which the - module plays. The playback state images enable DUMB to seek more quickly - when you pass a nonzero time to al_start_duh() or duh_start_sigrenderer(). - Note that dumb_it_start_at_order() is unaffected and always executes fast. - - This is called automatically by some of the loading functions, so you will - not normally need to call it. If you do decide to call it yourself, be - aware that it cannot execute concurrently with playback. This will be - addressed in the future. - - This function does nothing if the parameter is NULL or does not represent - a module. - - -long dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata); - - This is the functionality of dumb_it_do_initial_runthrough() detached from - the DUH struct. It does the same thing, but the length is returned. The - function does nothing if sigdata is NULL. - - -const unsigned char *dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd); - - This function retrieves the song message from an IT file, if it was - present and there was sufficient memory to load it. Otherwise it returns - NULL. XM, S3M and MOD files never contain song messages as such, although - there is often a message embedded in the sample and instrument names. - - According to Impulse Tracker's documentation, the message uses CR - characters ('\r', ASCII code 13) for line breaks and is null-terminated. - DUMB adds a NUL to the end just in case. You can therefore use strlen() - and otherwise treat the return value as a normal C string. - - When interpreting the message, bear in mind that Impulse Tracker is a DOS - program, and extended ASCII from the DOS days does not match the usual - character encodings on modern systems. If you find characters outside the - range 32 to 126 (and not '\r'), you may need to convert in some way for - display. - - If anyone knows how to map DOS extended ASCII to Unicode, please feel free - to write an explanation for me to include here. Credit will be given! - - Impulse Tracker's message editor generally restricts lines to 74 - characters plus the CR, although it is possible to create a 75-character- - long line with no spaces. The documentation says the message may be up to - 8000 bytes long. Other IT-compatible trackers may not impose these - restrictions. - - -int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd); - - This function returns the number of orders in the module. See - dumb_it_start_at_order() for an explanation of orders. - - -int dumb_it_sd_get_n_samples(DUMB_IT_SIGDATA *sd); -int dumb_it_sd_get_n_instruments(DUMB_IT_SIGDATA *sd); - - These functions respectively return the number of samples and the number - of instruments in the module. Note that MOD and S3M files don't support - instruments, and instruments are optional in IT files. - dumb_it_sd_get_n_instruments() will return 0 for modules that only use - samples. - - -const unsigned char *dumb_it_sd_get_sample_name(DUMB_IT_SIGDATA *sd, int i); -const unsigned char *dumb_it_sd_get_sample_filename - (DUMB_IT_SIGDATA *sd, int i); -const unsigned char *dumb_it_sd_get_instrument_name - (DUMB_IT_SIGDATA *sd, int i); -const unsigned char *dumb_it_sd_get_instrument_filename - (DUMB_IT_SIGDATA *sd, int i); - - The trackers allow the author to set a name and sometimes also a file name - for each sample and each instrument. These functions allow you to retrieve - the names. The samples and instruments are numbered from 0 for the - purposes of these functions, and you can determine how many are available - using dumb_it_sd_get_n_samples() and dumb_it_sd_get_n_instruments(). - - Very often, displaying the names in order will produce a message from the - author. These functions will always return something, but if the field - does not exist, the result will be an empty string. The return value is - null-terminated. - - The comments under dumb_it_sd_get_song_message() about code pages applies, - except not all modules were created in DOS; the original MOD files were - born on the Amiga, and many files were transferred from there. If anyone - knows about the characters available on the Amiga, please get in touch so - I can add the information here. Credit will be given! - - The table to the right Field | MOD | S3M | XM | IT - specifies the maximum ----------------------+-----+-----+-----+----- - length of each field for Song title | 20 | 28 | 20 | 26 - each format, or '-' if Sample name | 22 | 28 | 22 | 26 - the field does not exist. Sample file name | - | 13 | - | 13 - Instrument name | - | - | 22 | 26 - Instrument file name | - | - | - | 13 - - -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. - - -int dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel); -void dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel, - int muted); - - These functions obtain or set the flag indicating whether each channel is - muted. Modules cannot override this during playback, although some formats - can make some channels muted initially. - - -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_generate_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_generate_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_generate_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_sample_analyser_callback( - DUH_SIGRENDERER *sigrenderer, - DUH_SIGRENDERER_SAMPLE_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_SAMPLE_ANALYSER_CALLBACK is defined as follows: - - typedef void (*DUH_SIGRENDERER_SAMPLE_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 buffer'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_generate_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_generate_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. It consists of zero or more - interleaved stereo sample buffers, possibly followed by one monaural - buffer. You can access the samples as follows: - - n_channels == 1: samples[0][sample_position] - n_channels == 2: samples[0][sample_position*2+channel_number] - n_channels > 2: - channel_number < n_channels & ~1: - samples[channel_number>>1][sample_position*2+(channel_number&1)] - channel_number == n_channels & ~1: - samples[channel_number>>1][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_sample_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_sample_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_generate_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 allocate_sample_buffer(); see - duh_sigrenderer_set_sample_analyser_callback() for details. - duh_sigrenderer_generate_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_generate_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. - - -void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, - float volume, sample_t *samples); - - This generates one sample (or two for a stereo DUH_SIGRENDERER) and stores - them in the array passed in. It does not update the state (with the - exception of potentially having to initialise playback). It is used for - click removal. - - -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_generate_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_generate_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, where n_channels distinguishes between - mono and stereo and was passed in when the DUH_SIGRENDERER was - constructed. - - 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_generate_samples(), you - must specify a sample buffer for the output. (If you don't need any - output, call duh_sigrenderer_generate_samples() instead.) - - -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); -void dumb_register_dat_it_quick(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) or - dumb_register_dat_it_quick(DUMB_DAT_IT) in your program, before you load - the datafile. If 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. - - The *_quick() version will cause the initial run-through to be skipped, - speeding up loading. See dumb_load_it() for an explanation. - - 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); -void dumb_register_dat_xm_quick(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 - functions are dumb_register_dat_xm() and dumb_register_dat_xm_quick(), 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); -void dumb_register_dat_s3m_quick(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 - functions are dumb_register_dat_s3m() and dumb_register_dat_s3m_quick(), - 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); -void dumb_register_dat_mod_quick(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 - functions are dumb_register_dat_mod() and dumb_register_dat_mod_quick(), - 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; - - This is effectively a two-dimensional array. It consists of zero or more - interleaved stereo sample buffers, possibly followed by one monaural - buffer. You can access the samples as follows: - - n_channels == 1: samples[0][sample_position] - n_channels == 2: samples[0][sample_position*2+channel_number] - n_channels > 2: - channel_number < n_channels & ~1: - samples[channel_number>>1][sample_position*2+(channel_number&1)] - channel_number == n_channels & ~1: - samples[channel_number>>1][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 **allocate_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 buffers will be stored consecutively in memory, so - the following technique will work and 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 - allocate_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. - - -float al_duh_get_volume(AL_DUH_PLAYER *dp); -void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume); - - These functions get and set the volume of an AL_DUH_PLAYER. See - al_start_duh() for details on the volume parameter. DUMB will always leave - the audio stream volume at maximum and use its own volume control, since - it is more accurate and the click remover will handle changes to the - volume. - - -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_SIGRENDERERs (or separate AL_DUH_PLAYERS). - -- You may not load two IT files concurrently (the sample decompression - algorithm has some static state). - - -****************** -*** 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. If you are in Canada, the Blank Media Levy is -non-refundable, although this is irrelevant since the rate is zero for -computer storage devices. I shall not be held accountable for inaccuracies in -the preceding text.) - - -Ben Davis -entheh@users.sf.net diff --git a/dumb/dumb-0.9.3/docs/faq.txt b/dumb/dumb-0.9.3/docs/faq.txt deleted file mode 100644 index 37355677..00000000 --- a/dumb/dumb-0.9.3/docs/faq.txt +++ /dev/null @@ -1,286 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * faq.txt - Frequently Asked Questions. / / \ \ - * | < / \_ - * This file covers some of the common problems | \/ /\ / - * and misconceptions people have with DUMB. If \_ / > / - * your problem is not covered here, please | \ / / - * contact me and I'll do my best to help. | ' / - * \__/ - */ - - -***************************************************************************** -* I get a lot of strange warnings and errors when I compile my projects * -* with this release of DUMB. They work with older versions! What happened? * -***************************************************************************** - - Some parts of DUMB's API have been deprecated. See docs/deprec.txt for - full details, including an explanation as to why your compiler warnings - and errors are so unfriendly, and information on how to fix each warning - or error. - - -***************************************************************************** -* When I try to compile DUMB with Allegro, it complains that it cannot find * -* 'internal/alconfig.h'! What's wrong? * -***************************************************************************** - - In Allegro 4.0.1, and quite likely some other versions of Allegro, the - msvcmake batch file does not install Allegro properly. I believe this was - fixed in Allegro 4.0.2, but don't take my word for it. Some include files - are neglected, including alconfig.h. The fix is quite easy; you need to - copy all of Allegro's include files to your compiler's directory. The - following should do this for you (alter it accordingly depending on where - MSVC and Allegro are installed): - - cd\progra~1\msvc\include - xcopy/s \allegro\include\*.* - - You can safely tell it to overwrite all files. - - -***************************************************************************** -* When I build a project that uses DUMB, I get an error that it doesn't * -* find -laldmbd! What's wrong? * -***************************************************************************** - - See the notes for DUMB v0.8 in release.txt; the existence of libaldmbd.a - in DUMB v0.7 was due to a mistake in the makefiles. It should be - libaldmd.a, in order to maintain DOS compatibility. All subsequent - releases get it right, but you will have to change your project files to - allow for the change. If this is someone else's project, please let them - know that it needs changing. - - -***************************************************************************** -* When I build a project that uses DUMB, I get some linker errors about * -* _free, _malloc, etc. already being defined in LIBC.lib! What's wrong? * -***************************************************************************** - - MSVC offers three different implementations of the standard libraries. - When you link statically with a library, you have to use the same - implementation that the library uses. You need the multithreaded DLL - implementation, which you can select by passing /MD when you compile (not - when you link). See howto.txt for details. - - -***************************************************************************** -* I created an IT file with Impulse Tracker, but DUMB won't play it! Why? * -***************************************************************************** - - You probably created some patterns but didn't give any information on the - order in which they should be played. Impulse Tracker will also fail to - play your music if you press F5. Press F11 and you will have an - opportunity to create an order list, required for playback. - - -***************************************************************************** -* I created an IT file with ModPlug Tracker and I have it fading out at the * -* end. Why won't it loop when I play it with DUMB? * -***************************************************************************** - - It loops at zero volume. This is what Impulse Tracker itself does. Fix the - IT file by setting the global volume explicitly (Vxx in the effects - column), either at the start, or right at the end before looping. Also see - the next two questions. - - -***************************************************************************** -* My module plays too loud and distorts badly with DUMB! What can I do? * -***************************************************************************** - - This problem is most often caused by ModPlug Tracker, which has a complete - lack of regard for the playback volume of the original tracker. See the - next question for DUMB's official position with regard to ModPlug Tracker. - If you wrote your module with ModPlug Tracker, please try loading it with - the original tracker and see if it distorts there too. If it does, reduce - the volume. If not, then it's a problem with DUMB; please let me know. - - If for whatever reason you cannot modify the module file itself, you can - make it sound better by reducing the volume passed to al_start_duh(). Try - halving or quartering the value; search for a level at which the - distortion goes away. - - -***************************************************************************** -* I created a music module with ModPlug Tracker, and DUMB doesn't play it * -* right! * -***************************************************************************** - - ModPlug Tracker differs from the original trackers in several ways, which - means modules written in one will not always play correctly or even load - in the other. DUMB's first loyalty is to the original trackers, which are - listed in readme.txt. This means it will have to differ from ModPlug - Tracker in several ways. For more information, please see - docs/modplug.txt. - - If you find DUMB plays your module differently from the original tracker - for the format you are using, then please contact me. - - -***************************************************************************** -* My program crashes as soon as I try to load anything with DUMB! * -***************************************************************************** - - Please take my advice and use the debugging build of DUMB, not the - optimised build. Then you'll probably find it aborts instead of crashing. - In this case you probably forgot to register a DUMBFILE system; this is - necessary for loading stand-alone files, though not for loading Allegro - datafiles with embedded music. Follow the instructions in docs/howto.txt - carefully and you shouldn't have this problem. - - The system is designed this way to make sure you can exclude code you are - not using. If DUMB set you up for standard file access by default, then - the standard library code for accessing files would get pulled in even if - you never used it. This is especially important for dedicated systems that - have limited standard libraries. - - If DUMB crashes with a specific music module, please let me know. - - -***************************************************************************** -* I want to use the stdio file access functions to load stand-alone music * -* files, but I also want to load datafiles containing music files. The docs * -* say I shouldn't call both dumb_register_stdfiles() and * -* dumb_register_packfiles(). What shall I do? * -***************************************************************************** - - When you register a DUMBFILE system, it only applies to files opened with - dumbfile_open(), i.e. separate files. When a file is embedded in a - datafile, dumbfile_open_ex() is used to read it, enabling it to use - PACKFILEs regardless of which DUMBFILE system is registered. In short, you - do not need to call dumb_register_packfiles() in order to load datafiles - with embedded music. See the section on "Sequential File Input" in - docs/dumb.txt if you're interested in how all this works. - - -***************************************************************************** -* I want to read a specific object in a datafile using Allegro's * -* "demo.dat#MY_MUSIC" syntax. Why won't it work? * -***************************************************************************** - - Did you call dumb_register_packfiles(), or did you call - dumb_register_stdfiles()? It will only work if you use the former. - - -***************************************************************************** -* My program runs, but no music plays! What am I doing wrong? * -***************************************************************************** - - There are a number of possible causes for this. The most likely reason is - that you aren't calling al_poll_duh(); see docs/howto.txt for further - information. - - Other possible causes are as follows: - - - The speakers are turned down (duh); - - The volume of some system mixer is turned down; - - Another program is using the sound card (not a problem for most modern - systems); - - You didn't initialise Allegro's sound system; see install_sound() in - Allegro's docs; - - Allegro's drivers don't work on your system and chosen platform. - - In order to narrow down the cause, consider the following: - - - Do you get any other sound from your program? - - Do other Allegro+DUMB programs generate sound? - - Do other Allegro programs generate sound? - - Do other non-Allegro programs generate sound? - - Does your program fail only on a specific platform (e.g. DOS but not - Windows)? - - This problem is highly system-specific; please try hard to solve it by - yourself before contacting me. However, if you think this problem could - affect other people, please let me know what the problem is and how you - fixed it, if you did. Be as specific as possible. - - -***************************************************************************** -* The music stutters! What can I do? * -***************************************************************************** - - If you have an older computer, it may not be able to cope with the load. - Try reducing quality options; look up dumb_resampling_quality and - dumb_it_max_to_mix in docs/dumb.txt, and consider changing the frequency - you pass to al_start_duh(). - - Stuttering may not be caused by excessive load. To find out, try - increasing the buffer size passed to al_start_duh(). Beware of making it - too big though; older systems will freeze periodically if it's too big, - because they render larger chunks less frequently. The timing of callbacks - will also be less accurate, if you are using those. - - If you're using the 'dumbplay' example, you can control these parameters - by editing dumb.ini. - - -***************************************************************************** -* Why does DUMB use so much processor time compared with other players? * -***************************************************************************** - - It doesn't! It is now on a par with the ModPlug rendering engine (tested - using ModPlugXMMS with reverb, surround and other such effects disabled). - Previous releases were less than optimal, but DUMB's resampling algorithm - was - and still is - one of a kind. Take a look at the code. Come on, I - dare ya. - - All that said, you can reduce the amount of processor time DUMB uses by - reducing the quality. - - By default, DUMB uses the most expensive resampling quality option. I've - found on an AthlonXP 1800+ and on a Pentium 233 that it typically uses - about twice as much processor time as the least expensive option. - - Try setting dumb_resampling_quality to DUMB_RQ_ALIASING or DUMB_RQ_LINEAR. - See dumb.txt for more information. If you're using the example programs, - you can control this variable by editing dumb.ini. - - DUMB uses 32-bit ints for mixing. Some players use 16-bit ints, and are - therefore marginally faster (not much!) and lower quality. So you can't - expect DUMB to beat these players. Furthermore, DUMB is currently written - entirely in C. GCC does an impressive job on the C code, but that's not to - say some custom-written assembly language couldn't beat it ... - - -***************************************************************************** -* Why does DUMB generate so much background noise? * -***************************************************************************** - - You're probably using the DOS build on a system with bad Sound Blaster - compatibility (most Windows XP systems fall in this category). This would - mean DUMB could only access an 8-bit driver. The Windows build will almost - certainly give better results. Your DOS binary will still give good - results on systems with better compatibility (like my Windows 98 system). - - -***************************************************************************** -* I e-mailed you and you replied with "RTFM"! What does that mean? * -***************************************************************************** - - It means Read The Manual. I would only say this to someone who has clearly - not even tried reading the documentation. So if you are reading this FAQ - entry, you have too much time on your hands! - - -***************************************************************************** -* What happened to DUMB's IRC channel? * -***************************************************************************** - - It has been discontinued. It wasn't used very much, and it only really - works if I'm there at the same time as someone wants to chat. For most - problems, e-mail is much more effective. However, if you would like to - chat about something, please do e-mail me and we'll arrange it. - - -Ben Davis -entheh@users.sf.net diff --git a/dumb/dumb-0.9.3/docs/fnptr.txt b/dumb/dumb-0.9.3/docs/fnptr.txt deleted file mode 100644 index a902e193..00000000 --- a/dumb/dumb-0.9.3/docs/fnptr.txt +++ /dev/null @@ -1,111 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * fnptr.txt - Function pointer explanation. / / \ \ - * | < / \_ - * | \/ /\ / - * \_ / > / - * | \ / / - * | ' / - * \__/ - */ - - -C allows you to create and use function pointers. A function pointer is a -variable that points to a function, and you can use it to call that function. -Why is this useful? - -Function pointers can be passed as parameters. As an example, here's a -function from Allegro: - - void create_light_table(COLOR_MAP *table, const PALETTE pal, int r, g, b, - void (*callback)(int pos)); - -Don't worry about the syntax just yet, but the last parameter, 'callback', is -a pointer to a function that takes an int parameter. create_light_table() can -take some time to complete its work, and you may want to display a progress -indicator. So you write a function to draw the progress indicator, and then, -for 'callback', you specify a pointer to your function. This will enable -create_light_table() to call your function at intervals during its -processing. (If you don't want to use the callback, you can pass NULL, but -this only works because create_light_table() checks actively for NULL. You -can't always specify NULL when you want nothing to happen.) - -There are many other uses. In addition to using function pointers as -parameters, Allegro has some global function pointers you can set to point to -your functions. Function pointers can also be used in structs, and this is -where DUMB makes the most use of them. - -So how are they used? - - void bar(void) { ... } /* Here's a function */ - void (*foo)(void) = &bar; /* Take a pointer */ - (*foo)(); /* Call the function */ - - char *baz(float a) { ... } /* Here's another function */ - char *(*foobarbaz)(float a) = &baz; /* Take a pointer */ - char *rv = (*foobarbaz)(0.1); /* Call the function */ - -In both these cases, note how the statement for calling the pointed-to -function (third line) resembles the definition of the function pointer -(second line). This is true of any variable in C, and can lead to some truly -obfuscated definitions if you are that way inclined. Such definitions can be -clarified with typedefs, but before you use those, it is important you -understand how the above statements work. I speak from experience: function -pointer notation looks random and scary, until you understand why it's the -way it is; then it makes perfect sense. - -(It is actually permissible to omit the & when taking a pointer and to write -e.g. foobarbaz(0.1) instead of (*foobarbaz)(0.1). However, I recommend not -doing this, since the syntax for using the pointer no longer resembles the -definition. Writing e.g. (*foobarbaz)(0.1) also makes a clear distinction -between function pointer calls and ordinary function calls, which makes code -more readable.) - -Note that function pointers have the return value and parameter list -specified. A function pointer can only point to a function with a matching -return value and matching parameters. (You can break this rule by casting the -pointer explicitly, but there is no situation where doing so is portable to -all computers, and I strongly advise against it unless you're writing system -code. If you're not sure whether you're writing system code or not, then -you're not.) - -The parameter names need not match (although the types must). If you wish to -rename a parameter in your function, you do not have to change the function -pointer accordingly. In fact, when you define a function pointer, you don't -even have to specify the names of parameters if you don't want to. I normally -do so for clarity. - -It is possible to typedef a function pointer. In order to typedef a function -pointer, you start by declaring the pointer as a variable: - - void (*myfunc)(void); - -Then you write 'typedef' before it and replace the variable name, which is -myfunc, with the type name (this rule can be applied to any variable when you -want to use typedef): - - typedef void (*MYTYPE)(void); - -Now 'MYTYPE' represents a pointer to a function with no parameters and no -return value. The following two lines are completely equivalent: - - MYTYPE myfunc; - void (*myfunc)(void); - -Note that we use MYTYPE without an asterisk (*), since it is already a -pointer. - -That's it. If you feel anything should be explained better here, or if you -feel something should be added, please don't hesitate to let me know! - - -Ben Davis -entheh@users.sf.net diff --git a/dumb/dumb-0.9.3/docs/howto.txt b/dumb/dumb-0.9.3/docs/howto.txt deleted file mode 100644 index b9d1a1b2..00000000 --- a/dumb/dumb-0.9.3/docs/howto.txt +++ /dev/null @@ -1,864 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * howto.txt - How To Use DUMB. / / \ \ - * | < / \_ - * See readme.txt for general information on | \/ /\ / - * DUMB and how to set it up. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - - -******************** -*** Introduction *** -******************** - - -Welcome to the DUMB How-To! It is assumed here that you have already set DUMB -up on your system, with or without Allegro. If not, please see readme.txt. - - -********************************* -*** Adding music to your game *** -********************************* - - -These instructions will help you add a piece of music to your game, assuming -your music is stored in a stand-alone IT, XM, S3M or MOD file. If you wish to -use a different method (such as putting the music file in an Allegro -datafile), please follow these instructions first, test your program, and -then follow the instructions further down for adapting your code. - - -1. You need to include DUMB's header file. If you have Allegro, add the - following line to the top of your source file (or at the top of each file - where you wish to use DUMB): - - #include <aldumb.h> - - If you do not have Allegro or do not wish to use it, use dumb.h instead. - - -2. You need to link with DUMB's library file or files. If you are compiling - with GCC from a command line on any platform, you need to add the - following to the command line: - - If you are using Allegro: -laldmd -ldumbd - If you are not using Allegro: -ldumbd - - If you are using MSVC from the command line: - - If you are using Allegro: /link aldmd.lib dumbd.lib - If you are not using Allegro: /link dumbd.lib - - With MSVC, you must also add /MD to the command line when compiling (not - when linking). - - Note that -laldmd or aldmd.lib must PRECEDE alleg.lib, -lalleg_s, - `allegro-config --libs`, or whatever you are already using to link with - Allegro. For MSVC users, the /MD flag selects the multithreaded DLL - implementation of the standard libraries; since DUMB is statically linked, - you have to use the same library DUMB uses. You would also need this flag - to link statically with Allegro; if you already have it, there's no need - to put it twice. - - (If anyone would like to contribute instructions for doing the above using - MSVC's IDE, please contact me. Contact details are at the end of this - file.) - - If you are using RHIDE, go to Options -> Libraries. You will need to type - 'aldmd' and 'dumbd' in two boxes, making sure 'aldmd' comes above whatever - you are using to link with Allegro (or just put 'dumbd' if you are not - using Allegro). Make sure the box next to each of these libraries is - checked. - - The above are the debugging libraries. It is VERY HIGHLY RECOMMENDED that - you use the debugging libraries at first. The reason is as follows. - Although DUMB is supposedly robust against corrupt music files and things - like lack of memory, it will NOT tolerate programmer error. If you write - faulty code, DUMB will probably crash rather than returning an error code - for you. However, the debugging libraries will abort in many cases, - enabling you to find out what the cause is. - - Once your program is up and running reliably, you can replace 'aldmd' with - 'aldmb' and 'dumbd' with 'dumb'. Don't forget to do this, or DUMB will be - a lot slower than it should be! - - -3. As you use DUMB, it may claim system resources (memory in particular). You - will need to arrange for these resources to be freed at the end. Doing so - is very easy. Simply write the following line at the top of your main - function, but below allegro_init() if you are using Allegro: - - atexit(&dumb_exit); - - This arranges for the function dumb_exit() to be called when your program - exits; you do not need to call dumb_exit() yourself. This method is - preferable to calling dumb_exit() manually, as it will free resources even - if your program aborts unexpectedly. - - If you are happy with this, please skip ahead to Step 4. If you are - interested in alternative methods, read on, but read on carefully. - - In fact it mostly doesn't matter where you put the above atexit() line, - provided it gets called only once, and before you do anything with DUMB. - If you are using DUMB with Allegro, it is recommended that you write the - functions in this order: - - allegro_init(); - atexit(&dumb_exit); - - And then you must NOT call allegro_exit() yourself (because it has to be - called after dumb_exit()). Alternatively, if you prefer not to use - atexit() (or you cannot), you will have to do the following before - exiting: - - dumb_exit(); - allegro_exit(); - - -4. DUMB does not automatically know how to open files. If you are loading - stand-alone files, you have to tell it how to open them. Don't worry, it's - easy. Simply call the following function near the beginning of your - program, after your atexit() call: - - dumb_register_stdfiles(); - - Once you've done this, a stdio FILE will be opened each time DUMB wants to - open a file (specifically, when dumbfile_open() is called). If you are - using Allegro and would rather DUMB used PACKFILEs, call the following - function instead: - - dumb_register_packfiles(); - - In the latter case, DUMB will be affected by any password you set with - packfile_password() in the same way that other PACKFILEs are. - - Note that the procedure for loading datafiles with embedded music is - independent of these two functions; even if you will be loading datafiles, - you can use either of these functions. dumb_register_stdfiles() will - probably be faster. If you are only ever going to load datafiles and never - stand-alone files, you can actually leave this step out; but I would - recommend you put this in, test your code with a stand-alone file, then - follow the instructions in the next section in order to adapt your code to - use the datafile (the instructions will remind you that you can remove the - function call). - - -5. If you are using Allegro, you will have to initialise Allegro's sound - system. In most cases the following line will do the job: - - install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL); - - Put this line after allegro_init(). See Allegro's documentation if you - want to initialise a MIDI driver too. - - -6. All pieces of music are stored in memory in DUH structs. To handle these, - you must define pointers to them. Such pointers look like this: - - DUH *myduh; - - You can of course replace 'myduh' with anything you like. If you are - unfamiliar with pointers, please see ptr.txt. It is very important that - you understand these if you wish to use DUMB correctly. - - You do not have direct access to the contents of a DUH struct, because - they are liable to change. It is hoped that DUMB's functions will provide - everything you need; if you need something else, please let me know and I - shall see what I can do. Contact details are at the end of this file. - - Given the above definition, you can load a piece of music using one of the - following lines, depending on what file format you want to load: - - myduh = dumb_load_it_quick("a_one.it"); - myduh = dumb_load_xm_quick("a_two.xm"); - myduh = dumb_load_s3m_quick("a_one_two.s3m"); - myduh = dumb_load_mod_quick("three_four.mod"); - - You can use relative or absolute paths as normal. You should always use - forward slash (/), not backslash (\), when coding in C and similar - languages. - - There are non-"quick" versions of the functions too; for information on - what this means, please see dumb.txt. - - Every piece of music you load must be unloaded when you've finished with - it. When you type the above line in, it is good practice to type the - following line in at the same time, but put it at the end of the program: - - unload_duh(myduh); - - You will now be able to use the DUH struct anywhere in between the two - lines you just added. There is no need to check the return value; if the - DUH failed to load for one reason or another (this could be due to lack of - memory as well as the file not being there), then DUMB will do nothing - - safely. - - -7. From this step onwards, it will be assumed you're using Allegro. If not, - please read these steps anyway, and then see the section entitled - "Rendering music into a buffer". You will have to write your own playback - code using whatever sound output system is available. Alternatively you - may like to write data to a file (especially if you have a module that - consumes a lot of processor time). - - In order to play the DUH you loaded, you need to define a pointer to an - AL_DUH_PLAYER struct: - - AL_DUH_PLAYER *dp; - - Two of the functions you will need are prototyped as follows: - - AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos, - float volume, long bufsize, int freq); - - void al_stop_duh(AL_DUH_PLAYER *dp); - - As you can see, al_start_duh() returns a pointer to an AL_DUH_PLAYER - struct when you call it. You then pass this pointer to all the other - functions. Again, if it is a NULL pointer for whatever reason (usually - lack of memory), DUMB will safely do nothing. When you call al_stop_duh(), - the pointer becomes invalid and you should not use it again; if there's - any risk of the pointer being used again, it is wise to set it to NULL at - this point. You can reassign the variable with a new call to - al_start_duh() of course. - - Set 'n_channels' to 1 or 2 for mono or stereo respectively. Note that this - parameter has nothing to do with the number of samples that can play at - once in a music module. Set 'pos' to 0 to play from the beginning; each - time you add 65536, you will have advanced one second into the piece. (If - you use the non-"quick" loaders, seeking like this will be faster.) As a - general rule, set the volume to 1.0f and adjust it later if the music is - too loud or too quiet - but see Allegro's set_volume_per_voice() function - first. - - 'bufsize' can generally be set to 4096. If your music stutters, try - increasing it; if your game freezes periodically, try reducing it. Find a - happy medium. Set 'freq' to 48000 for the best quality, though 44100 will - do in most cases. 22050 will be fine for a lot of music, though 11025 may - sound muffled. You can choose any other value, higher, lower or in - between. If your music stutters, and increasing 'bufsize' doesn't fix it, - try reducing this value. - - Once you have put in a call to al_start_duh(), it is good practice to - insert the call to al_stop_duh() at the same time. You must call - al_stop_duh() before the DUH is unloaded (unload_duh(), Step 6 above). - - Don't get impetuous, your program is not ready yet! Proceed to Step 8. - - -8. DUMB does not play music in the background for you; if you were expecting - it to do so, please see the explanation at the end of this step. For your - music to be played, you have to call another function at regular - intervals. Here is its prototype: - - int al_poll_duh(AL_DUH_PLAYER *dp); - - Do NOT call this function from inside a timer function unless you really - know what you are doing. The reasons why this is bad are explained - further down. You should call it from your main program. - - Simply writing the following line will be sufficient in general, if you - have a variable 'dp' that points to your AL_DUH_PLAYER struct. - - al_poll_duh(dp); - - As a general rule, calling this once for each logic update will do the - trick. If, however, you are executing time-consuming algorithms such as - software 3D rendering, you may wish to insert calls to this function in - the middle of those algorithms. You cannot call this function too often - (within reason); if it has nothing to do it will return immediately. - - Exactly how often you need to call the function depends on the values for - 'bufsize' and 'freq' that you passed to al_start_duh(): - - n = freq / bufsize; - - You have to call al_poll_duh() at least n times a second. Do not hesitate - to call it more often for safety; if the sound stutters, you may need to - do just that. (Or you may need to increase the buffer size or reduce the - quality settings; the only way to find out is to try.) - - For now, don't worry about al_poll_duh()'s return value. As soon as you - need it, it will be explained. - - If you are happy, please skip to Step 9. If you were expecting DUMB to - play your music in the background, please read on. - - The natural way to play music in the background on most operating systems - nowadays is to use threads. DOS was not built with multithreading in mind, - and its system operations (notably disk access) assume they will only be - used from a single thread. - - Interrupts are the next best thing to threads. A DOS hardware interrupt - could be triggered at any moment, and a handler function will be called. - This is how Allegro's timer functions work. Unfortunately, what you can do - inside an interrupt handler is very limited. For one thing, all code and - data used by the handler must be locked in memory; if not, it could get - written to disk (virtual memory). If the main program was accessing the - disk when it got interrupted, the system would then die a horrible death. - This precludes the possibility of allocating extra memory inside the - handler, and DUMB does a lot of that in al_poll_duh(). - - Given DUMB's architecture, which cannot change for reasons which will - become apparent in future versions, this renders it impossible to come up - with a portable solution for making DUMB play music in the background. - Having said that, if you wish to write your own wrapper for al_poll_duh() - and use it in a thread, there is nothing stopping you. If you do do this, - you will have to be very careful when stopping the music; see the - description of al_poll_duh() in dumb.txt for more information. - - So why not remove DOS support from DUMB? It is all too common a practice - among programmers to quote the phrase, "DOS is as dead as the dodo." - Despite being a decidedly derisible demonstation of the dreary device of - alliteration, it shows a distinct lack of experience. Many embedded - systems still use DOS because it provides hardware access capabilities and - real-time possibilities unparalleled by any current multitasking operating - system. For an argument closer to home, I used to use RHIDE for DOS before - I switched to Linux, and I have not found a single Freeware Windows IDE - that measures up to RHIDE. I'm sure many people are in the same boat, and - really appreciate DUMB's DOS port. - - That, and the fact that you don't have to use the DOS support just because - it is there. Shame on you for not thinking this through. :) - - We will not be removing DOS support from DUMB. Any blind suggestions to do - so will be met with fiery flames. You have been warned. - - -9. Test your program! - - If you have trouble, check through the above steps to make sure you didn't - miss one out. Refer to faq.txt to see if your problem is addressed there. - If you still have trouble, contact me; details are at the end of this - file. - - -********************************** -*** Controlling music playback *** -********************************** - - -Here I describe some common operations you may wish to perform. The method -for doing so will seem a bit strange sometimes, as will the names of the -structs. However, there is a reason behind everything. If you would like to -do more exotic things, or better understand some of the methods used here, -then see dumb.txt, which covers everything from the ground up. - - -To control playback quality: - - #define DUMB_RQ_ALIASING - #define DUMB_RQ_LINEAR - #define DUMB_RQ_CUBIC - #define DUMB_RQ_N_LEVELS - extern int dumb_resampling_quality; - extern int dumb_it_max_to_mix; - - Please note that dumb_resampling_quality was changed in DUMB v0.9.2. See - deprec.txt for more details on the change. - - dumb_resampling_quality can be set to any of the DUMB_RQ_* constants - (except DUMB_RQ_N_LEVELS; see below). Resampling is the term given to the - process of adjusting a sample's pitch (in this context). - dumb_resampling_quality defaults to DUMB_RQ_CUBIC, which sounds nice but - may take too much processor power on slower systems. Try reducing it if - you have an older computer (less than 300 MHz) or if you are trying to mix - an insane number of samples (or both!). See dumb.txt for details on what - the different values actually do. - - If you wish to give this option to your user, you can use - DUMB_RQ_N_LEVELS. All the values from 0 to DUMB_RQ_N_LEVELS - 1 will be - valid resampling levels. If a value outside this range is chosen, it is - not the end of the world; DUMB will behave as if you had chosen the value - at whichever extreme you went beyond. - - dumb_it_max_to_mix, defaulting to 64, is the maximum number of samples - DUMB will ever mix together when playing an IT, XM, S3M or MOD file. - Unlike many other music systems, DUMB will still keep track of all samples - (up to a fixed maximum of 256 of them, roughly speaking), and then will - just render as many of them as this variable permits, starting with the - loudest ones. When samples are cut or come back in, the exact timings will - not generally be predictable - but it is hoped this will not be important! - - dumb_it_max_to_mix applies to each currently playing module file - independently. So if you set it to 64, but render two modules - simultaneously, DUMB could end up mixing up to 128 samples. - - -To pause and resume playback, set the volume, get the current playback -position, or get the length of time a DUH will play for before either looping -or freezing (effect F00 in XM and MOD files, which means no new notes will be -played but any existing notes will continue): - - void al_pause_duh(AL_DUH_PLAYER *dp); - void al_resume_duh(AL_DUH_PLAYER *dp); - void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume); - long al_duh_get_position(AL_DUH_PLAYER *dp); - - long duh_get_length(DUH *duh); - - These functions are pretty self-explanatory. The volume passed to - al_duh_set_volume() and the position returned by al_duh_get_position() are - in the same units as those you passed to al_start_duh(). Be careful with - al_duh_get_position(); it will return a position slightly ahead of what - you can hear, because the system has to keep ahead slightly to avoid - stuttering. - - duh_get_length() returns the playback length, in the same units as the - aforementioned position, but beware: the length will not be known if you - have used the "quick" loader functions, and this function will return -1. - If you want to calculate the length later, use - dumb_it_do_initial_runthrough(). See dumb.txt for more information. - - -To prevent the music from looping and/or freezing: - - DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp); - DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer); - - void dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer, - int (*callback)(void *data), void *data); - void dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, - int (*callback)(void *data), void *data); - - int dumb_it_callback_terminate(void *data); - - If you are unfamiliar with function pointers, please see fnptr.txt. - - Note that these functions apply to IT, XM, S3M and MOD files - not just to - IT files. This holds true throughout DUMB, for all functions with "it" in - the name. The xm_speed_zero event can only occur with XM and MOD files. - - The first two functions will return a pointer to a struct contained by the - struct you pass. This system is necessary to ensure that these operations - are possible when not using Allegro. Typically you would write the - following code: - - { - DUH_SIGRENDERER *sr = al_duh_get_sigrenderer(dp); - DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sigrenderer); - dumb_it_set_loop_callback(itsr, &dumb_it_callback_terminate, NULL); - dumb_it_set_xm_speed_zero_callback - (itsr, &dumb_it_callback_terminate, NULL); - } - - Once you have done this, the return value of al_poll_duh() becomes - significant. It will be 0 as long as the music is playing. When the music - stops, al_poll_duh() will return nonzero. You can call al_stop_duh() and - do something else as soon as you wish, but calling al_poll_duh() some more - will not do any harm. - - al_poll_duh() will also return 1 if the music could not be loaded, or if - memory was short when trying to play it, or if it was a quirky music file - with no music in it (technically one with an empty order list). This - happens regardless of whether or not you execute the above code to disable - looping. Normally you shouldn't need to worry about this. - - To undo the above and make DUMB loop or freeze again, pass NULL instead of - &dumb_it_callback_terminate. If you would like to fade on looping, or loop - a finite number of times, or display a message when looping, or whatever, - you will have to write your own callback function. In this case, please - see dumb.txt. - - Note that the above code can safely be applied for a DUH that doesn't - contain a music module but contains some other kind of music. - duh_get_it_sigrenderer() will return NULL, and the code will do nothing. - - -To analyse the audio as it is generated: - - typedef int sample_t; - - typedef void (*DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK)(void *data, - const sample_t *const *samples, int n_channels, long length); - - void duh_sigrenderer_set_sample_analyser_callback( - DUH_SIGRENDERER *sigrenderer, - DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data); - - If the above confuses you, see fnptr.txt. These functions, along with - al_duh_get_sigrenderer() from the last section, enable you to register a - callback function. Every time some samples are generated, they will be - passed to this function. This enables you to display an oscilloscope or - spectrum analyser, for example. - - 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. 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_generate_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, but the first index will always be 0 - for mono and stereo sound. Refer to it as follows: - - n_channels == 1: samples[0][sample_position] - n_channels == 2: samples[0][sample_position*2+channel_number] - - where 0 <= channel_number < n_channels, - and 0 <= sample_position < length. - - There is a more thorough explanation in dumb.txt. - - In addition you can pass any 'data' pointer you like to - duh_sigrenderer_set_sample_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_sample_analyser_callback(). - - -Everything below this point assumes some knowledge of how a music module is -constructed. If you do not have this knowledge, talk to whoever is writing -music for you, or download a tracking program and play with it (see -readme.txt). - - -To start playing an IT, XM, S3M or MOD from an arbitrary order number (the -default being 0, the beginning of the song), use the following: - - DUH_SIGRENDERER *dumb_it_start_at_order - (DUH *duh, int n_channels, int startorder); - AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer - (DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq); - - The usage of these functions is as follows: - - { - DUH_SIGRENDERER *sr = dumb_it_start_at_order - (duh, n_channels, startorder); - dp = al_duh_encapsulate_sigrenderer(sr, volume, bufsize, freq); - if (!dp) duh_end_sigrenderer(sr); - } - - Replace 'dp' with whatever your AL_DUH_PLAYER pointer is. You also need - to insert suitable values for n_channels, startorder, volume, bufsize and - freq. These have the same meaning as those passed to al_start_duh(). - - Whenever you call al_duh_encapsulate_sigrenderer(), be sure to check the - return value. If an AL_DUH_PLAYER was returned, then the encapsulated - DUH_SIGRENDERER will be destroyed when you destroy the AL_DUH_PLAYER. If - not, you will have to destroy the DUH_SIGRENDERER yourself. The above code - includes this check. - - The above functions will fail (safely) if you try to use them with a DUH - that contains a different type of music. No music will play. - - Notice that there is no 'pos' parameter. If you would like to skip through - the music, you can use this function: - - long duh_sigrenderer_generate_samples( - DUH_SIGRENDERER *sigrenderer, - float volume, float delta, - long size, sample_t **samples - ); - - Pass 0 for volume and NULL for samples, and this function will skip - through the music nice and quickly. So insert the following between the - two above statements: - - duh_sigrenderer_generate_samples(sr, 0, 65536.0f / freq, pos, NULL); - - Substitute for 'freq' and 'pos'. An explanation of the 'delta' parameter - can be found further down in this file. - - Finally, note that duh_get_length() is only meaningful when you start - playing music from order 0. - - -If an IT file contains Zxx effects, DUMB will generate MIDI messages, which -will control the low-pass resonant filters unless the IT file actively -specifies something else. In rare cases this may not be what the Zxx effects -were intended to do; if this is the case, you can block the MIDI messages as -follows. Note that this does NOT mean filters are disabled; if an instrument -specifies initial cut-off and resonance values, or has a filter envelope, -then filters will be applied. It only makes sense to use this procedure at -the beginning of playback. - - void dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer, - int (*callback)(void *data, int channel, unsigned char byte), - void *data); - - int dumb_it_callback_midi_block(void *data, int channel, - unsigned char byte); - - Using some functions described in the previous section, we arrive at the - following code: - - { - DUH_SIGRENDERER *sr = al_duh_get_sigrenderer(dp); - DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sigrenderer); - dumb_it_set_midi_callback(itsr, &dumb_it_callback_midi_block, NULL); - } - -DUMB offers no way of disabling filters completely. Disabling filters is not -recommended as a means to reduce processor usage, as it will completely -damage any piece of music that uses the filters. If you want lower processor -consumption, use a piece of music that does not use filters. - - -Finally, DUMB offers a myriad of functions for querying and adjusting -module playback. Those beginning with "dumb_it_sd" operate on the -DUMB_IT_SIGDATA struct, which represents the piece of music before it starts -to play. Those beginning with "dumb_it_sr" operate on the DUMB_IT_SIGRENDERER -struct, which represents a currently playing instance of the music. Note that -duh_get_length(), described above, becomes meaningless after some of these -functions are used, although you can correct this by calling -dumb_it_build_checkpoints() again. - -The method for getting a DUMB_IT_SIGRENDERER struct has already been given, -but the function prototypes are repeated here for convenience: - - DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp); - DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer); - -Getting a DUMB_IT_SIGDATA struct is simpler: - - DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh); - -For a list of dumb_it_sd_*() and dumb_it_sr_*() functions, please see -dumb.txt. These functions are new, and may not provide exactly what you need; -if not, please let me know. - - -************************************************** -*** Embedding music files in Allegro datafiles *** -************************************************** - - -In this section it is assumed you are already reasonably familiar with how -Allegro datafiles are used. If not, please refer to Allegro's documentation. -At the time of writing, the documentation you need is off the beaten track, -so to speak, in allegro/tools/grabber.txt. - -To add a piece of music to a datafile, you need to create an object of type -"IT ", "XM ", "S3M " or "MOD " (note the spaces used as padding, although -you do not need to type these into the grabber). Then grab the piece of music -in. The grabber will treat it as a binary object. Save the datafile as usual. - - -To use a piece of music you added to the datafile, follow these steps: - - -1. Before loading the datafile, call one or more of these functions, - depending on which music format or formats you'd like to support: - - dumb_register_dat_it_quick(DUMB_DAT_IT); - dumb_register_dat_xm_quick(DUMB_DAT_XM); - dumb_register_dat_s3m_quick(DUMB_DAT_S3M); - dumb_register_dat_mod_quick(DUMB_DAT_MOD); - - There are non-"quick" versions too. - - Remember, do not call multiple functions unless you want to support - multiple formats. Calling more functions will add unused code to your - executable. - - It is important that you call these before loading the datafile, since - they tell Allegro how to load the respective files straight from datafiles - in the future. They will not help Allegro interpret any module files that - have already been loaded as binary objects. If you ever need to interpret - a module that has been loaded in this fashion, have a look at - dumbfile_open_memory() in dumb.txt. - - If for whatever reason your music objects are identified by a different - type in the datafile, you can tell DUMB what that type is by changing the - parameter to the registration function above. Use Allegro's DAT_ID() - macro, e.g. DAT_ID('B','L','A','H'). This is not really recommended - though, since it would prevent a hypothetical grabber plug-in from being - able to play your music files. Use the above types if possible. - - -2. Whenever you need a pointer to a DUH struct, simply use the 'dat' field. - Do this in the same way you would for a pointer to a BITMAP struct or - anything else. If it makes you feel more comfortable, you can extract the - pointer in advance: - - DATAFILE *dat = load_datafile("smurf.dat"); - if (!dat) abort(); /* There are much nicer ways of handling failure! */ - DUH *myduh = (DUH *)dat[GAME_MUSIC].dat; - - The explicit (DUH *) cast is only necessary for C++, not for C. However, - it does no harm. - - Be sure that you do NOT call unload_duh() for anything stored in the - datafile. These DUHs will be freed when you call unload_datafile(), and - freeing them twice is practically guaranteed to crash your program. (But - do call unload_duh() if you have used dumbfile_open_memory().) - - -3. If you only ever load music as part of a datafile, and you never load any - stand-alone music files, you do not need to register a file input system - for DUMB to use. If you followed the instructions for the first section - you will have one of these two lines in your program: - - dumb_register_stdfiles(); - dumb_register_packfiles(); - - You can safely delete this line - but only if you never load any - stand-alone music files. The debugging library will bale you out if you - delete it when you shouldn't; the optimised library won't. - - -************************************* -*** Rendering music into a buffer *** -************************************* - - -NOTE: much of the API formerly described in this section has been deprecated, - and you will need to alter your code. See deprec.txt for details. If - you are reading this section for the first time, you can ignore this - note. - -Rendering to a buffer is similar to playing using an AL_DUH_PLAYER. However, -you must use a DUH_SIGRENDERER struct instead. Here are the functions: - - DUH_SIGRENDERER *duh_start_sigrenderer - (DUH *duh, int sig, int n_channels, long pos); - - int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer); - long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer); - - long duh_sigrenderer_generate_samples(DUH_SIGRENDERER *sigrenderer, - float volume, float delta, long size, sample_t **samples); - - void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, - float volume, sample_t *samples); - - long duh_render(DUH_SIGRENDERER *sigrenderer, - int bits, int unsign, float volume, float delta, long size, void *sptr); - - void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer); - -The parameters to duh_start_sigrenderer() have the same meanings as those to -al_start_duh(). However, note that the volume is not set at this stage. You -pass the desired volume each time you want to render a block. The 'sig' -parameter should be set to 0 for now. - -Notice that there are two rendering functions. -duh_sigrenderer_generate_samples() will generate samples in the internal -32-bit format, with a normal range from -0x800000 to 0x7FFFFF; duh_render() -will convert to 8 or 16 bits, signed or unsigned. Both functions will -interleave stereo samples, left first. - -When you call duh_render(), pass 8 or 16 for 'bits'. If you pass 8, 'sptr' is -expected to be an array of chars. If you pass 16, 'sptr' is expected to be an -array of shorts. Endianness therefore depends on the platform, and you should -not try to interpret 16-bit wave data as an array of chars (unless you're -writing highly system-specific code anyway). Because DUMB renders internally -with 32 bits, there is no significant speed increase in rendering an 8-bit -stream. - -If you are rendering in stereo, make sure your 'sptr' array is twice as big! - -If you set 'unsign' to a nonzero value, then the samples generated will be -centred on 0x80 or 0x8000, suitably stored in an array of unsigned chars or -unsigned shorts. If 'unsign' is zero, the samples will be centred on 0, -suitably stored in an array of signed chars or signed shorts. Note that 8-bit -WAV files are unsigned while 16-bit WAV files are signed. This convention was -used by the SoundBlaster 16 when receiving samples to be sent to the -speakers. If you wish to write 16-bit sample data to a WAV file, don't use -fwrite(); instead, take the shorts one at a time, split them up into chars as -follows, and write the chars to the file. - - short sptr[n]; - char lsb = (char)sptr[n]; - char msb = (char)(sptr[n] >> 8); - -For a 16-bit WAV file, write the LSB (less significant byte) first. - -The following applies equally to duh_render() and -duh_sigrenderer_generate_samples(), except where otherwise stated. - -If you set 'delta' to 1.0f, the sound generated will be suitable for playback -at 65536 Hz. Increasing 'delta' causes the wave to speed up, given a constant -sampling rate for playback. Supposing you want to vary the playback sampling -rate but keep the pitch constant, here's the equation for 'delta': - - delta = 65536.0f / sampling_rate; - -'size' is the number of samples you want rendered. For duh_render(), they -will be rendered into an array which you pass as 'sptr'. Note that stereo -samples count as one; so if you set n_channels to 2, your array must contain -(2 * size) elements. - -For duh_sigrenderer_generate_samples() you will have to use the following -functions: - - sample_t **allocate_sample_buffer(int n_channels, long length); - void destroy_sample_buffer(sample_t **samples); - - void dumb_silence(sample_t *samples, long length); - -allocate_sample_buffer() allocates the buffers sequentially in memory in the -hypothetical future case where there are more than two channels, so the -following technique is valid and officially supported: - - sample_t **samples = allocate_sample_buffer(n_channels, length); - dumb_silence(samples[0], n_channels * length); - -It is necessary to fill the buffer with silence like this because -duh_sigrenderer_generate_samples() mixes what it renders with the existing -contents of the buffer. - -The return values from duh_render() and duh_sigrenderer_generate_samples() -tell you how many samples were actually generated. In most cases, this will -be the same as the 'size' parameter. However, if you reach the end of the DUH -(which will happen if you disable looping or freezing as described further -up), this function will return less. When that happens, you can assume the -stream has finished. In the case of duh_render(), the remainder of the array -will not have been initialised, so you either have to initialise it yourself -or avoid using it. - -If for whatever reason duh_start_sigrenderer() returns NULL, then -duh_render() and duh_sigrenderer_generate_samples() will generate exactly 0 -samples, duh_sigrenderer_get_n_channels() will return 0, -duh_sigrenderer_get_position() will return -1, and duh_end_sigrenderer() will -safely do nothing. - -duh_sigrenderer_get_current_sample() is used by the click removal algorithm. -It simply returns the current sample without updating the position, so you -can use it to sniff what is coming next. - - -********************* -*** Miscellaneous *** -********************* - - -Please see dumb.txt for an API reference and for information on thread safety -with DUMB. The API reference has been stripped down, since some functions and -variables are subject to change. If something does not appear in dumb.txt, -please do not use it. - - -****************** -*** Conclusion *** -****************** - - -If you have any difficulties, or if you use DUMB successfully, please don't -hesitate to contact me (see below). - -Enjoy! - - -Ben Davis -entheh@users.sf.net diff --git a/dumb/dumb-0.9.3/docs/modplug.txt b/dumb/dumb-0.9.3/docs/modplug.txt deleted file mode 100644 index 2172126d..00000000 --- a/dumb/dumb-0.9.3/docs/modplug.txt +++ /dev/null @@ -1,155 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * modplug.txt - Some comments on ModPlug Tracker / / \ \ - * and its compatibility with other | < / \_ - * tracking tools. | \/ /\ / - * \_ / > / - * | \ / / - * | ' / - * \__/ - */ - - -******************** -*** Introduction *** -******************** - -There are two 'authorities' on how the various tracker files should be -played. The first is the original trackers; I consider these the true -authorities because they were around earlier, they created their own formats, -and they mostly play the music the same on every computer (exception: IT's -support for MIDI output). - -The second is ModPlug Tracker. It is not the only third-party tracker, but it -is by far the most used. I have some issues with ModPlug Tracker, which I -shall explain below. However, I do use ModPlug Tracker because it is user- -friendly. I recommend that anyone planning to compose music in ModPlug -Tracker read this document. - -DUMB's loyalty is to the original trackers, not ModPlug Tracker. Please bear -this in mind when reporting bugs. ModPlug Tracker is now available with -source code, so you may be able to use its own music playback engine if you -prefer; but read this file anyway! - - ModPlug Tracker - http://www.modplug.com/ - Open Source Version - http://sourceforge.net/projects/modplug/ - - -************************* -*** Incompatibilities *** -************************* - -There are a few situations in which ModPlug Tracker's playback engine differs -from the original trackers' playback engines. I shall list the five I am most -aware of, in order from least to most annoying: - -5. Create a new IT file. Create a multisample instrument, for example a - piano. Play a low note. Then go up the scale, but in the pattern data, - make sure the instrument column is blank; put in only the notes. Play this - with ModPlug Tracker, and play it with Impulse Tracker or DUMB. Impulse - Tracker and DUMB change sample as you go up the scale; ModPlug Tracker - does not. - -4. Arpeggio and Retrigger Note effects behave badly when combined with - Portamento, which can appear in the volume column. While Retrigger Note - isn't too bad, Arpeggio sounds completely wrong. Try it and see what - happens. Then repeat the experiment in Impulse Tracker, or play the file - with DUMB. - -3. The filter algorithm is incorrect. Impulse Tracker uses a standard low- - pass resonant filter algorithm with a slight modification to increase the - resonance (the poles are closer to the unit circle). ModPlug Tracker does - not incorporate this modification. As a result, filtered channels sound - somewhat weaker. - -2. When looping, ModPlug Tracker resets all variables. The original trackers - do not do this. - -1. Worst of all, ModPlug Tracker has no regard for playback volume, and - generally has a much lower output level than the original trackers. You - can adjust this in the program set-up. The control has been moved out of - the file into the user's domain, which makes it difficult to ensure that - your file will play at a reasonable volume everywhere. I have plenty of - files that distort horribly with DUMB and Impulse Tracker because they - were written with ModPlug Tracker. - -Cases 3, 2 and 1 lead people to create IT files that play badly in the -original trackers. If some of these problems could be fixed, I'd be all for -it - but I was once told these problems were reported to the author and he -had no motivation to fix them. ModPlug Tracker is now open source, but I -suspect fixing 3, 2 and 1 would be deemed detrimental to too many people's -music by now. - -If you are incorporating music into a game, you can work around the volume -problem in your program. When you pass a volume to al_start_duh() or -equivalent, try passing a lower value than 1.0f. Be drastic; try 0.5f, 0.2f, -and maybe even 0.1f, until you find a level that sounds loud enough but -doesn't distort. However, for neatness I would always recommend fixing the -module by changing its mixing volume. - - -****************** -*** Extensions *** -****************** - -ModPlug Tracker has also made various extensions, mostly to the IT format. -These are useful if you are keeping your module files private and -distributing MP3 or OGG files. However, if you wish to distribute the module -files, you will want to avoid them. - -DUMB currently supports one of ModPlug Tracker's extensions, namely stereo -samples, but supporting the others is not high on my list of priorities. The -support for stereo samples is only in there because I did not know it was an -extension at first! Impulse Tracker's own format documentation makes -provision for stereo samples but states that they are not supported yet. - -Other extensions ModPlug Tracker has provided mostly take the form of extra -effects. For instance, S98 and S99 can be used to enable or disable reverb. I -believe the latest versions of ModPlug Tracker offer alternative types of -filter, such as high-pass and band-pass. As soon as an IT file uses any of -these features, it will play incorrectly with Impulse Tracker. - -By far the most evil extension provided by ModPlug Tracker is the effect -plug-ins. These enable IT files to use VST effects. I recently downloaded an -IT file that uses some effects from a collection named "DirectX Media Audio -Effects". I doubt these effects will be ported to Linux any time soon. - -All in all, the extensions are having the result of making all the other IT -players, and Impulse Tracker itself, look bad. - - -****************** -*** Conclusion *** -****************** - -ModPlug Tracker is trying to be two things at once, and is going about it -slightly wrong. It wants to be an editor for the existing formats, allowing -Windows users who have limited DOS support to continue tracking using the -same file formats. This is fairly noble. The problem arose when it took it -upon itself to modify the formats, make up its own rules and take advantage -of everything available including system-specific features, which is useful -as long as you will be distributing your music prerendered. In my opinion, -ModPlug Tracker should have come out with its own file format, in which all -these extensions would have found a home. As it stands, you can use all the -extensions and still save your music as an .it or .xm file, which is asking -for trouble. - -Despite all the above problems, I do recommend ModPlug Tracker as an editor, -provided you are careful not to use ModPlug Tracker's extensions or rely on -its incompatibilities unless you really don't intend to distribute your -'source' module file. - -Oh, and by the way, save your final version with Impulse Tracker. Then the -samples will be compressed for you! - - -Ben Davis -entheh@users.sf.net diff --git a/dumb/dumb-0.9.3/docs/ptr.txt b/dumb/dumb-0.9.3/docs/ptr.txt deleted file mode 100644 index a7f6c97e..00000000 --- a/dumb/dumb-0.9.3/docs/ptr.txt +++ /dev/null @@ -1,127 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * ptr.txt - Pointer explanation. / / \ \ - * | < / \_ - * | \/ /\ / - * \_ / > / - * | \ / / - * | ' / - * \__/ - */ - - -A pointer is a small variable (often the same size as an int BUT NOT ALWAYS) -that holds the address of something in memory. You create a pointer by adding -a * to a variable, as follows: - - int x, *y; - - x = 5; - y = &x; - -The & means 'address of', so &x gives us a pointer to x. We are storing it in -y. - - (*y)++; - -The * here means 'value at'. It's known as the 'dereferencing' operator. When -written before a pointer, as it is here, it allows you to treat the value -like a normal variable. In this case we are incrementing the value. If we -look at x, we'll find that it now contains 6, not 5. - - y++; - -Here we are incrementing the pointer itself. This is useful for traversing -through an array, but in this particular example it is not much use. - - *y++; - -Beware; this will increment the pointer, not the value stored there. It will -return the value stored at the pointer (before incrementing the pointer), so -you can use this in a bigger expression. This is why we needed brackets in -the first example. - -Note that you will not need these three examples when working with DUMB; they -are simply to help illustrate the idea of pointers. - -Also be aware that when defining pointers you attach the * to the variable, -not to the type. The following example will create a pointer and an int, not -two pointers: - - int *a, b; - -That is why I believe it's a good idea to put a space before the * and not -after it, although programmers are divided on this. - - y = 0; - y = NULL; - -These two statements are equivalent. 0, or NULL, is a special value that is -guaranteed to have a different value from any valid pointer. This is most -often used to indicate that something doesn't point anywhere. DUMB's -functions may return it on occasion. However, in simple usage of DUMB, you -will not actually need to check for it. - -Some of DUMB's functions return pointers to structs. (A struct is an -aggregration of other variables, such as ints, pointers, or other structs. -You can generally treat a struct as a single unit.) Here's an example of such -a function: - - DUH *dumb_load_it(const char *filename); - -You do not know what the DUH struct actually contains; dumb.h and aldumb.h -only give the compiler enough information to deal with pointers to them. DUMB -will take charge of everything that happens inside a DUH struct. - -The above function will create a DUH struct for you. First it allocates -the memory it needs, then it fills the struct with data, then it returns a -pointer. This DUH struct will contain the data necessary to play an IT file. -You can define a suitable variable and store the pointer in it as follows: - - DUH *duh = dumb_load_it("music.it"); - -Or this can be split up: - - DUH *duh; - duh = dumb_load_it("music.it"); - -In order to use this DUH struct later, you must pass its pointer to other -functions. To pass the pointer to a function, simply write 'duh' for the -appropriate parameter. - -When you've finished with a DUH struct (this applies equally to the other -structs DUMB deals with), you must pass it to an appropriate function for -freeing up the memory: - - unload_duh(duh); - -After you've done this, the memory will no longer be allocated, and the -pointer will have no meaning. You may wish to set it to NULL at this point -for safety. Alternatively just be sure not to use the present value of the -pointer any more. You can of course assign a new value to the pointer, e.g. -by calling dumb_load_it() again. - -Note the following: - - DUH *duh2 = duh; - -This only duplicates the pointer, not the DUH itself. You still only have one -copy of the DUH. There is no way of duplicating a DUH, short of loading it -twice. This is not a problem, because DUMB can play it 'twice at the same -time' anyway. - -That should be all you need to know about pointers in order to use DUMB. If -there's anything you feel should be explained better here, or anything else -that should be added, please don't hesitate to let me know! - - -Ben Davis -entheh@users.sf.net |