diff options
author | Michiel Van Der Kolk <not.valid@email.address> | 2005-03-17 20:50:03 +0000 |
---|---|---|
committer | Michiel Van Der Kolk <not.valid@email.address> | 2005-03-17 20:50:03 +0000 |
commit | 27be5bc72855a0fbbdae230bc144624c9eb85f5e (patch) | |
tree | b553f1321df924c4b744ffcab48dce5f4f081f7d /apps/codecs/dumb/docs | |
parent | 7e7662bb716917ca431204f0113d400c1014f2e8 (diff) | |
download | rockbox-27be5bc72855a0fbbdae230bc144624c9eb85f5e.tar.gz rockbox-27be5bc72855a0fbbdae230bc144624c9eb85f5e.zip |
Initial check in dumb 0.9.2 - has a few usages of floating point that should
be rewritten to fixed point. seems to compile cleanly for iriver.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6197 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/dumb/docs')
-rw-r--r-- | apps/codecs/dumb/docs/deprec.txt | 281 | ||||
-rw-r--r-- | apps/codecs/dumb/docs/dumb.txt | 1699 | ||||
-rw-r--r-- | apps/codecs/dumb/docs/faq.txt | 263 | ||||
-rw-r--r-- | apps/codecs/dumb/docs/fnptr.txt | 113 | ||||
-rw-r--r-- | apps/codecs/dumb/docs/howto.txt | 845 | ||||
-rw-r--r-- | apps/codecs/dumb/docs/modplug.txt | 137 | ||||
-rw-r--r-- | apps/codecs/dumb/docs/ptr.txt | 129 |
7 files changed, 3467 insertions, 0 deletions
diff --git a/apps/codecs/dumb/docs/deprec.txt b/apps/codecs/dumb/docs/deprec.txt new file mode 100644 index 0000000000..88ca2e9fda --- /dev/null +++ b/apps/codecs/dumb/docs/deprec.txt | |||
@@ -0,0 +1,281 @@ | |||
1 | /* _______ ____ __ ___ ___ | ||
2 | * \ _ \ \ / \ / \ \ / / ' ' ' | ||
3 | * | | \ \ | | || | \/ | . . | ||
4 | * | | | | | | || ||\ /| | | ||
5 | * | | | | | | || || \/ | | ' ' ' | ||
6 | * | | | | | | || || | | . . | ||
7 | * | |_/ / \ \__// || | | | ||
8 | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque | ||
9 | * / \ | ||
10 | * / . \ | ||
11 | * deprec.txt - Deprecated functions, why they / / \ \ | ||
12 | * were deprecated, and what to do | < / \_ | ||
13 | * instead. | \/ /\ / | ||
14 | * \_ / > / | ||
15 | * | \ / / | ||
16 | * | ' / | ||
17 | * \__/ | ||
18 | */ | ||
19 | |||
20 | |||
21 | ********************************************** | ||
22 | *** How the functions have been deprecated *** | ||
23 | ********************************************** | ||
24 | |||
25 | |||
26 | GCC 3.1 and later provide a very useful attribute. The following: | ||
27 | |||
28 | __attribute__((__deprecated__)) | ||
29 | |||
30 | when written alongside a function prototype, variable declaration or type | ||
31 | definition, will result in a warning from GCC if any such part of the API | ||
32 | is used. The warning will even tell you where the declaration is, and I | ||
33 | have inserted comments by all the deprecated declarations, telling you | ||
34 | what to do. | ||
35 | |||
36 | Unfortunately, GCC 2.x and 3.0.x and MSVC do not have any means to | ||
37 | deprecate things. The approach I have taken with these compilers is to | ||
38 | avoid prototyping the declared functions. This means you will get | ||
39 | warnings and errors, and they won't be very helpful. If your program | ||
40 | compiles, you may get strange crashes when you run it, since the compiler | ||
41 | needs the declarations in order to make sure function calls are carried | ||
42 | out correctly. | ||
43 | |||
44 | If you would like the deprecated parts of the API to be declared, you can | ||
45 | compile with the -DDUMB_DECLARE_DEPRECATED switch for GCC, or the | ||
46 | -D"DUMB_DECLARE_DEPRECATED" switch for MSVC. This will be accepted by | ||
47 | GCC 3.x but is unnecessary. Use this switch with other people's projects | ||
48 | if necessary, but please make the effort to update your own projects to | ||
49 | use the new API, as the deprecated parts may be removed in the future. | ||
50 | |||
51 | The rest of this file explains why some parts of the API were deprecated, | ||
52 | and how to adapt your code. | ||
53 | |||
54 | |||
55 | ************************************** | ||
56 | *** What happened to DUH_RENDERER? *** | ||
57 | ************************************** | ||
58 | |||
59 | |||
60 | The DUH_RENDERER struct was designed for rendering audio to an end-user | ||
61 | format - 8-bit or 16-bit, signed or unsigned, with stereo samples | ||
62 | interleaved. In order for it to do this, it was built on top of the | ||
63 | hitherto undocumented DUH_SIGRENDERER struct, which rendered audio in | ||
64 | DUMB's internal 32-bit signed format with channels (left/right) stored | ||
65 | separately. The DUH_RENDERER struct contained a pointer to a | ||
66 | DUH_SIGRENDERER struct, along with some other data like the position and | ||
67 | number of channels. | ||
68 | |||
69 | There were then some developments in the API. The DUH_SIGRENDERER struct | ||
70 | also stored the position and the number of channels, so I decided to write | ||
71 | functions for returning these. Suddenly there was no need to store them in | ||
72 | the DUH_RENDERER struct. Before long, the DUH_RENDERER struct contained | ||
73 | nothing but a pointer to a DUH_SIGRENDERER. | ||
74 | |||
75 | I decided it would be a good idea to unify the structs. After all, there | ||
76 | really is no difference between the data stored in each, and it would be | ||
77 | easy to make duh_render(DUH_RENDERER *dr, ...) and | ||
78 | duh_render_signal(DUH_SIGRENDERER *sr, ...) work on the same type of | ||
79 | struct. (Note that duh_render_signal() is now deprecated too; see the next | ||
80 | section.) It took some deliberation, but I decided I didn't want functions | ||
81 | to be #defined (it prevents you from using these names for member | ||
82 | functions in C++ classes), and that meant they had to be defined | ||
83 | somewhere. Defining redundant functions is a source of bloat, inefficiency | ||
84 | and general inelegance. After weighing things up, I decided it was better | ||
85 | to deprecate the redundant functions and have people begin to use the more | ||
86 | efficient versions, and eventually the redundant functions will be able to | ||
87 | be removed. | ||
88 | |||
89 | So why did I choose to keep the more complicated name, DUH_SIGRENDERER? | ||
90 | The reason has to do with what DUMB will become in the future. Signals are | ||
91 | an inherent part of the DUH struct and how .duh files will be constructed. | ||
92 | It will be possible to have multiple signals in a single DUH struct, and | ||
93 | you will be able to choose which one you want to play (this is the 'sig' | ||
94 | parameter passed to duh_start_sigrenderer()). But don't hold your breath; | ||
95 | we still have a long way to go before .duh files will start to appear... | ||
96 | |||
97 | |||
98 | typedef DUH_SIGRENDERER DUH_RENDERER; | ||
99 | |||
100 | Wherever you are using DUH_RENDERER in your program, simply replace it | ||
101 | with DUH_SIGRENDERER. An automated (case-sensitive!) search and replace | ||
102 | operation should get this done. | ||
103 | |||
104 | |||
105 | DUH_RENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos); | ||
106 | |||
107 | Use duh_start_sigrenderer() instead. It takes an extra parameter, 'sig', | ||
108 | which comes after 'duh' and before 'n_channels'; pass 0 for this. So an | ||
109 | example would be, replace: | ||
110 | |||
111 | sr = duh_start_renderer(duh, 2, 0); | ||
112 | |||
113 | with: | ||
114 | |||
115 | sr = duh_start_sigrenderer(duh, 0, 2, 0); | ||
116 | |||
117 | |||
118 | int duh_renderer_get_n_channels(DUH_RENDERER *dr); | ||
119 | long duh_renderer_get_position(DUH_RENDERER *dr); | ||
120 | void duh_end_renderer(DUH_RENDERER *dr); | ||
121 | |||
122 | These are easy enough to fix; all you have to do is replace 'renderer' | ||
123 | with 'sigrenderer'. So the new functions are: | ||
124 | |||
125 | int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer); | ||
126 | long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer); | ||
127 | void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer); | ||
128 | |||
129 | |||
130 | Note that duh_render() has NOT been deprecated. It now uses DUH_SIGRENDERER | ||
131 | instead of DUH_RENDERER, but its functionality is unchanged. You do not have | ||
132 | to change calls to this function in any way. | ||
133 | |||
134 | |||
135 | DUH_RENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sr); | ||
136 | DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_RENDERER *dr); | ||
137 | DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_RENDERER *dr); | ||
138 | |||
139 | These functions did not exist in the last release of DUMB, so you are | ||
140 | probably not using them, but they are included here for completeness. All | ||
141 | you have to do here is unwrap the function, since the structs have been | ||
142 | unified. So, for instance, replace: | ||
143 | |||
144 | duh_renderer_encapsulate_sigrenderer(my_sigrenderer) | ||
145 | |||
146 | with: | ||
147 | |||
148 | my_sigrenderer | ||
149 | |||
150 | Simple! | ||
151 | |||
152 | |||
153 | AL_DUH_PLAYER *al_duh_encapsulate_renderer(DUH_RENDERER *dr, | ||
154 | float volume, long bufsize, int freq); | ||
155 | DUH_RENDERER *al_duh_get_renderer(AL_DUH_PLAYER *dp); | ||
156 | DUH_RENDERER *al_duh_decompose_to_renderer(AL_DUH_PLAYER *dp); | ||
157 | |||
158 | Again, these functions were not in the last release, so you probably | ||
159 | aren't using them. Nevertheless, the fix is simple as always: simply | ||
160 | replace 'renderer' with 'sigrenderer'. So the new functions are: | ||
161 | |||
162 | AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer(DUH_SIGRENDERER *sr, | ||
163 | float volume, long bufsize, int freq); | ||
164 | DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp); | ||
165 | DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp); | ||
166 | |||
167 | |||
168 | ********************* | ||
169 | *** Miscellaneous *** | ||
170 | ********************* | ||
171 | |||
172 | |||
173 | long duh_render_signal(DUH_SIGRENDERER *sigrenderer, | ||
174 | float volume, float delta, | ||
175 | long size, sample_t **samples); | ||
176 | |||
177 | This function used to return samples in DUMB's internal format. This | ||
178 | format consisted of 32-bit integers whose 'normal range' was -0x8000 to | ||
179 | 0x7FFF (any samples outside this range would have to be clipped when sent | ||
180 | to the sound card). | ||
181 | |||
182 | DUMB's internal format has changed. DUMB still uses 32-bit integers, but | ||
183 | now the normal range is -0x800000 to 0x7FFFFF. The lowest eight bits are | ||
184 | discarded at the final stage by duh_render() when you ask for 16-bit | ||
185 | output. A new function, duh_sigrenderer_get_samples(), will return samples | ||
186 | in DUMB's new internal format. It takes exactly the same parameters, so | ||
187 | all you have to do to the call itself is change the name; however, you | ||
188 | will most likely have to change your code to account for the new | ||
189 | normalised range. | ||
190 | |||
191 | duh_render_signal() will still be able to give you the samples in DUMB's | ||
192 | old internal format, but it is inefficient. You should change your code as | ||
193 | soon as possible. | ||
194 | |||
195 | |||
196 | typedef void (*DUH_SIGRENDERER_CALLBACK)(void *data, sample_t **samples, | ||
197 | int n_channels, long length); | ||
198 | |||
199 | void duh_sigrenderer_set_callback(DUH_SIGRENDERER *sigrenderer, | ||
200 | DUH_SIGRENDERER_CALLBACK callback, void *data); | ||
201 | |||
202 | This callback was intended to allow you to analyse the output. It was by | ||
203 | no means intended to let you modify the output. For this reason, the names | ||
204 | have been changed to DUH_SIGRENDERER_ANALYSER_CALLBACK and | ||
205 | duh_sigrenderer_set_analyser_callback, and the 'samples' parameter to your | ||
206 | callback should now be specified as follows: | ||
207 | |||
208 | const sample_t *const *samples | ||
209 | |||
210 | The first 'const' indicates that you must not modify the samples. The | ||
211 | second indicates that you must not modify the pointers to each channel. | ||
212 | |||
213 | There is a second reason why this change was necessary, and it is the one | ||
214 | described further up for duh_render_signal()'s entry: the format in which | ||
215 | the samples themselves are stored has changed. They are 256 times as | ||
216 | large, with a normal range from -0x800000 to 0x7FFFFF. You will most | ||
217 | likely need to change your code to account for this. | ||
218 | |||
219 | If you try to call the old function, it will print a message to stderr | ||
220 | directing you to this file, and it will not install the callback. You | ||
221 | shouldn't be able to get this far without a compiler warning (or, if you | ||
222 | don't have GCC 3.1 or later, some compiler errors). | ||
223 | |||
224 | If you wanted to use this callback to apply a DSP effect, don't worry; | ||
225 | there is a better way of doing this. It is undocumented, so contact me | ||
226 | and I shall try to help. Contact details are at the bottom of this file. | ||
227 | |||
228 | For reference, here are the new definitions: | ||
229 | |||
230 | typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data, | ||
231 | const sample_t *const *samples, int n_channels, long length); | ||
232 | |||
233 | void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer, | ||
234 | DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data); | ||
235 | |||
236 | |||
237 | int dumb_resampling_quality; | ||
238 | |||
239 | This variable has changed meaning. It used to hold a value from 0 to 4, | ||
240 | whose meaning was as follows: | ||
241 | |||
242 | 0 - aliasing | ||
243 | 1,2 - linear interpolation | ||
244 | 3 - quadratic interpolation | ||
245 | 4 - cubic interpolation | ||
246 | |||
247 | 0,1 - always use a straightforward interpolation algorithm | ||
248 | 2,3,4 - when decimating (increasing the pitch), use a linear average | ||
249 | algorithm designed to reduce frequencies that would otherwise | ||
250 | reflect off the Nyquist | ||
251 | |||
252 | Now the variable only holds values from 0 to 2, and these values have | ||
253 | preprocessor constants associated with them. The somewhat inappropriate | ||
254 | quadratic interpolation has been removed. The linear average algorithm has | ||
255 | also been removed, and may or may not come back; there are probably more | ||
256 | efficient ways of achieving the same effect, which I shall be | ||
257 | investigating in the future. | ||
258 | |||
259 | This change will have hardly any noticeable effect on existing programs. | ||
260 | Levels 2, 3 and 4 used considerably more processor time because of the | ||
261 | linear average algorithm. Likewise, Level 2 in the new scheme (cubic) uses | ||
262 | considerably more processor time than Levels 1 and 0, and Levels 3 and 4 | ||
263 | will behave identically to Level 2. | ||
264 | |||
265 | |||
266 | ****************** | ||
267 | *** Conclusion *** | ||
268 | ****************** | ||
269 | |||
270 | |||
271 | "I conclude that... DUMB is the bestest music player in the world because... | ||
272 | Complete this sentence in fifteen words or fewer... D'OH!" | ||
273 | |||
274 | The preceding conclusion formerly appeared in dumb.txt, and is deprecated | ||
275 | because it's lame. | ||
276 | |||
277 | |||
278 | Ben Davis | ||
279 | entheh@users.sf.net | ||
280 | IRC EFnet #dumb | ||
281 | See readme.txt for details on using IRC. | ||
diff --git a/apps/codecs/dumb/docs/dumb.txt b/apps/codecs/dumb/docs/dumb.txt new file mode 100644 index 0000000000..86b2cc3374 --- /dev/null +++ b/apps/codecs/dumb/docs/dumb.txt | |||
@@ -0,0 +1,1699 @@ | |||
1 | /* _______ ____ __ ___ ___ | ||
2 | * \ _ \ \ / \ / \ \ / / ' ' ' | ||
3 | * | | \ \ | | || | \/ | . . | ||
4 | * | | | | | | || ||\ /| | | ||
5 | * | | | | | | || || \/ | | ' ' ' | ||
6 | * | | | | | | || || | | . . | ||
7 | * | |_/ / \ \__// || | | | ||
8 | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque | ||
9 | * / \ | ||
10 | * / . \ | ||
11 | * dumb.txt - DUMB library reference. / / \ \ | ||
12 | * | < / \_ | ||
13 | * See readme.txt for general information on | \/ /\ / | ||
14 | * DUMB and how to set it up. \_ / > / | ||
15 | * | \ / / | ||
16 | * If you are new to DUMB, see howto.txt. | ' / | ||
17 | * \__/ | ||
18 | */ | ||
19 | |||
20 | |||
21 | *********************************** | ||
22 | *** Include Files and Libraries *** | ||
23 | *********************************** | ||
24 | |||
25 | |||
26 | dumb.h | ||
27 | |||
28 | Include this if you only want the core DUMB library functions. You will | ||
29 | be able to load music files and render them into memory buffers at your | ||
30 | own pace. The core library is completely portable, and as such does not | ||
31 | access hardware; you must relay the sound data to the sound card yourself. | ||
32 | A stdio file input module is available, but you must actively register it | ||
33 | if you wish to use it (see dumb_register_stdfiles()); if you do not | ||
34 | register it, it will not be linked into your executable. You must register | ||
35 | it, or a DUMBFILE module of your own, in order to load stand-alone music | ||
36 | files. | ||
37 | |||
38 | Optimised: -ldumb or /link dumb.lib | ||
39 | Debugging: -ldumbd or /link dumbd.lib | ||
40 | |||
41 | |||
42 | aldumb.h | ||
43 | |||
44 | Include this if you wish to use DUMB with Allegro. This will provide you | ||
45 | with functions to play DUHs back through Allegro's audio streams and embed | ||
46 | music files in Allegro datafiles. A file input module using Allegro's | ||
47 | packfiles is provided; you have a choice between this and the stdio | ||
48 | module (or provide one of your own). You will be able to load datafiles | ||
49 | containing music files no matter which file input module you register, or | ||
50 | even if you register no file input module. However, you must register a | ||
51 | file input module in order to load stand-alone files. | ||
52 | |||
53 | Optimised: -laldmb -ldumb -lalleg or /link aldmb.lib alleg.lib dumb.lib | ||
54 | Debugging: -laldmd -ldumbd -lalld or /link aldmd.lib alld.lib dumbd.lib | ||
55 | |||
56 | aldmb or aldmd must be linked in first, so the symbols can be resolved | ||
57 | when linking in the other two libraries. | ||
58 | |||
59 | |||
60 | *************************** | ||
61 | *** Version Information *** | ||
62 | *************************** | ||
63 | |||
64 | |||
65 | #define DUMB_MAJOR_VERSION | ||
66 | #define DUMB_MINOR_VERSION | ||
67 | #define DUMB_REVISION_VERSION | ||
68 | |||
69 | Numeric constants representing this version of DUMB. If this were version | ||
70 | 1.0, DUMB_MAJOR_VERSION would be 1 and DUMB_MINOR_VERSION would be 0. | ||
71 | DUMB_REVISION_VERSION will be 0 on any significant releases, and will be | ||
72 | incremented as releases with bugfixes and minor features are made. | ||
73 | |||
74 | Typical usage: | ||
75 | |||
76 | #if DUMB_MAJOR_VERSION < 1 | ||
77 | #error This add-on requires DUMB v1.0 or higher. Please upgrade. | ||
78 | #endif | ||
79 | |||
80 | |||
81 | #define DUMB_VERSION | ||
82 | |||
83 | A numeric constant which appears in the format MMmmrr when displayed in | ||
84 | decimal (M for major, m for minor, r for revision). This is most useful | ||
85 | for comparing version numbers; it has little other practical use. | ||
86 | |||
87 | Typical usage: | ||
88 | |||
89 | #if DUMB_VERSION < 801 | ||
90 | #error This game requires DUMB v0.8.1 or higher. Please upgrade. | ||
91 | #endif | ||
92 | |||
93 | #if DUMB_VERSION < 10002 | ||
94 | #error This game requires DUMB v1.0.2 or higher. Please upgrade. | ||
95 | #endif | ||
96 | |||
97 | |||
98 | #define DUMB_VERSION_STR | ||
99 | |||
100 | String constant representing this version of DUMB. If this were Version | ||
101 | 1.0, DUMB_VERSION_STR would be "1.0". DUMB_REVISION_VERSION will only | ||
102 | appear on the end if it is nonzero; then DUMB_VERSION_STR might be | ||
103 | "1.0.1". | ||
104 | |||
105 | |||
106 | #define DUMB_NAME | ||
107 | |||
108 | A string identifying DUMB and its version. If this were Version 1.0, | ||
109 | DUMB_NAME might be "DUMB v1.0". This constant is suitable for use in your | ||
110 | Credits screen if you wish to acknowledge the use of DUMB there. | ||
111 | |||
112 | |||
113 | #define DUMB_YEAR | ||
114 | #define DUMB_MONTH | ||
115 | #define DUMB_DAY | ||
116 | |||
117 | Numeric constants representing the year, month and day of this release of | ||
118 | DUMB. All four digits are included in the year. Please note that | ||
119 | DUMB_MONTH and DUMB_DAY were inadvertently swapped in the v0.8 release. | ||
120 | |||
121 | |||
122 | #define DUMB_YEAR_STR4 | ||
123 | #define DUMB_YEAR_STR2 | ||
124 | #define DUMB_MONTH_STR2 | ||
125 | #define DUMB_MONTH_STR1 | ||
126 | #define DUMB_DAY_STR2 | ||
127 | #define DUMB_DAY_STR1 | ||
128 | |||
129 | String constants representing the year, month and day of this release of | ||
130 | DUMB. DUMB_MONTH_STR2 and DUMB_DAY_STR2 include a leading zero if the | ||
131 | month or day respectively are less than ten; the STR1 variations do not. | ||
132 | DUMB_YEAR_STR2 contains only the two rightmost digits of the year, while | ||
133 | DUMB_YEAR_STR4 contains all four. I recommend using DUMB_YEAR_STR4, | ||
134 | especially so soon after the turn of the century (indeed the millennium). | ||
135 | However, it is a matter of personal preference which you use. | ||
136 | |||
137 | Please note that the month and day were inadvertently swapped in the v0.8 | ||
138 | release. | ||
139 | |||
140 | |||
141 | #define DUMB_DATE | ||
142 | |||
143 | A numeric constant that appears in the form yyyymmdd when displayed in | ||
144 | decimal. This is most useful for comparing release dates; it has little | ||
145 | other practical use. | ||
146 | |||
147 | WARNING: The month and day were inadvertently swapped in the v0.8 release. | ||
148 | Please do not compare this constant against any date in 2002. In | ||
149 | any case, DUMB_VERSION is probably more useful for this purpose. | ||
150 | |||
151 | |||
152 | #define DUMB_DATE_STR | ||
153 | |||
154 | The date as a string. The format is "d.m.yyyy", with dots used as | ||
155 | separators, the day written first, four digits for the year, and no | ||
156 | leading zeros on the day or month. This is my preferred format. If you | ||
157 | don't like it, you can construct your own format using the other | ||
158 | constants. For example, "mm/dd/yy" could be constructed as follows: | ||
159 | |||
160 | DUMB_MONTH_STR2 "/" DUMB_DAY_STR2 "/" DUMB_YEAR_STR2 | ||
161 | |||
162 | Please note that the month and day were inadvertently swapped in the v0.8 | ||
163 | release. | ||
164 | |||
165 | |||
166 | ************************* | ||
167 | *** Basic Sample Type *** | ||
168 | ************************* | ||
169 | |||
170 | |||
171 | typedef int sample_t; | ||
172 | |||
173 | DUMB works internally with 32-bit integer samples, with a 'normal range' | ||
174 | from -0x800000 to 0x7FFFFF (as of DUMB v0.9.2; previously they ranged from | ||
175 | -0x8000 to 0x7FFF). Any samples that exceed this range will eventually be | ||
176 | clipped, and could cause integer overflow in extreme cases. | ||
177 | |||
178 | |||
179 | *********************************** | ||
180 | *** Library Clean-up Management *** | ||
181 | *********************************** | ||
182 | |||
183 | |||
184 | int dumb_atexit(void (*proc)(void)); | ||
185 | |||
186 | Registers a function to be called at the end of your program. You can | ||
187 | register multiple functions to be called, and the one you register last | ||
188 | will be called first. If you try to register the same function twice, the | ||
189 | second attempt will have no effect. | ||
190 | |||
191 | See fnptr.txt for help with function pointers. | ||
192 | |||
193 | You must call dumb_exit() before exiting your program for this to work | ||
194 | properly. The library itself registers functions with dumb_atexit(), so it | ||
195 | is important to call dumb_exit() even if you do not use dumb_atexit() | ||
196 | yourself. | ||
197 | |||
198 | This function will return zero on success. It will return zero when | ||
199 | trying to install the same function twice. If it fails through lack of | ||
200 | memory, it will return nonzero. Generally you can ignore the return code; | ||
201 | in the worst case some memory will not be freed at the end. If it is | ||
202 | crucial that your function be called (e.g. to shut down some hardware or | ||
203 | save critical data), then you should call your function manually at the | ||
204 | end of the program instead of registering it here - or use the stdlib | ||
205 | function atexit(), guaranteed under ANSI C to succeed for at least 32 | ||
206 | functions. | ||
207 | |||
208 | |||
209 | void dumb_exit(void); | ||
210 | |||
211 | You should call this before exiting your program if you have used any part | ||
212 | of DUMB in the program. Some parts of DUMB will allocate memory, and this | ||
213 | function will free it all up. | ||
214 | |||
215 | More specifically, this function will call any functions that have been | ||
216 | registered with dumb_atexit(). If a part of DUMB needs shutting down, the | ||
217 | shutdown procedure will have been registered in this way. | ||
218 | |||
219 | dumb_exit() will, of course, also call any functions you registered with | ||
220 | dumb_atexit() yourself. | ||
221 | |||
222 | After a call to dumb_exit(), the list of functions is erased. If you are | ||
223 | not ready to exit your program, you can start using DUMB anew as if your | ||
224 | program had just started. (Note that not everything will be reset in | ||
225 | practice - dumb_resampling_quality will retain whatever you set it to, for | ||
226 | example, though you should not assume it will.) | ||
227 | |||
228 | If you only need to call dumb_exit() once at the end of the program, you | ||
229 | can use the following to register dumb_exit() with stdlib.h atexit(): | ||
230 | |||
231 | #include <stdlib.h> | ||
232 | |||
233 | atexit(&dumb_exit); | ||
234 | |||
235 | Then dumb_exit() will be called for you when your program exits. This is | ||
236 | the recommended method, since it will ensure clean-up even if your program | ||
237 | aborts. You should only call dumb_exit() manually if you need to shut DUMB | ||
238 | down prematurely, or if atexit() is unavailable for one reason or another. | ||
239 | |||
240 | |||
241 | ***************************** | ||
242 | *** Sequential File Input *** | ||
243 | ***************************** | ||
244 | |||
245 | |||
246 | DUMB provides a strictly sequential file input system which uses the | ||
247 | DUMBFILE struct. "Strictly sequential" means you cannot seek backwards. | ||
248 | However, the system will keep track of how many bytes you have read, | ||
249 | enabling you to seek forwards. DUMBFILEs provide a convenient error | ||
250 | detection system, so you do not have to check the return value from every | ||
251 | function call in the way you do with the ANSI C functions. | ||
252 | |||
253 | Note that DUMBFILEs cannot be used for output, nor can they be used | ||
254 | portably for text files. | ||
255 | |||
256 | If an error occurs when reading data from a DUMBFILE, the DUMBFILE will | ||
257 | become inoperative. All subsequent activities on the DUMBFILE will return | ||
258 | error codes without attempting to read from the file. The position in the | ||
259 | file will also be forgotten. You can find out if this has happened at any | ||
260 | stage with the dumbfile_error() function. You are still required to close | ||
261 | the DUMBFILE, and the return value from dumbfile_close() will tell you if | ||
262 | an error has occurred. | ||
263 | |||
264 | This system allows you to input large chunks of your file, neither | ||
265 | checking every return value nor wasting time accessing a file that has | ||
266 | already experienced an error. However, before you allocate an amount of | ||
267 | memory or read in a quantity of data depending on previous input from the | ||
268 | file, you should always check that such input was valid. In particular you | ||
269 | should avoid passing zero or negative numbers to malloc(), and avoid | ||
270 | passing negative numbers to dumbfile_skip() and dumbfile_getnc(). | ||
271 | |||
272 | DUMBFILEs can be hooked. In other words, you can specify your own | ||
273 | functions to do the work of reading from a file. While DUMB contains two | ||
274 | modules for this purpose, it does not set them up for you automatically. | ||
275 | In most cases you must register one of these modules yourself, or provide | ||
276 | your own module. See register_dumbfile_system(), dumb_register_stdfiles() | ||
277 | and dumb_register_packfiles(). | ||
278 | |||
279 | |||
280 | void register_dumbfile_system(DUMBFILE_SYSTEM *dfs); | ||
281 | |||
282 | Use this function to register a set of functions for use by the DUMBFILEs | ||
283 | (a DUMBFILE system). The DUMBFILE_SYSTEM struct contains the following | ||
284 | fields: | ||
285 | |||
286 | void *(*open)(const char *filename); | ||
287 | int (*skip)(void *f, long n); | ||
288 | int (*getc)(void *f); | ||
289 | long (*getnc)(char *ptr, long n, void *f); | ||
290 | void (*close)(void *f); | ||
291 | |||
292 | See fnptr.txt for help with function pointers such as these. | ||
293 | |||
294 | Your 'open' function should open the file specified and return a pointer | ||
295 | to a struct representing the open file. This pointer will be passed to | ||
296 | your other functions as 'f'. Your 'close' function should close the file | ||
297 | and free all memory pointed to by 'f'. Note that the 'close' operation | ||
298 | should never be able to fail; if you are calling a function with a return | ||
299 | value, you can generally ignore it. | ||
300 | |||
301 | Your 'getc' function should read one byte from the file and return its | ||
302 | value in the range 0 to 255. If an error occurs, you should return -1. Do | ||
303 | not worry about remembering that an error has occurred; DUMB will do that | ||
304 | for you. | ||
305 | |||
306 | 'skip' is for skipping parts of the file, and should skip n bytes, | ||
307 | returning 0 on success or any other number on failure. 'getnc' should read | ||
308 | n bytes from the file, store them at 'ptr', and return the number of bytes | ||
309 | read (n on success, fewer on failure). However, these two functions are | ||
310 | optional, and you should only provide them if the operations can be done | ||
311 | more efficiently than with repeated calls to your 'getc' function. If this | ||
312 | is not the case, specify NULL for 'skip', 'getnc' or both, and DUMB will | ||
313 | use your 'getc' function to do the work. | ||
314 | |||
315 | Once you have written all your functions, you need to create a | ||
316 | DUMBFILE_SYSTEM struct to hold them, and pass its pointer to | ||
317 | register_dumbfile_system(). | ||
318 | |||
319 | The DUMBFILE_SYSTEM struct must be permanent. In other words, it must be | ||
320 | either global or static, and you should not modify it later. DUMB will not | ||
321 | make its own copy. | ||
322 | |||
323 | You will most likely create your own struct to represent the open file, | ||
324 | but do not be tempted to specify that struct in the function prototypes | ||
325 | and pacify the compiler warnings by casting your function pointers. There | ||
326 | exist computer systems where a (void *) pointer and a (MY_STRUCT *) | ||
327 | pointer are represented differently in memory, and a cast of such a | ||
328 | pointer causes a tangible conversion to take place. If you cast the | ||
329 | function pointers, the computer cannot know when such a conversion is | ||
330 | necessary. Instead, use the following structure: | ||
331 | |||
332 | int myskip(void *f, long n) | ||
333 | { | ||
334 | FILE *file = f; | ||
335 | /* Do some stuff with 'file' */ | ||
336 | return something; | ||
337 | } | ||
338 | |||
339 | If you need examples, have a look at the two existing DUMBFILE systems in | ||
340 | dumb/src/core/stdfile.c and dumb/src/allegro/packfile.c. | ||
341 | |||
342 | |||
343 | DUMBFILE *dumbfile_open(const char *filename); | ||
344 | |||
345 | Open the specified file for input. You must pass the DUMBFILE pointer | ||
346 | whenever you wish to operate on this file. When you have finished with the | ||
347 | file, you must pass it to dumbfile_close(). | ||
348 | |||
349 | Before you use this function, make sure you have registered a DUMBFILE | ||
350 | system. See register_dumbfile_system(), dumb_register_stdfiles() and | ||
351 | dumb_register_packfiles(). | ||
352 | |||
353 | You must check the return value from this function. If it is NULL, the | ||
354 | file could not be opened, and you must not pass the DUMBFILE to any other | ||
355 | function. The debugging library will abort if you get this wrong; the | ||
356 | optimised library will act weird. | ||
357 | |||
358 | |||
359 | DUMBFILE *dumbfile_open_ex(void *file, DUMBFILE_SYSTEM *dfs); | ||
360 | |||
361 | This function is provided for more specialised use. You should create a | ||
362 | DUMBFILE_SYSTEM specially for the purpose. Its 'open' field is irrelevant; | ||
363 | for neatness, set it to NULL, unless you are using this DUMBFILE_SYSTEM | ||
364 | with register_dumbfile_system() as well. | ||
365 | |||
366 | When you have called this function, the DUMBFILE struct it returned can be | ||
367 | used as normal. The specified DUMBFILE_SYSTEM will be used for all input, | ||
368 | with 'file' passed to your 'skip', 'getc' and 'getnc' functions as 'f'. | ||
369 | This can be used, for example, to read from an already open file. | ||
370 | |||
371 | Note that the position will always be initialised to 0 for this DUMBFILE. | ||
372 | This means for example that offsets in the file do not need adjusting when | ||
373 | embedding data in a larger file. | ||
374 | |||
375 | There are two ways to use this function. If you want 'file' to persist | ||
376 | after using a DUMBFILE returned by this function, you should make sure the | ||
377 | 'close' field in the DUMBFILE is set to NULL. When the DUMBFILE is closed, | ||
378 | 'file' will be left alone, and you can and should deal with it yourself | ||
379 | when the DUMBFILE has been closed. | ||
380 | |||
381 | Alternatively, you can provide a 'close' function to get rid of 'file' for | ||
382 | you when the DUMBFILE is closed. If you do this, you should not otherwise | ||
383 | use 'file' after a call to this function. | ||
384 | |||
385 | If dumbfile_open_ex() has to return NULL, owing to lack of memory, then | ||
386 | your 'close' function will be called if provided. In other words, if you | ||
387 | have provided a 'close' function, then you no longer need to worry about | ||
388 | 'file' whether this function succeeds or not. | ||
389 | |||
390 | See dumb/src/helpers/stdfile.c and dumb/src/allegro/packfile.c for | ||
391 | examples of how to use this function. Neither provides a 'close' function, | ||
392 | so I hope my explanation here will suffice. If not, please feel free to | ||
393 | contact me so I can make the explanation clearer and help you do what you | ||
394 | want to do. Contact details are at the end of this file. | ||
395 | |||
396 | |||
397 | long dumbfile_pos(DUMBFILE *f); | ||
398 | |||
399 | Returns the number of bytes read from the DUMBFILE (or skipped) since it | ||
400 | was opened, or -1 if an error has occurred while reading. | ||
401 | |||
402 | |||
403 | int dumbfile_skip(DUMBFILE *f, long n); | ||
404 | |||
405 | Skips n bytes of the specified DUMBFILE. Returns zero on success. | ||
406 | |||
407 | |||
408 | int dumbfile_getc(DUMBFILE *f); | ||
409 | |||
410 | Reads one byte from the DUMBFILE and returns it in unsigned format (from 0 | ||
411 | to 255). If an error occurs, or occurred before, this function returns -1. | ||
412 | |||
413 | |||
414 | int dumbfile_igetw(DUMBFILE *f); | ||
415 | |||
416 | Reads two bytes from the DUMBFILE and combines them into a word ranging | ||
417 | from 0 to 65535. The first byte read is the least significant byte, as | ||
418 | with Intel processors. This function returns -1 on error. | ||
419 | |||
420 | |||
421 | int dumbfile_mgetw(DUMBFILE *f); | ||
422 | |||
423 | Reads two bytes from the DUMBFILE and combines them into a word ranging | ||
424 | from 0 to 65535. The first byte read is the most significant byte, as | ||
425 | with the Apple Macintosh. This function returns -1 on error. | ||
426 | |||
427 | |||
428 | long dumbfile_igetl(DUMBFILE *f); | ||
429 | |||
430 | Reads four bytes from the DUMBFILE and combines them into a long integer | ||
431 | ranging from -2147483648 to 2147483647. The first byte read is the least | ||
432 | significant byte, as with Intel processors. This function returns -1 on | ||
433 | error, but -1 is also a valid return value. After a call to this function, | ||
434 | you can use dumbfile_error() to find out if an error occurred. | ||
435 | |||
436 | |||
437 | long dumbfile_mgetl(DUMBFILE *f); | ||
438 | |||
439 | Reads four bytes from the DUMBFILE and combines them into a long integer | ||
440 | ranging from -2147483648 to 2147483647. The first byte read is the most | ||
441 | significant byte, as with the Apple Macintosh. This function returns -1 on | ||
442 | error, but -1 is also a valid return value. After a call to this function, | ||
443 | you can use dumbfile_error() to find out if an error occurred. | ||
444 | |||
445 | |||
446 | unsigned long dumbfile_cgetul(DUMBFILE *f); | ||
447 | |||
448 | Reads an unsigned (nonnegative) integer from the DUMBFILE. The integer is | ||
449 | stored in a condensed format where smaller numbers use less space: | ||
450 | |||
451 | 0 to 127 1 byte | ||
452 | 128 to 16383 2 bytes | ||
453 | 16384 to 2097151 3 bytes | ||
454 | 2097152 to 268435455 4 bytes | ||
455 | 268435456 to 4294967295 5 bytes | ||
456 | |||
457 | This format is the same as that used for the times between notes in MIDI | ||
458 | files. | ||
459 | |||
460 | If an error occurs, this function returns (unsigned long)(-1), but that | ||
461 | may be a valid return value. After a call to this function, you can use | ||
462 | dumbfile_error() to find out if an error occurred. | ||
463 | |||
464 | |||
465 | signed long dumbfile_cgetsl(DUMBFILE *f); | ||
466 | |||
467 | Reads a signed integer from the DUMBFILE. The integer is stored in a | ||
468 | condensed format where numbers closer to zero use less space: | ||
469 | |||
470 | -64 to 63 1 byte | ||
471 | -8192 to 8191 2 bytes | ||
472 | -1048576 to 1048575 3 bytes | ||
473 | -134217728 to 134217727 4 bytes | ||
474 | -2147483648 to 2147483647 5 bytes | ||
475 | |||
476 | If an error occurs, this function returns -1, but -1 is also a valid | ||
477 | return value. After a call to this function, you can use dumbfile_error() | ||
478 | to find out if an error occurred. | ||
479 | |||
480 | |||
481 | long dumbfile_getnc(char *ptr, long n, DUMBFILE *f); | ||
482 | |||
483 | Reads n bytes from the DUMBFILE and stores them at 'ptr'. Note that the | ||
484 | pointer is to a series of chars. You may also use this function to read in | ||
485 | a series of signed chars or unsigned chars (which are both officially | ||
486 | distinct types from char), but do not use this to read ints, structs or | ||
487 | any other data type from the file. Integers must be read one at a time | ||
488 | using dumbfile_igetl(), dumbfile_cgetul(), etc. To load a struct in, you | ||
489 | must read each field separately using an appropriate function for each | ||
490 | one. For complicated data types, you can simplify this process by writing | ||
491 | a function for each struct. | ||
492 | |||
493 | dumbfile_getnc() returns the number of bytes successfully read, which will | ||
494 | be less than n if an error occurs, and may be as low as zero. If | ||
495 | dumbfile_getnc() returns -1, that means an error occurred on this DUMBFILE | ||
496 | earlier, before this function was called. | ||
497 | |||
498 | |||
499 | int dumbfile_error(DUMBFILE *f); | ||
500 | |||
501 | This function returns -1 if an error has occurred with the specified | ||
502 | DUMBFILE, or 0 if all is well. | ||
503 | |||
504 | |||
505 | int dumbfile_close(DUMBFILE *f); | ||
506 | |||
507 | This function closes the DUMBFILE, after which the pointer will be | ||
508 | invalid. dumbfile_close() returns the value that dumbfile_error() would | ||
509 | have returned, which is -1 if an error occurred while reading or 0 | ||
510 | otherwise. Regardless of the return value, the file will always be closed | ||
511 | properly. | ||
512 | |||
513 | |||
514 | ******************************* | ||
515 | *** stdio File Input Module *** | ||
516 | ******************************* | ||
517 | |||
518 | |||
519 | void dumb_register_stdfiles(void); | ||
520 | |||
521 | This function registers the stdio file input module for use by DUMBFILEs. | ||
522 | FILE structs and their corresponding functions, as defined by the ANSI C | ||
523 | header stdio.h, will be used internally for all DUMBFILE input (unless | ||
524 | opened with dumbfile_open_ex()). | ||
525 | |||
526 | This must be called before dumbfile_open() is used, or else an alternative | ||
527 | system must be registered (see register_dumbfile_system() and | ||
528 | dumb_register_packfiles()). | ||
529 | |||
530 | |||
531 | DUMBFILE *dumbfile_open_stdfile(FILE *p); | ||
532 | |||
533 | If you have a stdio FILE struct representing an open file, you can call | ||
534 | this if you wish to read from it using a DUMBFILE. This is useful when you | ||
535 | need to pass a DUMBFILE struct to a library function, to read an embedded | ||
536 | music file for example. When you close the DUMBFILE, you can continue | ||
537 | using the FILE struct to read what follows the embedded data. | ||
538 | |||
539 | |||
540 | ******************************** | ||
541 | *** Memory File Input Module *** | ||
542 | ******************************** | ||
543 | |||
544 | |||
545 | DUMBFILE *dumbfile_open_memory(const char *data, long size); | ||
546 | |||
547 | This function is useful if you have an image of a music file in memory. | ||
548 | You might have such an image if you use dat2s to encode a datafile | ||
549 | directly into the executable. Pass a pointer to the start of the memory, | ||
550 | and the size of the image to make sure DUMB doesn't overrun the buffer. | ||
551 | The resulting DUMBFILE will feed the contents of the image to you. | ||
552 | |||
553 | Note that the pointer is of type 'char *'. Files are series of chars, and | ||
554 | interpreting them directly as anything else isn't portable. | ||
555 | |||
556 | |||
557 | ********************** | ||
558 | *** DUH Management *** | ||
559 | ********************** | ||
560 | |||
561 | |||
562 | void unload_duh(DUH *duh); | ||
563 | |||
564 | Removes a DUH from memory. You must call this for all DUHs you load, | ||
565 | making sure they're not playing at the time. | ||
566 | |||
567 | |||
568 | long duh_get_length(DUH *duh); | ||
569 | |||
570 | Returns the length of a DUH; 65536 represents one second. This value is | ||
571 | calculated when the DUH is created, and this function simply lifts it from | ||
572 | the struct. It may not truly correspond to the time for which the DUH will | ||
573 | generate sound. For module files, it will represent the point at which the | ||
574 | module first loops (or, in the case of some XM and MOD files, freezes). | ||
575 | Any add-ons to DUMB will provide their own code for calculating this. | ||
576 | |||
577 | The algorithm for calculating the length of a module file can be fooled, | ||
578 | but only by very deliberate methods. In the early days, when modules could | ||
579 | only be played by their editors and had to be exported to .wav or similar | ||
580 | in order to be used elsewhere, musicians would sometimes make the player | ||
581 | think it was looping when it wasn't in order to prevent their music from | ||
582 | being exported properly. If the length of a module seems a lot less than | ||
583 | it should be, the module is probably protected in this way. | ||
584 | |||
585 | Getting around this protection reliably would be extremely difficult, but | ||
586 | after considering it for a while I decided it would be better not to. The | ||
587 | musician has a right to protect his or her music in this way, and I have | ||
588 | no interest in actively breaking that protection. | ||
589 | |||
590 | (On the other hand, some musicians were just showing off!) | ||
591 | |||
592 | |||
593 | *********************************** | ||
594 | *** IT, XM, S3M and MOD Support *** | ||
595 | *********************************** | ||
596 | |||
597 | |||
598 | int dumb_it_max_to_mix; | ||
599 | |||
600 | Specifies the maximum number of samples DUMB will mix at any one time. The | ||
601 | default number is 64. Regardless of this value, all samples will continue | ||
602 | to be processed up to an internal maximum of 256 (roughly speaking; in | ||
603 | fact it will process one sample for each channel plus up to 192 extra | ||
604 | samples that are continuing to play owing to Impulse Tracker's New Note | ||
605 | Actions), and samples that have been cut will sound again as soon as the | ||
606 | congestion clears. Samples are given priority according to their final | ||
607 | volume after all factors affecting the volume of a sample have been | ||
608 | considered. | ||
609 | |||
610 | If you play two or more modules at once, this value represents the | ||
611 | maximum number of samples for each one. You will have to reduce it further | ||
612 | if your computer cannot keep up. | ||
613 | |||
614 | Despite the name, this variable controls XM, S3M and MOD files as well as | ||
615 | IT files. | ||
616 | |||
617 | |||
618 | DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh); | ||
619 | |||
620 | This function attempts to retrieve the DUMB_IT_SIGDATA struct from a DUH. | ||
621 | This struct will exist for any IT, XM, S3M or MOD file, and you can use it | ||
622 | to obtain or override module-specific information. If 'duh' is NULL, or if | ||
623 | the DUH you pass contains something other than a music module, then this | ||
624 | function will return NULL (which can safely be passed to any other | ||
625 | function). | ||
626 | |||
627 | |||
628 | DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer); | ||
629 | |||
630 | This function attempts to retrieve the DUMB_IT_SIGRENDERER struct from a | ||
631 | DUH_SIGRENDERER. This struct will exist for any currently playing IT, XM, | ||
632 | S3M or MOD file, and you can use it to obtain or override information | ||
633 | specific to module playback. If 'sigrenderer' is NULL, or if the | ||
634 | DUH_SIGRENDERER you pass is rendering something other than a music module, | ||
635 | then this function will return NULL (which can safely be passed to any | ||
636 | other function). | ||
637 | |||
638 | |||
639 | DUH_SIGRENDERER *dumb_it_start_at_order | ||
640 | (DUH *duh, int n_channels, int startorder); | ||
641 | |||
642 | This function, given a DUH containing an IT, XM, S3M or MOD file, will | ||
643 | start playing it at the specified order. If the DUH does not contain a | ||
644 | module, this function will fail and return NULL. | ||
645 | |||
646 | Note that starting at an arbitrary order may result in missing notes or | ||
647 | other playback oddities. It should be used primarily for modules that | ||
648 | contain multiple songs that start on different orders. If you wish just to | ||
649 | start some music in the middle, consider using duh_start_sigrenderer() or | ||
650 | al_start_duh() with the pos parameter set appropriately. | ||
651 | |||
652 | |||
653 | void dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer, | ||
654 | int (*callback)(void *data), void *data); | ||
655 | |||
656 | Installs a callback which will be called every time the module loops. You | ||
657 | can pass any data pointer you like, and it will be passed to the callback | ||
658 | for you. DUMB considers a file to loop when it reaches the end, or when a | ||
659 | 'Jump to order' effect (Bxx in both IT/S3M and XM/MOD) jumps to the same | ||
660 | order or a preceding order. This can result in the loop callback being | ||
661 | called when the module isn't really looping, but this only happens if the | ||
662 | module has a very deliberate design. See duh_get_length() for further | ||
663 | musings on this subject. | ||
664 | |||
665 | If your callback returns nonzero, the music will stop abruptly. Samples | ||
666 | will be cut, and the main program will be notified that the | ||
667 | DUH_SIGRENDERER has ended. | ||
668 | |||
669 | Alternatively, if you pass the DUMB_IT_SIGRENDERER for 'data', or | ||
670 | otherwise arrange for it to be available to the callback, then you can | ||
671 | call: | ||
672 | |||
673 | dumb_it_sr_set_speed(sigrenderer, 0); | ||
674 | |||
675 | from inside the callback, and this will cause the music to freeze but | ||
676 | samples will be able to continue playing. The xm_speed_zero callback will | ||
677 | NOT be called in this case (see below for information on this callback). | ||
678 | Note also that setting the speed in this way will work equally for IT and | ||
679 | S3M files, even though a 'speed zero' effect can only exist in XM and MOD | ||
680 | files. Beware when using this method; samples might not fade at all! | ||
681 | |||
682 | A helper callback, dumb_it_callback_terminate(), is provided; installing | ||
683 | this will cause the music to terminate when it tries to loop for the first | ||
684 | time. | ||
685 | |||
686 | Pass NULL to remove the callback function; the module will then loop as | ||
687 | normal. | ||
688 | |||
689 | |||
690 | void dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, | ||
691 | int (*callback)(void *data), void *data); | ||
692 | |||
693 | Installs a callback which is in many ways similar to the loop callback | ||
694 | (see dumb_it_set_loop_callback()). This callback will be called whenever | ||
695 | an F00 effect is encountered in a MOD or XM file, setting the speed to | ||
696 | zero. If the callback returns nonzero, the music will terminate. If not, | ||
697 | any currently playing samples will continue to play. You can pass any data | ||
698 | pointer you like to this function, and it will be passed to your callback | ||
699 | for you. | ||
700 | |||
701 | The helper callback, dumb_it_callback_terminate(), will also work here; | ||
702 | installing it will cause the music to terminate as soon as an F00 effect | ||
703 | is encountered. | ||
704 | |||
705 | Pass NULL to remove the callback function. | ||
706 | |||
707 | |||
708 | void dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer, | ||
709 | int (*callback)(void *data, int channel, unsigned char byte), | ||
710 | void *data); | ||
711 | |||
712 | Installs a callback function which will be called whenever MIDI data are | ||
713 | generated by an IT file. (No other module formats are capable of | ||
714 | generating MIDI data, so your callback will never be called.) | ||
715 | |||
716 | Zxx macros will generate MIDI data. These are most often used to set the | ||
717 | parameters for IT's low-pass resonant filters, and DUMB will handle these | ||
718 | messages by itself by default. See Impulse Tracker's documentation for | ||
719 | the MIDI messages that control filters. However, Zxx macros can be used | ||
720 | to send any kind of MIDI data. | ||
721 | |||
722 | If you wish to interpret MIDI messages yourself, you can use this | ||
723 | callback. Note that the only MIDI messages generated by DUMB at present | ||
724 | are from Zxx macros; there are no messages for note start, stop, or | ||
725 | anything else. | ||
726 | |||
727 | If you return 1 from this callback, DUMB will subsequently ignore the byte | ||
728 | of MIDI data. You can use this to prevent Zxx macros from controlling the | ||
729 | filters, useful if they were intended to do something else. Note that this | ||
730 | is NOT an effective way to disable filters, since instruments can have | ||
731 | filter envelopes and initial filter parameters. DUMB provides no means to | ||
732 | disable filters, as any IT file that uses them will sound wrong without | ||
733 | them. If you want lower processor consumption, use a different piece of | ||
734 | music. | ||
735 | |||
736 | A helper callback, dumb_it_callback_midi_block(), is provided for blocking | ||
737 | all MIDI messages and making Zxx macros do nothing. | ||
738 | |||
739 | Pass NULL to remove the callback. | ||
740 | |||
741 | |||
742 | int dumb_it_callback_terminate(void *data); | ||
743 | |||
744 | This is a helper callback that can be installed with both | ||
745 | dumb_it_set_loop_callback() and dumb_it_set_xm_speed_zero_callback(). In | ||
746 | each case it will cause the music to terminate abruptly. | ||
747 | |||
748 | |||
749 | int dumb_it_callback_midi_block(void *data, int channel, unsigned char byte); | ||
750 | |||
751 | This helper callback, for use with dumb_it_set_midi_callback(), will | ||
752 | absorb all MIDI messages, returning 1 to prevent DUMB from interpreting | ||
753 | them itself. | ||
754 | |||
755 | |||
756 | DUH *dumb_load_it(const char *filename); | ||
757 | |||
758 | Loads the specified Impulse Tracker file, encapsulating it in a DUH | ||
759 | struct. Once the file is loaded, it can be treated exactly the same as any | ||
760 | other DUH in memory. If this fails it will return NULL, but you can safely | ||
761 | pass this NULL value to DUMB's other functions, so you do not need to | ||
762 | check the return value explicitly. | ||
763 | |||
764 | |||
765 | DUH *dumb_read_it(DUMBFILE *f); | ||
766 | |||
767 | Reads an Impulse Tracker file from an already open DUMBFILE. This leaves | ||
768 | the DUMBFILE open, but the DUMBFILE may not be positioned at the end of | ||
769 | the IT data. If you are embedding an IT in another file, you are advised | ||
770 | to store the size of the IT file and make up for it at the end using | ||
771 | dumbfile_pos(). | ||
772 | |||
773 | Otherwise, this function is identical to dumb_load_it(). | ||
774 | |||
775 | WARNING: The behaviour of this function is undefined if you pass a | ||
776 | DUMBFILE from which data have already been read; it is likely not | ||
777 | to work. This oversight will be fixed in future releases. | ||
778 | |||
779 | |||
780 | DUH *dumb_load_xm(const char *filename); | ||
781 | |||
782 | Loads the specified Fast Tracker II file, encapsulating it in a DUH | ||
783 | struct. Once the file is loaded, it can be treated exactly the same as any | ||
784 | other DUH in memory. If this fails it will return NULL, but you can safely | ||
785 | pass this NULL value to DUMB's other functions, so you do not need to | ||
786 | check the return value explicitly. | ||
787 | |||
788 | |||
789 | DUH *dumb_read_xm(DUMBFILE *f); | ||
790 | |||
791 | Reads a Fast Tracker II file from an already open DUMBFILE. This leaves | ||
792 | the DUMBFILE open, but the DUMBFILE may not be positioned at the end of | ||
793 | the XM data. If you are embedding an XM in another file, you are advised | ||
794 | to store the size of the XM file and make up for it at the end using | ||
795 | dumbfile_pos(). | ||
796 | |||
797 | Otherwise, this function is identical to dumb_load_xm(). | ||
798 | |||
799 | WARNING: The behaviour of this function is undefined if you pass a | ||
800 | DUMBFILE from which data have already been read; it is likely not | ||
801 | to work. This oversight will be fixed in future releases. | ||
802 | |||
803 | |||
804 | DUH *dumb_load_s3m(const char *filename); | ||
805 | |||
806 | Loads the specified Scream Tracker 3 file, encapsulating it in a DUH | ||
807 | struct. Once the file is loaded, it can be treated exactly the same as any | ||
808 | other DUH in memory. If this fails it will return NULL, but you can safely | ||
809 | pass this NULL value to DUMB's other functions, so you do not need to | ||
810 | check the return value explicitly. | ||
811 | |||
812 | |||
813 | DUH *dumb_read_s3m(DUMBFILE *f); | ||
814 | |||
815 | Reads a Scream Tracker 3 file from an already open DUMBFILE. This leaves | ||
816 | the DUMBFILE open, but the DUMBFILE may not be positioned at the end of | ||
817 | the S3M data. If you are embedding an S3M in another file, you are advised | ||
818 | to store the size of the S3M file and make up for it at the end using | ||
819 | dumbfile_pos(). | ||
820 | |||
821 | Otherwise, this function is identical to dumb_load_s3m(). | ||
822 | |||
823 | WARNING: The behaviour of this function is undefined if you pass a | ||
824 | DUMBFILE from which data have already been read; it is likely not | ||
825 | to work. This oversight will be fixed in future releases. | ||
826 | |||
827 | |||
828 | DUH *dumb_load_mod(const char *filename); | ||
829 | |||
830 | Loads the specified Amiga module file, encapsulating it in a DUH struct. | ||
831 | Once the file is loaded, it can be treated exactly the same as any other | ||
832 | DUH in memory. If this fails it will return NULL, but you can safely pass | ||
833 | this NULL value to DUMB's other functions, so you do not need to check the | ||
834 | return value explicitly. | ||
835 | |||
836 | |||
837 | DUH *dumb_read_mod(DUMBFILE *f); | ||
838 | |||
839 | Reads an Amiga module file from an already open DUMBFILE. This leaves the | ||
840 | DUMBFILE open, but the DUMBFILE may not be positioned at the end of the | ||
841 | MOD data. If you are embedding a MOD in another file, you are advised to | ||
842 | store the size of the MOD file and make up for it at the end using | ||
843 | dumbfile_pos(). | ||
844 | |||
845 | Otherwise, this function is identical to dumb_load_mod(). | ||
846 | |||
847 | WARNING: The behaviour of this function is undefined if you pass a | ||
848 | DUMBFILE from which data have already been read; it is likely not | ||
849 | to work. This oversight will be fixed in future releases. | ||
850 | |||
851 | |||
852 | int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd); | ||
853 | |||
854 | This function returns the number of orders in the module. | ||
855 | |||
856 | |||
857 | int dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd); | ||
858 | void dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv); | ||
859 | |||
860 | These functions obtain and set the initial global volume for the module. | ||
861 | This value ranges from 0 to 128 inclusive. The module can set the global | ||
862 | volume itself during playback, so your change may not last throughout the | ||
863 | playback. | ||
864 | |||
865 | |||
866 | int dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd); | ||
867 | void dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv); | ||
868 | |||
869 | These functions obtain and set the mixing volume for the module. This | ||
870 | value ranges from 0 to 128 inclusive, and does not change during playback. | ||
871 | IT files have the mixing volume stored in them; for other formats it is | ||
872 | set to 48 on loading. | ||
873 | |||
874 | |||
875 | int dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd); | ||
876 | void dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed); | ||
877 | int dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd); | ||
878 | void dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo); | ||
879 | |||
880 | These functions obtain and set the initial speed and tempo for the module. | ||
881 | During module playback, everything happens on a tick. If a beat is 24 | ||
882 | ticks, then the tempo is measured in beats per second. The speed is then | ||
883 | the number of ticks per row. With a speed of 6, a beat is then four rows. | ||
884 | |||
885 | Modules can set these values during playback, so your change may not last | ||
886 | throughout the playback. MOD files have to set the speed and tempo on the | ||
887 | first row if they want anything other than the default 6/125, so your | ||
888 | change may not be noticed at all! | ||
889 | |||
890 | |||
891 | int dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel); | ||
892 | void dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel, | ||
893 | int volume); | ||
894 | |||
895 | These functions obtain and set the initial volume for the specified | ||
896 | channel. The channel parameter is 0-based (contrary to the display in most | ||
897 | trackers so be careful), and can range from 0 to DUMB_IT_N_CHANNELS - 1, | ||
898 | i.e. from 0 to 63. | ||
899 | |||
900 | Modules can set their channel volumes during playback, so your changes may | ||
901 | not last throughout the playback. | ||
902 | |||
903 | |||
904 | int dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr); | ||
905 | int dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr); | ||
906 | |||
907 | These functions return the current order and row of playback. Both are | ||
908 | 0-based. If the DUMB_IT_SIGRENDERER is invalid, or has been terminated | ||
909 | by a callback (see dumb_it_set_loop_callback() and | ||
910 | dumb_it_set_xm_speed_zero_callback()), these functions will both return | ||
911 | -1. | ||
912 | |||
913 | |||
914 | int dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr); | ||
915 | void dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv); | ||
916 | |||
917 | These functions obtain and set the current global volume for the module. | ||
918 | This value ranges from 0 to 128 inclusive. The module can set the global | ||
919 | volume itself during playback, so your change may not last. | ||
920 | |||
921 | |||
922 | int dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr); | ||
923 | void dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo); | ||
924 | int dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr); | ||
925 | void dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed); | ||
926 | |||
927 | These functions obtain and set the current speed and tempo of the module. | ||
928 | See the dumb_it_sd_*() equivalents of these functions for details on what | ||
929 | the speed and tempo mean. | ||
930 | |||
931 | Modules can set these values during playback, so your change may not last. | ||
932 | |||
933 | |||
934 | int dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel); | ||
935 | void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, | ||
936 | int volume); | ||
937 | |||
938 | These functions obtain and set the current volume for the specified | ||
939 | channel. The channel parameter is 0-based (contrary to the display in most | ||
940 | trackers so be careful), and can range from 0 to DUMB_IT_N_CHANNELS - 1, | ||
941 | i.e. from 0 to 63. | ||
942 | |||
943 | Modules can set their channel volumes during playback, so your changes may | ||
944 | not last. | ||
945 | |||
946 | |||
947 | void dumb_it_sr_get_channel_state(DUMB_IT_SIGRENDERER *sr, int channel, | ||
948 | DUMB_IT_CHANNEL_STATE *state); | ||
949 | |||
950 | Returns the current playback state of the given channel. If you pass a | ||
951 | channel in the range 0 to DUMB_IT_N_CHANNELS-1 (0 to 63), you will get the | ||
952 | state of the most recently played note on that physical channel, if it is | ||
953 | still playing. For MOD, S3M and XM files, that's all there is to it. | ||
954 | |||
955 | IT files can have more than one note playing on a single channel, courtesy | ||
956 | of New Note Actions. This function also lets you query all the notes that | ||
957 | have been forced into the background and are still playing. For this, set | ||
958 | 'channel' to a value from DUMB_IT_N_CHANNELS to DUMB_IT_TOTAL_CHANNELS-1. | ||
959 | DUMB_IT_TOTAL_CHANNELS is defined as follows: | ||
960 | |||
961 | #define DUMB_IT_TOTAL_CHANNELS \ | ||
962 | (DUMB_IT_N_CHANNELS + DUMB_IT_N_NNA_CHANNELS) | ||
963 | |||
964 | Querying these background channels for MOD, S3M and XM files will not do | ||
965 | any harm; the function will report that these channels are inactive. For | ||
966 | all files, be sure not to query any channel numbers greater than or equal | ||
967 | to DUMB_IT_TOTAL_CHANNELS. | ||
968 | |||
969 | You must provide a pointer to a preallocated DUMB_IT_CHANNEL_STATE struct. | ||
970 | The easiest way to do this is as follows: | ||
971 | |||
972 | DUMB_IT_CHANNEL_STATE state; | ||
973 | dumb_it_sr_get_channel_state(sr, channel, &state); | ||
974 | |||
975 | or: | ||
976 | |||
977 | DUMB_IT_CHANNEL_STATE state[IT_TOTAL_CHANNELS]; | ||
978 | dumb_it_sr_get_channel_state(sr, channel, &state[channel]); | ||
979 | |||
980 | This struct contains the following fields: | ||
981 | |||
982 | int channel; | ||
983 | int sample; | ||
984 | int freq; | ||
985 | float volume; | ||
986 | unsigned char pan; | ||
987 | signed char subpan; | ||
988 | unsigned char filter_cutoff; | ||
989 | unsigned char filter_subcutoff; | ||
990 | unsigned char filter_resonance; | ||
991 | |||
992 | The first field to check is 'sample'; if this is 0, then the channel is | ||
993 | inactive and the other fields are undefined. Otherwise, it is the index of | ||
994 | the currently playing sample, and is 1-based. | ||
995 | |||
996 | The channel number is returned, 0-based. This will be the same as the | ||
997 | channel number you passed, unless you are querying a background channel in | ||
998 | which case it will represent the channel the note originated on. | ||
999 | |||
1000 | The freq field is the current playback frequency, taking into account all | ||
1001 | phenomena such as slides, vibrato and arpeggio. | ||
1002 | |||
1003 | The volume field ranges from 0.0f to 1.0f. In practical terms, it will | ||
1004 | rarely reach 1.0f; if it does, the module is probably clipping a lot. This | ||
1005 | takes mixing volume into account, along with all the other volume | ||
1006 | phenomena in the IT file. The only one it doesn't take into account is the | ||
1007 | one you pass to duh_render() or duh_sigrenderer_get_samples(), or the one | ||
1008 | you passed to al_start_duh() (these are in fact the same thing). | ||
1009 | |||
1010 | The pan field ranges from 0 to 64 for a normally panned sample, but will | ||
1011 | be 100 if the sample is playing using IT's surround mode where the right- | ||
1012 | hand channel is inverted. If you want a more accurate pan reading, use one | ||
1013 | of the following to get one: | ||
1014 | |||
1015 | int scaled_pan = ((int)state.pan << 8) + state.subpan; | ||
1016 | float float_pan = state.pan + state.subpan / 256.0f; | ||
1017 | |||
1018 | The first will give a scaled value ranging (strictly) from 0 to 64*256. | ||
1019 | The second will give a floating-point value whose scale corresponds to | ||
1020 | that of the pan field. These results will only be valid if surround mode | ||
1021 | is off, so you should check that pan <= 64 before using the above | ||
1022 | expressions. At the time of writing, pitch-pan separation and panning | ||
1023 | envelopes take advantage of the extra accuracy offered by subpan. | ||
1024 | |||
1025 | Note that subpan is signed. This means applications that only look at the | ||
1026 | pan field will get an unbiased reading. | ||
1027 | |||
1028 | The filter cut-off and resonance both range from 0 to 127. If the cut-off | ||
1029 | is 127 and the resonance is 0, then no filters are applied. These | ||
1030 | parameters only ever change from the default values for IT files. | ||
1031 | |||
1032 | While IT allows you to set 127 different filter cut-off levels in the | ||
1033 | patterns and as a default value per instrument, it also allows you to | ||
1034 | create a filter envelope, which will result in an actual cut-off somewhere | ||
1035 | between 0 and the first-mentioned value. By the time this has been | ||
1036 | calculated, the actual cut-off may lie in between two levels on the | ||
1037 | original scale. If this is the case, filter_subcutoff will be nonzero and | ||
1038 | you can combine it with filter_cutoff. Typically you will want to use one | ||
1039 | of the following: | ||
1040 | |||
1041 | int scaled_cutoff = ((int)state.filter_cutoff << 8) + | ||
1042 | state.filter_subcutoff; | ||
1043 | |||
1044 | float float_cutoff = state.filter_cutoff + | ||
1045 | state.filter_subcutoff / 256.0f; | ||
1046 | |||
1047 | The first will give you a scaled value whose maximum is 127*256. The | ||
1048 | second will give you a floating-point value whose scale corresponds to the | ||
1049 | scale used by filter_cutoff. These match the expressions given further up | ||
1050 | for pan and subpan, but in this case, filter_subcutoff is unsigned. | ||
1051 | |||
1052 | Note that filter_subcutoff will always be zero if filter_cutoff is 127, so | ||
1053 | you need not check it if you simply wish to determine whether filters are | ||
1054 | being applied. | ||
1055 | |||
1056 | |||
1057 | ******************************* | ||
1058 | *** DUH Rendering Functions *** | ||
1059 | ******************************* | ||
1060 | |||
1061 | |||
1062 | Use these functions to generate samples from a DUH. First you call | ||
1063 | duh_start_sigrenderer() with the DUH, the number of channels you want and | ||
1064 | the position at which you want to start. Then you use duh_render() or | ||
1065 | duh_sigrenderer_get_samples() to generate the samples. You can call these | ||
1066 | functions as many times as you like, and they will generate as many or as | ||
1067 | few samples as you require. When you have finished, call | ||
1068 | duh_end_sigrenderer(). | ||
1069 | |||
1070 | |||
1071 | DUH_SIGRENDERER *duh_start_sigrenderer | ||
1072 | (DUH *duh, int sig, int n_channels, long pos); | ||
1073 | |||
1074 | Starts a DUH_SIGRENDERER off. This is the struct you can use to get | ||
1075 | samples from a DUH. This function does not generate any samples; you must | ||
1076 | pass the struct to duh_render() or duh_sigrenderer_get_samples() for that. | ||
1077 | When you have finished with it, you must pass it to duh_end_sigrenderer(). | ||
1078 | You can use as many DUH_SIGRENDERER structs as you like at the same time. | ||
1079 | |||
1080 | Set sig to 0 for now. Currently, n_channels can only be 1 or 2, for | ||
1081 | monaural and stereo sound respectively. The debugging library will cause | ||
1082 | your program to abort if you pass anything else. Future versions will be | ||
1083 | enhanced to support more channels as soon as someone needs them. | ||
1084 | |||
1085 | When specifying the position, 0 represents the start of the DUH, and 65536 | ||
1086 | represents one second. Unlike most other music systems, DUMB will always | ||
1087 | make sure every note is there right from the start (assuming you aren't | ||
1088 | using any broken add-ons). In other words, you can start a DUH at a point | ||
1089 | halfway through a long note, and you will still hear the long note. | ||
1090 | |||
1091 | |||
1092 | void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer, | ||
1093 | DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data); | ||
1094 | |||
1095 | Installs a callback function which will be called every time the given | ||
1096 | sigrenderer is used to generate some samples. This can be used to create | ||
1097 | an oscilloscope or spectrum analyser. DUH_SIGRENDERER_ANALYSER_CALLBACK is | ||
1098 | defined as follows: | ||
1099 | |||
1100 | typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data, | ||
1101 | const sample_t *const *samples, int n_channels, long length); | ||
1102 | |||
1103 | If the above confuses you, see fnptr.txt. As for the 'samples' parameter, | ||
1104 | the first 'const' says that the samples are read-only; the second says | ||
1105 | that each channel's sample pointer is also read-only. If you don't | ||
1106 | understand this, don't worry about it. | ||
1107 | |||
1108 | Beware: your callback function may occasionally be called with | ||
1109 | samples == NULL. This means the main program has decided to skip through | ||
1110 | the music without generating any data (see duh_sigrenderer_get_samples()). | ||
1111 | You should handle this case elegantly, typically by returning immediately, | ||
1112 | but you may wish to make a note of the fact that the music is being | ||
1113 | skipped, for whatever reason. | ||
1114 | |||
1115 | Beware again: if the main program ever calls duh_sigrenderer_get_samples() | ||
1116 | on a buffer that isn't all silence, this callback function will be passed | ||
1117 | the existing buffer after mixing, and thus it will include the original | ||
1118 | data. This will not be an issue if you stick to duh_render(), which always | ||
1119 | starts with a buffer filled with silence. | ||
1120 | |||
1121 | The samples array is two-dimensional. Refer to it as follows: | ||
1122 | |||
1123 | samples[channel_number][sample_position] | ||
1124 | |||
1125 | where 0 <= channel_number < n_channels, | ||
1126 | and 0 <= sample_position < length. | ||
1127 | |||
1128 | In addition you can pass any 'data' pointer you like to | ||
1129 | duh_sigrenderer_set_analyser_callback(), and this pointer will be relayed | ||
1130 | to your callback function each time. | ||
1131 | |||
1132 | To remove the callback function, pass NULL to | ||
1133 | duh_sigrenderer_set_analyser_callback(). | ||
1134 | |||
1135 | |||
1136 | int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer); | ||
1137 | |||
1138 | Tells you how many channels a DUH_SIGRENDERER is set up to generate, or 0 | ||
1139 | if it is invalid (perhaps owing to lack of memory). This will be 1 for | ||
1140 | monaural sound or 2 for stereo, in this release. | ||
1141 | |||
1142 | |||
1143 | long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer); | ||
1144 | |||
1145 | Tells you what position a DUH_SIGRENDERER is up to, or -1 if it is invalid | ||
1146 | (perhaps owing to lack of memory). As usual, 65536 is one second. | ||
1147 | |||
1148 | |||
1149 | long duh_sigrenderer_get_samples(DUH_SIGRENDERER *sigrenderer, | ||
1150 | float volume, float delta, | ||
1151 | long size, sample_t **samples); | ||
1152 | |||
1153 | Generates some samples in DUMB's internal 32-bit format (see sample_t; see | ||
1154 | also duh_render()). The samples buffer is a two-dimensional array, and can | ||
1155 | be allocated with create_sample_buffer(); see | ||
1156 | duh_sigrenderer_set_analyser_callback() for details. | ||
1157 | duh_sigrenderer_get_samples() mixes sample data with what's already in the | ||
1158 | buffer, so you have to call dumb_silence() first. | ||
1159 | |||
1160 | The volume is a float. 1.0f is the pseudo-maximum. If you pass 1.0f, any | ||
1161 | properly designed DUH will play nice and loud, but will not clip. You can | ||
1162 | pass a greater volume if you like, but be prepared for the possibility of | ||
1163 | distortion due to integer overflow. Of course you can pass smaller values | ||
1164 | to play the DUH more quietly, and this will also resolve clipping issues | ||
1165 | in badly designed DUHs. | ||
1166 | |||
1167 | Use delta to control the speed of the output signal. If you pass 1.0f, the | ||
1168 | resultant signal will be suitable for a 65536-Hz sampling rate (which | ||
1169 | isn't a commonly used rate). The most common sampling rates are 11025 Hz, | ||
1170 | 22050 Hz, 44100 Hz and 48000 Hz. You can work out the required delta value | ||
1171 | as follows: | ||
1172 | |||
1173 | delta = 65536.0f / sampling_rate; | ||
1174 | |||
1175 | If you then increase this value, the DUH will speed up and increase in | ||
1176 | pitch. If you decrease it, the DUH will slow down and decrease in pitch. | ||
1177 | |||
1178 | This function will attempt to render 'size' samples. In most cases it will | ||
1179 | succeed. However, if the end of the DUH is reached, it may render fewer. | ||
1180 | The number of samples rendered will be returned. Therefore, if the return | ||
1181 | value is less than the value of 'size' passed, you know the DUH has | ||
1182 | finished. It is safe to continue calling duh_sigrenderer_get_samples() if | ||
1183 | you wish, and it will continually return 0. | ||
1184 | |||
1185 | If the DUH_SIGRENDERER is a null pointer, this function will generate | ||
1186 | precisely 0 samples. If you pass NULL for 'samples', the function will | ||
1187 | behave exactly the same as if you provided a sample buffer, except the | ||
1188 | samples won't be stored anywhere and the function will execute very | ||
1189 | quickly. This can be used to skip ahead in the audio. | ||
1190 | |||
1191 | |||
1192 | long duh_render(DUH_SIGRENDERER *sigrenderer, | ||
1193 | int bits, int unsign, | ||
1194 | float volume, float delta, | ||
1195 | long size, void *sptr); | ||
1196 | |||
1197 | Generates some samples and converts them to an 8-bit or 16-bit format (see | ||
1198 | also duh_sigrenderer_get_samples()). Pass the DUH_SIGRENDERER as returned | ||
1199 | by duh_start_sigrenderer(). Pass the number of bits, which should be 8 or | ||
1200 | 16. If unsign is nonzero, the samples will be unsigned (centred on 0x80 or | ||
1201 | 0x8000 for 8 bits and 16 bits respectively). If unsign is zero, the | ||
1202 | samples will be signed. | ||
1203 | |||
1204 | Allegro's audio streams always take unsigned samples. 8-bit .wav files | ||
1205 | always take unsigned samples. 16-bit .wav files always take signed | ||
1206 | samples. | ||
1207 | |||
1208 | The volume and delta parameters work the same as for | ||
1209 | duh_sigrenderer_get_samples(). | ||
1210 | |||
1211 | This function will attempt to render 'size' samples. In most cases it will | ||
1212 | succeed. However, if the end of the DUH is reached, it may render fewer. | ||
1213 | The number of samples rendered will be returned. Therefore, if the return | ||
1214 | value is less than the value of 'size' passed, you know the DUH has | ||
1215 | finished. It is safe to continue calling duh_render() if you wish, and it | ||
1216 | will continually return 0. However, if you wish to do this, you will | ||
1217 | probably have to fill the rest of the buffer with silence, which is 0 for | ||
1218 | signed, 0x80 for 8-bit unsigned or 0x8000 for 16-bit unsigned. | ||
1219 | |||
1220 | The samples will be placed at sptr. Use an array of chars for 8 bits or an | ||
1221 | array of shorts for 16 bits. Stereo samples will be interleaved, left | ||
1222 | first. Your array should contain at least (size * n_channels) elements of | ||
1223 | the appropriate bit resolution. | ||
1224 | |||
1225 | From an aesthetic standpoint if nothing else, it is wise to use the C | ||
1226 | qualifiers 'signed' or 'unsigned' depending on whether the samples are | ||
1227 | signed or unsigned. This is also convenient if you wish to process the | ||
1228 | samples further yourself. | ||
1229 | |||
1230 | If the DUH_SIGRENDERER is a null pointer, this function will generate | ||
1231 | precisely 0 samples. Unlike with duh_sigrenderer_get_samples(), you must | ||
1232 | specify a sample buffer. | ||
1233 | |||
1234 | |||
1235 | void duh_end_sigrenderer(DUH_SIGRENDERER *dr); | ||
1236 | |||
1237 | Terminates a DUH_SIGRENDERER. Be sure to call this when you've finished | ||
1238 | with one. You can safely pass a null pointer. | ||
1239 | |||
1240 | |||
1241 | ******************************** | ||
1242 | *** Allegro Packfile Support *** | ||
1243 | ******************************** | ||
1244 | |||
1245 | |||
1246 | void dumb_register_packfiles(void); | ||
1247 | |||
1248 | This function registers the Allegro PACKFILE input module for use by | ||
1249 | DUMBFILEs. PACKFILE structs and their corresponding functions, as defined | ||
1250 | by Allegro's header file allegro.h, will be used internally for all | ||
1251 | DUMBFILE input (unless opened with dumbfile_open_ex()). | ||
1252 | |||
1253 | This must be called before dumbfile_open() is used, or else an alternative | ||
1254 | system must be registered (see register_dumbfile_system() and | ||
1255 | dumb_register_stdfiles()). Note that you don't have to call this function | ||
1256 | in order to load datafiles that contain music. | ||
1257 | |||
1258 | |||
1259 | DUMBFILE *dumbfile_open_packfile(PACKFILE *p); | ||
1260 | |||
1261 | If you have an Allegro PACKFILE struct representing an open file, you can | ||
1262 | call this if you wish to read from it using a DUMBFILE. This is useful | ||
1263 | when you need to pass a DUMBFILE struct to a library function, to read an | ||
1264 | embedded music file for example. When you close the DUMBFILE, you can | ||
1265 | continue using the PACKFILE struct to read what follows the embedded data. | ||
1266 | |||
1267 | |||
1268 | DUMBFILE *dumbfile_from_packfile(PACKFILE *p); | ||
1269 | |||
1270 | This function is the same as dumbfile_open_packfile(), except it will | ||
1271 | check if p is NULL, and arrange for pack_fclose() to be called on the | ||
1272 | PACKFILE when you close the DUMBFILE. It can be seen as a function for | ||
1273 | converting a PACKFILE to a DUMBFILE, but it will only work for a PACKFILE | ||
1274 | you obtained with pack_fopen(), not pack_fopen_chunk(). If this function | ||
1275 | fails, which may happen if memory is short, then the PACKFILE will be | ||
1276 | closed immediately, so you need not worry about potential memory leaks or | ||
1277 | files being left open when this happens. | ||
1278 | |||
1279 | The following is typical usage, and will open the compressed file foo.bin: | ||
1280 | |||
1281 | DUMBFILE *f = dumbfile_from_packfile(pack_fopen("foo.bin", | ||
1282 | F_READ_PACKED)); | ||
1283 | |||
1284 | This differs from calling dumb_register_packfiles() and dumbfile_open() in | ||
1285 | that the latter will only read uncompressed files (and is thus a method | ||
1286 | suitable for reading music modules). | ||
1287 | |||
1288 | |||
1289 | *********************************************** | ||
1290 | *** Allegro Datafile Registration Functions *** | ||
1291 | *********************************************** | ||
1292 | |||
1293 | |||
1294 | void dumb_register_dat_it(long type); | ||
1295 | |||
1296 | If you wish to embed an IT file in an Allegro datafile, it is recommended | ||
1297 | that you use "IT " for the type. The grabber will have a box for the type | ||
1298 | when you insert a new object. The grabber will treat the IT file as binary | ||
1299 | data, which means the datafile will contain an exact copy of the IT file | ||
1300 | on disk. | ||
1301 | |||
1302 | You must then call dumb_register_dat_it(DUMB_DAT_IT) in your program | ||
1303 | before you load the datafile. Once you've done this, you'll be able to | ||
1304 | access the DUH using the usual datafile[n].dat notation. You do not need | ||
1305 | to call unload_duh() on this DUH; unload_datafile() will do that for you. | ||
1306 | |||
1307 | If you are using a different type for whatever reason, you can use | ||
1308 | Allegro's DAT_ID() macro for encoding it and passing it to this function. | ||
1309 | For example: | ||
1310 | |||
1311 | dumb_register_dat_it(DAT_ID('B','L','A','H')); | ||
1312 | |||
1313 | Assuming you used the recommended type, the following example iterates | ||
1314 | through all the ITs in disan.dat: | ||
1315 | |||
1316 | DATAFILE *dat; | ||
1317 | int n; | ||
1318 | |||
1319 | dumb_register_dat_it(); | ||
1320 | dat = load_datafile("disan.dat"); | ||
1321 | |||
1322 | for (n = 0; dat[n].type != DAT_END; n++) { | ||
1323 | if (dat[n].type == DUMB_DAT_IT) { | ||
1324 | DUH *duh = dat[n].dat; | ||
1325 | /* Insert code here to play 'duh' or whatever you want to do. */ | ||
1326 | } | ||
1327 | } | ||
1328 | |||
1329 | unload_datafile(dat); | ||
1330 | |||
1331 | |||
1332 | void dumb_register_dat_xm(long type); | ||
1333 | |||
1334 | Inserting an XM file in an Allegro datafile is the same as inserting an IT | ||
1335 | file, except that the recommended type is "XM ", the registration | ||
1336 | function is dumb_register_dat_xm(), and the macro DUMB_DAT_XM is provided | ||
1337 | for the type. The intuitive process of substituting XM for IT in the above | ||
1338 | method will work. | ||
1339 | |||
1340 | |||
1341 | void dumb_register_dat_s3m(long type); | ||
1342 | |||
1343 | Inserting an S3M file in an Allegro datafile is the same as inserting an | ||
1344 | IT file, except that the recommended type is "S3M ", the registration | ||
1345 | function is dumb_register_dat_s3m(), and the macro DUMB_DAT_S3M is | ||
1346 | provided for the type. The intuitive process of substituting S3M for IT in | ||
1347 | the above method will work. | ||
1348 | |||
1349 | |||
1350 | void dumb_register_dat_mod(long type); | ||
1351 | |||
1352 | Inserting a MOD file in an Allegro datafile is the same as inserting an IT | ||
1353 | file, except that the recommended type is "MOD ", the registration | ||
1354 | function is dumb_register_dat_mod(), and the macro DUMB_DAT_MOD is | ||
1355 | provided for the type. The intuitive process of substituting MOD for IT in | ||
1356 | the above method will work. | ||
1357 | |||
1358 | |||
1359 | **************************************** | ||
1360 | *** Sample Buffer Allocation Helpers *** | ||
1361 | **************************************** | ||
1362 | |||
1363 | |||
1364 | Many parts of DUMB require sample buffers allocated in a special way. A | ||
1365 | pointer to one looks like this: | ||
1366 | |||
1367 | sample_t **samples; | ||
1368 | |||
1369 | and it can be indexed as follows: | ||
1370 | |||
1371 | samples[channel_number][sample_position] | ||
1372 | |||
1373 | where 0 <= channel_number < n_channels | ||
1374 | and 0 <= sample_position < length. | ||
1375 | |||
1376 | The following helpers will allocate and deallocate such buffers for you. | ||
1377 | They will not initialise them, and DUMB always writes into these buffers | ||
1378 | by adding to what's already there, so you will generally have to call | ||
1379 | dumb_silence() too. | ||
1380 | |||
1381 | |||
1382 | sample_t **create_sample_buffer(int n_channels, long length); | ||
1383 | |||
1384 | This will allocate a sample buffer to hold the specified number of samples | ||
1385 | for the specified number of channels. Don't forget to check the return | ||
1386 | value! | ||
1387 | |||
1388 | You will generally have to initialise the buffer by calling | ||
1389 | dumb_silence(); the channels will be stored consecutively in memory, so | ||
1390 | the following technique is officially supported: | ||
1391 | |||
1392 | dumb_silence(samples[0], n_channels * length); | ||
1393 | |||
1394 | See dumb_silence() for general information on what this function does. | ||
1395 | |||
1396 | |||
1397 | void destroy_sample_buffer(sample_t **samples); | ||
1398 | |||
1399 | This function does the obvious: it frees up a sample buffer when you've | ||
1400 | finished with it. It is safe to pass a null pointer to this function. | ||
1401 | |||
1402 | |||
1403 | ************************ | ||
1404 | *** Silencing Helper *** | ||
1405 | ************************ | ||
1406 | |||
1407 | |||
1408 | void dumb_silence(sample_t *samples, long length); | ||
1409 | |||
1410 | This function simply stores 'length' samples' worth of silence in the | ||
1411 | array. It is typically used straight after allocating a sample buffer with | ||
1412 | create_sample_buffer(). | ||
1413 | |||
1414 | |||
1415 | ************************** | ||
1416 | *** Resampling Helpers *** | ||
1417 | ************************** | ||
1418 | |||
1419 | |||
1420 | Please forgive the odd section name; it has to do with DUMB's internal | ||
1421 | structure and the fact that the resampling algorithm is there not just for | ||
1422 | use in rendering module files but for use anywhere that a waveform needs | ||
1423 | resampling. Unfortunately DUMB's resampling algorithm is not ready to be | ||
1424 | documented and used yet. However, one thing can be documented, and that's | ||
1425 | the global variable controlling the resampling quality. | ||
1426 | |||
1427 | (Ironically, even this variable has changed! See deprec.txt for | ||
1428 | information on what it used to do.) | ||
1429 | |||
1430 | |||
1431 | int dumb_resampling_quality; | ||
1432 | |||
1433 | Allows you to control the quality of all resampling that takes place. This | ||
1434 | may be set to any DUMB_RQ_* constant (except DUMB_RQ_N_LEVELS). Higher | ||
1435 | values will sound better, but lower values will use up less processor | ||
1436 | time. You may compare any two DUMB_RQ_* constants or values using the | ||
1437 | integer inequalities <, <=, > and >=; higher numbers represent higher- | ||
1438 | quality algorithms. | ||
1439 | |||
1440 | #define DUMB_RQ_ALIASING | ||
1441 | |||
1442 | | --___ 'Aliasing' has very noticeable and usually unwanted | ||
1443 | |__--- __ overtones. It will occasionally produce acceptable | ||
1444 | | ___-- results for noisy (impure) samples (or for cheap | ||
1445 | speakers!), but usually you will want to pay for | ||
1446 | the extra processor time, which isn't much, and go for linear | ||
1447 | interpolation. | ||
1448 | |||
1449 | #define DUMB_RQ_LINEAR | ||
1450 | |||
1451 | | __ Linear interpolation is a pretty good algorithm in most | ||
1452 | | / \ /\ cases. When resampling down a few octaves, however, you | ||
1453 | |/ \/ \__ may begin to notice unwanted high frequencies. You can | ||
1454 | reduce these by switching to cubic interpolation, but it | ||
1455 | will cost you some processor time. | ||
1456 | |||
1457 | #define DUMB_RQ_CUBIC | ||
1458 | |||
1459 | Cubic interpolation looks like a smooth curve to the eye, and will | ||
1460 | produce good results in most cases. At present this is the highest | ||
1461 | quality offered by DUMB, and also the default. While this may seem | ||
1462 | extravagant, GCC 3.x and an AthlonXP handle it quite well - and the | ||
1463 | general trend is for processors to get better! | ||
1464 | |||
1465 | #define DUMB_RQ_N_LEVELS | ||
1466 | |||
1467 | This represents the number of resampling quality levels DUMB provides. | ||
1468 | Values of dumb_resampling_quality from 0 to DUMB_RQ_N_LEVELS - 1 are | ||
1469 | valid. You can use this constant if you wish to offer the resampling | ||
1470 | quality as an option for the user. | ||
1471 | |||
1472 | |||
1473 | ************************************* | ||
1474 | *** Allegro DUH Playing Functions *** | ||
1475 | ************************************* | ||
1476 | |||
1477 | |||
1478 | The functions in this section allow you to play back a DUH through | ||
1479 | Allegro's sound system. You must call Allegro's install_sound() function | ||
1480 | before you use them. | ||
1481 | |||
1482 | |||
1483 | AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos, | ||
1484 | float volume, long bufsize, int freq); | ||
1485 | |||
1486 | Starts playing the specified DUH. | ||
1487 | |||
1488 | An AL_DUH_PLAYER represents one instance of the DUH playing. If you wish, | ||
1489 | you can have two or more AL_DUH_PLAYERs going at the same time, for the | ||
1490 | same DUH or for different ones. Each uses one of Allegro's audio streams | ||
1491 | and hence one voice. The voice will be given priority 255 initially, so a | ||
1492 | build-up of sound effects will not cause your music streams to cut off (as | ||
1493 | long as you don't give all your sound effects priority 255!). You can | ||
1494 | change the priority of a stream with al_duh_set_priority(). See Allegro's | ||
1495 | documentation for more information on how voice priorities work. | ||
1496 | |||
1497 | At present, n_channels can either be 1 or 2 for monaural or stereo | ||
1498 | respectively. If you use the debugging library, your program will abort if | ||
1499 | other values are passed; otherwise weird things will happen. | ||
1500 | |||
1501 | The DUH will start playing from position 'pos'. 0 represents the start of | ||
1502 | the DUH, and 65536 represents one second. Unlike other music systems, DUMB | ||
1503 | will always make sure every note is there right from the start. In other | ||
1504 | words, you can start a DUH at a point halfway through a long note, and you | ||
1505 | will still hear the long note. | ||
1506 | |||
1507 | The volume is a float. 1.0f is the pseudo-maximum. If you pass 1.0f, any | ||
1508 | properly designed DUH file will play nice and loud, but will not clip. You | ||
1509 | can pass a greater volume if you like, but be prepared for clipping to | ||
1510 | occur. Of course you can pass smaller values to play the DUH more quietly, | ||
1511 | and this will also resolve clipping issues in badly designed DUH files. | ||
1512 | |||
1513 | You will need to pass the AL_DUH_PLAYER to other functions when you need | ||
1514 | to stop or pause the DUH, change its volume, or otherwise modify the way | ||
1515 | it is playing. You will also need to pass it to al_poll_duh() at regular | ||
1516 | intervals; if the sound is choppy, try calling al_poll_duh() more often. | ||
1517 | |||
1518 | 'bufsize' is the number of samples that will be rendered at once. 1024 is | ||
1519 | a suitable value for most purposes. The greater this is, the less often | ||
1520 | you will have to call al_poll_duh() - but when al_poll_duh() decides to | ||
1521 | fill the buffer, it will take longer doing so. If your game exhibits | ||
1522 | regular brief freezes, try reducing the buffer size. If the sound is | ||
1523 | choppy, however, you may have to increase it. | ||
1524 | |||
1525 | 'freq' specifies the sampling frequency at which the DUH should be | ||
1526 | rendered. At present there is no (official and portable) way of knowing | ||
1527 | the frequency at which Allegro is mixing - but if you do know that | ||
1528 | frequency, passing it here will give the highest quality sound. If you | ||
1529 | reduce it, the DUH will sound less crisp but use less processor time. | ||
1530 | |||
1531 | When you have finished, you must pass the AL_DUH_PLAYER to al_stop_duh() | ||
1532 | to free up memory. Do not destroy the DUH beforehand. | ||
1533 | |||
1534 | There is no real need to check the return value from this function. The | ||
1535 | other functions can be called safely with null pointers, so if there is a | ||
1536 | problem, your music will simply not play. | ||
1537 | |||
1538 | |||
1539 | void al_stop_duh(AL_DUH_PLAYER *dp); | ||
1540 | |||
1541 | This will stop an AL_DUH_PLAYER. You must call this when you have finished | ||
1542 | with it, before destroying the DUH. The pointer will no longer be valid on | ||
1543 | return from this function. | ||
1544 | |||
1545 | |||
1546 | void al_pause_duh(AL_DUH_PLAYER *dp); | ||
1547 | |||
1548 | This will pause an AL_DUH_PLAYER. Use al_resume_duh() when you want it to | ||
1549 | continue. You can safely call al_poll_duh() while the music is paused, and | ||
1550 | it will do nothing. | ||
1551 | |||
1552 | |||
1553 | void al_resume_duh(AL_DUH_PLAYER *dp); | ||
1554 | |||
1555 | Causes a paused AL_DUH_PLAYER to resume playing (see al_pause_duh()). | ||
1556 | |||
1557 | |||
1558 | void al_duh_set_priority(AL_DUH_PLAYER *dp, int priority); | ||
1559 | |||
1560 | This will set the priority of the audio stream underlying an | ||
1561 | AL_DUH_PLAYER. The priority is an integer ranging from 0 to 255. When | ||
1562 | too many samples play at the same time, those with lower priorities will | ||
1563 | be cut. 128 is the usual default with Allegro, but DUMB overrides the | ||
1564 | default for all AL_DUH_PLAYER structs: they will be set up initially with | ||
1565 | priority 255, so your music won't be cut (unless you play too many other | ||
1566 | streams or samples with priority 255). See Allegro's documentation for | ||
1567 | more information on priorities. | ||
1568 | |||
1569 | |||
1570 | void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume); | ||
1571 | |||
1572 | This will set the volume of an AL_DUH_PLAYER. See al_start_duh() for | ||
1573 | details on the volume parameter. | ||
1574 | |||
1575 | |||
1576 | int al_poll_duh(AL_DUH_PLAYER *dp); | ||
1577 | |||
1578 | An AL_DUH_PLAYER is not interrupt-driven. That means it will not play by | ||
1579 | itself. You must keep it alive from your main program. Call this function | ||
1580 | at regular intervals. If the sound crackles, try calling it more often. | ||
1581 | (There is nothing you can do if Windows decides to play with the hard | ||
1582 | disk; that will make your sound crackle no matter what you do.) | ||
1583 | |||
1584 | Normally this function will return zero. However, if it returns nonzero, | ||
1585 | that means the AL_DUH_PLAYER will not generate any more sound. Indeed the | ||
1586 | underlying audio stream and DUH_SIGRENDERER have been destroyed. When this | ||
1587 | happens, you can call al_stop_duh() whenever you wish - but you do not | ||
1588 | have to. Note that this function will wait two buffers' worth of samples | ||
1589 | before taking this action, allowing Allegro to mix the trailing sound | ||
1590 | before the audio stream is destroyed. This is an attempt to make sure your | ||
1591 | music does not get cut off prematurely, and it should work when using | ||
1592 | Allegro's mixer (the only option on DOS, the default on Linux as far as I | ||
1593 | know, but not the default on Windows). That said, if you immediately call | ||
1594 | Allegro's remove_sound() or exit your program, the music may get cut off. | ||
1595 | If you are using another mixer and experience problems, let me know (but I | ||
1596 | don't guarantee to be able to come up with an elegant solution, i.e. it | ||
1597 | might not get fixed). | ||
1598 | |||
1599 | In case you were wondering, it is not safe on all platforms to call | ||
1600 | al_poll_duh() from an interrupt context (that means an Allegro timer | ||
1601 | handler). Not only is no part of DUMB locked in memory, but many parts of | ||
1602 | DUMB allocate and free their memory on a call-by-call basis! Remember that | ||
1603 | any disk access that occurs in interrupt context is likely to crash the | ||
1604 | machine; this is explained more fully in howto.txt. This limitation only | ||
1605 | applies to DOS at present, and is due to the fact that the DOS file access | ||
1606 | functions are not re-entrant. | ||
1607 | |||
1608 | Multitasking systems are generally safe. If you are sure you don't want to | ||
1609 | target DOS, you can call al_poll_duh() from inside a timer handler, but I | ||
1610 | recommend including a construction like the following! | ||
1611 | |||
1612 | #ifdef ALLEGRO_DOS | ||
1613 | #error calling al_poll_duh() from a timer handler will not work in DOS! | ||
1614 | #endif | ||
1615 | |||
1616 | Furthermore, if you call al_poll_duh() from inside a timer handler, you | ||
1617 | must use a semaphore or other threading mechanism to make sure it is not | ||
1618 | executing when you call al_stop_duh(). If you don't know what a semaphore | ||
1619 | is, for Heaven's sake follow my advice and call al_poll_duh() from your | ||
1620 | main loop! | ||
1621 | |||
1622 | |||
1623 | long al_duh_get_position(AL_DUH_PLAYER *dp); | ||
1624 | |||
1625 | Tells you what position an AL_DUH_PLAYER is up to, or -1 if it is invalid | ||
1626 | (perhaps owing to lack of memory). As usual, 65536 is one second. Note | ||
1627 | that this is a whole number, whereas a fractional part is stored | ||
1628 | internally; the sample will not be continuous if you terminate the | ||
1629 | AL_DUH_PLAYER and then reinitiate it with the same position. Furthermore, | ||
1630 | note that Allegro will not have mixed in all the sound up to this point; | ||
1631 | if you wait for this to reach a certain position and then terminate the | ||
1632 | AL_DUH_PLAYER, the sound will cut off too early. Please contact me if you | ||
1633 | need to get around this. | ||
1634 | |||
1635 | |||
1636 | AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer | ||
1637 | (DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq); | ||
1638 | |||
1639 | If you have a DUH_SIGRENDERER, and would like to start playing music from | ||
1640 | it through an Allegro audio stream, use this function. Beware that it may | ||
1641 | return NULL, in which case you will have to call duh_end_sigrenderer() | ||
1642 | yourself instead of relying on the encapsulating AL_DUH_PLAYER to do it | ||
1643 | for you. | ||
1644 | |||
1645 | |||
1646 | DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp); | ||
1647 | |||
1648 | This returns the DUH_SIGRENDERER contained in an AL_DUH_PLAYER, useful for | ||
1649 | controlling playback, installing callbacks, etc. | ||
1650 | |||
1651 | |||
1652 | DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp); | ||
1653 | |||
1654 | This destroys an AL_DUH_PLAYER, but preserves the DUH_SIGRENDERER it | ||
1655 | contains, and returns it to you. You can then continue rendering samples | ||
1656 | from the DUH_SIGRENDERER and do whatever you like with them. | ||
1657 | |||
1658 | |||
1659 | ********************* | ||
1660 | *** Thread Safety *** | ||
1661 | ********************* | ||
1662 | |||
1663 | |||
1664 | The following points should pretty much sum up the essence of DUMB's thread | ||
1665 | safety. If I haven't covered the one thing you'd like to do, please don't | ||
1666 | hesitate to ask about it. | ||
1667 | |||
1668 | DOs: | ||
1669 | |||
1670 | - You may load and use multiple DUHs in separate threads. | ||
1671 | |||
1672 | - You may change dumb_resampling_quality and dumb_it_max_to_mix while another | ||
1673 | thread is generating samples. | ||
1674 | |||
1675 | DON'Ts: | ||
1676 | |||
1677 | - You may not generate samples from the same DUH in multiple threads, even if | ||
1678 | you are using separate DUH_RENDERERs (separate AL_DUH_PLAYERS). | ||
1679 | |||
1680 | |||
1681 | ****************** | ||
1682 | *** Conclusion *** | ||
1683 | ****************** | ||
1684 | |||
1685 | |||
1686 | "DUMB is the bestest music player in the world because ..." | ||
1687 | |||
1688 | Complete this sentence in fifteen words or fewer and receive a free copy of | ||
1689 | DUMB! (Your Internet Service Provider may issue charges for your connection, | ||
1690 | required for download of the Product. Your electricity supplier may issue | ||
1691 | charges for the electricity consumed in writing the Product to a Permanent | ||
1692 | Storage Device. You may have been charged for a Permanent Storage Device on | ||
1693 | which to store the Product.) | ||
1694 | |||
1695 | |||
1696 | Ben Davis | ||
1697 | entheh@users.sf.net | ||
1698 | IRC EFnet #dumb | ||
1699 | See readme.txt for details on using IRC. | ||
diff --git a/apps/codecs/dumb/docs/faq.txt b/apps/codecs/dumb/docs/faq.txt new file mode 100644 index 0000000000..48b5ef3fff --- /dev/null +++ b/apps/codecs/dumb/docs/faq.txt | |||
@@ -0,0 +1,263 @@ | |||
1 | TO DO: add question regarding set_close_button_callback vs set_window_close_hook | ||
2 | |||
3 | /* _______ ____ __ ___ ___ | ||
4 | * \ _ \ \ / \ / \ \ / / ' ' ' | ||
5 | * | | \ \ | | || | \/ | . . | ||
6 | * | | | | | | || ||\ /| | | ||
7 | * | | | | | | || || \/ | | ' ' ' | ||
8 | * | | | | | | || || | | . . | ||
9 | * | |_/ / \ \__// || | | | ||
10 | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque | ||
11 | * / \ | ||
12 | * / . \ | ||
13 | * faq.txt - Frequently Asked Questions. / / \ \ | ||
14 | * | < / \_ | ||
15 | * This file covers some of the common problems | \/ /\ / | ||
16 | * and misconceptions people have with DUMB. If \_ / > / | ||
17 | * your problem is not covered here, please | \ / / | ||
18 | * contact me. I'll do my best to help - but | ' / | ||
19 | * don't be offended if I just direct you to the \__/ | ||
20 | * manual! | ||
21 | */ | ||
22 | |||
23 | |||
24 | ***************************************************************************** | ||
25 | * I get a lot of strange warnings and errors when I compile my projects * | ||
26 | * with this release of DUMB. They work with older versions! What happened? * | ||
27 | ***************************************************************************** | ||
28 | |||
29 | Some parts of DUMB's API have been deprecated. See docs/deprec.txt for | ||
30 | full details, including an explanation as to why your compiler warnings | ||
31 | and errors are so unfriendly, and information on how to fix each warning | ||
32 | or error. | ||
33 | |||
34 | |||
35 | ***************************************************************************** | ||
36 | * When I try to compile DUMB with Allegro, it complains that it cannot find * | ||
37 | * 'internal/alconfig.h'! What's wrong? * | ||
38 | ***************************************************************************** | ||
39 | |||
40 | In Allegro 4.0.1, and quite likely some other versions of Allegro, the | ||
41 | msvcmake batch file does not install Allegro properly. I believe this was | ||
42 | fixed in Allegro 4.0.2, but don't take my word for it. Some include files | ||
43 | are neglected, including alconfig.h. The fix is quite easy; you need to | ||
44 | copy all of Allegro's include files to your compiler's directory. The | ||
45 | following should do this for you (alter it accordingly depending on where | ||
46 | MSVC and Allegro are installed): | ||
47 | |||
48 | cd\progra~1\msvc\include | ||
49 | xcopy/s \allegro\include\*.* | ||
50 | |||
51 | You can safely tell it to overwrite all files. | ||
52 | |||
53 | |||
54 | ***************************************************************************** | ||
55 | * When I build a project that uses DUMB, I get an error that it doesn't * | ||
56 | * find -laldmbd! What's wrong? * | ||
57 | ***************************************************************************** | ||
58 | |||
59 | See the notes for DUMB v0.8 in release.txt; the existence of libaldmbd.a | ||
60 | in DUMB v0.7 was due to a mistake in the makefiles. It should be | ||
61 | libaldmd.a, in order to maintain DOS compatibility. All subsequent | ||
62 | releases get it right, but you will have to change your project files to | ||
63 | allow for the change. If this is someone else's project, please let them | ||
64 | know that it needs changing. | ||
65 | |||
66 | |||
67 | ***************************************************************************** | ||
68 | * When I build a project that uses DUMB, I get some linker errors about * | ||
69 | * _free, _malloc, etc. already being defined in LIBC.lib! What's wrong? * | ||
70 | ***************************************************************************** | ||
71 | |||
72 | MSVC offers three different implementations of the standard libraries. | ||
73 | When you link statically with a library, you have to use the same | ||
74 | implementation that the library uses. You need the multithreaded DLL | ||
75 | implementation, which you can select by passing /MD when you compile (not | ||
76 | when you link). See howto.txt for details. | ||
77 | |||
78 | |||
79 | ***************************************************************************** | ||
80 | * I created an IT file with Impulse Tracker, but DUMB won't play it! Why? * | ||
81 | ***************************************************************************** | ||
82 | |||
83 | You probably created some patterns but didn't give any information on the | ||
84 | order in which they should be played. Impulse Tracker will also fail to | ||
85 | play your music if you press F5. Press F11 and you will have an | ||
86 | opportunity to create an order list, required for playback. | ||
87 | |||
88 | |||
89 | ***************************************************************************** | ||
90 | * I created an IT file with ModPlug Tracker and I have it fading out at the * | ||
91 | * end. Why won't it loop when I play it with DUMB? * | ||
92 | ***************************************************************************** | ||
93 | |||
94 | It loops at zero volume. This is what Impulse Tracker itself does. Fix the | ||
95 | IT file by setting the global volume explicitly (Vxx in the effects | ||
96 | column), either at the start, or right at the end before looping. Also see | ||
97 | the next two questions. | ||
98 | |||
99 | |||
100 | ***************************************************************************** | ||
101 | * My module plays too loud and distorts badly with DUMB! What can I do? * | ||
102 | ***************************************************************************** | ||
103 | |||
104 | This problem is most often caused by ModPlug Tracker, which has a complete | ||
105 | lack of regard for the playback volume of the original tracker. See the | ||
106 | next question for DUMB's official position with regard to ModPlug Tracker. | ||
107 | If you wrote your module with ModPlug Tracker, please try loading it with | ||
108 | the original tracker and see if it distorts there too. If it does, reduce | ||
109 | the volume. If not, then it's a problem with DUMB; please let me know. | ||
110 | |||
111 | If for whatever reason you cannot modify the module file itself, you can | ||
112 | make it sound better by reducing the volume passed to al_start_duh(). | ||
113 | |||
114 | |||
115 | ***************************************************************************** | ||
116 | * I created a music module with ModPlug Tracker, and DUMB doesn't play it * | ||
117 | * right! * | ||
118 | ***************************************************************************** | ||
119 | |||
120 | DUMB cannot and will not support ModPlug Tracker. Please see | ||
121 | docs/modplug.txt for details. The original trackers, which DUMB is | ||
122 | designed to mimic as closely as possible, are listed in readme.txt. | ||
123 | If you find DUMB plays your module differently from the original tracker, | ||
124 | then please contact me. | ||
125 | |||
126 | |||
127 | ***************************************************************************** | ||
128 | * My program crashes as soon as I try to load anything with DUMB! * | ||
129 | ***************************************************************************** | ||
130 | |||
131 | Please take my advice and use the debugging build of DUMB, not the | ||
132 | optimised build. Then you'll probably find it aborts instead of crashing. | ||
133 | In this case you probably forgot to register a DUMBFILE system; this is | ||
134 | necessary for loading stand-alone files, though not for loading Allegro | ||
135 | datafiles with embedded music. Follow the instructions in docs/howto.txt | ||
136 | carefully and you shouldn't have this problem. | ||
137 | |||
138 | If DUMB crashes with a specific music module, please let me know. | ||
139 | |||
140 | |||
141 | ***************************************************************************** | ||
142 | * I want to use the stdio file access functions to load stand-alone music * | ||
143 | * files, but I also want to load datafiles containing music files. The docs * | ||
144 | * say I shouldn't call both dumb_register_stdfiles() and * | ||
145 | * dumb_register_packfiles(). What shall I do? * | ||
146 | ***************************************************************************** | ||
147 | |||
148 | When you register a DUMBFILE system, it only applies to files opened with | ||
149 | dumbfile_open(), i.e. separate files. When a file is embedded in a | ||
150 | datafile, dumbfile_open_ex() is used to read it, enabling it to use | ||
151 | PACKFILEs regardless of which DUMBFILE system is registered. In short, you | ||
152 | do not need to call dumb_register_packfiles() in order to load datafiles | ||
153 | with embedded music. See the section on "Sequential File Input" in | ||
154 | docs/dumb.txt if you're interested in how all this works. | ||
155 | |||
156 | |||
157 | ***************************************************************************** | ||
158 | * I want to read a specific object in a datafile using Allegro's * | ||
159 | * "demo.dat#MY_MUSIC" syntax. Why won't it work? * | ||
160 | ***************************************************************************** | ||
161 | |||
162 | Did you call dumb_register_packfiles(), or did you call | ||
163 | dumb_register_stdfiles()? It will only work if you use the former. | ||
164 | |||
165 | |||
166 | ***************************************************************************** | ||
167 | * My program runs, but no music plays! What am I doing wrong? * | ||
168 | ***************************************************************************** | ||
169 | |||
170 | There are a number of possible causes for this. The most likely reason is | ||
171 | that you aren't calling al_poll_duh(); see docs/howto.txt for further | ||
172 | information. | ||
173 | |||
174 | Other possible causes are as follows: | ||
175 | |||
176 | - The speakers are turned down (duh) | ||
177 | - The volume of some system mixer is turned down | ||
178 | - Another program is using the sound card (not a problem for most modern | ||
179 | systems) | ||
180 | - You didn't initialise Allegro's sound system; see install_sound() in | ||
181 | Allegro's docs | ||
182 | - Allegro's drivers don't work on your system and chosen platform | ||
183 | |||
184 | In order to narrow down the cause, consider the following: | ||
185 | |||
186 | - Do you get any other sound from your program? | ||
187 | - Do other Allegro+DUMB programs generate sound? | ||
188 | - Do other Allegro programs generate sound? | ||
189 | - Do other non-Allegro programs generate sound? | ||
190 | - Does your program fail only on a specific platform (e.g. DOS but not | ||
191 | Windows)? | ||
192 | |||
193 | This problem is highly system-specific; please try hard to solve it by | ||
194 | yourself before contacting me. However, if you think this problem could | ||
195 | affect other people, please let me know what the problem is and how you | ||
196 | fixed it, if you did. Be as specific as possible. | ||
197 | |||
198 | |||
199 | ***************************************************************************** | ||
200 | * The music stutters! What can I do? * | ||
201 | ***************************************************************************** | ||
202 | |||
203 | If you have an older computer, it may not be able to cope with the load. | ||
204 | Try reducing quality options; look up dumb_resampling_quality and | ||
205 | dumb_it_max_to_mix in docs/dumb.txt, and consider changing the frequency | ||
206 | you pass to al_start_duh(). | ||
207 | |||
208 | Stuttering may not be caused by excessive load. To find out, try | ||
209 | increasing the buffer size passed to al_start_duh(). Beware of making it | ||
210 | too big though; older systems will freeze periodically if it's too big, | ||
211 | because they render larger chunks less frequently. The timing of callbacks | ||
212 | will also be less accurate, if you are using those. | ||
213 | |||
214 | If you're using the 'dumbplay' example, you can control these parameters | ||
215 | by editing dumb.ini. | ||
216 | |||
217 | |||
218 | ***************************************************************************** | ||
219 | * Why does DUMB use so much processor time compared with other players? * | ||
220 | ***************************************************************************** | ||
221 | |||
222 | This should be less so in this release than in previous releases; the | ||
223 | resampling and filtering algorithms have been optimised. | ||
224 | |||
225 | By default, DUMB uses the most expensive resampling quality option. I've | ||
226 | found on an AthlonXP 1800+ and on a Pentium 233 that it typically uses | ||
227 | about twice as much processor time as the least expensive option. | ||
228 | |||
229 | Try setting dumb_resampling_quality to DUMB_RQ_ALIASING or DUMB_RQ_LINEAR. | ||
230 | See dumb.txt for more information. If you're using the example programs, | ||
231 | you can control this variable by editing dumb.ini. | ||
232 | |||
233 | DUMB uses 32-bit ints for mixing. Some players use 16-bit ints, and are | ||
234 | therefore marginally faster (not much!) and lower quality. So you can't | ||
235 | expect DUMB to beat these players. Furthermore, DUMB is currently written | ||
236 | entirely in C. GCC does an impressive job on the C code, but that's not to | ||
237 | say some custom-written assembly language couldn't beat it ... | ||
238 | |||
239 | |||
240 | ***************************************************************************** | ||
241 | * Why does DUMB generate so much background noise? * | ||
242 | ***************************************************************************** | ||
243 | |||
244 | You're probably using the DOS build on a system with bad Sound Blaster | ||
245 | compatibility (most Windows XP systems fall in this category). This would | ||
246 | mean DUMB could only access an 8-bit driver. The Windows build will almost | ||
247 | certainly give better results. Your DOS binary will still give good | ||
248 | results on systems with better compatibility (like my Windows 98 system). | ||
249 | |||
250 | |||
251 | ***************************************************************************** | ||
252 | * I e-mailed you and you replied with "RTFM"! What does that mean? * | ||
253 | ***************************************************************************** | ||
254 | |||
255 | Read The Manual. If it's a specific problem, I'll probably be kind and | ||
256 | tell you where to look in the manual. However, if I get the impression you | ||
257 | haven't even looked for a solution in the manual, expect no mercy ... | ||
258 | |||
259 | |||
260 | Ben Davis | ||
261 | entheh@users.sf.net | ||
262 | IRC EFnet #dumb | ||
263 | See readme.txt for details on using IRC. | ||
diff --git a/apps/codecs/dumb/docs/fnptr.txt b/apps/codecs/dumb/docs/fnptr.txt new file mode 100644 index 0000000000..a5fb216822 --- /dev/null +++ b/apps/codecs/dumb/docs/fnptr.txt | |||
@@ -0,0 +1,113 @@ | |||
1 | /* _______ ____ __ ___ ___ | ||
2 | * \ _ \ \ / \ / \ \ / / ' ' ' | ||
3 | * | | \ \ | | || | \/ | . . | ||
4 | * | | | | | | || ||\ /| | | ||
5 | * | | | | | | || || \/ | | ' ' ' | ||
6 | * | | | | | | || || | | . . | ||
7 | * | |_/ / \ \__// || | | | ||
8 | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque | ||
9 | * / \ | ||
10 | * / . \ | ||
11 | * fnptr.txt - Function pointer explanation. / / \ \ | ||
12 | * | < / \_ | ||
13 | * | \/ /\ / | ||
14 | * \_ / > / | ||
15 | * | \ / / | ||
16 | * | ' / | ||
17 | * \__/ | ||
18 | */ | ||
19 | |||
20 | |||
21 | C allows you to create and use function pointers. A function pointer is a | ||
22 | variable that points to a function, and you can use it to call that function. | ||
23 | Why is this useful? | ||
24 | |||
25 | Function pointers can be passed as parameters. As an example, here's a | ||
26 | function from Allegro: | ||
27 | |||
28 | void create_light_table(COLOR_MAP *table, const PALETTE pal, int r, g, b, | ||
29 | void (*callback)(int pos)); | ||
30 | |||
31 | Don't worry about the syntax just yet, but the last parameter, 'callback', is | ||
32 | a pointer to a function that takes an int parameter. create_light_table() can | ||
33 | take some time to complete its work, and you may want to display a progress | ||
34 | indicator. So you write a function to draw the progress indicator, and then, | ||
35 | for 'callback', you specify a pointer to your function. This will enable | ||
36 | create_light_table() to call your function at intervals during its | ||
37 | processing. (If you don't want to use the callback, you can pass NULL, but | ||
38 | this only works because create_light_table() checks actively for NULL. You | ||
39 | can't always specify NULL when you want nothing to happen.) | ||
40 | |||
41 | There are many other uses. In addition to using function pointers as | ||
42 | parameters, Allegro has some global function pointers you can set to point to | ||
43 | your functions. Function pointers can also be used in structs, and this is | ||
44 | where DUMB makes the most use of them. | ||
45 | |||
46 | So how are they used? | ||
47 | |||
48 | void bar(void) { ... } /* Here's a function */ | ||
49 | void (*foo)(void) = &bar; /* Take a pointer */ | ||
50 | (*foo)(); /* Call the function */ | ||
51 | |||
52 | char *baz(float a) { ... } /* Here's another function */ | ||
53 | char *(*foobarbaz)(float a) = &baz; /* Take a pointer */ | ||
54 | char *rv = (*foobarbaz)(0.1); /* Call the function */ | ||
55 | |||
56 | In both these cases, note how the statement for calling the pointed-to | ||
57 | function (third line) resembles the definition of the function pointer | ||
58 | (second line). This is true of any variable in C, and can lead to some truly | ||
59 | obfuscated definitions if you are that way inclined. Such definitions can be | ||
60 | clarified with typedefs, but before you use those, it is important you | ||
61 | understand how the above statements work. I speak from experience: function | ||
62 | pointer notation looks random and scary, until you understand why it's the | ||
63 | way it is; then it makes perfect sense. | ||
64 | |||
65 | (It is actually permissible to omit the & when taking a pointer and to write | ||
66 | e.g. foobarbaz(0.1) instead of (*foobarbaz)(0.1). However, I recommend not | ||
67 | doing this, since the syntax for using the pointer no longer resembles the | ||
68 | definition. Writing e.g. (*foobarbaz)(0.1) also makes a clear distinction | ||
69 | between function pointer calls and ordinary function calls, which makes code | ||
70 | more readable.) | ||
71 | |||
72 | Note that function pointers have the return value and parameter list | ||
73 | specified. A function pointer can only point to a function with a matching | ||
74 | return value and matching parameters. (You can break this rule by casting the | ||
75 | pointer explicitly, but there is no situation where doing so is portable to | ||
76 | all computers, and I strongly advise against it unless you're writing system | ||
77 | code. If you're not sure whether you're writing system code or not, then | ||
78 | you're not.) | ||
79 | |||
80 | The parameter names need not match (although the types must). If you wish to | ||
81 | rename a parameter in your function, you do not have to change the function | ||
82 | pointer accordingly. In fact, when you define a function pointer, you don't | ||
83 | even have to specify the names of parameters if you don't want to. I normally | ||
84 | do so for clarity. | ||
85 | |||
86 | It is possible to typedef a function pointer. In order to typedef a function | ||
87 | pointer, you start by declaring the pointer as a variable: | ||
88 | |||
89 | void (*myfunc)(void); | ||
90 | |||
91 | Then you write 'typedef' before it and replace the variable name, which is | ||
92 | myfunc, with the type name (this rule can be applied to any variable when you | ||
93 | want to use typedef): | ||
94 | |||
95 | typedef void (*MYTYPE)(void); | ||
96 | |||
97 | Now 'MYTYPE' represents a pointer to a function with no parameters and no | ||
98 | return value. The following two lines are completely equivalent: | ||
99 | |||
100 | MYTYPE myfunc; | ||
101 | void (*myfunc)(void); | ||
102 | |||
103 | Note that we use MYTYPE without an asterisk (*), since it is already a | ||
104 | pointer. | ||
105 | |||
106 | That's it. If you feel anything should be explained better here, or if you | ||
107 | feel something should be added, please don't hesitate to let me know! | ||
108 | |||
109 | |||
110 | Ben Davis | ||
111 | entheh@users.sf.net | ||
112 | IRC EFnet #dumb | ||
113 | See readme.txt for details on using IRC. | ||
diff --git a/apps/codecs/dumb/docs/howto.txt b/apps/codecs/dumb/docs/howto.txt new file mode 100644 index 0000000000..0e7057da2c --- /dev/null +++ b/apps/codecs/dumb/docs/howto.txt | |||
@@ -0,0 +1,845 @@ | |||
1 | /* _______ ____ __ ___ ___ | ||
2 | * \ _ \ \ / \ / \ \ / / ' ' ' | ||
3 | * | | \ \ | | || | \/ | . . | ||
4 | * | | | | | | || ||\ /| | | ||
5 | * | | | | | | || || \/ | | ' ' ' | ||
6 | * | | | | | | || || | | . . | ||
7 | * | |_/ / \ \__// || | | | ||
8 | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque | ||
9 | * / \ | ||
10 | * / . \ | ||
11 | * howto.txt - How To Use DUMB. / / \ \ | ||
12 | * | < / \_ | ||
13 | * See readme.txt for general information on | \/ /\ / | ||
14 | * DUMB and how to set it up. \_ / > / | ||
15 | * | \ / / | ||
16 | * | ' / | ||
17 | * \__/ | ||
18 | */ | ||
19 | |||
20 | |||
21 | ******************** | ||
22 | *** Introduction *** | ||
23 | ******************** | ||
24 | |||
25 | |||
26 | Welcome to the DUMB How-To! It is assumed here that you have already set DUMB | ||
27 | up on your system, with or without Allegro. If not, please see readme.txt. | ||
28 | |||
29 | |||
30 | ********************************* | ||
31 | *** Adding music to your game *** | ||
32 | ********************************* | ||
33 | |||
34 | |||
35 | These instructions will help you add a piece of music to your game, assuming | ||
36 | your music is stored in a stand-alone IT, XM, S3M or MOD file. If you wish to | ||
37 | use a different method (such as putting the music file in an Allegro | ||
38 | datafile), please follow these instructions first, test your program, and | ||
39 | then follow the instructions further down for adapting your code. | ||
40 | |||
41 | |||
42 | 1. You need to include DUMB's header file. If you have Allegro, add the | ||
43 | following line to the top of your source file (or at the top of each file | ||
44 | where you wish to use DUMB): | ||
45 | |||
46 | #include <aldumb.h> | ||
47 | |||
48 | If you do not have Allegro or do not wish to use it, use dumb.h instead. | ||
49 | |||
50 | |||
51 | 2. You need to link with DUMB's library file or files. If you are compiling | ||
52 | with GCC from a command line on any platform, you need to add the | ||
53 | following to the command line: | ||
54 | |||
55 | If you are using Allegro: -laldmd -ldumbd | ||
56 | If you are not using Allegro: -ldumbd | ||
57 | |||
58 | If you are using MSVC from the command line: | ||
59 | |||
60 | If you are using Allegro: /link aldmd.lib dumbd.lib | ||
61 | If you are not using Allegro: /link dumbd.lib | ||
62 | |||
63 | With MSVC, you must also add /MD to the command line when compiling (not | ||
64 | when linking). | ||
65 | |||
66 | Note that -laldmd or aldmd.lib must PRECEDE alleg.lib, -lalleg_s, | ||
67 | `allegro-config --libs`, or whatever you are already using to link with | ||
68 | Allegro. For MSVC users, the /MD flag selects the multithreaded DLL | ||
69 | implementation of the standard libraries; since DUMB is statically linked, | ||
70 | you have to use the same library DUMB uses. You would also need this flag | ||
71 | to link statically with Allegro; if you already have it, there's no need | ||
72 | to put it twice. | ||
73 | |||
74 | (If anyone would like to contribute instructions for doing the above using | ||
75 | MSVC's IDE, please contact me. Contact details are at the end of this | ||
76 | file.) | ||
77 | |||
78 | If you are using RHIDE, go to Options -> Libraries. You will need to type | ||
79 | 'aldmd' and 'dumbd' in two boxes, making sure 'aldmd' comes above whatever | ||
80 | you are using to link with Allegro (or just put 'dumbd' if you are not | ||
81 | using Allegro). Make sure the box next to each of these libraries is | ||
82 | checked. | ||
83 | |||
84 | The above are the debugging libraries. It is VERY HIGHLY RECOMMENDED that | ||
85 | you use the debugging libraries at first. The reason is as follows. | ||
86 | Although DUMB is supposedly robust against corrupt music files and things | ||
87 | like lack of memory, it will NOT tolerate programmer error. If you write | ||
88 | faulty code, DUMB will probably crash rather than returning an error code | ||
89 | for you. However, the debugging libraries will abort in many cases, | ||
90 | enabling you to find out what the cause is. | ||
91 | |||
92 | Once your program is up and running reliably, you can replace 'aldmd' with | ||
93 | 'aldmb' and 'dumbd' with 'dumb'. Don't forget to do this, or DUMB will be | ||
94 | a lot slower than it should be! | ||
95 | |||
96 | |||
97 | 3. As you use DUMB, it may claim system resources (memory in particular). You | ||
98 | will need to arrange for these resources to be freed at the end. Doing so | ||
99 | is very easy. Simply write the following line at the top of your main | ||
100 | function, but below allegro_init() if you are using Allegro: | ||
101 | |||
102 | atexit(&dumb_exit); | ||
103 | |||
104 | This arranges for the function dumb_exit() to be called when your program | ||
105 | exits; you do not need to call dumb_exit() yourself. This method is | ||
106 | preferable to calling dumb_exit() manually, as it will free resources even | ||
107 | if your program aborts unexpectedly. | ||
108 | |||
109 | If you are happy with this, please skip ahead to Step 4. If you are | ||
110 | interested in alternative methods, read on, but read on carefully. | ||
111 | |||
112 | In fact it mostly doesn't matter where you put the above atexit() line, | ||
113 | provided it gets called only once, and before you do anything with DUMB. | ||
114 | If you are using DUMB with Allegro, it is recommended that you write the | ||
115 | functions in this order: | ||
116 | |||
117 | allegro_init(); | ||
118 | atexit(&dumb_exit); | ||
119 | |||
120 | And then you must NOT call allegro_exit() yourself (because it has to be | ||
121 | called after dumb_exit()). Alternatively, if you prefer not to use | ||
122 | atexit() (or you cannot), you will have to do the following before | ||
123 | exiting: | ||
124 | |||
125 | dumb_exit(); | ||
126 | allegro_exit(); | ||
127 | |||
128 | |||
129 | 4. DUMB does not automatically do any of its own file input. You have to tell | ||
130 | it how to read files. Don't worry, it's easy. Simply call the following | ||
131 | function near the beginning of your program, after your atexit() call: | ||
132 | |||
133 | dumb_register_stdfiles(); | ||
134 | |||
135 | This tells DUMB to use ordinary stdio FILE structs for reading and writing | ||
136 | files. If you are using Allegro and would rather DUMB used PACKFILEs, call | ||
137 | the following function INSTEAD: | ||
138 | |||
139 | dumb_register_packfiles(); | ||
140 | |||
141 | In the latter case, DUMB will be affected by any password you set with | ||
142 | packfile_password() in the same way that other PACKFILEs are. | ||
143 | |||
144 | Note that the procedure for loading datafiles with embedded music is | ||
145 | independent of these two functions; even if you will be loading datafiles, | ||
146 | you can use either of these functions. If you are loading datafiles, your | ||
147 | executable might be slightly smaller if you use dumb_register_packfiles(). | ||
148 | On the other hand, dumb_register_stdfiles() will probably be faster. If | ||
149 | you are only ever going to load datafiles and never stand-alone files, you | ||
150 | can actually leave this step out; but I would recommend you put this in, | ||
151 | test your code with a stand-alone file, then follow the instructions in | ||
152 | the next section in order to adapt your code to use the datafile (you will | ||
153 | be reminded that you can remove the function call). | ||
154 | |||
155 | |||
156 | 5. If you are using Allegro, you'll have to initialise Allegro's sound | ||
157 | system. In most cases the following line will do the job: | ||
158 | |||
159 | install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL); | ||
160 | |||
161 | You may like to initialise a MIDI driver though; see Allegro's docs for | ||
162 | details. Put this line after allegro_init(). | ||
163 | |||
164 | |||
165 | 6. All pieces of music are stored in memory in DUH structs. To handle these, | ||
166 | you must define pointers to them. Such pointers look like this: | ||
167 | |||
168 | DUH *myduh; | ||
169 | |||
170 | You can of course replace 'myduh' with anything you like. If you are | ||
171 | unfamiliar with pointers, please see ptr.txt. It is very important that | ||
172 | you understand these if you wish to use DUMB correctly. | ||
173 | |||
174 | You do not have direct access to the contents of a DUH struct, so do not | ||
175 | try. DUMB's functions provide everything you need; if you disagree, please | ||
176 | let me know and I shall see what I can do. Contact details are at the end | ||
177 | of this file. | ||
178 | |||
179 | Given the above definition, you can load a piece of music using one of the | ||
180 | following lines, depending on what file format you want to load: | ||
181 | |||
182 | myduh = dumb_load_it("a_one.it"); | ||
183 | myduh = dumb_load_xm("a_two.xm"); | ||
184 | myduh = dumb_load_s3m("a_one_two.s3m"); | ||
185 | myduh = dumb_load_mod("three_four.mod"); | ||
186 | |||
187 | Obviously you can use relative or absolute paths as normal. You should | ||
188 | always use forward slash (/), not backslash (\), when coding in C and | ||
189 | similar languages. | ||
190 | |||
191 | Every piece of music you load must be unloaded when you've finished with | ||
192 | it. When you type the above line in, it is good practice to type the | ||
193 | following line in at the same time, but put it at the end of the program: | ||
194 | |||
195 | unload_duh(myduh); | ||
196 | |||
197 | You will now be able to use the DUH struct anywhere in between the two | ||
198 | lines you just added. There is no need to check the return value; if the | ||
199 | DUH failed to load for one reason or another (this could be due to lack of | ||
200 | memory as well as the file not being there), then DUMB will do nothing - | ||
201 | safely. | ||
202 | |||
203 | |||
204 | 7. From this step onwards, it will be assumed you're using Allegro. If not, | ||
205 | please read these steps anyway, and then see the section entitled | ||
206 | "Rendering music into a buffer". You will have to write your own playback | ||
207 | code using whatever sound output system is available. Alternatively you | ||
208 | may like to write data to a file (especially if you have a file that | ||
209 | consumes a lot of processor time), but beware that any streaming audio | ||
210 | format is likely to be substantially larger than the module file you | ||
211 | generate it from, and formats like MP3 will be lower quality. You might | ||
212 | not be able to hear the difference between the MP3 and the original, but | ||
213 | many people can and don't like it, so please consider them. I'm one of | ||
214 | them. If you really want to use a lossy compression format, I highly | ||
215 | recommend Ogg Vorbis: | ||
216 | |||
217 | http://www.vorbis.com/ | ||
218 | |||
219 | But I digress. | ||
220 | |||
221 | In order to play the DUH you loaded, you need to define a pointer to an | ||
222 | AL_DUH_PLAYER struct: | ||
223 | |||
224 | AL_DUH_PLAYER *dp; | ||
225 | |||
226 | Two of the functions you will need are prototyped as follows: | ||
227 | |||
228 | AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos, | ||
229 | float volume, long bufsize, int freq); | ||
230 | |||
231 | void al_stop_duh(AL_DUH_PLAYER *dp); | ||
232 | |||
233 | As you can see, al_start_duh() returns a pointer to an AL_DUH_PLAYER | ||
234 | struct when you call it. You then pass this pointer to all the other | ||
235 | functions. Again, if it is a NULL pointer for whatever reason (usually | ||
236 | lack of memory), DUMB will safely do nothing. When you call al_stop_duh(), | ||
237 | the pointer becomes invalid and you should not use it again; if there's | ||
238 | any risk of the pointer being used again, it is wise to set it to NULL at | ||
239 | this point. You can reassign the variable with a new call to | ||
240 | al_start_duh() of course. | ||
241 | |||
242 | Set 'n_channels' to 1 or 2 for mono or stereo respectively. Note that this | ||
243 | parameter has nothing to do with the number of samples that can play at | ||
244 | once in a music module. Set 'pos' to 0 to play from the beginning; each | ||
245 | time you add 65536, you will have advanced one second into the piece. As a | ||
246 | general rule, set the volume to 1.0f and adjust it later if the music is | ||
247 | too loud or too quiet - but see Allegro's set_volume_per_voice() function | ||
248 | first. | ||
249 | |||
250 | 'bufsize' can generally be set to 4096. If your music stutters, try | ||
251 | increasing it; if your game freezes periodically, try reducing it. Find a | ||
252 | happy medium. Set 'freq' to 48000 for the best quality, though 44100 will | ||
253 | do in most cases. 22050 will be fine for a lot of music, though 11025 may | ||
254 | sound muffled. You can choose any other value, higher, lower or in | ||
255 | between. If your music stutters, and increasing 'bufsize' doesn't fix it, | ||
256 | try reducing this value. | ||
257 | |||
258 | Once you have put in a call to al_start_duh(), it is good practice to | ||
259 | insert the call to al_stop_duh() at the same time. You must call | ||
260 | al_stop_duh() before the DUH is unloaded (unload_duh(), Step 6 above). | ||
261 | |||
262 | Don't get impetuous, your program is not ready yet! Proceed to Step 8. | ||
263 | |||
264 | |||
265 | 8. DUMB does not play music in the background for you; if you were expecting | ||
266 | it to do so, please see the explanation at the end of this step. For your | ||
267 | music to be played, you have to call another function at regular | ||
268 | intervals. Here is its prototype: | ||
269 | |||
270 | int al_poll_duh(AL_DUH_PLAYER *dp); | ||
271 | |||
272 | Do NOT call this function from inside a timer function unless you really | ||
273 | know what you are doing. The reasons why this is bad are explained | ||
274 | further down. You should call it from your main program. | ||
275 | |||
276 | Simply writing the following line will be sufficient in general, if you | ||
277 | have a variable 'dp' that points to your AL_DUH_PLAYER struct. | ||
278 | |||
279 | al_poll_duh(dp); | ||
280 | |||
281 | As a general rule, calling this once for each logic update will do the | ||
282 | trick. If, however, you are executing time-consuming algorithms such as | ||
283 | software 3D rendering, you may wish to insert calls to this function in | ||
284 | the middle of those algorithms. You cannot call this function too often | ||
285 | (within reason); if it has nothing to do it will return immediately. | ||
286 | |||
287 | Exactly how often you need to call the function depends on the values for | ||
288 | 'bufsize' and 'freq' that you passed to al_start_duh(): | ||
289 | |||
290 | n = freq / bufsize; | ||
291 | |||
292 | You have to call al_poll_duh() at least n times a second. Do not hesitate | ||
293 | to call it more often for safety; if the sound stutters, you may need to | ||
294 | do just that. (Or you may need to increase the buffer size or reduce the | ||
295 | quality settings; the only way to find out is to try.) | ||
296 | |||
297 | For now, don't worry about al_poll_duh()'s return value. As soon as you | ||
298 | need it, it will be explained. | ||
299 | |||
300 | If you are happy, please skip to Step 9. If you were expecting DUMB to | ||
301 | play your music in the background, please read on. | ||
302 | |||
303 | The natural way to play music in the background on most operating systems | ||
304 | nowadays is to use threads. DOS was not built with multithreading in mind, | ||
305 | and its system operations (notably disk access) assume they will only be | ||
306 | used from a single thread. | ||
307 | |||
308 | Interrupts are the next best thing to threads. A DOS hardware interrupt | ||
309 | could be triggered at any moment, and a handler function will be called. | ||
310 | This is how Allegro's timer functions work. Unfortunately, what you can do | ||
311 | inside an interrupt handler is very limited. For one thing, all code and | ||
312 | data used by the handler must be locked in memory; if not, it could get | ||
313 | written to disk (virtual memory). If the main program was accessing the | ||
314 | disk when it got interrupted, the system would then die a horrible death. | ||
315 | This precludes the possibility of allocating extra memory inside the | ||
316 | handler, and DUMB does a lot of that in al_poll_duh(). | ||
317 | |||
318 | Given DUMB's architecture, which cannot change for reasons which will | ||
319 | become apparent in future versions, this renders it impossible to come up | ||
320 | with a portable solution for making DUMB play music in the background. | ||
321 | Having said that, if you wish to write your own wrapper for al_poll_duh() | ||
322 | and use it in a thread, there is nothing stopping you. If you do do this, | ||
323 | you will have to be very careful when stopping the music; see the | ||
324 | description of al_poll_duh() in dumb.txt for more information. | ||
325 | |||
326 | So why not kill DOS? It is all too common a practice among programmers to | ||
327 | quote the phrase, "DOS is as dead as the dodo." Despite being a decidedly | ||
328 | derisible demonstation of the dreary device of alliteration, it shows a | ||
329 | distinct lack of experience. Many embedded systems still use DOS because | ||
330 | it provides hardware access capabilities and real-time possibilities | ||
331 | unparalleled by any current multitasking operating system. For an argument | ||
332 | closer to home, I used to use RHIDE for DOS before I switched to Linux, | ||
333 | and I have not found a single Freeware Windows IDE that measures up to | ||
334 | RHIDE. I'm sure many people are in the same boat, and really appreciate | ||
335 | DUMB's DOS port. | ||
336 | |||
337 | We will not be removing DOS support from DUMB. Any blind suggestions to do | ||
338 | so will be met with fiery flames. You have been warned. | ||
339 | |||
340 | |||
341 | 9. Test your program! | ||
342 | |||
343 | If you have trouble, check through the above steps to make sure you didn't | ||
344 | miss one out. Refer to faq.txt to see if your problem is addressed there. | ||
345 | If you still have trouble, contact me; details are at the end of this | ||
346 | file. | ||
347 | |||
348 | |||
349 | ********************************** | ||
350 | *** Controlling music playback *** | ||
351 | ********************************** | ||
352 | |||
353 | |||
354 | Here I describe some common operations you may wish to perform. The method | ||
355 | for doing so will seem a bit strange sometimes, as will the names of the | ||
356 | structs. However, there is a reason behind everything. If you would like to | ||
357 | do more exotic things, or better understand some of the methods used here, | ||
358 | then see dumb.txt, which covers everything from the ground up. | ||
359 | |||
360 | |||
361 | To control playback quality: | ||
362 | |||
363 | #define DUMB_RQ_ALIASING | ||
364 | #define DUMB_RQ_LINEAR | ||
365 | #define DUMB_RQ_CUBIC | ||
366 | #define DUMB_RQ_N_LEVELS | ||
367 | extern int dumb_resampling_quality; | ||
368 | extern int dumb_it_max_to_mix; | ||
369 | |||
370 | Please note that dumb_resampling_quality has changed in DUMB v0.9.2. See | ||
371 | deprec.txt for more details on the change. | ||
372 | |||
373 | dumb_resampling_quality can be set to any of the DUMB_RQ_* constants | ||
374 | (except DUMB_RQ_N_LEVELS; see below). Resampling is the term given to the | ||
375 | process of adjusting a sample's pitch (in this context). | ||
376 | dumb_resampling_quality defaults to DUMB_RQ_CUBIC, which sounds nice but | ||
377 | takes a lot of processor power. Try reducing it if you have an older | ||
378 | computer or if you are trying to mix an insane number of samples (or | ||
379 | both!). See dumb.txt for details on what the different values actually do. | ||
380 | |||
381 | If you wish to give this option to your user, you can use | ||
382 | DUMB_RQ_N_LEVELS. All the values from 0 to DUMB_RQ_N_LEVELS - 1 will be | ||
383 | valid resampling levels. If a value outside this range is chosen, it is | ||
384 | not the end of the world; DUMB will behave as if you had chosen the value | ||
385 | at whichever extreme you went beyond. | ||
386 | |||
387 | dumb_it_max_to_mix, defaulting to 64, is the maximum number of samples | ||
388 | DUMB will ever mix together when playing an IT, XM, S3M or MOD file. | ||
389 | Unlike many other music systems, DUMB will still keep track of all samples | ||
390 | (up to a fixed maximum of 256 of them, roughly speaking), and then will | ||
391 | just render as many of them as this variable permits, starting with the | ||
392 | loudest ones. When samples are cut or come back in, the exact timings will | ||
393 | not generally be predictable - but nor will they be important. | ||
394 | |||
395 | dumb_it_max_to_mix applies to each currently playing module file | ||
396 | independently. So if you set it to 64, but render two modules | ||
397 | simultaneously, DUMB could end up mixing up to 128 samples. | ||
398 | |||
399 | |||
400 | To pause and resume playback, set the volume, get the current playback | ||
401 | position, or get the length of time a DUH will play for before either looping | ||
402 | or freezing (effect F00 in XM and MOD files, which means no new notes will be | ||
403 | played but any existing notes will continue): | ||
404 | |||
405 | void al_pause_duh(AL_DUH_PLAYER *dp); | ||
406 | void al_resume_duh(AL_DUH_PLAYER *dp); | ||
407 | void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume); | ||
408 | long al_duh_get_position(AL_DUH_PLAYER *dp); | ||
409 | |||
410 | long duh_get_length(DUH *duh); | ||
411 | |||
412 | These functions are pretty self-explanatory. The volume passed to | ||
413 | al_duh_set_volume() and the position returned by al_duh_get_position() are | ||
414 | in the same units as those you passed to al_start_duh(). The length | ||
415 | returned by duh_get_length() is in the same units as the aforementioned | ||
416 | position; see dumb.txt for more information on this function. Be careful | ||
417 | with al_duh_get_position(); it will return a position slightly ahead of | ||
418 | what you can hear, because the system has to keep ahead slightly to avoid | ||
419 | stuttering. | ||
420 | |||
421 | |||
422 | To prevent the music from looping and/or freezing: | ||
423 | |||
424 | DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp); | ||
425 | DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer); | ||
426 | |||
427 | void dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer, | ||
428 | int (*callback)(void *data), void *data); | ||
429 | void dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, | ||
430 | int (*callback)(void *data), void *data); | ||
431 | |||
432 | int dumb_it_callback_terminate(void *data); | ||
433 | |||
434 | If you are unfamiliar with function pointers, please see fnptr.txt. | ||
435 | |||
436 | Note that these functions apply to IT, XM, S3M and MOD files - not just to | ||
437 | IT files. This holds true throughout DUMB, for all functions with "it" in | ||
438 | the name. The xm_speed_zero event can only occur with XM and MOD files. | ||
439 | |||
440 | The first two functions will return a pointer to a struct contained by the | ||
441 | struct you pass. This system is necessary to ensure that these operations | ||
442 | are possible when not using Allegro. Typically you would write the | ||
443 | following code: | ||
444 | |||
445 | { | ||
446 | DUH_SIGRENDERER *sr = al_duh_get_sigrenderer(dp); | ||
447 | DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sigrenderer); | ||
448 | dumb_it_set_loop_callback(itsr, &dumb_it_callback_terminate, NULL); | ||
449 | dumb_it_set_xm_speed_zero_callback | ||
450 | (itsr, &dumb_it_callback_terminate, NULL); | ||
451 | } | ||
452 | |||
453 | Once you have done this, the return value of al_poll_duh() becomes | ||
454 | significant. It will be 0 as long as the music is playing. When the music | ||
455 | stops, al_poll_duh() will return nonzero. You can call al_stop_duh() and | ||
456 | do something else as soon as you wish, but calling al_poll_duh() some more | ||
457 | will not do any harm. | ||
458 | |||
459 | al_poll_duh() will also return 1 if the music could not be loaded, or if | ||
460 | memory was short when trying to play it, or if it was a quirky music file | ||
461 | with no music in it (technically one with an empty order list). This | ||
462 | happens regardless of whether or not you execute the above code to disable | ||
463 | looping. Normally you shouldn't need to worry about this. | ||
464 | |||
465 | To undo the above and make DUMB loop or freeze again, pass NULL instead of | ||
466 | &dumb_it_callback_terminate. If you would like to fade on looping, or loop | ||
467 | a finite number of times, or display a message when looping, or whatever, | ||
468 | you will have to write your own callback function. In this case, please | ||
469 | see dumb.txt. | ||
470 | |||
471 | Note that the above code can safely be applied for a DUH that doesn't | ||
472 | contain a music module but contains some other kind of music. | ||
473 | duh_get_it_sigrenderer() will return NULL, and the code will do nothing. | ||
474 | |||
475 | |||
476 | To analyse the audio as it's generated: | ||
477 | |||
478 | typedef int sample_t; | ||
479 | |||
480 | typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data, | ||
481 | const sample_t *const *samples, int n_channels, long length); | ||
482 | |||
483 | void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer, | ||
484 | DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data); | ||
485 | |||
486 | If the above confuses you, see fnptr.txt. These functions, along with | ||
487 | al_duh_get_sigrenderer() from the last section, enable you to register a | ||
488 | callback function. Every time some samples are generated, they will be | ||
489 | passed to this function. This enables you to display an oscilloscope or | ||
490 | spectrum analyser, for example. | ||
491 | |||
492 | Beware: your callback function may occasionally be called with | ||
493 | samples == NULL. This means the main program has decided to skip through | ||
494 | the music without generating any data. You should handle this case | ||
495 | elegantly, typically by returning immediately, but you may wish to make a | ||
496 | note of the fact that the music is being skipped, for whatever reason. | ||
497 | |||
498 | Beware again: if the main program ever calls duh_sigrenderer_get_samples() | ||
499 | on a buffer that isn't all silence, this callback function will be passed | ||
500 | the existing buffer after mixing, and thus it will include the original | ||
501 | data. This will not be an issue if you stick to duh_render(), which always | ||
502 | starts with a buffer filled with silence. | ||
503 | |||
504 | The samples array is two-dimensional. Refer to it as follows: | ||
505 | |||
506 | samples[channel_number][sample_position] | ||
507 | |||
508 | where 0 <= channel_number < n_channels, | ||
509 | and 0 <= sample_position < length. | ||
510 | |||
511 | In addition you can pass any 'data' pointer you like to | ||
512 | duh_sigrenderer_set_analyser_callback(), and this pointer will be relayed | ||
513 | to your callback function each time. | ||
514 | |||
515 | To remove the callback function, pass NULL to | ||
516 | duh_sigrenderer_set_analyser_callback(). | ||
517 | |||
518 | |||
519 | Everything below this point assumes some knowledge of how a music module is | ||
520 | constructed. If you do not have this knowledge, talk to whoever is writing | ||
521 | music for you, or download a tracking program and play with it (see | ||
522 | readme.txt). | ||
523 | |||
524 | |||
525 | To start playing an IT, XM, S3M or MOD from an arbitrary order number (the | ||
526 | default being 0, the beginning of the song), use the following: | ||
527 | |||
528 | DUH_SIGRENDERER *dumb_it_start_at_order | ||
529 | (DUH *duh, int n_channels, int startorder); | ||
530 | AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer | ||
531 | (DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq); | ||
532 | |||
533 | The usage of these functions is as follows: | ||
534 | |||
535 | { | ||
536 | DUH_SIGRENDERER *sr = dumb_it_start_at_order | ||
537 | (duh, n_channels, startorder); | ||
538 | dp = al_duh_encapsulate_sigrenderer(sr, volume, bufsize, freq); | ||
539 | } | ||
540 | |||
541 | Replace 'dp' with whatever your AL_DUH_PLAYER pointer is. You also need | ||
542 | to insert suitable values for n_channels, startorder, volume, bufsize and | ||
543 | freq. These have the same meaning as those passed to al_start_duh(). | ||
544 | |||
545 | WARNING: after passing a pointer to an "encapsulate" function, do not use | ||
546 | that pointer again. (More specifically, do not use it again if | ||
547 | the function returns NULL, because the function will have | ||
548 | destroyed the pointer if this happens, to help prevent memory | ||
549 | leaks.) There will be a "get" function with which you can obtain | ||
550 | the original pointer if it is still valid, or NULL otherwise. | ||
551 | |||
552 | The above functions will fail (safely) if you try to use them with a DUH | ||
553 | that contains a different type of music. | ||
554 | |||
555 | Notice that there is no 'pos' parameter. If you would like to skip through | ||
556 | the music, you can use this function: | ||
557 | |||
558 | long duh_sigrenderer_get_samples( | ||
559 | DUH_SIGRENDERER *sigrenderer, | ||
560 | float volume, float delta, | ||
561 | long size, sample_t **samples | ||
562 | ); | ||
563 | |||
564 | Pass 0 for volume and NULL for samples, and this function will skip | ||
565 | through the music nice and quickly. So insert the following between the | ||
566 | two above statements: | ||
567 | |||
568 | duh_sigrenderer_get_samples(sr, 0, 65536.0f / freq, pos, NULL); | ||
569 | |||
570 | Substitute for 'freq' and 'pos'. An explanation of the 'delta' parameter | ||
571 | can be found further down in this file. | ||
572 | |||
573 | Finally, note that duh_get_length() is only meaningful when you start | ||
574 | playing music from order 0. | ||
575 | |||
576 | |||
577 | If an IT file contains Zxx effects, DUMB will generate MIDI messages, which | ||
578 | will control the low-pass resonant filters unless the IT file actively | ||
579 | specifies something else. In rare cases this may not be what the Zxx effects | ||
580 | were intended to do; if this is the case, you can block the MIDI messages as | ||
581 | follows. Note that this does NOT mean filters are disabled; if an instrument | ||
582 | specifies initial cut-off and resonance values, or has a filter envelope, | ||
583 | then filters will be applied. It only makes sense to use this procedure at | ||
584 | the beginning of playback. | ||
585 | |||
586 | void dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer, | ||
587 | int (*callback)(void *data, int channel, unsigned char byte), | ||
588 | void *data); | ||
589 | |||
590 | int dumb_it_callback_midi_block(void *data, int channel, | ||
591 | unsigned char byte); | ||
592 | |||
593 | Using some functions described in the previous section, we arrive at the | ||
594 | following code: | ||
595 | |||
596 | { | ||
597 | DUH_SIGRENDERER *sr = al_duh_get_sigrenderer(dp); | ||
598 | DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sigrenderer); | ||
599 | dumb_it_set_midi_callback(itsr, &dumb_it_callback_midi_block, NULL); | ||
600 | } | ||
601 | |||
602 | DUMB offers no way of disabling filters completely. Disabling filters is not | ||
603 | recommended as a means to reduce processor usage, as it will completely | ||
604 | damage any piece of music that uses the filters. If you want lower processor | ||
605 | consumption, use a piece of music that does not use filters. | ||
606 | |||
607 | |||
608 | Finally, DUMB offers a myriad of functions for querying and adjusting | ||
609 | module playback. Those beginning with "dumb_it_sd" operate on the | ||
610 | DUMB_IT_SIGDATA struct, which represents the piece of music before it starts | ||
611 | to play. Those beginning with "dumb_it_sr" operate on the DUMB_IT_SIGRENDERER | ||
612 | struct, which represents a currently playing instance of the music. Note that | ||
613 | duh_get_length(), described above, becomes meaningless after some of these | ||
614 | functions are used. | ||
615 | |||
616 | The method for getting a DUMB_IT_SIGRENDERER struct has already been given, | ||
617 | but the function prototypes are repeated here for convenience: | ||
618 | |||
619 | DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp); | ||
620 | DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer); | ||
621 | |||
622 | Getting a DUMB_IT_SIGDATA struct is simpler: | ||
623 | |||
624 | DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh); | ||
625 | |||
626 | For a list of dumb_it_sd_*() and dumb_it_sr_*() functions, please see | ||
627 | dumb.txt. These functions are new, and may not provide exactly what you need; | ||
628 | if not, please let me know. | ||
629 | |||
630 | |||
631 | ************************************************** | ||
632 | *** Embedding music files in Allegro datafiles *** | ||
633 | ************************************************** | ||
634 | |||
635 | |||
636 | In this section it is assumed you are already reasonably familiar with how | ||
637 | Allegro datafiles are used. If not, please refer to Allegro's documentation. | ||
638 | At the time of writing, the documentation you need is off the beaten track, | ||
639 | so to speak, in allegro/tools/grabber.txt. | ||
640 | |||
641 | To add a piece of music to a datafile, you need to create an object of type | ||
642 | "IT ", "XM ", "S3M " or "MOD " (note the spaces used as padding, although | ||
643 | you do not need to type these into the grabber). Then grab the piece of music | ||
644 | in. The grabber will treat it as a binary object. Save the datafile as usual. | ||
645 | |||
646 | |||
647 | To use a piece of music you added to the datafile, follow these steps: | ||
648 | |||
649 | |||
650 | 1. Before loading the datafile, call one or more of these functions, | ||
651 | depending on which music format or formats you'd like to support: | ||
652 | |||
653 | dumb_register_dat_it(DUMB_DAT_IT); | ||
654 | dumb_register_dat_xm(DUMB_DAT_XM); | ||
655 | dumb_register_dat_s3m(DUMB_DAT_S3M); | ||
656 | dumb_register_dat_mod(DUMB_DAT_MOD); | ||
657 | |||
658 | Remember, do not call multiple functions unless you want to support | ||
659 | multiple formats. Calling more functions will add unused code to your | ||
660 | executable. | ||
661 | |||
662 | It is important that you make call these before loading the datafile, | ||
663 | since they tell Allegro how to load the respective files straight from | ||
664 | datafiles in the future. They will not help Allegro interpret any module | ||
665 | files that have already been loaded as binary objects (but if you really | ||
666 | need to interpret a module that has been loaded in this fashion, have a | ||
667 | look at dumbfile_open_memory() in dumb.txt). | ||
668 | |||
669 | If for whatever reason your music objects are identified by a different | ||
670 | type in the datafile, you can tell DUMB what that type is by changing the | ||
671 | parameter to the registration function above. Use Allegro's DAT_ID() | ||
672 | macro, e.g. DAT_ID('B','L','A','H'). This is not really recommended | ||
673 | though, since it would prevent a hypothetical grabber plug-in from being | ||
674 | able to play your music files. Use the above types if possible. | ||
675 | |||
676 | |||
677 | 2. Whenever you need a pointer to a DUH struct, simply use the 'dat' field. | ||
678 | Do this in the same way you would for a pointer to a BITMAP struct or | ||
679 | anything else. If it makes you feel more comfortable, you can extract the | ||
680 | pointer in advance: | ||
681 | |||
682 | DATAFILE *dat = load_datafile("smurf.dat"); | ||
683 | if (!dat) abort(); /* There are much nicer ways of handling failure! */ | ||
684 | DUH *myduh = (DUH *)dat[GAME_MUSIC].dat; | ||
685 | |||
686 | Note that the explicit (DUH *) cast is only necessary for C++, not for C. | ||
687 | However, it does no harm. | ||
688 | |||
689 | Be sure that you do NOT call unload_duh() for anything stored in the | ||
690 | datafile. These DUHs will be freed when you call unload_datafile(), and | ||
691 | freeing them twice is practically guaranteed to crash your program. | ||
692 | |||
693 | |||
694 | 3. If you only ever load music as part of a datafile, and you never load any | ||
695 | stand-alone music files, you do not need to register a file input system | ||
696 | for DUMB to use. If you followed the instructions for the first section | ||
697 | you will have one of these two lines in your program: | ||
698 | |||
699 | dumb_register_stdfiles(); | ||
700 | dumb_register_packfiles(); | ||
701 | |||
702 | You can safely delete this line - but only if you never load any | ||
703 | stand-alone music files. The debugging library will bale you out if you | ||
704 | delete it when you shouldn't; the optimised library won't. | ||
705 | |||
706 | |||
707 | ************************************* | ||
708 | *** Rendering music into a buffer *** | ||
709 | ************************************* | ||
710 | |||
711 | |||
712 | NOTE: much of the API formerly described in this section has been deprecated, | ||
713 | and you will need to alter your code. See deprec.txt for details. If | ||
714 | you are reading this section for the first time, you can ignore this | ||
715 | note. | ||
716 | |||
717 | Rendering to a buffer is similar to playing using an AL_DUH_PLAYER. However, | ||
718 | you must use a DUH_SIGRENDERER struct instead. Here are the functions: | ||
719 | |||
720 | DUH_SIGRENDERER *duh_start_sigrenderer | ||
721 | (DUH *duh, int sig, int n_channels, long pos); | ||
722 | |||
723 | int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer); | ||
724 | long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer); | ||
725 | |||
726 | long duh_sigrenderer_get_samples(DUH_SIGRENDERER *sigrenderer, | ||
727 | float volume, float delta, long size, sample_t **samples); | ||
728 | |||
729 | long duh_render(DUH_SIGRENDERER *sigrenderer, | ||
730 | int bits, int unsign, float volume, float delta, long size, void *sptr); | ||
731 | |||
732 | void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer); | ||
733 | |||
734 | The parameters to duh_start_sigrenderer() have the same meanings as those to | ||
735 | al_start_duh(). However, note that the volume is not set at this stage. You | ||
736 | pass the desired volume each time you want to render a block. The 'sig' | ||
737 | parameter should be set to 0 for now. | ||
738 | |||
739 | Notice that there are two rendering functions. duh_sigrenderer_get_samples() | ||
740 | will generate samples in the internal 32-bit format, with a normal range from | ||
741 | -0x800000 to 0x7FFFFF and with each channel in a separate array; duh_render() | ||
742 | will convert to 8 or 16 bits, signed or unsigned, with stereo samples | ||
743 | interleaved, left first. | ||
744 | |||
745 | When you call duh_render(), pass 8 or 16 for 'bits'. If you pass 8, 'sptr' is | ||
746 | expected to be an array of chars. If you pass 16, 'sptr' is expected to be an | ||
747 | array of shorts. Endianness therefore depends on the platform, and you should | ||
748 | not try to interpret 16-bit wave data as an array of chars (unless you're | ||
749 | writing highly system-specific code anyway). Because DUMB renders internally | ||
750 | with 32 bits, there is no significant speed increase in rendering an 8-bit | ||
751 | stream. | ||
752 | |||
753 | If you are rendering in stereo, make sure your 'sptr' array is twice as big! | ||
754 | |||
755 | If you set 'unsign' to a nonzero value, then the samples generated will be | ||
756 | centred on 0x80 or 0x8000, suitably stored in an array of unsigned chars or | ||
757 | unsigned shorts. If 'unsign' is zero, the samples will be centred on 0, | ||
758 | suitably stored in an array of signed chars or signed shorts. Note that 8-bit | ||
759 | WAV files are unsigned while 16-bit WAV files are signed. This convention was | ||
760 | used by the SoundBlaster 16 when receiving samples to be sent to the | ||
761 | speakers. If you wish to write 16-bit sample data to a WAV file, don't use | ||
762 | fwrite(); instead, take the shorts one at a time, split them up into chars as | ||
763 | follows, and write the chars to the file. | ||
764 | |||
765 | short sptr[n]; | ||
766 | char lsb = (char)sptr[n]; | ||
767 | char msb = (char)(sptr[n] >> 8); | ||
768 | |||
769 | For a 16-bit WAV file, write the LSB (less significant byte) first. | ||
770 | |||
771 | The following applies equally to duh_render() and | ||
772 | duh_sigrenderer_get_samples(), except where otherwise stated. | ||
773 | |||
774 | If you set 'delta' to 1.0f, the sound generated will be suitable for playback | ||
775 | at 65536 Hz. Increasing 'delta' causes the wave to speed up, given a constant | ||
776 | sampling rate for playback. Supposing you want to vary the playback sampling | ||
777 | rate but keep the pitch constant, here's the equation for 'delta': | ||
778 | |||
779 | delta = 65536.0f / sampling_rate; | ||
780 | |||
781 | 'size' is the number of samples you want rendered. For duh_render(), they | ||
782 | will be rendered into an array which you pass as 'sptr'. Note that stereo | ||
783 | samples count as one; so if you set n_channels to 2, your array must contain | ||
784 | (2 * size) elements. | ||
785 | |||
786 | For duh_sigrenderer_get_samples() you will have to use the following | ||
787 | functions: | ||
788 | |||
789 | sample_t **create_sample_buffer(int n_channels, long length); | ||
790 | void destroy_sample_buffer(sample_t **samples); | ||
791 | |||
792 | void dumb_silence(sample_t *samples, long length); | ||
793 | |||
794 | create_sample_buffer() allocates the channels sequentially in memory, so the | ||
795 | following technique is valid: | ||
796 | |||
797 | sample_t **samples = create_sample_buffer(n_channels, length); | ||
798 | dumb_silence(samples[0], n_channels * length); | ||
799 | |||
800 | It is necessary to fill the buffer with silence like this because | ||
801 | duh_sigrenderer_get_samples() mixes what it renders with the existing | ||
802 | contents of the buffer. | ||
803 | |||
804 | The return values from duh_render() and duh_sigrenderer_get_samples() tell | ||
805 | you how many samples were actually generated. In most cases, this will be the | ||
806 | same as the 'size' parameter. However, if you reach the end of the DUH (which | ||
807 | will happen if you disable looping or freezing as described further up), this | ||
808 | function will return less. When that happens, you can assume the stream has | ||
809 | finished. In the case of duh_render(), the remainder of the array will not | ||
810 | have been initialised, so you either have to initialise it yourself or avoid | ||
811 | using it. | ||
812 | |||
813 | If for whatever reason duh_start_sigrenderer() returns NULL, then | ||
814 | duh_render() and duh_sigrenderer_get_samples() will generate exactly 0 | ||
815 | samples, duh_sigrenderer_get_n_channels() will return 0, | ||
816 | duh_sigrenderer_get_position() will return -1, and duh_end_sigrenderer() will | ||
817 | safely do nothing. | ||
818 | |||
819 | |||
820 | ********************* | ||
821 | *** Miscellaneous *** | ||
822 | ********************* | ||
823 | |||
824 | |||
825 | Please see dumb.txt for an API reference and for information on thread safety | ||
826 | with DUMB. The API reference has been stripped down, since some functions and | ||
827 | variables are subject to change. If something does not appear in dumb.txt, | ||
828 | please do not use it. | ||
829 | |||
830 | |||
831 | ****************** | ||
832 | *** Conclusion *** | ||
833 | ****************** | ||
834 | |||
835 | |||
836 | If you have any difficulties, or if you use DUMB successfully, please don't | ||
837 | hesitate to contact me (see below). | ||
838 | |||
839 | Enjoy! | ||
840 | |||
841 | |||
842 | Ben Davis | ||
843 | entheh@users.sf.net | ||
844 | IRC EFnet #dumb | ||
845 | See readme.txt for details on using IRC. | ||
diff --git a/apps/codecs/dumb/docs/modplug.txt b/apps/codecs/dumb/docs/modplug.txt new file mode 100644 index 0000000000..a02ddd8bdd --- /dev/null +++ b/apps/codecs/dumb/docs/modplug.txt | |||
@@ -0,0 +1,137 @@ | |||
1 | /* _______ ____ __ ___ ___ | ||
2 | * \ _ \ \ / \ / \ \ / / ' ' ' | ||
3 | * | | \ \ | | || | \/ | . . | ||
4 | * | | | | | | || ||\ /| | | ||
5 | * | | | | | | || || \/ | | ' ' ' | ||
6 | * | | | | | | || || | | . . | ||
7 | * | |_/ / \ \__// || | | | ||
8 | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque | ||
9 | * / \ | ||
10 | * / . \ | ||
11 | * modplug.txt - Our official position regarding / / \ \ | ||
12 | * compatibility with ModPlug | < / \_ | ||
13 | * Tracker. | \/ /\ / | ||
14 | * \_ / > / | ||
15 | * | \ / / | ||
16 | * | ' / | ||
17 | * \__/ | ||
18 | */ | ||
19 | |||
20 | |||
21 | ******************** | ||
22 | *** Introduction *** | ||
23 | ******************** | ||
24 | |||
25 | ModPlug Tracker is a very popular tracker for Windows. Its popularity is due | ||
26 | to the intuitive interface and its many advanced features. The author has | ||
27 | done a good job with this piece of software, but sadly in doing so he has | ||
28 | desecrated the IT file format. | ||
29 | |||
30 | I am not against ModPlug Tracker being used to write music modules. As | ||
31 | already stated, it has some very advanced and convenient features; I use it | ||
32 | myself. However, I believe its users should be aware of the entire situation | ||
33 | before using it for any serious work. | ||
34 | |||
35 | ModPlug Tracker - http://www.modplug.com/ | ||
36 | |||
37 | |||
38 | ************************* | ||
39 | *** Incompatibilities *** | ||
40 | ************************* | ||
41 | |||
42 | There are a few situations in which ModPlug Tracker misinterprets the | ||
43 | original module formats. I shall list the five I am most aware of, from least | ||
44 | to most annoying: | ||
45 | |||
46 | 5. Create a multisample instrument, for example a piano. Play a low note. | ||
47 | Then go up the scale, but in the pattern data, make sure the instrument | ||
48 | column is blank; put in only the notes. Play this with ModPlug Tracker, | ||
49 | and play it with Impulse Tracker. Impulse Tracker changes sample as you go | ||
50 | up the scale; ModPlug Tracker does not. | ||
51 | |||
52 | 4. Arpeggio and Retrigger Note effects behave badly when combined with | ||
53 | Portamento, which can appear in the volume column. While Retrigger Note | ||
54 | isn't too bad, Arpeggio sounds completely wrong. Try it and see what | ||
55 | happens. Then repeat the experiment in Impulse Tracker. | ||
56 | |||
57 | 3. The filter algorithm is incorrect, in more ways than one. When Jeffrey Lim | ||
58 | programmed the low-pass resonant filters into Impulse Tracker, he used a | ||
59 | standard filter algorithm with a slight modification to achieve greater | ||
60 | resonance. ModPlug Tracker does not incorporate this modification. | ||
61 | Furthermore, ModPlug Tracker uses integer arithmetic with nowhere near | ||
62 | enough precision; the wave output is really poor in some cases. I don't | ||
63 | doubt it damages the acoustic properties of the filters in subtle ways. | ||
64 | |||
65 | 2. When looping, ModPlug Tracker resets all variables. The original trackers | ||
66 | do not do this. | ||
67 | |||
68 | 1. Worst of all, ModPlug Tracker has no regard for playback volume, and | ||
69 | generally has a much lower output level than the original trackers. | ||
70 | |||
71 | Cases 3, 2 and 1 lead people to write IT files that play badly in the | ||
72 | original trackers. If some of these problems could be fixed, I'd be all for | ||
73 | it - but these problems have been reported to the author and he had no | ||
74 | motivation to fix them. ModPlug Tracker has been around long enough that | ||
75 | fixing 3, 2 and 1 would be detrimental to too many people's music. | ||
76 | |||
77 | |||
78 | ****************** | ||
79 | *** Extensions *** | ||
80 | ****************** | ||
81 | |||
82 | Worse than the incompatibilities are the extensions ModPlug Tracker makes, | ||
83 | mostly to the IT format. DUMB currently supports one of these extensions, | ||
84 | namely stereo samples, but supporting the others is not high on my list of | ||
85 | priorities. | ||
86 | |||
87 | Other extensions ModPlug Tracker has provided mostly take the form of extra | ||
88 | effects. For instance, S98 and S99 can be used to enable or disable reverb. I | ||
89 | believe the latest versions of ModPlug Tracker offer alternative types of | ||
90 | filter, such as high-pass and band-pass. As soon as an IT file uses any of | ||
91 | these features, it will play incorrectly with Impulse Tracker. | ||
92 | |||
93 | By far the most evil extension provided by ModPlug Tracker is the effect | ||
94 | plug-ins. These enable IT files to use VST effects. I recently downloaded an | ||
95 | IT file that uses some effects from a collection named "DirectX Media Audio | ||
96 | Effects". When can we expect these effects to be ported to Linux? | ||
97 | |||
98 | |||
99 | ****************** | ||
100 | *** Conclusion *** | ||
101 | ****************** | ||
102 | |||
103 | ModPlug Tracker is trying to be two things at once. It wants to be an editor | ||
104 | for the existing formats, but at the same time it wants to be proprietary, | ||
105 | with all its own features and extensions. Unfortunately it is succeeding; | ||
106 | there are many IT files out there that only play right in ModPlug Tracker. In | ||
107 | my opinion, ModPlug Tracker should have come out with its own file format, in | ||
108 | which all these extensions would have found a home. | ||
109 | |||
110 | If you are going to use ModPlug Tracker's extensions, I recommend you | ||
111 | ultimately convert your music to a streamed format such as Ogg Vorbis. (If | ||
112 | you were thinking of using MP3, then don't - consider using Ogg Vorbis | ||
113 | instead.) If you release IT files that use ModPlug Tracker's extensions, | ||
114 | please state prominently that the files are designed to be played with | ||
115 | ModPlug Tracker. Finally, don't ask me to support ModPlug Tracker's | ||
116 | extensions; ModPlug Tracker's playback code is available for use in your | ||
117 | games, so use that instead. | ||
118 | |||
119 | Ogg Vorbis - http://www.vorbis.com/ | ||
120 | |||
121 | Despite all the above problems, don't forget that ModPlug Tracker does have a | ||
122 | lot of very useful features for editing files. These include a function for | ||
123 | removing unused patterns, samples and instruments, drag-and-drop sample and | ||
124 | instrument ripping, drop-down menus for selecting the effects by name without | ||
125 | having to memorise the codes or refer to help, and lots of other nice things. | ||
126 | I do recommend it as an editor, provided you make sure you are aware of the | ||
127 | situation and do not use ModPlug Tracker's extensions or incompatibilities | ||
128 | inadvertently. | ||
129 | |||
130 | Oh, and by the way, save your final version with Impulse Tracker. Then the | ||
131 | samples will be compressed for you! | ||
132 | |||
133 | |||
134 | Ben Davis | ||
135 | entheh@users.sf.net | ||
136 | IRC EFnet #dumb | ||
137 | See readme.txt for details on using IRC. | ||
diff --git a/apps/codecs/dumb/docs/ptr.txt b/apps/codecs/dumb/docs/ptr.txt new file mode 100644 index 0000000000..0eb42ccf02 --- /dev/null +++ b/apps/codecs/dumb/docs/ptr.txt | |||
@@ -0,0 +1,129 @@ | |||
1 | /* _______ ____ __ ___ ___ | ||
2 | * \ _ \ \ / \ / \ \ / / ' ' ' | ||
3 | * | | \ \ | | || | \/ | . . | ||
4 | * | | | | | | || ||\ /| | | ||
5 | * | | | | | | || || \/ | | ' ' ' | ||
6 | * | | | | | | || || | | . . | ||
7 | * | |_/ / \ \__// || | | | ||
8 | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque | ||
9 | * / \ | ||
10 | * / . \ | ||
11 | * ptr.txt - Pointer explanation. / / \ \ | ||
12 | * | < / \_ | ||
13 | * | \/ /\ / | ||
14 | * \_ / > / | ||
15 | * | \ / / | ||
16 | * | ' / | ||
17 | * \__/ | ||
18 | */ | ||
19 | |||
20 | |||
21 | A pointer is a small variable (often the same size as an int BUT NOT ALWAYS) | ||
22 | that holds the address of something in memory. You create a pointer by adding | ||
23 | a * to a variable, as follows: | ||
24 | |||
25 | int x, *y; | ||
26 | |||
27 | x = 5; | ||
28 | y = &x; | ||
29 | |||
30 | The & means 'address of', so &x gives us a pointer to x. We are storing it in | ||
31 | y. | ||
32 | |||
33 | (*y)++; | ||
34 | |||
35 | The * here means 'value at'. It's known as the 'dereferencing' operator. When | ||
36 | written before a pointer, as it is here, it allows you to treat the value | ||
37 | like a normal variable. In this case we are incrementing the value. If we | ||
38 | look at x, we'll find that it now contains 6, not 5. | ||
39 | |||
40 | y++; | ||
41 | |||
42 | Here we are incrementing the pointer itself. This is useful for traversing | ||
43 | through an array, but in this particular example it is not much use. | ||
44 | |||
45 | *y++; | ||
46 | |||
47 | Beware; this will increment the pointer, not the value stored there. It will | ||
48 | return the value stored at the pointer (before incrementing the pointer), so | ||
49 | you can use this in a bigger expression. This is why we needed brackets in | ||
50 | the first example. | ||
51 | |||
52 | Note that you will not need these three examples when working with DUMB; they | ||
53 | are simply to help illustrate the idea of pointers. | ||
54 | |||
55 | Also be aware that when defining pointers you attach the * to the variable, | ||
56 | not to the type. The following example will create a pointer and an int, not | ||
57 | two pointers: | ||
58 | |||
59 | int *a, b; | ||
60 | |||
61 | That is why I believe it's a good idea to put a space before the * and not | ||
62 | after it, although programmers are divided on this. | ||
63 | |||
64 | y = 0; | ||
65 | y = NULL; | ||
66 | |||
67 | These two statements are equivalent. 0, or NULL, is a special value that is | ||
68 | guaranteed to have a different value from any valid pointer. This is most | ||
69 | often used to indicate that something doesn't point anywhere. DUMB's | ||
70 | functions may return it on occasion. However, in simple usage of DUMB, you | ||
71 | will not actually need to check for it. | ||
72 | |||
73 | Some of DUMB's functions return pointers to structs. (A struct is an | ||
74 | aggregration of other variables, such as ints, pointers, or other structs. | ||
75 | You can generally treat a struct as a single unit.) Here's an example of such | ||
76 | a function: | ||
77 | |||
78 | DUH *dumb_load_it(const char *filename); | ||
79 | |||
80 | You do not know what the DUH struct actually contains; dumb.h and aldumb.h | ||
81 | only give the compiler enough information to deal with pointers to them. DUMB | ||
82 | will take charge of everything that happens inside a DUH struct. | ||
83 | |||
84 | The above function will create a DUH struct for you. First it allocates | ||
85 | the memory it needs, then it fills the struct with data, then it returns a | ||
86 | pointer. This DUH struct will contain the data necessary to play an IT file. | ||
87 | You can define a suitable variable and store the pointer in it as follows: | ||
88 | |||
89 | DUH *duh = dumb_load_it("music.it"); | ||
90 | |||
91 | Or this can be split up: | ||
92 | |||
93 | DUH *duh; | ||
94 | duh = dumb_load_it("music.it"); | ||
95 | |||
96 | In order to use this DUH struct later, you must pass its pointer to other | ||
97 | functions. To pass the pointer to a function, simply write 'duh' for the | ||
98 | appropriate parameter. | ||
99 | |||
100 | When you've finished with a DUH struct (this applies equally to the other | ||
101 | structs DUMB deals with), you must pass it to an appropriate function for | ||
102 | freeing up the memory: | ||
103 | |||
104 | unload_duh(duh); | ||
105 | |||
106 | After you've done this, the memory will no longer be allocated, and the | ||
107 | pointer will have no meaning. You may wish to set it to NULL at this point | ||
108 | for safety. Alternatively just be sure not to use the present value of the | ||
109 | pointer any more. You can of course assign a new value to the pointer, e.g. | ||
110 | by calling dumb_load_it() again. | ||
111 | |||
112 | Note the following: | ||
113 | |||
114 | DUH *duh2 = duh; | ||
115 | |||
116 | This only duplicates the pointer, not the DUH itself. You still only have one | ||
117 | copy of the DUH. There is no way of duplicating a DUH, short of loading it | ||
118 | twice. This is not a problem, because DUMB can play it 'twice at the same | ||
119 | time' anyway. | ||
120 | |||
121 | That should be all you need to know about pointers in order to use DUMB. If | ||
122 | there's anything you feel should be explained better here, or anything else | ||
123 | that should be added, please don't hesitate to let me know! | ||
124 | |||
125 | |||
126 | Ben Davis | ||
127 | entheh@users.sf.net | ||
128 | IRC EFnet #dumb | ||
129 | See readme.txt for details on using IRC. | ||