From 4810f9a0af507bb405e6a3c58decfa9c9980b2ff Mon Sep 17 00:00:00 2001 From: Alexey Yakovenko Date: Thu, 27 May 2010 22:51:35 +0200 Subject: merged parts of DUMB-0.9.3 --- plugins/dumb/dumb-kode54/docs/howto.txt | 263 +++++++++++++++++--------------- 1 file changed, 141 insertions(+), 122 deletions(-) (limited to 'plugins/dumb/dumb-kode54/docs/howto.txt') diff --git a/plugins/dumb/dumb-kode54/docs/howto.txt b/plugins/dumb/dumb-kode54/docs/howto.txt index 1d9a439f..7cfa194f 100644 --- a/plugins/dumb/dumb-kode54/docs/howto.txt +++ b/plugins/dumb/dumb-kode54/docs/howto.txt @@ -126,15 +126,17 @@ then follow the instructions further down for adapting your code. allegro_exit(); -4. DUMB does not automatically do any of its own file input. You have to tell - it how to read files. Don't worry, it's easy. Simply call the following - function near the beginning of your program, after your atexit() call: +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(); - This tells DUMB to use ordinary stdio FILE structs for reading and writing - files. If you are using Allegro and would rather DUMB used PACKFILEs, call - the following function INSTEAD: + 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(); @@ -143,23 +145,22 @@ then follow the instructions further down for adapting your code. 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. If you are loading datafiles, your - executable might be slightly smaller if you use dumb_register_packfiles(). - On the other hand, 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 (you will - be reminded that you can remove the function call). + 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'll have to initialise Allegro's sound +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); - You may like to initialise a MIDI driver though; see Allegro's docs for - details. Put this line after allegro_init(). + 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, @@ -171,22 +172,25 @@ then follow the instructions further down for adapting your code. 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, so do not - try. DUMB's functions provide everything you need; if you disagree, please - let me know and I shall see what I can do. Contact details are at the end - of this file. + 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("a_one.it"); - myduh = dumb_load_xm("a_two.xm"); - myduh = dumb_load_s3m("a_one_two.s3m"); - myduh = dumb_load_mod("three_four.mod"); + 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"); - Obviously you can use relative or absolute paths as normal. You should - always use forward slash (/), not backslash (\), when coding in C and - similar languages. + 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 @@ -205,18 +209,8 @@ then follow the instructions further down for adapting your code. 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 file that - consumes a lot of processor time), but beware that any streaming audio - format is likely to be substantially larger than the module file you - generate it from, and formats like MP3 will be lower quality. You might - not be able to hear the difference between the MP3 and the original, but - many people can and don't like it, so please consider them. I'm one of - them. If you really want to use a lossy compression format, I highly - recommend Ogg Vorbis: - - http://www.vorbis.com/ - - But I digress. + 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: @@ -242,7 +236,8 @@ then follow the instructions further down for adapting your code. 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. As a + 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. @@ -323,16 +318,19 @@ then follow the instructions further down for adapting your code. 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 kill DOS? 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. + 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. @@ -367,16 +365,17 @@ To control playback quality: extern int dumb_resampling_quality; extern int dumb_it_max_to_mix; - Please note that dumb_resampling_quality has changed in DUMB v0.9.2. See + 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 - takes a lot of processor power. Try reducing it if you have an older - computer 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. + 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 @@ -390,7 +389,7 @@ To control playback quality: (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 nor will they be important. + 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 @@ -411,13 +410,17 @@ played but any existing notes will continue): 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(). The length - returned by duh_get_length() is in the same units as the aforementioned - position; see dumb.txt for more information on this function. 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 + 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: @@ -473,15 +476,16 @@ To prevent the music from looping and/or freezing: duh_get_it_sigrenderer() will return NULL, and the code will do nothing. -To analyse the audio as it's generated: +To analyse the audio as it is generated: typedef int sample_t; - typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data, + typedef void (*DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK)(void *data, const sample_t *const *samples, int n_channels, long length); - void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer, - DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data); + 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 @@ -495,25 +499,30 @@ To analyse the audio as it's generated: elegantly, typically by returning immediately, but you may wish to make a note of the fact that the music is being skipped, for whatever reason. - Beware again: if the main program ever calls duh_sigrenderer_get_samples() - on a buffer that isn't all silence, this callback function will be passed - the existing buffer after mixing, and thus it will include the original - data. This will not be an issue if you stick to duh_render(), which always - starts with a buffer filled with silence. + 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. Refer to it as follows: + The samples array is two-dimensional, but the first index will always be 0 + for mono and stereo sound. Refer to it as follows: - samples[channel_number][sample_position] + 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_analyser_callback(), and this pointer will be relayed - to your callback function each time. + 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_analyser_callback(). + duh_sigrenderer_set_sample_analyser_callback(). Everything below this point assumes some knowledge of how a music module is @@ -536,26 +545,26 @@ default being 0, the beginning of the song), use the following: 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(). - WARNING: after passing a pointer to an "encapsulate" function, do not use - that pointer again. (More specifically, do not use it again if - the function returns NULL, because the function will have - destroyed the pointer if this happens, to help prevent memory - leaks.) There will be a "get" function with which you can obtain - the original pointer if it is still valid, or NULL otherwise. + 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. + 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_get_samples( + long duh_sigrenderer_generate_samples( DUH_SIGRENDERER *sigrenderer, float volume, float delta, long size, sample_t **samples @@ -565,7 +574,7 @@ default being 0, the beginning of the song), use the following: through the music nice and quickly. So insert the following between the two above statements: - duh_sigrenderer_get_samples(sr, 0, 65536.0f / freq, pos, NULL); + 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. @@ -611,7 +620,8 @@ 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. +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: @@ -650,21 +660,23 @@ 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(DUMB_DAT_IT); - dumb_register_dat_xm(DUMB_DAT_XM); - dumb_register_dat_s3m(DUMB_DAT_S3M); - dumb_register_dat_mod(DUMB_DAT_MOD); + 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 make 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 (but if you really - need to interpret a module that has been loaded in this fashion, have a - look at dumbfile_open_memory() in dumb.txt). + 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 @@ -683,12 +695,13 @@ To use a piece of music you added to the datafile, follow these steps: if (!dat) abort(); /* There are much nicer ways of handling failure! */ DUH *myduh = (DUH *)dat[GAME_MUSIC].dat; - Note that the explicit (DUH *) cast is only necessary for C++, not for C. - However, it does no harm. + 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. + 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 @@ -723,9 +736,12 @@ you must use a DUH_SIGRENDERER struct instead. Here are the functions: int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer); long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer); - long duh_sigrenderer_get_samples(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); @@ -736,11 +752,11 @@ 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_get_samples() -will generate samples in the internal 32-bit format, with a normal range from --0x800000 to 0x7FFFFF and with each channel in a separate array; duh_render() -will convert to 8 or 16 bits, signed or unsigned, with stereo samples -interleaved, left first. +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 @@ -769,7 +785,7 @@ follows, and write the chars to the file. For a 16-bit WAV file, write the LSB (less significant byte) first. The following applies equally to duh_render() and -duh_sigrenderer_get_samples(), except where otherwise stated. +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 @@ -783,39 +799,44 @@ 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_get_samples() you will have to use the following +For duh_sigrenderer_generate_samples() you will have to use the following functions: - sample_t **create_sample_buffer(int n_channels, long length); + 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); -create_sample_buffer() allocates the channels sequentially in memory, so the -following technique is valid: +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 = create_sample_buffer(n_channels, length); + 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_get_samples() mixes what it renders with the existing +duh_sigrenderer_generate_samples() mixes what it renders with the existing contents of the buffer. -The return values from duh_render() and duh_sigrenderer_get_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. +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_get_samples() will generate exactly 0 +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 *** @@ -841,5 +862,3 @@ Enjoy! Ben Davis entheh@users.sf.net -IRC EFnet #dumb -See readme.txt for details on using IRC. -- cgit v1.2.3