diff options
Diffstat (limited to 'dumb/dumb-0.9.3/docs/howto.txt')
-rw-r--r-- | dumb/dumb-0.9.3/docs/howto.txt | 864 |
1 files changed, 0 insertions, 864 deletions
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 |