summaryrefslogtreecommitdiff
path: root/plugins/dumb
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2010-05-27 22:51:35 +0200
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2010-05-27 22:51:35 +0200
commit4810f9a0af507bb405e6a3c58decfa9c9980b2ff (patch)
tree75ac9c06345b23528e6771bb1bae697ff5c29c1c /plugins/dumb
parentad71971955594ada4a0b14d176a192d050c9ee36 (diff)
merged parts of DUMB-0.9.3
Diffstat (limited to 'plugins/dumb')
-rw-r--r--plugins/dumb/cdumb.c4
-rw-r--r--plugins/dumb/dumb-kode54/docs/deprec.txt102
-rw-r--r--plugins/dumb/dumb-kode54/docs/dumb.txt430
-rw-r--r--plugins/dumb/dumb-kode54/docs/faq.txt70
-rw-r--r--plugins/dumb/dumb-kode54/docs/fnptr.txt2
-rw-r--r--plugins/dumb/dumb-kode54/docs/howto.txt263
-rw-r--r--plugins/dumb/dumb-kode54/docs/modplug.txt150
-rw-r--r--plugins/dumb/dumb-kode54/docs/ptr.txt2
-rw-r--r--plugins/dumb/dumb-kode54/examples/dumb2wav.c962
-rw-r--r--plugins/dumb/dumb-kode54/examples/dumbout.c187
-rw-r--r--plugins/dumb/dumb-kode54/examples/dumbplay.c577
-rw-r--r--plugins/dumb/dumb-kode54/examples/playduh.c338
-rw-r--r--plugins/dumb/dumb-kode54/include/aldumb.h192
-rw-r--r--plugins/dumb/dumb-kode54/include/dumb.h1514
-rw-r--r--plugins/dumb/dumb-kode54/include/internal/aldumb.h61
-rw-r--r--plugins/dumb/dumb-kode54/include/internal/barray.h40
-rw-r--r--plugins/dumb/dumb-kode54/include/internal/dumb.h122
-rw-r--r--plugins/dumb/dumb-kode54/include/internal/it.h1774
-rw-r--r--plugins/dumb/dumb-kode54/include/internal/riff.h42
-rw-r--r--plugins/dumb/dumb-kode54/licence.txt37
-rw-r--r--plugins/dumb/dumb-kode54/make/Makefile.inc2
-rw-r--r--plugins/dumb/dumb-kode54/make/config.sh6
-rw-r--r--plugins/dumb/dumb-kode54/make/djgpp.inc1
-rw-r--r--plugins/dumb/dumb-kode54/make/dumbask.c4
-rw-r--r--plugins/dumb/dumb-kode54/make/mingw.inc1
-rw-r--r--plugins/dumb/dumb-kode54/make/unix.inc1
-rw-r--r--plugins/dumb/dumb-kode54/readme.txt344
-rw-r--r--plugins/dumb/dumb-kode54/release.txt155
-rw-r--r--plugins/dumb/dumb-kode54/src/allegro/alplay.c561
-rw-r--r--plugins/dumb/dumb-kode54/src/allegro/datduh.c120
-rw-r--r--plugins/dumb/dumb-kode54/src/allegro/datit.c124
-rw-r--r--plugins/dumb/dumb-kode54/src/allegro/datmod.c122
-rw-r--r--plugins/dumb/dumb-kode54/src/allegro/dats3m.c122
-rw-r--r--plugins/dumb/dumb-kode54/src/allegro/datunld.c62
-rw-r--r--plugins/dumb/dumb-kode54/src/allegro/datxm.c124
-rw-r--r--plugins/dumb/dumb-kode54/src/allegro/packfile.c196
-rw-r--r--plugins/dumb/dumb-kode54/src/core/atexit.c142
-rw-r--r--plugins/dumb/dumb-kode54/src/core/duhlen.c87
-rw-r--r--plugins/dumb/dumb-kode54/src/core/duhtag.c76
-rw-r--r--plugins/dumb/dumb-kode54/src/core/dumbfile.c802
-rw-r--r--plugins/dumb/dumb-kode54/src/core/loadduh.c84
-rw-r--r--plugins/dumb/dumb-kode54/src/core/makeduh.c267
-rw-r--r--plugins/dumb/dumb-kode54/src/core/rawsig.c88
-rw-r--r--plugins/dumb/dumb-kode54/src/core/readduh.c214
-rw-r--r--plugins/dumb/dumb-kode54/src/core/register.c208
-rw-r--r--plugins/dumb/dumb-kode54/src/core/rendduh.c368
-rw-r--r--plugins/dumb/dumb-kode54/src/core/rendsig.c690
-rw-r--r--plugins/dumb/dumb-kode54/src/core/unload.c128
-rw-r--r--plugins/dumb/dumb-kode54/src/helpers/barray.c318
-rw-r--r--plugins/dumb/dumb-kode54/src/helpers/clickrem.c562
-rw-r--r--plugins/dumb/dumb-kode54/src/helpers/memfile.c192
-rw-r--r--plugins/dumb/dumb-kode54/src/helpers/resample.c786
-rw-r--r--plugins/dumb/dumb-kode54/src/helpers/riff.c176
-rw-r--r--plugins/dumb/dumb-kode54/src/helpers/sampbuf.c128
-rw-r--r--plugins/dumb/dumb-kode54/src/helpers/silence.c58
-rw-r--r--plugins/dumb/dumb-kode54/src/helpers/stdfile.c186
-rw-r--r--plugins/dumb/dumb-kode54/src/it/itload.c85
-rw-r--r--plugins/dumb/dumb-kode54/src/it/itload2.c58
-rw-r--r--plugins/dumb/dumb-kode54/src/it/itmisc.c496
-rw-r--r--plugins/dumb/dumb-kode54/src/it/itorder.c126
-rw-r--r--plugins/dumb/dumb-kode54/src/it/itread.c2675
-rw-r--r--plugins/dumb/dumb-kode54/src/it/itread2.c58
-rw-r--r--plugins/dumb/dumb-kode54/src/it/itrender.c27
-rw-r--r--plugins/dumb/dumb-kode54/src/it/itunload.c144
-rw-r--r--plugins/dumb/dumb-kode54/src/it/load669.c84
-rw-r--r--plugins/dumb/dumb-kode54/src/it/load6692.c68
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadasy.c84
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadasy2.c68
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadmod.c84
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadmod2.c58
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadmtm.c84
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadmtm2.c68
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadoldpsm.c86
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadoldpsm2.c68
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadpsm.c84
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadpsm2.c68
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadptm.c84
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadptm2.c68
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadriff.c84
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadriff2.c58
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loads3m.c84
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loads3m2.c58
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadstm.c84
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadstm2.c58
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadxm.c84
-rw-r--r--plugins/dumb/dumb-kode54/src/it/loadxm2.c58
-rw-r--r--plugins/dumb/dumb-kode54/src/it/ptmeffect.c250
-rw-r--r--plugins/dumb/dumb-kode54/src/it/read669.c894
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readam.c1504
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readasy.c662
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readdsmf.c746
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readmod.c1562
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readmod2.c58
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readmtm.c824
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readoldpsm.c1454
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readpsm.c2546
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readptm.c1148
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readriff.c146
-rw-r--r--plugins/dumb/dumb-kode54/src/it/reads3m.c1728
-rw-r--r--plugins/dumb/dumb-kode54/src/it/reads3m2.c58
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readstm.c794
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readstm2.c58
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readxm.c2426
-rw-r--r--plugins/dumb/dumb-kode54/src/it/readxm2.c58
-rw-r--r--plugins/dumb/dumb-kode54/src/it/xmeffect.c486
-rw-r--r--plugins/dumb/dumb-kode54/src/sigtypes/combine.c486
-rw-r--r--plugins/dumb/dumb-kode54/src/sigtypes/sample.c680
-rw-r--r--plugins/dumb/dumb-kode54/src/sigtypes/sequence.c1184
-rw-r--r--plugins/dumb/dumb-kode54/src/sigtypes/sterpan.c412
-rw-r--r--plugins/dumb/dumb-kode54/src/tools/it/load_it.cpp1648
-rw-r--r--plugins/dumb/dumb-kode54/src/tools/it/modulus.h386
-rw-r--r--plugins/dumb/dumb-kode54/studio/include/dumbdesk.h88
-rw-r--r--plugins/dumb/dumb-kode54/studio/include/dumbgui.h164
-rw-r--r--plugins/dumb/dumb-kode54/studio/include/dumbmenu.h88
-rw-r--r--plugins/dumb/dumb-kode54/studio/include/guiproc.h104
-rw-r--r--plugins/dumb/dumb-kode54/studio/include/guitop.h34
-rw-r--r--plugins/dumb/dumb-kode54/studio/include/main.h20
-rw-r--r--plugins/dumb/dumb-kode54/studio/include/options.h68
-rw-r--r--plugins/dumb/dumb-kode54/studio/include/subclip.h16
-rw-r--r--plugins/dumb/dumb-kode54/studio/src/dumbdesk.c542
-rw-r--r--plugins/dumb/dumb-kode54/studio/src/dumbgui.c240
-rw-r--r--plugins/dumb/dumb-kode54/studio/src/dumbmenu.c382
-rw-r--r--plugins/dumb/dumb-kode54/studio/src/guiproc.c32
-rw-r--r--plugins/dumb/dumb-kode54/studio/src/guitop.c262
-rw-r--r--plugins/dumb/dumb-kode54/studio/src/main.c236
-rw-r--r--plugins/dumb/dumb-kode54/studio/src/options.c62
-rw-r--r--plugins/dumb/dumb-kode54/studio/src/subclip.c66
-rw-r--r--plugins/dumb/dumb-kode54/tools/cit.c5936
-rw-r--r--plugins/dumb/dumb-kode54/winamp/gui.c662
-rw-r--r--plugins/dumb/dumb-kode54/winamp/gui.h52
-rw-r--r--plugins/dumb/dumb-kode54/winamp/in2.h246
-rw-r--r--plugins/dumb/dumb-kode54/winamp/in_duh.c1310
-rw-r--r--plugins/dumb/dumb-kode54/winamp/in_duh.h80
-rw-r--r--plugins/dumb/dumb-kode54/winamp/minalleg.c4358
-rw-r--r--plugins/dumb/dumb-kode54/winamp/out.h142
-rw-r--r--plugins/dumb/dumb-kode54/winamp/resource.h72
136 files changed, 28917 insertions, 28210 deletions
diff --git a/plugins/dumb/cdumb.c b/plugins/dumb/cdumb.c
index 84aa4fe4..3f6d12e5 100644
--- a/plugins/dumb/cdumb.c
+++ b/plugins/dumb/cdumb.c
@@ -25,8 +25,8 @@
#include "internal/it.h"
#include "../../deadbeef.h"
-//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
-#define trace(fmt,...)
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
static DB_decoder_t plugin;
static DB_functions_t *deadbeef;
diff --git a/plugins/dumb/dumb-kode54/docs/deprec.txt b/plugins/dumb/dumb-kode54/docs/deprec.txt
index 6ab7b60a..d9c2125f 100644
--- a/plugins/dumb/dumb-kode54/docs/deprec.txt
+++ b/plugins/dumb/dumb-kode54/docs/deprec.txt
@@ -170,27 +170,48 @@ DUH_RENDERER *al_duh_decompose_to_renderer(AL_DUH_PLAYER *dp);
*********************
+sample_t **create_sample_buffer(int n_channels, long length);
+
long duh_render_signal(DUH_SIGRENDERER *sigrenderer,
float volume, float delta,
long size, sample_t **samples);
- This function used to return samples in DUMB's internal format. This
- format consisted of 32-bit integers whose 'normal range' was -0x8000 to
- 0x7FFF (any samples outside this range would have to be clipped when sent
- to the sound card).
+long duh_sigrenderer_get_samples(DUH_SIGRENDERER *sigrenderer,
+ float volume, float delta,
+ long size, sample_t **samples);
+
+ These functions dealt with samples in DUMB's internal format, which
+ consists of 32-bit integers. For duh_render_signal(), the older of the two
+ rendering functions, the integers had a 'normal range' of -0x8000 to
+ 0x7FFF: any samples outside this range would have to be clipped when sent
+ to the sound card. For duh_sigrenderer_get_samples(), the range had
+ increased to -0x800000 to 0x7FFFFF, hence the new function was created and
+ the old turned into an inefficient wrapper and deprecated.
+
+ Since then, another change has taken place: DUMB now interleaves left and
+ right samples when processing stereo data. This meant
+ create_sample_buffer() and duh_sigrenderer_get_samples() both had to be
+ deprecated, because if you were using them yourself, you were probably
+ processing the sample data. The functions still exist and will convert the
+ data into the right form for you, but they are inefficient.
+
+ To update your code, first call allocate_sample_buffer() instead of
+ create_sample_buffer(), and then call duh_sigrenderer_generate_samples()
+ with the same arguments as whichever renderer function you were using
+ before. Be aware first that the range is -0x800000 to 0x7FFFFF, so you
+ will need to account for this if you were using duh_render_signal(). Then
+ change the way you index the samples. Whereas before you had to write
+ samples[channel][position], you now have to write
- DUMB's internal format has changed. DUMB still uses 32-bit integers, but
- now the normal range is -0x800000 to 0x7FFFFF. The lowest eight bits are
- discarded at the final stage by duh_render() when you ask for 16-bit
- output. A new function, duh_sigrenderer_get_samples(), will return samples
- in DUMB's new internal format. It takes exactly the same parameters, so
- all you have to do to the call itself is change the name; however, you
- will most likely have to change your code to account for the new
- normalised range.
+ samples[0][position] for mono (no change);
+ samples[0][position*2+channel] for stereo.
- duh_render_signal() will still be able to give you the samples in DUMB's
- old internal format, but it is inefficient. You should change your code as
- soon as possible.
+ The [0] is still there in anticipation of surround sound support: samples
+ will only ever be interleaved in twos, because each new interleaving
+ pattern results in more code duplication.
+
+ destroy_sample_buffer() has not been deprecated, since it is compatible
+ with both the old and the new allocation functions.
typedef void (*DUH_SIGRENDERER_CALLBACK)(void *data, sample_t **samples,
@@ -199,39 +220,50 @@ typedef void (*DUH_SIGRENDERER_CALLBACK)(void *data, sample_t **samples,
void duh_sigrenderer_set_callback(DUH_SIGRENDERER *sigrenderer,
DUH_SIGRENDERER_CALLBACK callback, void *data);
- This callback was intended to allow you to analyse the output. It was by
- no means intended to let you modify the output. For this reason, the names
- have been changed to DUH_SIGRENDERER_ANALYSER_CALLBACK and
- duh_sigrenderer_set_analyser_callback, and the 'samples' parameter to your
- callback should now be specified as follows:
+typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)
+ (void *data, sample_t **samples,
+ int n_channels, long length);
+
+void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer,
+ DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data);
+
+ For the same reasons as explained above for create_sample_buffer() and
+ friends, these two functions (and corresponding typedefs) have had to be
+ deprecated.
+
+ If you were using duh_sigrenderer_set_callback(), then be aware that it
+ was only intended to allow you to analyse the output, not modify it. For
+ this reason, the names were changed to DUH_SIGRENDERER_ANALYSER_CALLBACK
+ and duh_sigrenderer_set_analyser_callback(), and the 'samples' parameter
+ to your callback needed to be specified as follows:
const sample_t *const *samples
The first 'const' indicates that you must not modify the samples. The
second indicates that you must not modify the pointers to each channel.
- There is a second reason why this change was necessary, and it is the one
- described further up for duh_render_signal()'s entry: the format in which
- the samples themselves are stored has changed. They are 256 times as
- large, with a normal range from -0x800000 to 0x7FFFFF. You will most
- likely need to change your code to account for this.
-
- If you try to call the old function, it will print a message to stderr
- directing you to this file, and it will not install the callback. You
- shouldn't be able to get this far without a compiler warning (or, if you
- don't have GCC 3.1 or later, some compiler errors).
-
If you wanted to use this callback to apply a DSP effect, don't worry;
there is a better way of doing this. It is undocumented, so contact me
and I shall try to help. Contact details are at the bottom of this file.
+ Having corrected that, follow the instructions under
+ create_sample_buffer() to update your code to handle the new sample
+ format. Then call duh_sigrenderer_set_sample_analyser_callback() instead
+ (note the addition of 'sample' to the name).
+
+ If you try to call one of the old functions, it will print a message to
+ stderr directing you to this file, and it will not install the callback.
+ You shouldn't be able to get this far without a compiler warning (or, if
+ you don't have GCC 3.1 or later, some compiler errors).
+
For reference, here are the new definitions:
- typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data,
+ typedef void (*DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK)(void *data,
const sample_t *const *samples, int n_channels, long length);
- void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer,
- DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data);
+ void duh_sigrenderer_set_sample_analyser_callback(
+ DUH_SIGRENDERER *sigrenderer,
+ DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data);
int dumb_resampling_quality;
@@ -277,5 +309,3 @@ because it's lame.
Ben Davis
entheh@users.sf.net
-IRC EFnet #dumb
-See readme.txt for details on using IRC.
diff --git a/plugins/dumb/dumb-kode54/docs/dumb.txt b/plugins/dumb/dumb-kode54/docs/dumb.txt
index 4f6cc69b..e9492300 100644
--- a/plugins/dumb/dumb-kode54/docs/dumb.txt
+++ b/plugins/dumb/dumb-kode54/docs/dumb.txt
@@ -102,6 +102,8 @@ aldumb.h
appear on the end if it is nonzero; then DUMB_VERSION_STR might be
"1.0.1".
+ This was broken in DUMB v0.9 and earlier.
+
#define DUMB_NAME
@@ -109,6 +111,9 @@ aldumb.h
DUMB_NAME might be "DUMB v1.0". This constant is suitable for use in your
Credits screen if you wish to acknowledge the use of DUMB there.
+ This was broken in DUMB v0.9 and earlier, since it depends on
+ DUMB_VERSION_STR.
+
#define DUMB_YEAR
#define DUMB_MONTH
@@ -135,7 +140,7 @@ aldumb.h
However, it is a matter of personal preference which you use.
Please note that the month and day were inadvertently swapped in the v0.8
- release.
+ release, and the STR4 and STR1 constants were broken in v0.9 and earlier.
#define DUMB_DATE
@@ -153,14 +158,14 @@ aldumb.h
The date as a string. The format is "d.m.yyyy", with dots used as
separators, the day written first, four digits for the year, and no
- leading zeros on the day or month. This is my preferred format. If you
+ leading zeros on the day or month. This is my personal preference. If you
don't like it, you can construct your own format using the other
constants. For example, "mm/dd/yy" could be constructed as follows:
DUMB_MONTH_STR2 "/" DUMB_DAY_STR2 "/" DUMB_YEAR_STR2
Please note that the month and day were inadvertently swapped in the v0.8
- release.
+ release, and this was broken anyway in v0.9 and earlier.
*************************
@@ -590,6 +595,19 @@ long duh_get_length(DUH *duh);
(On the other hand, some musicians were just showing off!)
+const char *duh_get_tag(DUH *duh, const char *key);
+
+ DUH structs can contain a number of 'tags'. You can retrieve a tag by
+ giving its key. At present, module files are set up with a single tag,
+ which you can retrieve by setting key to "TITLE" (case matters). The value
+ returned is the title of the module.
+
+ You can retrieve other author information from the module by calling
+ duh_get_it_sigdata() and then using the dumb_it_sd_*() functions. See the
+ descriptions of the relevant functions for the maximum length of the title
+ for each format and some comments on non-ASCII characters.
+
+
***********************************
*** IT, XM, S3M and MOD Support ***
***********************************
@@ -639,14 +657,22 @@ DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer);
DUH_SIGRENDERER *dumb_it_start_at_order
(DUH *duh, int n_channels, int startorder);
+ Module files contain a set of patterns, numbered from zero, but they are
+ not necessarily played in order. Some patterns may be repeated, and some
+ may be left out altogether. When a module is played, the player runs
+ through a sequence of pattern numbers stored in the file, playing the
+ corresponding pattern for each number. Each entry in the sequence is
+ called an 'order', and the orders are numbered from from zero.
+
This function, given a DUH containing an IT, XM, S3M or MOD file, will
start playing it at the specified order. If the DUH does not contain a
module, this function will fail and return NULL.
Note that starting at an arbitrary order may result in missing notes or
other playback oddities. It should be used primarily for modules that
- contain multiple songs that start on different orders. If you wish just to
- start some music in the middle, consider using duh_start_sigrenderer() or
+ contain multiple songs that start on different orders. If you wish to seek
+ to a specific time in the music, as if you have recorded it and are
+ starting playback in the middle, then use duh_start_sigrenderer() or
al_start_duh() with the pos parameter set appropriately.
@@ -754,104 +780,161 @@ int dumb_it_callback_midi_block(void *data, int channel, unsigned char byte);
DUH *dumb_load_it(const char *filename);
+DUH *dumb_load_xm(const char *filename);
+DUH *dumb_load_s3m(const char *filename);
+DUH *dumb_load_mod(const char *filename);
- Loads the specified Impulse Tracker file, encapsulating it in a DUH
- struct. Once the file is loaded, it can be treated exactly the same as any
- other DUH in memory. If this fails it will return NULL, but you can safely
- pass this NULL value to DUMB's other functions, so you do not need to
- check the return value explicitly.
+ These load the specified Impulse Tracker, Fast Tracker II, Scream Tracker
+ 3 or Amiga module file, encapsulating it in a DUH struct. Once the file is
+ loaded, it can be treated exactly the same as any other DUH in memory. If
+ this fails it will return NULL, but you can safely pass this NULL value to
+ DUMB's other functions, so you do not need to check the return value
+ explicitly.
+ These functions call dumb_it_do_initial_runthrough(), which takes time and
+ memory but means the playback time is known and fast seeking is possible.
+ See dumb_it_do_initial_runthrough() for more information. If you do not
+ need this functionality, consider calling the *_quick() equivalents of
+ these functions instead.
-DUH *dumb_read_it(DUMBFILE *f);
- Reads an Impulse Tracker file from an already open DUMBFILE. This leaves
- the DUMBFILE open, but the DUMBFILE may not be positioned at the end of
- the IT data. If you are embedding an IT in another file, you are advised
- to store the size of the IT file and make up for it at the end using
- dumbfile_pos().
+DUH *dumb_read_it(DUMBFILE *f);
+DUH *dumb_read_xm(DUMBFILE *f);
+DUH *dumb_read_s3m(DUMBFILE *f);
+DUH *dumb_read_mod(DUMBFILE *f);
- Otherwise, this function is identical to dumb_load_it().
+ These read an Impulse Tracker, Fast Tracker II, Scream Tracker 3 or Amiga
+ module file from an already open DUMBFILE. They leave the DUMBFILE open,
+ but the DUMBFILE may not be positioned at the end of the data. If you are
+ embedding a module in another file, you are advised to store the size of
+ the module file and make up for it at the end using dumbfile_pos().
- WARNING: The behaviour of this function is undefined if you pass a
- DUMBFILE from which data have already been read; it is likely not
- to work. This oversight will be fixed in future releases.
+ Otherwise, these functions are identical to dumb_load_*(), and have
+ *_quick() equivalents.
+ WARNING: The behaviour of these functions are undefined if you pass a
+ DUMBFILE from which data have already been read; they are likely
+ not to work. This oversight will be fixed in future releases.
-DUH *dumb_load_xm(const char *filename);
- Loads the specified Fast Tracker II file, encapsulating it in a DUH
- struct. Once the file is loaded, it can be treated exactly the same as any
- other DUH in memory. If this fails it will return NULL, but you can safely
- pass this NULL value to DUMB's other functions, so you do not need to
- check the return value explicitly.
+DUH *dumb_load_it_quick(const char *filename);
+DUH *dumb_load_xm_quick(const char *filename);
+DUH *dumb_load_s3m_quick(const char *filename);
+DUH *dumb_load_mod_quick(const char *filename);
+DUH *dumb_read_it_quick(DUMBFILE *f);
+DUH *dumb_read_xm_quick(DUMBFILE *f);
+DUH *dumb_read_s3m_quick(DUMBFILE *f);
+DUH *dumb_read_mod_quick(DUMBFILE *f);
+ These functions are identical to the versions without the _quick suffix,
+ except they omit the initial run-through. They execute faster and the
+ resultant DUH structs use less memory. However, seeking by time is slower
+ (seeking with dumb_it_start_at_order() is unaffected), and the length is
+ unknown and returned as -1.
-DUH *dumb_read_xm(DUMBFILE *f);
- Reads a Fast Tracker II file from an already open DUMBFILE. This leaves
- the DUMBFILE open, but the DUMBFILE may not be positioned at the end of
- the XM data. If you are embedding an XM in another file, you are advised
- to store the size of the XM file and make up for it at the end using
- dumbfile_pos().
+void dumb_it_do_initial_runthrough(DUH *duh);
- Otherwise, this function is identical to dumb_load_xm().
+ This runs through the module represented by the DUH and stores a copy of
+ the playback state at 30-second intervals. It stops when it first
+ encounters a jump to an earlier pattern or a MOD/XM speed zero effect, at
+ which point it adds to the DUH struct the length of time for which the
+ module plays. The playback state images enable DUMB to seek more quickly
+ when you pass a nonzero time to al_start_duh() or duh_start_sigrenderer().
+ Note that dumb_it_start_at_order() is unaffected and always executes fast.
- WARNING: The behaviour of this function is undefined if you pass a
- DUMBFILE from which data have already been read; it is likely not
- to work. This oversight will be fixed in future releases.
+ This is called automatically by some of the loading functions, so you will
+ not normally need to call it. If you do decide to call it yourself, be
+ aware that it cannot execute concurrently with playback. This will be
+ addressed in the future.
+ This function does nothing if the parameter is NULL or does not represent
+ a module.
-DUH *dumb_load_s3m(const char *filename);
- Loads the specified Scream Tracker 3 file, encapsulating it in a DUH
- struct. Once the file is loaded, it can be treated exactly the same as any
- other DUH in memory. If this fails it will return NULL, but you can safely
- pass this NULL value to DUMB's other functions, so you do not need to
- check the return value explicitly.
+long dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata);
+ This is the functionality of dumb_it_do_initial_runthrough() detached from
+ the DUH struct. It does the same thing, but the length is returned. The
+ function does nothing if sigdata is NULL.
-DUH *dumb_read_s3m(DUMBFILE *f);
- Reads a Scream Tracker 3 file from an already open DUMBFILE. This leaves
- the DUMBFILE open, but the DUMBFILE may not be positioned at the end of
- the S3M data. If you are embedding an S3M in another file, you are advised
- to store the size of the S3M file and make up for it at the end using
- dumbfile_pos().
+const unsigned char *dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd);
- Otherwise, this function is identical to dumb_load_s3m().
+ This function retrieves the song message from an IT file, if it was
+ present and there was sufficient memory to load it. Otherwise it returns
+ NULL. XM, S3M and MOD files never contain song messages as such, although
+ there is often a message embedded in the sample and instrument names.
- WARNING: The behaviour of this function is undefined if you pass a
- DUMBFILE from which data have already been read; it is likely not
- to work. This oversight will be fixed in future releases.
+ According to Impulse Tracker's documentation, the message uses CR
+ characters ('\r', ASCII code 13) for line breaks and is null-terminated.
+ DUMB adds a NUL to the end just in case. You can therefore use strlen()
+ and otherwise treat the return value as a normal C string.
+ When interpreting the message, bear in mind that Impulse Tracker is a DOS
+ program, and extended ASCII from the DOS days does not match the usual
+ character encodings on modern systems. If you find characters outside the
+ range 32 to 126 (and not '\r'), you may need to convert in some way for
+ display.
-DUH *dumb_load_mod(const char *filename);
+ If anyone knows how to map DOS extended ASCII to Unicode, please feel free
+ to write an explanation for me to include here. Credit will be given!
- Loads the specified Amiga module file, encapsulating it in a DUH struct.
- Once the file is loaded, it can be treated exactly the same as any other
- DUH in memory. If this fails it will return NULL, but you can safely pass
- this NULL value to DUMB's other functions, so you do not need to check the
- return value explicitly.
+ Impulse Tracker's message editor generally restricts lines to 74
+ characters plus the CR, although it is possible to create a 75-character-
+ long line with no spaces. The documentation says the message may be up to
+ 8000 bytes long. Other IT-compatible trackers may not impose these
+ restrictions.
-DUH *dumb_read_mod(DUMBFILE *f);
+int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd);
- Reads an Amiga module file from an already open DUMBFILE. This leaves the
- DUMBFILE open, but the DUMBFILE may not be positioned at the end of the
- MOD data. If you are embedding a MOD in another file, you are advised to
- store the size of the MOD file and make up for it at the end using
- dumbfile_pos().
+ This function returns the number of orders in the module. See
+ dumb_it_start_at_order() for an explanation of orders.
- Otherwise, this function is identical to dumb_load_mod().
- WARNING: The behaviour of this function is undefined if you pass a
- DUMBFILE from which data have already been read; it is likely not
- to work. This oversight will be fixed in future releases.
+int dumb_it_sd_get_n_samples(DUMB_IT_SIGDATA *sd);
+int dumb_it_sd_get_n_instruments(DUMB_IT_SIGDATA *sd);
+ These functions respectively return the number of samples and the number
+ of instruments in the module. Note that MOD and S3M files don't support
+ instruments, and instruments are optional in IT files.
+ dumb_it_sd_get_n_instruments() will return 0 for modules that only use
+ samples.
-int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd);
- This function returns the number of orders in the module.
+const unsigned char *dumb_it_sd_get_sample_name(DUMB_IT_SIGDATA *sd, int i);
+const unsigned char *dumb_it_sd_get_sample_filename
+ (DUMB_IT_SIGDATA *sd, int i);
+const unsigned char *dumb_it_sd_get_instrument_name
+ (DUMB_IT_SIGDATA *sd, int i);
+const unsigned char *dumb_it_sd_get_instrument_filename
+ (DUMB_IT_SIGDATA *sd, int i);
+
+ The trackers allow the author to set a name and sometimes also a file name
+ for each sample and each instrument. These functions allow you to retrieve
+ the names. The samples and instruments are numbered from 0 for the
+ purposes of these functions, and you can determine how many are available
+ using dumb_it_sd_get_n_samples() and dumb_it_sd_get_n_instruments().
+
+ Very often, displaying the names in order will produce a message from the
+ author. These functions will always return something, but if the field
+ does not exist, the result will be an empty string. The return value is
+ null-terminated.
+
+ The comments under dumb_it_sd_get_song_message() about code pages applies,
+ except not all modules were created in DOS; the original MOD files were
+ born on the Amiga, and many files were transferred from there. If anyone
+ knows about the characters available on the Amiga, please get in touch so
+ I can add the information here. Credit will be given!
+
+ The table to the right Field | MOD | S3M | XM | IT
+ specifies the maximum ----------------------+-----+-----+-----+-----
+ length of each field for Song title | 20 | 28 | 20 | 26
+ each format, or '-' if Sample name | 22 | 28 | 22 | 26
+ the field does not exist. Sample file name | - | 13 | - | 13
+ Instrument name | - | - | 22 | 26
+ Instrument file name | - | - | - | 13
int dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd);
@@ -944,6 +1027,15 @@ void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel,
not last.
+int dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel);
+void dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel,
+ int muted);
+
+ These functions obtain or set the flag indicating whether each channel is
+ muted. Modules cannot override this during playback, although some formats
+ can make some channels muted initially.
+
+
void dumb_it_sr_get_channel_state(DUMB_IT_SIGRENDERER *sr, int channel,
DUMB_IT_CHANNEL_STATE *state);
@@ -1004,8 +1096,8 @@ void dumb_it_sr_get_channel_state(DUMB_IT_SIGRENDERER *sr, int channel,
rarely reach 1.0f; if it does, the module is probably clipping a lot. This
takes mixing volume into account, along with all the other volume
phenomena in the IT file. The only one it doesn't take into account is the
- one you pass to duh_render() or duh_sigrenderer_get_samples(), or the one
- you passed to al_start_duh() (these are in fact the same thing).
+ one you pass to duh_render() or duh_sigrenderer_generate_samples(), or the
+ one you passed to al_start_duh() (these are in fact the same thing).
The pan field ranges from 0 to 64 for a normally panned sample, but will
be 100 if the sample is playing using IT's surround mode where the right-
@@ -1062,9 +1154,9 @@ void dumb_it_sr_get_channel_state(DUMB_IT_SIGRENDERER *sr, int channel,
Use these functions to generate samples from a DUH. First you call
duh_start_sigrenderer() with the DUH, the number of channels you want and
the position at which you want to start. Then you use duh_render() or
- duh_sigrenderer_get_samples() to generate the samples. You can call these
- functions as many times as you like, and they will generate as many or as
- few samples as you require. When you have finished, call
+ duh_sigrenderer_generate_samples() to generate the samples. You can call
+ these functions as many times as you like, and they will generate as many
+ or as few samples as you require. When you have finished, call
duh_end_sigrenderer().
@@ -1073,9 +1165,10 @@ DUH_SIGRENDERER *duh_start_sigrenderer
Starts a DUH_SIGRENDERER off. This is the struct you can use to get
samples from a DUH. This function does not generate any samples; you must
- pass the struct to duh_render() or duh_sigrenderer_get_samples() for that.
- When you have finished with it, you must pass it to duh_end_sigrenderer().
- You can use as many DUH_SIGRENDERER structs as you like at the same time.
+ pass the struct to duh_render() or duh_sigrenderer_generate_samples() for
+ that. When you have finished with it, you must pass it to
+ duh_end_sigrenderer(). You can use as many DUH_SIGRENDERER structs as you
+ like at the same time.
Set sig to 0 for now. Currently, n_channels can only be 1 or 2, for
monaural and stereo sound respectively. The debugging library will cause
@@ -1089,48 +1182,58 @@ DUH_SIGRENDERER *duh_start_sigrenderer
halfway through a long note, and you will still hear the long note.
-void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer,
- DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data);
+void duh_sigrenderer_set_sample_analyser_callback(
+ DUH_SIGRENDERER *sigrenderer,
+ DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data);
Installs a callback function which will be called every time the given
sigrenderer is used to generate some samples. This can be used to create
- an oscilloscope or spectrum analyser. DUH_SIGRENDERER_ANALYSER_CALLBACK is
- defined as follows:
+ an oscilloscope or spectrum analyser.
+ DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK is defined as follows:
- typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data,
+ typedef void (*DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK)(void *data,
const sample_t *const *samples, int n_channels, long length);
If the above confuses you, see fnptr.txt. As for the 'samples' parameter,
the first 'const' says that the samples are read-only; the second says
- that each channel's sample pointer is also read-only. If you don't
+ that each buffer's sample pointer is also read-only. If you don't
understand this, don't worry about it.
Beware: your callback function may occasionally be called with
samples == NULL. This means the main program has decided to skip through
- the music without generating any data (see duh_sigrenderer_get_samples()).
- You should handle this case elegantly, typically by returning immediately,
- but you may wish to make a note of the fact that the music is being
- skipped, for whatever reason.
-
- Beware again: if the main program ever calls duh_sigrenderer_get_samples()
- on a buffer that isn't all silence, this callback function will be passed
- the existing buffer after mixing, and thus it will include the original
- data. This will not be an issue if you stick to duh_render(), which always
- starts with a buffer filled with silence.
-
- The samples array is two-dimensional. Refer to it as follows:
-
- samples[channel_number][sample_position]
+ the music without generating any data (see
+ duh_sigrenderer_generate_samples()). You should handle this case
+ elegantly, typically by returning immediately, but you may wish to make a
+ note of the fact that the music is being skipped, for whatever reason.
+
+ Beware again: if the main program ever calls
+ duh_sigrenderer_generate_samples() on a buffer that isn't all silence,
+ this callback function will be passed the existing buffer after mixing,
+ and thus it will include the original data. This will not be an issue if
+ you stick to duh_render(), which always starts with a buffer filled with
+ silence.
+
+ The samples array is two-dimensional. It consists of zero or more
+ interleaved stereo sample buffers, possibly followed by one monaural
+ buffer. You can access the samples as follows:
+
+ n_channels == 1: samples[0][sample_position]
+ n_channels == 2: samples[0][sample_position*2+channel_number]
+ n_channels > 2:
+ channel_number < n_channels & ~1:
+ samples[channel_number>>1][sample_position*2+(channel_number&1)]
+ channel_number == n_channels & ~1:
+ samples[channel_number>>1][sample_position]
where 0 <= channel_number < n_channels,
and 0 <= sample_position < length.
In addition you can pass any 'data' pointer you like to
- duh_sigrenderer_set_analyser_callback(), and this pointer will be relayed
- to your callback function each time.
+ duh_sigrenderer_set_sample_analyser_callback(), and this pointer will be
+ relayed to your callback function each time.
To remove the callback function, pass NULL to
- duh_sigrenderer_set_analyser_callback().
+ duh_sigrenderer_set_sample_analyser_callback().
int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer);
@@ -1146,16 +1249,16 @@ long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer);
(perhaps owing to lack of memory). As usual, 65536 is one second.
-long duh_sigrenderer_get_samples(DUH_SIGRENDERER *sigrenderer,
- float volume, float delta,
- long size, sample_t **samples);
+long duh_sigrenderer_generate_samples(DUH_SIGRENDERER *sigrenderer,
+ float volume, float delta,
+ long size, sample_t **samples);
Generates some samples in DUMB's internal 32-bit format (see sample_t; see
also duh_render()). The samples buffer is a two-dimensional array, and can
- be allocated with create_sample_buffer(); see
- duh_sigrenderer_set_analyser_callback() for details.
- duh_sigrenderer_get_samples() mixes sample data with what's already in the
- buffer, so you have to call dumb_silence() first.
+ be allocated with allocate_sample_buffer(); see
+ duh_sigrenderer_set_sample_analyser_callback() for details.
+ duh_sigrenderer_generate_samples() mixes sample data with what's already
+ in the buffer, so you have to call dumb_silence() first.
The volume is a float. 1.0f is the pseudo-maximum. If you pass 1.0f, any
properly designed DUH will play nice and loud, but will not clip. You can
@@ -1179,8 +1282,9 @@ long duh_sigrenderer_get_samples(DUH_SIGRENDERER *sigrenderer,
succeed. However, if the end of the DUH is reached, it may render fewer.
The number of samples rendered will be returned. Therefore, if the return
value is less than the value of 'size' passed, you know the DUH has
- finished. It is safe to continue calling duh_sigrenderer_get_samples() if
- you wish, and it will continually return 0.
+ finished. It is safe to continue calling
+ duh_sigrenderer_generate_samples() if you wish, and it will continually
+ return 0.
If the DUH_SIGRENDERER is a null pointer, this function will generate
precisely 0 samples. If you pass NULL for 'samples', the function will
@@ -1189,24 +1293,33 @@ long duh_sigrenderer_get_samples(DUH_SIGRENDERER *sigrenderer,
quickly. This can be used to skip ahead in the audio.
+void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer,
+ float volume, sample_t *samples);
+
+ This generates one sample (or two for a stereo DUH_SIGRENDERER) and stores
+ them in the array passed in. It does not update the state (with the
+ exception of potentially having to initialise playback). It is used for
+ click removal.
+
+
long duh_render(DUH_SIGRENDERER *sigrenderer,
int bits, int unsign,
float volume, float delta,
long size, void *sptr);
Generates some samples and converts them to an 8-bit or 16-bit format (see
- also duh_sigrenderer_get_samples()). Pass the DUH_SIGRENDERER as returned
- by duh_start_sigrenderer(). Pass the number of bits, which should be 8 or
- 16. If unsign is nonzero, the samples will be unsigned (centred on 0x80 or
- 0x8000 for 8 bits and 16 bits respectively). If unsign is zero, the
- samples will be signed.
+ also duh_sigrenderer_generate_samples()). Pass the DUH_SIGRENDERER as
+ returned by duh_start_sigrenderer(). Pass the number of bits, which should
+ be 8 or 16. If unsign is nonzero, the samples will be unsigned (centred on
+ 0x80 or 0x8000 for 8 bits and 16 bits respectively). If unsign is zero,
+ the samples will be signed.
Allegro's audio streams always take unsigned samples. 8-bit .wav files
always take unsigned samples. 16-bit .wav files always take signed
samples.
The volume and delta parameters work the same as for
- duh_sigrenderer_get_samples().
+ duh_sigrenderer_generate_samples().
This function will attempt to render 'size' samples. In most cases it will
succeed. However, if the end of the DUH is reached, it may render fewer.
@@ -1220,7 +1333,9 @@ long duh_render(DUH_SIGRENDERER *sigrenderer,
The samples will be placed at sptr. Use an array of chars for 8 bits or an
array of shorts for 16 bits. Stereo samples will be interleaved, left
first. Your array should contain at least (size * n_channels) elements of
- the appropriate bit resolution.
+ the appropriate bit resolution, where n_channels distinguishes between
+ mono and stereo and was passed in when the DUH_SIGRENDERER was
+ constructed.
From an aesthetic standpoint if nothing else, it is wise to use the C
qualifiers 'signed' or 'unsigned' depending on whether the samples are
@@ -1228,8 +1343,9 @@ long duh_render(DUH_SIGRENDERER *sigrenderer,
samples further yourself.
If the DUH_SIGRENDERER is a null pointer, this function will generate
- precisely 0 samples. Unlike with duh_sigrenderer_get_samples(), you must
- specify a sample buffer.
+ precisely 0 samples. Unlike with duh_sigrenderer_generate_samples(), you
+ must specify a sample buffer for the output. (If you don't need any
+ output, call duh_sigrenderer_generate_samples() instead.)
void duh_end_sigrenderer(DUH_SIGRENDERER *dr);
@@ -1292,6 +1408,7 @@ DUMBFILE *dumbfile_from_packfile(PACKFILE *p);
void dumb_register_dat_it(long type);
+void dumb_register_dat_it_quick(long type);
If you wish to embed an IT file in an Allegro datafile, it is recommended
that you use "IT " for the type. The grabber will have a box for the type
@@ -1299,10 +1416,14 @@ void dumb_register_dat_it(long type);
data, which means the datafile will contain an exact copy of the IT file
on disk.
- You must then call dumb_register_dat_it(DUMB_DAT_IT) in your program
- before you load the datafile. Once you've done this, you'll be able to
- access the DUH using the usual datafile[n].dat notation. You do not need
- to call unload_duh() on this DUH; unload_datafile() will do that for you.
+ You must then call dumb_register_dat_it(DUMB_DAT_IT) or
+ dumb_register_dat_it_quick(DUMB_DAT_IT) in your program, before you load
+ the datafile. If you've done this, you'll be able to access the DUH using
+ the usual datafile[n].dat notation. You do not need to call unload_duh()
+ on this DUH; unload_datafile() will do that for you.
+
+ The *_quick() version will cause the initial run-through to be skipped,
+ speeding up loading. See dumb_load_it() for an explanation.
If you are using a different type for whatever reason, you can use
Allegro's DAT_ID() macro for encoding it and passing it to this function.
@@ -1330,30 +1451,33 @@ void dumb_register_dat_it(long type);
void dumb_register_dat_xm(long type);
+void dumb_register_dat_xm_quick(long type);
Inserting an XM file in an Allegro datafile is the same as inserting an IT
file, except that the recommended type is "XM ", the registration
- function is dumb_register_dat_xm(), and the macro DUMB_DAT_XM is provided
- for the type. The intuitive process of substituting XM for IT in the above
- method will work.
+ functions are dumb_register_dat_xm() and dumb_register_dat_xm_quick(), and
+ the macro DUMB_DAT_XM is provided for the type. The intuitive process of
+ substituting XM for IT in the above method will work.
void dumb_register_dat_s3m(long type);
+void dumb_register_dat_s3m_quick(long type);
Inserting an S3M file in an Allegro datafile is the same as inserting an
IT file, except that the recommended type is "S3M ", the registration
- function is dumb_register_dat_s3m(), and the macro DUMB_DAT_S3M is
- provided for the type. The intuitive process of substituting S3M for IT in
- the above method will work.
+ functions are dumb_register_dat_s3m() and dumb_register_dat_s3m_quick(),
+ and the macro DUMB_DAT_S3M is provided for the type. The intuitive process
+ of substituting S3M for IT in the above method will work.
void dumb_register_dat_mod(long type);
+void dumb_register_dat_mod_quick(long type);
Inserting a MOD file in an Allegro datafile is the same as inserting an IT
file, except that the recommended type is "MOD ", the registration
- function is dumb_register_dat_mod(), and the macro DUMB_DAT_MOD is
- provided for the type. The intuitive process of substituting MOD for IT in
- the above method will work.
+ functions are dumb_register_dat_mod() and dumb_register_dat_mod_quick(),
+ and the macro DUMB_DAT_MOD is provided for the type. The intuitive process
+ of substituting MOD for IT in the above method will work.
****************************************
@@ -1366,11 +1490,19 @@ void dumb_register_dat_mod(long type);
sample_t **samples;
- and it can be indexed as follows:
+ This is effectively a two-dimensional array. It consists of zero or more
+ interleaved stereo sample buffers, possibly followed by one monaural
+ buffer. You can access the samples as follows:
- samples[channel_number][sample_position]
+ n_channels == 1: samples[0][sample_position]
+ n_channels == 2: samples[0][sample_position*2+channel_number]
+ n_channels > 2:
+ channel_number < n_channels & ~1:
+ samples[channel_number>>1][sample_position*2+(channel_number&1)]
+ channel_number == n_channels & ~1:
+ samples[channel_number>>1][sample_position]
- where 0 <= channel_number < n_channels
+ where 0 <= channel_number < n_channels,
and 0 <= sample_position < length.
The following helpers will allocate and deallocate such buffers for you.
@@ -1379,15 +1511,15 @@ void dumb_register_dat_mod(long type);
dumb_silence() too.
-sample_t **create_sample_buffer(int n_channels, long length);
+sample_t **allocate_sample_buffer(int n_channels, long length);
This will allocate a sample buffer to hold the specified number of samples
for the specified number of channels. Don't forget to check the return
value!
You will generally have to initialise the buffer by calling
- dumb_silence(); the channels will be stored consecutively in memory, so
- the following technique is officially supported:
+ dumb_silence(); the buffers will be stored consecutively in memory, so
+ the following technique will work and is officially supported:
dumb_silence(samples[0], n_channels * length);
@@ -1409,7 +1541,7 @@ void dumb_silence(sample_t *samples, long length);
This function simply stores 'length' samples' worth of silence in the
array. It is typically used straight after allocating a sample buffer with
- create_sample_buffer().
+ allocate_sample_buffer().
**************************
@@ -1567,10 +1699,14 @@ void al_duh_set_priority(AL_DUH_PLAYER *dp, int priority);
more information on priorities.
+float al_duh_get_volume(AL_DUH_PLAYER *dp);
void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume);
- This will set the volume of an AL_DUH_PLAYER. See al_start_duh() for
- details on the volume parameter.
+ These functions get and set the volume of an AL_DUH_PLAYER. See
+ al_start_duh() for details on the volume parameter. DUMB will always leave
+ the audio stream volume at maximum and use its own volume control, since
+ it is more accurate and the click remover will handle changes to the
+ volume.
int al_poll_duh(AL_DUH_PLAYER *dp);
@@ -1675,7 +1811,10 @@ DOs:
DON'Ts:
- You may not generate samples from the same DUH in multiple threads, even if
- you are using separate DUH_RENDERERs (separate AL_DUH_PLAYERS).
+ you are using separate DUH_SIGRENDERERs (or separate AL_DUH_PLAYERS).
+
+- You may not load two IT files concurrently (the sample decompression
+ algorithm has some static state).
******************
@@ -1690,10 +1829,11 @@ DUMB! (Your Internet Service Provider may issue charges for your connection,
required for download of the Product. Your electricity supplier may issue
charges for the electricity consumed in writing the Product to a Permanent
Storage Device. You may have been charged for a Permanent Storage Device on
-which to store the Product.)
+which to store the Product. If you are in Canada, the Blank Media Levy is
+non-refundable, although this is irrelevant since the rate is zero for
+computer storage devices. I shall not be held accountable for inaccuracies in
+the preceding text.)
Ben Davis
entheh@users.sf.net
-IRC EFnet #dumb
-See readme.txt for details on using IRC.
diff --git a/plugins/dumb/dumb-kode54/docs/faq.txt b/plugins/dumb/dumb-kode54/docs/faq.txt
index 63913f76..ff3e8719 100644
--- a/plugins/dumb/dumb-kode54/docs/faq.txt
+++ b/plugins/dumb/dumb-kode54/docs/faq.txt
@@ -1,6 +1,3 @@
-TO DO: add question regarding set_close_button_callback vs set_window_close_hook
-TO DO: add question regarding mixing of DJGPP and MinGW object files
-
/* _______ ____ __ ___ ___
* \ _ \ \ / \ / \ \ / / ' ' '
* | | \ \ | | || | \/ | . .
@@ -16,9 +13,8 @@ TO DO: add question regarding mixing of DJGPP and MinGW object files
* This file covers some of the common problems | \/ /\ /
* and misconceptions people have with DUMB. If \_ / > /
* your problem is not covered here, please | \ / /
- * contact me. I'll do my best to help - but | ' /
- * don't be offended if I just direct you to the \__/
- * manual!
+ * contact me and I'll do my best to help. | ' /
+ * \__/
*/
@@ -110,7 +106,9 @@ TO DO: add question regarding mixing of DJGPP and MinGW object files
the volume. If not, then it's a problem with DUMB; please let me know.
If for whatever reason you cannot modify the module file itself, you can
- make it sound better by reducing the volume passed to al_start_duh().
+ make it sound better by reducing the volume passed to al_start_duh(). Try
+ halving or quartering the value; search for a level at which the
+ distortion goes away.
*****************************************************************************
@@ -118,11 +116,15 @@ TO DO: add question regarding mixing of DJGPP and MinGW object files
* right! *
*****************************************************************************
- DUMB cannot and will not support ModPlug Tracker. Please see
- docs/modplug.txt for details. The original trackers, which DUMB is
- designed to mimic as closely as possible, are listed in readme.txt.
- If you find DUMB plays your module differently from the original tracker,
- then please contact me.
+ ModPlug Tracker differs from the original trackers in several ways, which
+ means modules written in one will not always play correctly or even load
+ in the other. DUMB's first loyalty is to the original trackers, which are
+ listed in readme.txt. This means it will have to differ from ModPlug
+ Tracker in several ways. For more information, please see
+ docs/modplug.txt.
+
+ If you find DUMB plays your module differently from the original tracker
+ for the format you are using, then please contact me.
*****************************************************************************
@@ -136,6 +138,12 @@ TO DO: add question regarding mixing of DJGPP and MinGW object files
datafiles with embedded music. Follow the instructions in docs/howto.txt
carefully and you shouldn't have this problem.
+ The system is designed this way to make sure you can exclude code you are
+ not using. If DUMB set you up for standard file access by default, then
+ the standard library code for accessing files would get pulled in even if
+ you never used it. This is especially important for dedicated systems that
+ have limited standard libraries.
+
If DUMB crashes with a specific music module, please let me know.
@@ -174,13 +182,13 @@ TO DO: add question regarding mixing of DJGPP and MinGW object files
Other possible causes are as follows:
- - The speakers are turned down (duh)
- - The volume of some system mixer is turned down
+ - The speakers are turned down (duh);
+ - The volume of some system mixer is turned down;
- Another program is using the sound card (not a problem for most modern
- systems)
+ systems);
- You didn't initialise Allegro's sound system; see install_sound() in
- Allegro's docs
- - Allegro's drivers don't work on your system and chosen platform
+ Allegro's docs;
+ - Allegro's drivers don't work on your system and chosen platform.
In order to narrow down the cause, consider the following:
@@ -220,8 +228,14 @@ TO DO: add question regarding mixing of DJGPP and MinGW object files
* Why does DUMB use so much processor time compared with other players? *
*****************************************************************************
- This should be less so in this release than in previous releases; the
- resampling and filtering algorithms have been optimised.
+ It doesn't! It is now on a par with the ModPlug rendering engine (tested
+ using ModPlugXMMS with reverb, surround and other such effects disabled).
+ Previous releases were less than optimal, but DUMB's resampling algorithm
+ was - and still is - one of a kind. Take a look at the code. Come on, I
+ dare ya.
+
+ All that said, you can reduce the amount of processor time DUMB uses by
+ reducing the quality.
By default, DUMB uses the most expensive resampling quality option. I've
found on an AthlonXP 1800+ and on a Pentium 233 that it typically uses
@@ -253,12 +267,20 @@ TO DO: add question regarding mixing of DJGPP and MinGW object files
* I e-mailed you and you replied with "RTFM"! What does that mean? *
*****************************************************************************
- Read The Manual. If it's a specific problem, I'll probably be kind and
- tell you where to look in the manual. However, if I get the impression you
- haven't even looked for a solution in the manual, expect no mercy ...
+ It means Read The Manual. I would only say this to someone who has clearly
+ not even tried reading the documentation. So if you are reading this FAQ
+ entry, you have too much time on your hands!
+
+
+*****************************************************************************
+* What happened to DUMB's IRC channel? *
+*****************************************************************************
+
+ It has been discontinued. It wasn't used very much, and it only really
+ works if I'm there at the same time as someone wants to chat. For most
+ problems, e-mail is much more effective. However, if you would like to
+ chat about something, please do e-mail me and we'll arrange it.
Ben Davis
entheh@users.sf.net
-IRC EFnet #dumb
-See readme.txt for details on using IRC.
diff --git a/plugins/dumb/dumb-kode54/docs/fnptr.txt b/plugins/dumb/dumb-kode54/docs/fnptr.txt
index 9a0d87b6..b876faaf 100644
--- a/plugins/dumb/dumb-kode54/docs/fnptr.txt
+++ b/plugins/dumb/dumb-kode54/docs/fnptr.txt
@@ -109,5 +109,3 @@ feel something should be added, please don't hesitate to let me know!
Ben Davis
entheh@users.sf.net
-IRC EFnet #dumb
-See readme.txt for details on using IRC.
diff --git a/plugins/dumb/dumb-kode54/docs/howto.txt b/plugins/dumb/dumb-kode54/docs/howto.txt
index 1d9a439f..7cfa194f 100644
--- a/plugins/dumb/dumb-kode54/docs/howto.txt
+++ b/plugins/dumb/dumb-kode54/docs/howto.txt
@@ -126,15 +126,17 @@ then follow the instructions further down for adapting your code.
allegro_exit();
-4. DUMB does not automatically do any of its own file input. You have to tell
- it how to read files. Don't worry, it's easy. Simply call the following
- function near the beginning of your program, after your atexit() call:
+4. DUMB does not automatically know how to open files. If you are loading
+ stand-alone files, you have to tell it how to open them. Don't worry, it's
+ easy. Simply call the following function near the beginning of your
+ program, after your atexit() call:
dumb_register_stdfiles();
- This tells DUMB to use ordinary stdio FILE structs for reading and writing
- files. If you are using Allegro and would rather DUMB used PACKFILEs, call
- the following function INSTEAD:
+ Once you've done this, a stdio FILE will be opened each time DUMB wants to
+ open a file (specifically, when dumbfile_open() is called). If you are
+ using Allegro and would rather DUMB used PACKFILEs, call the following
+ function instead:
dumb_register_packfiles();
@@ -143,23 +145,22 @@ then follow the instructions further down for adapting your code.
Note that the procedure for loading datafiles with embedded music is
independent of these two functions; even if you will be loading datafiles,
- you can use either of these functions. If you are loading datafiles, your
- executable might be slightly smaller if you use dumb_register_packfiles().
- On the other hand, dumb_register_stdfiles() will probably be faster. If
- you are only ever going to load datafiles and never stand-alone files, you
- can actually leave this step out; but I would recommend you put this in,
- test your code with a stand-alone file, then follow the instructions in
- the next section in order to adapt your code to use the datafile (you will
- be reminded that you can remove the function call).
+ you can use either of these functions. dumb_register_stdfiles() will
+ probably be faster. If you are only ever going to load datafiles and never
+ stand-alone files, you can actually leave this step out; but I would
+ recommend you put this in, test your code with a stand-alone file, then
+ follow the instructions in the next section in order to adapt your code to
+ use the datafile (the instructions will remind you that you can remove the
+ function call).
-5. If you are using Allegro, you'll have to initialise Allegro's sound
+5. If you are using Allegro, you will have to initialise Allegro's sound
system. In most cases the following line will do the job:
install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL);
- You may like to initialise a MIDI driver though; see Allegro's docs for
- details. Put this line after allegro_init().
+ Put this line after allegro_init(). See Allegro's documentation if you
+ want to initialise a MIDI driver too.
6. All pieces of music are stored in memory in DUH structs. To handle these,
@@ -171,22 +172,25 @@ then follow the instructions further down for adapting your code.
unfamiliar with pointers, please see ptr.txt. It is very important that
you understand these if you wish to use DUMB correctly.
- You do not have direct access to the contents of a DUH struct, so do not
- try. DUMB's functions provide everything you need; if you disagree, please
- let me know and I shall see what I can do. Contact details are at the end
- of this file.
+ You do not have direct access to the contents of a DUH struct, because
+ they are liable to change. It is hoped that DUMB's functions will provide
+ everything you need; if you need something else, please let me know and I
+ shall see what I can do. Contact details are at the end of this file.
Given the above definition, you can load a piece of music using one of the
following lines, depending on what file format you want to load:
- myduh = dumb_load_it("a_one.it");
- myduh = dumb_load_xm("a_two.xm");
- myduh = dumb_load_s3m("a_one_two.s3m");
- myduh = dumb_load_mod("three_four.mod");
+ myduh = dumb_load_it_quick("a_one.it");
+ myduh = dumb_load_xm_quick("a_two.xm");
+ myduh = dumb_load_s3m_quick("a_one_two.s3m");
+ myduh = dumb_load_mod_quick("three_four.mod");
- Obviously you can use relative or absolute paths as normal. You should
- always use forward slash (/), not backslash (\), when coding in C and
- similar languages.
+ You can use relative or absolute paths as normal. You should always use
+ forward slash (/), not backslash (\), when coding in C and similar
+ languages.
+
+ There are non-"quick" versions of the functions too; for information on
+ what this means, please see dumb.txt.
Every piece of music you load must be unloaded when you've finished with
it. When you type the above line in, it is good practice to type the
@@ -205,18 +209,8 @@ then follow the instructions further down for adapting your code.
please read these steps anyway, and then see the section entitled
"Rendering music into a buffer". You will have to write your own playback
code using whatever sound output system is available. Alternatively you
- may like to write data to a file (especially if you have a file that
- consumes a lot of processor time), but beware that any streaming audio
- format is likely to be substantially larger than the module file you
- generate it from, and formats like MP3 will be lower quality. You might
- not be able to hear the difference between the MP3 and the original, but
- many people can and don't like it, so please consider them. I'm one of
- them. If you really want to use a lossy compression format, I highly
- recommend Ogg Vorbis:
-
- http://www.vorbis.com/
-
- But I digress.
+ may like to write data to a file (especially if you have a module that
+ consumes a lot of processor time).
In order to play the DUH you loaded, you need to define a pointer to an
AL_DUH_PLAYER struct:
@@ -242,7 +236,8 @@ then follow the instructions further down for adapting your code.
Set 'n_channels' to 1 or 2 for mono or stereo respectively. Note that this
parameter has nothing to do with the number of samples that can play at
once in a music module. Set 'pos' to 0 to play from the beginning; each
- time you add 65536, you will have advanced one second into the piece. As a
+ time you add 65536, you will have advanced one second into the piece. (If
+ you use the non-"quick" loaders, seeking like this will be faster.) As a
general rule, set the volume to 1.0f and adjust it later if the music is
too loud or too quiet - but see Allegro's set_volume_per_voice() function
first.
@@ -323,16 +318,19 @@ then follow the instructions further down for adapting your code.
you will have to be very careful when stopping the music; see the
description of al_poll_duh() in dumb.txt for more information.
- So why not kill DOS? It is all too common a practice among programmers to
- quote the phrase, "DOS is as dead as the dodo." Despite being a decidedly
- derisible demonstation of the dreary device of alliteration, it shows a
- distinct lack of experience. Many embedded systems still use DOS because
- it provides hardware access capabilities and real-time possibilities
- unparalleled by any current multitasking operating system. For an argument
- closer to home, I used to use RHIDE for DOS before I switched to Linux,
- and I have not found a single Freeware Windows IDE that measures up to
- RHIDE. I'm sure many people are in the same boat, and really appreciate
- DUMB's DOS port.
+ So why not remove DOS support from DUMB? It is all too common a practice
+ among programmers to quote the phrase, "DOS is as dead as the dodo."
+ Despite being a decidedly derisible demonstation of the dreary device of
+ alliteration, it shows a distinct lack of experience. Many embedded
+ systems still use DOS because it provides hardware access capabilities and
+ real-time possibilities unparalleled by any current multitasking operating
+ system. For an argument closer to home, I used to use RHIDE for DOS before
+ I switched to Linux, and I have not found a single Freeware Windows IDE
+ that measures up to RHIDE. I'm sure many people are in the same boat, and
+ really appreciate DUMB's DOS port.
+
+ That, and the fact that you don't have to use the DOS support just because
+ it is there. Shame on you for not thinking this through. :)
We will not be removing DOS support from DUMB. Any blind suggestions to do
so will be met with fiery flames. You have been warned.
@@ -367,16 +365,17 @@ To control playback quality:
extern int dumb_resampling_quality;
extern int dumb_it_max_to_mix;
- Please note that dumb_resampling_quality has changed in DUMB v0.9.2. See
+ Please note that dumb_resampling_quality was changed in DUMB v0.9.2. See
deprec.txt for more details on the change.
dumb_resampling_quality can be set to any of the DUMB_RQ_* constants
(except DUMB_RQ_N_LEVELS; see below). Resampling is the term given to the
process of adjusting a sample's pitch (in this context).
dumb_resampling_quality defaults to DUMB_RQ_CUBIC, which sounds nice but
- takes a lot of processor power. Try reducing it if you have an older
- computer or if you are trying to mix an insane number of samples (or
- both!). See dumb.txt for details on what the different values actually do.
+ may take too much processor power on slower systems. Try reducing it if
+ you have an older computer (less than 300 MHz) or if you are trying to mix
+ an insane number of samples (or both!). See dumb.txt for details on what
+ the different values actually do.
If you wish to give this option to your user, you can use
DUMB_RQ_N_LEVELS. All the values from 0 to DUMB_RQ_N_LEVELS - 1 will be
@@ -390,7 +389,7 @@ To control playback quality:
(up to a fixed maximum of 256 of them, roughly speaking), and then will
just render as many of them as this variable permits, starting with the
loudest ones. When samples are cut or come back in, the exact timings will
- not generally be predictable - but nor will they be important.
+ not generally be predictable - but it is hoped this will not be important!
dumb_it_max_to_mix applies to each currently playing module file
independently. So if you set it to 64, but render two modules
@@ -411,13 +410,17 @@ played but any existing notes will continue):
These functions are pretty self-explanatory. The volume passed to
al_duh_set_volume() and the position returned by al_duh_get_position() are
- in the same units as those you passed to al_start_duh(). The length
- returned by duh_get_length() is in the same units as the aforementioned
- position; see dumb.txt for more information on this function. Be careful
- with al_duh_get_position(); it will return a position slightly ahead of
- what you can hear, because the system has to keep ahead slightly to avoid
+ in the same units as those you passed to al_start_duh(). Be careful with
+ al_duh_get_position(); it will return a position slightly ahead of what
+ you can hear, because the system has to keep ahead slightly to avoid
stuttering.
+ duh_get_length() returns the playback length, in the same units as the
+ aforementioned position, but beware: the length will not be known if you
+ have used the "quick" loader functions, and this function will return -1.
+ If you want to calculate the length later, use
+ dumb_it_do_initial_runthrough(). See dumb.txt for more information.
+
To prevent the music from looping and/or freezing:
@@ -473,15 +476,16 @@ To prevent the music from looping and/or freezing:
duh_get_it_sigrenderer() will return NULL, and the code will do nothing.
-To analyse the audio as it's generated:
+To analyse the audio as it is generated:
typedef int sample_t;
- typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data,
+ typedef void (*DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK)(void *data,
const sample_t *const *samples, int n_channels, long length);
- void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer,
- DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data);
+ void duh_sigrenderer_set_sample_analyser_callback(
+ DUH_SIGRENDERER *sigrenderer,
+ DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data);
If the above confuses you, see fnptr.txt. These functions, along with
al_duh_get_sigrenderer() from the last section, enable you to register a
@@ -495,25 +499,30 @@ To analyse the audio as it's generated:
elegantly, typically by returning immediately, but you may wish to make a
note of the fact that the music is being skipped, for whatever reason.
- Beware again: if the main program ever calls duh_sigrenderer_get_samples()
- on a buffer that isn't all silence, this callback function will be passed
- the existing buffer after mixing, and thus it will include the original
- data. This will not be an issue if you stick to duh_render(), which always
- starts with a buffer filled with silence.
+ Beware again: if the main program ever calls
+ duh_sigrenderer_generate_samples() on a buffer that isn't all silence,
+ this callback function will be passed the existing buffer after mixing,
+ and thus it will include the original data. This will not be an issue if
+ you stick to duh_render(), which always starts with a buffer filled with
+ silence.
- The samples array is two-dimensional. Refer to it as follows:
+ The samples array is two-dimensional, but the first index will always be 0
+ for mono and stereo sound. Refer to it as follows:
- samples[channel_number][sample_position]
+ n_channels == 1: samples[0][sample_position]
+ n_channels == 2: samples[0][sample_position*2+channel_number]
where 0 <= channel_number < n_channels,
and 0 <= sample_position < length.
+ There is a more thorough explanation in dumb.txt.
+
In addition you can pass any 'data' pointer you like to
- duh_sigrenderer_set_analyser_callback(), and this pointer will be relayed
- to your callback function each time.
+ duh_sigrenderer_set_sample_analyser_callback(), and this pointer will be
+ relayed to your callback function each time.
To remove the callback function, pass NULL to
- duh_sigrenderer_set_analyser_callback().
+ duh_sigrenderer_set_sample_analyser_callback().
Everything below this point assumes some knowledge of how a music module is
@@ -536,26 +545,26 @@ default being 0, the beginning of the song), use the following:
DUH_SIGRENDERER *sr = dumb_it_start_at_order
(duh, n_channels, startorder);
dp = al_duh_encapsulate_sigrenderer(sr, volume, bufsize, freq);
+ if (!dp) duh_end_sigrenderer(sr);
}
Replace 'dp' with whatever your AL_DUH_PLAYER pointer is. You also need
to insert suitable values for n_channels, startorder, volume, bufsize and
freq. These have the same meaning as those passed to al_start_duh().
- WARNING: after passing a pointer to an "encapsulate" function, do not use
- that pointer again. (More specifically, do not use it again if
- the function returns NULL, because the function will have
- destroyed the pointer if this happens, to help prevent memory
- leaks.) There will be a "get" function with which you can obtain
- the original pointer if it is still valid, or NULL otherwise.
+ Whenever you call al_duh_encapsulate_sigrenderer(), be sure to check the
+ return value. If an AL_DUH_PLAYER was returned, then the encapsulated
+ DUH_SIGRENDERER will be destroyed when you destroy the AL_DUH_PLAYER. If
+ not, you will have to destroy the DUH_SIGRENDERER yourself. The above code
+ includes this check.
The above functions will fail (safely) if you try to use them with a DUH
- that contains a different type of music.
+ that contains a different type of music. No music will play.
Notice that there is no 'pos' parameter. If you would like to skip through
the music, you can use this function:
- long duh_sigrenderer_get_samples(
+ long duh_sigrenderer_generate_samples(
DUH_SIGRENDERER *sigrenderer,
float volume, float delta,
long size, sample_t **samples
@@ -565,7 +574,7 @@ default being 0, the beginning of the song), use the following:
through the music nice and quickly. So insert the following between the
two above statements:
- duh_sigrenderer_get_samples(sr, 0, 65536.0f / freq, pos, NULL);
+ duh_sigrenderer_generate_samples(sr, 0, 65536.0f / freq, pos, NULL);
Substitute for 'freq' and 'pos'. An explanation of the 'delta' parameter
can be found further down in this file.
@@ -611,7 +620,8 @@ DUMB_IT_SIGDATA struct, which represents the piece of music before it starts
to play. Those beginning with "dumb_it_sr" operate on the DUMB_IT_SIGRENDERER
struct, which represents a currently playing instance of the music. Note that
duh_get_length(), described above, becomes meaningless after some of these
-functions are used.
+functions are used, although you can correct this by calling
+dumb_it_build_checkpoints() again.
The method for getting a DUMB_IT_SIGRENDERER struct has already been given,
but the function prototypes are repeated here for convenience:
@@ -650,21 +660,23 @@ To use a piece of music you added to the datafile, follow these steps:
1. Before loading the datafile, call one or more of these functions,
depending on which music format or formats you'd like to support:
- dumb_register_dat_it(DUMB_DAT_IT);
- dumb_register_dat_xm(DUMB_DAT_XM);
- dumb_register_dat_s3m(DUMB_DAT_S3M);
- dumb_register_dat_mod(DUMB_DAT_MOD);
+ dumb_register_dat_it_quick(DUMB_DAT_IT);
+ dumb_register_dat_xm_quick(DUMB_DAT_XM);
+ dumb_register_dat_s3m_quick(DUMB_DAT_S3M);
+ dumb_register_dat_mod_quick(DUMB_DAT_MOD);
+
+ There are non-"quick" versions too.
Remember, do not call multiple functions unless you want to support
multiple formats. Calling more functions will add unused code to your
executable.
- It is important that you make call these before loading the datafile,
- since they tell Allegro how to load the respective files straight from
- datafiles in the future. They will not help Allegro interpret any module
- files that have already been loaded as binary objects (but if you really
- need to interpret a module that has been loaded in this fashion, have a
- look at dumbfile_open_memory() in dumb.txt).
+ It is important that you call these before loading the datafile, since
+ they tell Allegro how to load the respective files straight from datafiles
+ in the future. They will not help Allegro interpret any module files that
+ have already been loaded as binary objects. If you ever need to interpret
+ a module that has been loaded in this fashion, have a look at
+ dumbfile_open_memory() in dumb.txt.
If for whatever reason your music objects are identified by a different
type in the datafile, you can tell DUMB what that type is by changing the
@@ -683,12 +695,13 @@ To use a piece of music you added to the datafile, follow these steps:
if (!dat) abort(); /* There are much nicer ways of handling failure! */
DUH *myduh = (DUH *)dat[GAME_MUSIC].dat;
- Note that the explicit (DUH *) cast is only necessary for C++, not for C.
- However, it does no harm.
+ The explicit (DUH *) cast is only necessary for C++, not for C. However,
+ it does no harm.
Be sure that you do NOT call unload_duh() for anything stored in the
datafile. These DUHs will be freed when you call unload_datafile(), and
- freeing them twice is practically guaranteed to crash your program.
+ freeing them twice is practically guaranteed to crash your program. (But
+ do call unload_duh() if you have used dumbfile_open_memory().)
3. If you only ever load music as part of a datafile, and you never load any
@@ -723,9 +736,12 @@ you must use a DUH_SIGRENDERER struct instead. Here are the functions:
int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer);
long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer);
- long duh_sigrenderer_get_samples(DUH_SIGRENDERER *sigrenderer,
+ long duh_sigrenderer_generate_samples(DUH_SIGRENDERER *sigrenderer,
float volume, float delta, long size, sample_t **samples);
+ void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer,
+ float volume, sample_t *samples);
+
long duh_render(DUH_SIGRENDERER *sigrenderer,
int bits, int unsign, float volume, float delta, long size, void *sptr);
@@ -736,11 +752,11 @@ al_start_duh(). However, note that the volume is not set at this stage. You
pass the desired volume each time you want to render a block. The 'sig'
parameter should be set to 0 for now.
-Notice that there are two rendering functions. duh_sigrenderer_get_samples()
-will generate samples in the internal 32-bit format, with a normal range from
--0x800000 to 0x7FFFFF and with each channel in a separate array; duh_render()
-will convert to 8 or 16 bits, signed or unsigned, with stereo samples
-interleaved, left first.
+Notice that there are two rendering functions.
+duh_sigrenderer_generate_samples() will generate samples in the internal
+32-bit format, with a normal range from -0x800000 to 0x7FFFFF; duh_render()
+will convert to 8 or 16 bits, signed or unsigned. Both functions will
+interleave stereo samples, left first.
When you call duh_render(), pass 8 or 16 for 'bits'. If you pass 8, 'sptr' is
expected to be an array of chars. If you pass 16, 'sptr' is expected to be an
@@ -769,7 +785,7 @@ follows, and write the chars to the file.
For a 16-bit WAV file, write the LSB (less significant byte) first.
The following applies equally to duh_render() and
-duh_sigrenderer_get_samples(), except where otherwise stated.
+duh_sigrenderer_generate_samples(), except where otherwise stated.
If you set 'delta' to 1.0f, the sound generated will be suitable for playback
at 65536 Hz. Increasing 'delta' causes the wave to speed up, given a constant
@@ -783,39 +799,44 @@ will be rendered into an array which you pass as 'sptr'. Note that stereo
samples count as one; so if you set n_channels to 2, your array must contain
(2 * size) elements.
-For duh_sigrenderer_get_samples() you will have to use the following
+For duh_sigrenderer_generate_samples() you will have to use the following
functions:
- sample_t **create_sample_buffer(int n_channels, long length);
+ sample_t **allocate_sample_buffer(int n_channels, long length);
void destroy_sample_buffer(sample_t **samples);
void dumb_silence(sample_t *samples, long length);
-create_sample_buffer() allocates the channels sequentially in memory, so the
-following technique is valid:
+allocate_sample_buffer() allocates the buffers sequentially in memory in the
+hypothetical future case where there are more than two channels, so the
+following technique is valid and officially supported:
- sample_t **samples = create_sample_buffer(n_channels, length);
+ sample_t **samples = allocate_sample_buffer(n_channels, length);
dumb_silence(samples[0], n_channels * length);
It is necessary to fill the buffer with silence like this because
-duh_sigrenderer_get_samples() mixes what it renders with the existing
+duh_sigrenderer_generate_samples() mixes what it renders with the existing
contents of the buffer.
-The return values from duh_render() and duh_sigrenderer_get_samples() tell
-you how many samples were actually generated. In most cases, this will be the
-same as the 'size' parameter. However, if you reach the end of the DUH (which
-will happen if you disable looping or freezing as described further up), this
-function will return less. When that happens, you can assume the stream has
-finished. In the case of duh_render(), the remainder of the array will not
-have been initialised, so you either have to initialise it yourself or avoid
-using it.
+The return values from duh_render() and duh_sigrenderer_generate_samples()
+tell you how many samples were actually generated. In most cases, this will
+be the same as the 'size' parameter. However, if you reach the end of the DUH
+(which will happen if you disable looping or freezing as described further
+up), this function will return less. When that happens, you can assume the
+stream has finished. In the case of duh_render(), the remainder of the array
+will not have been initialised, so you either have to initialise it yourself
+or avoid using it.
If for whatever reason duh_start_sigrenderer() returns NULL, then
-duh_render() and duh_sigrenderer_get_samples() will generate exactly 0
+duh_render() and duh_sigrenderer_generate_samples() will generate exactly 0
samples, duh_sigrenderer_get_n_channels() will return 0,
duh_sigrenderer_get_position() will return -1, and duh_end_sigrenderer() will
safely do nothing.
+duh_sigrenderer_get_current_sample() is used by the click removal algorithm.
+It simply returns the current sample without updating the position, so you
+can use it to sniff what is coming next.
+
*********************
*** Miscellaneous ***
@@ -841,5 +862,3 @@ Enjoy!
Ben Davis
entheh@users.sf.net
-IRC EFnet #dumb
-See readme.txt for details on using IRC.
diff --git a/plugins/dumb/dumb-kode54/docs/modplug.txt b/plugins/dumb/dumb-kode54/docs/modplug.txt
index 65eabe8a..c70ab299 100644
--- a/plugins/dumb/dumb-kode54/docs/modplug.txt
+++ b/plugins/dumb/dumb-kode54/docs/modplug.txt
@@ -8,9 +8,9 @@
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
* / \
* / . \
- * modplug.txt - Our official position regarding / / \ \
- * compatibility with ModPlug | < / \_
- * Tracker. | \/ /\ /
+ * modplug.txt - Some comments on ModPlug Tracker / / \ \
+ * and its compatibility with other | < / \_
+ * tracking tools. | \/ /\ /
* \_ / > /
* | \ / /
* | ' /
@@ -22,67 +22,94 @@
*** Introduction ***
********************
-ModPlug Tracker is a very popular tracker for Windows. Its popularity is due
-to the intuitive interface and its many advanced features. The author has
-done a good job with this piece of software, but sadly in doing so he has
-desecrated the IT file format.
+There are two 'authorities' on how the various tracker files should be
+played. The first is the original trackers; I consider these the true
+authorities because they were around earlier, they created their own formats,
+and they mostly play the music the same on every computer (exception: IT's
+support for MIDI output).
-I am not against ModPlug Tracker being used to write music modules. As
-already stated, it has some very advanced and convenient features; I use it
-myself. However, I believe its users should be aware of the entire situation
-before using it for any serious work.
+The second is ModPlug Tracker. It is not the only third-party tracker, but it
+is by far the most used. I have some issues with ModPlug Tracker, which I
+shall explain below. However, I do use ModPlug Tracker because it is user-
+friendly. I recommend that anyone planning to compose music in ModPlug
+Tracker read this document.
+
+DUMB's loyalty is to the original trackers, not ModPlug Tracker. Please bear
+this in mind when reporting bugs. ModPlug Tracker is now available with
+source code, so you may be able to use its own music playback engine if you
+prefer; but read this file anyway!
ModPlug Tracker - http://www.modplug.com/
+ Open Source Version - http://sourceforge.net/projects/modplug/
*************************
*** Incompatibilities ***
*************************
-There are a few situations in which ModPlug Tracker misinterprets the
-original module formats. I shall list the five I am most aware of, from least
-to most annoying:
+There are a few situations in which ModPlug Tracker's playback engine differs
+from the original trackers' playback engines. I shall list the five I am most
+aware of, in order from least to most annoying:
-5. Create a multisample instrument, for example a piano. Play a low note.
- Then go up the scale, but in the pattern data, make sure the instrument
- column is blank; put in only the notes. Play this with ModPlug Tracker,
- and play it with Impulse Tracker. Impulse Tracker changes sample as you go
- up the scale; ModPlug Tracker does not.
+5. Create a new IT file. Create a multisample instrument, for example a
+ piano. Play a low note. Then go up the scale, but in the pattern data,
+ make sure the instrument column is blank; put in only the notes. Play this
+ with ModPlug Tracker, and play it with Impulse Tracker or DUMB. Impulse
+ Tracker and DUMB change sample as you go up the scale; ModPlug Tracker
+ does not.
4. Arpeggio and Retrigger Note effects behave badly when combined with
Portamento, which can appear in the volume column. While Retrigger Note
isn't too bad, Arpeggio sounds completely wrong. Try it and see what
- happens. Then repeat the experiment in Impulse Tracker.
+ happens. Then repeat the experiment in Impulse Tracker, or play the file
+ with DUMB.
-3. The filter algorithm is incorrect, in more ways than one. When Jeffrey Lim
- programmed the low-pass resonant filters into Impulse Tracker, he used a
- standard filter algorithm with a slight modification to achieve greater
- resonance. ModPlug Tracker does not incorporate this modification.
- Furthermore, ModPlug Tracker uses integer arithmetic with nowhere near
- enough precision; the wave output is really poor in some cases. I don't
- doubt it damages the acoustic properties of the filters in subtle ways.
+3. The filter algorithm is incorrect. Impulse Tracker uses a standard low-
+ pass resonant filter algorithm with a slight modification to increase the
+ resonance (the poles are closer to the unit circle). ModPlug Tracker does
+ not incorporate this modification. As a result, filtered channels sound
+ somewhat weaker.
2. When looping, ModPlug Tracker resets all variables. The original trackers
do not do this.
1. Worst of all, ModPlug Tracker has no regard for playback volume, and
- generally has a much lower output level than the original trackers.
-
-Cases 3, 2 and 1 lead people to write IT files that play badly in the
+ generally has a much lower output level than the original trackers. You
+ can adjust this in the program set-up. The control has been moved out of
+ the file into the user's domain, which makes it difficult to ensure that
+ your file will play at a reasonable volume everywhere. I have plenty of
+ files that distort horribly with DUMB and Impulse Tracker because they
+ were written with ModPlug Tracker.
+
+Cases 3, 2 and 1 lead people to create IT files that play badly in the
original trackers. If some of these problems could be fixed, I'd be all for
-it - but these problems have been reported to the author and he had no
-motivation to fix them. ModPlug Tracker has been around long enough that
-fixing 3, 2 and 1 would be detrimental to too many people's music.
+it - but I was once told these problems were reported to the author and he
+had no motivation to fix them. ModPlug Tracker is now open source, but I
+suspect fixing 3, 2 and 1 would be deemed detrimental to too many people's
+music by now.
+
+If you are incorporating music into a game, you can work around the volume
+problem in your program. When you pass a volume to al_start_duh() or
+equivalent, try passing a lower value than 1.0f. Be drastic; try 0.5f, 0.2f,
+and maybe even 0.1f, until you find a level that sounds loud enough but
+doesn't distort. However, for neatness I would always recommend fixing the
+module by changing its mixing volume.
******************
*** Extensions ***
******************
-Worse than the incompatibilities are the extensions ModPlug Tracker makes,
-mostly to the IT format. DUMB currently supports one of these extensions,
-namely stereo samples, but supporting the others is not high on my list of
-priorities.
+ModPlug Tracker has also made various extensions, mostly to the IT format.
+These are useful if you are keeping your module files private and
+distributing MP3 or OGG files. However, if you wish to distribute the module
+files, you will want to avoid them.
+
+DUMB currently supports one of ModPlug Tracker's extensions, namely stereo
+samples, but supporting the others is not high on my list of priorities. The
+support for stereo samples is only in there because I did not know it was an
+extension at first! Impulse Tracker's own format documentation makes
+provision for stereo samples but states that they are not supported yet.
Other extensions ModPlug Tracker has provided mostly take the form of extra
effects. For instance, S98 and S99 can be used to enable or disable reverb. I
@@ -93,39 +120,32 @@ these features, it will play incorrectly with Impulse Tracker.
By far the most evil extension provided by ModPlug Tracker is the effect
plug-ins. These enable IT files to use VST effects. I recently downloaded an
IT file that uses some effects from a collection named "DirectX Media Audio
-Effects". When can we expect these effects to be ported to Linux?
+Effects". I doubt these effects will be ported to Linux any time soon.
+
+All in all, the extensions are having the result of making all the other IT
+players, and Impulse Tracker itself, look bad.
******************
*** Conclusion ***
******************
-ModPlug Tracker is trying to be two things at once. It wants to be an editor
-for the existing formats, but at the same time it wants to be proprietary,
-with all its own features and extensions. Unfortunately it is succeeding;
-there are many IT files out there that only play right in ModPlug Tracker. In
-my opinion, ModPlug Tracker should have come out with its own file format, in
-which all these extensions would have found a home.
-
-If you are going to use ModPlug Tracker's extensions, I recommend you
-ultimately convert your music to a streamed format such as Ogg Vorbis. (If
-you were thinking of using MP3, then don't - consider using Ogg Vorbis
-instead.) If you release IT files that use ModPlug Tracker's extensions,
-please state prominently that the files are designed to be played with
-ModPlug Tracker. Finally, don't ask me to support ModPlug Tracker's
-extensions; ModPlug Tracker's playback code is available for use in your
-games, so use that instead.
-
- Ogg Vorbis - http://www.vorbis.com/
-
-Despite all the above problems, don't forget that ModPlug Tracker does have a
-lot of very useful features for editing files. These include a function for
-removing unused patterns, samples and instruments, drag-and-drop sample and
-instrument ripping, drop-down menus for selecting the effects by name without
-having to memorise the codes or refer to help, and lots of other nice things.
-I do recommend it as an editor, provided you make sure you are aware of the
-situation and do not use ModPlug Tracker's extensions or incompatibilities
-inadvertently.
+ModPlug Tracker is trying to be two things at once, and is going about it
+slightly wrong. It wants to be an editor for the existing formats, allowing
+Windows users who have limited DOS support to continue tracking using the
+same file formats. This is fairly noble. The problem arose when it took it
+upon itself to modify the formats, make up its own rules and take advantage
+of everything available including system-specific features, which is useful
+as long as you will be distributing your music prerendered. In my opinion,
+ModPlug Tracker should have come out with its own file format, in which all
+these extensions would have found a home. As it stands, you can use all the
+extensions and still save your music as an .it or .xm file, which is asking
+for trouble.
+
+Despite all the above problems, I do recommend ModPlug Tracker as an editor,
+provided you are careful not to use ModPlug Tracker's extensions or rely on
+its incompatibilities unless you really don't intend to distribute your
+'source' module file.
Oh, and by the way, save your final version with Impulse Tracker. Then the
samples will be compressed for you!
@@ -133,5 +153,3 @@ samples will be compressed for you!
Ben Davis
entheh@users.sf.net
-IRC EFnet #dumb
-See readme.txt for details on using IRC.
diff --git a/plugins/dumb/dumb-kode54/docs/ptr.txt b/plugins/dumb/dumb-kode54/docs/ptr.txt
index bf7534d4..05445fab 100644
--- a/plugins/dumb/dumb-kode54/docs/ptr.txt
+++ b/plugins/dumb/dumb-kode54/docs/ptr.txt
@@ -125,5 +125,3 @@ that should be added, please don't hesitate to let me know!
Ben Davis
entheh@users.sf.net
-IRC EFnet #dumb
-See readme.txt for details on using IRC.
diff --git a/plugins/dumb/dumb-kode54/examples/dumb2wav.c b/plugins/dumb/dumb-kode54/examples/dumb2wav.c
index 9a4c5090..fae7fab6 100644
--- a/plugins/dumb/dumb-kode54/examples/dumb2wav.c
+++ b/plugins/dumb/dumb-kode54/examples/dumb2wav.c
@@ -1,481 +1,481 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * dumb2wav.c - Utility to convert DUH to WAV. / / \ \
- * | < / \_
- * By Chad Austin, based on dumbout.c by entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <time.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <math.h>
-#include <string.h>
-#include <dumb.h>
-
-#include <internal/it.h>
-
-union {
- float s32[4096];
- short s16[8192];
- char s8[16384];
-} buffer;
-
-sample_t ** internal_buffer;
-
-int loop_count = 1;
-
-
-static int write32_le(FILE* outf, unsigned int value) {
- int total = 0;
- total += fputc(value & 0xFF, outf);
- total += fputc((value >> 8) & 0xFF, outf);
- total += fputc((value >> 16) & 0xFF, outf);
- total += fputc((value >> 24) & 0xFF, outf);
- return total;
-}
-
-static int write16_le(FILE* outf, unsigned int value) {
- int total = 0;
- total += fputc(value & 0xFF, outf);
- total += fputc((value >> 8) & 0xFF, outf);
- return total;
-}
-
-
-static int loop_callback(void* data) {
- return (--loop_count <= 0 ? -1 : 0);
-}
-
-
-int main(int argc, const char *argv[])
-{
- DUH *duh;
- DUH_SIGRENDERER *sr;
-
- const char *fn = NULL;
- const char *fn_out = NULL;
- FILE *outf;
-
- int depth = 16;
- int unsign = 0;
- int freq = 44100;
- int n_channels = 2;
- int solo = -1;
- float volume = 1.0f;
- float delay = 0.0f;
- float delta;
- int bufsize;
- clock_t start, end;
- int data_written = 0; /* total bytes written to data chunk */
-
- int i = 1;
-
- LONG_LONG length;
- LONG_LONG done;
- int dots;
-
- while (i < argc) {
- const char *arg = argv[i++];
- if (*arg != '-') {
- if (fn) {
- fprintf(stderr,
- "Cannot specify multiple filenames!\n"
- "Second filename found: \"%s\"\n", arg);
- return 1;
- }
- fn = arg;
- continue;
- }
- arg++;
- while (*arg) {
- char *endptr;
- switch (*arg++) {
- case 'o':
- case 'O':
- if (i >= argc) {
- fprintf(stderr, "Out of arguments; output filename expected!\n");
- return 1;
- }
- fn_out = argv[i++];
- break;
- case 'd':
- case 'D':
- if (i >= argc) {
- fprintf(stderr, "Out of arguments; delay expected!\n");
- return 1;
- }
- delay = (float)strtod(argv[i++], &endptr);
- if (*endptr != 0 || delay < 0.0f || delay > 64.0f) {
- fprintf(stderr, "Invalid delay!\n");
- return 1;
- }
- break;
- case 'v':
- case 'V':
- if (i >= argc) {
- fprintf(stderr, "Out of arguments; volume expected!\n");
- return 1;
- }
- volume = (float)strtod(argv[i++], &endptr);
- if (*endptr != 0 || volume < -8.0f || volume > 8.0f) {
- fprintf(stderr, "Invalid volume!\n");
- return 1;
- }
- break;
- case 's':
- case 'S':
- if (i >= argc) {
- fprintf(stderr, "Out of arguments; sampling rate expected!\n");
- return 1;
- }
- freq = strtol(argv[i++], &endptr, 10);
- if (*endptr != 0 || freq < 1 || freq > 960000) {
- fprintf(stderr, "Invalid sampling rate!\n");
- return 1;
- }
- break;
- case 'f':
- depth = 32;
- break;
- case '8':
- depth = 8;
- break;
- case 'l':
- case 'L':
- if (i >= argc) {
- fprintf(stderr, "Out of arguments: loop count expected!\n");
- return 1;
- }
- loop_count = strtol(argv[i++], &endptr, 10);
- break;
- case 'm':
- case 'M':
- n_channels = 1;
- break;
- case 'u':
- case 'U':
- unsign = 1;
- break;
- case 'r':
- case 'R':
- if (i >= argc) {
- fprintf(stderr, "Out of arguments; resampling quality expected!\n");
- return 1;
- }
- dumb_resampling_quality = strtol(argv[i++], &endptr, 10);
- if (*endptr != 0 || dumb_resampling_quality < 0 || dumb_resampling_quality > 2) {
- fprintf(stderr, "Invalid resampling quality!\n");
- return 1;
- }
- break;
- case 'c':
- case 'C':
- if (i >= argc) {
- fprintf(stderr, "Out of arguments; channel number expected!\n");
- return 1;
- }
- solo = strtol(argv[i++], &endptr, 10);
- if (*endptr != 0 || solo < 0 || solo >= DUMB_IT_N_CHANNELS) {
- fprintf(stderr, "Invalid channel number!\n");
- return 1;
- }
- break;
- default:
- fprintf(stderr, "Invalid switch - '%c'!\n", isprint(arg[-1]) ? arg[-1] : '?');
- return 1;
- }
- }
- }
-
- if (!fn) {
- fprintf(stderr,
- "Usage: dumb2wav [options] module [more-options]\n"
- "\n"
- "The module can be any IT, XM, S3M or MOD file. It will be rendered to a .wav\n"
- "file of the same name, unless you specify otherwise with the -o option.\n"
- "\n"
- "The valid options are:\n"
- "-o <file> specify the output filename (defaults to the input filename with\n"
- " the extension replaced with .wav); use - to write to standard\n"
- " output or . to write nowhere (useful for measuring DUMB's\n"
- " performance, and DOS and Windows don't have /dev/null!)\n"
- "-d <delay> set the initial delay, in seconds (default 0.0)\n"
- "-v <volume> adjust the volume (default 1.0)\n"
- "-s <freq> set the sampling rate in Hz (default 44100)\n"
- "-8 generate 8-bit instead of 16-bit\n"
- "-f generate floating point samples instead of 16-bit\n"
- "-m generate mono output instead of stereo left/right pairs\n"
- "-u generated unsigned output instead of signed\n"
- "-r <value> specify the resampling quality to use\n"
- "-l <value> specify the number of times to loop (default 1)\n"
- "-c <value> specify a channel number to solo\n");
- return 1;
- }
-
- atexit(&dumb_exit);
- dumb_register_stdfiles();
-
- dumb_it_max_to_mix = 256;
-
- duh = load_duh(fn);
- if (!duh) {
- duh = dumb_load_it(fn);
- if (!duh) {
- duh = dumb_load_xm(fn);
- if (!duh) {
- duh = dumb_load_s3m(fn);
- if (!duh) {
- duh = dumb_load_mod(fn);
- if (!duh) {
- fprintf(stderr, "Unable to open %s!\n", fn);
- return 1;
- }
- }
- }
- }
- }
-
- sr = duh_start_sigrenderer(duh, 0, n_channels, 0);
- if (!sr) {
- unload_duh(duh);
- fprintf(stderr, "Unable to play file!\n");
- return 1;
- }
-
- if (solo >= 0) {
- DUMB_IT_SIGRENDERER * itsr = duh_get_it_sigrenderer(sr);
- if (itsr) {
- for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
- if (i != solo) {
- IT_CHANNEL * channel = &itsr->channel[i];
- IT_PLAYING * playing = channel->playing;
- channel->flags |= IT_CHANNEL_MUTED;
- /* start_sigrenderer leaves me all of the channels the first tick triggered */
- if (playing) {
- playing->ramp_volume[0] = 0;
- playing->ramp_volume[1] = 0;
- playing->ramp_delta[0] = 0;
- playing->ramp_delta[1] = 0;
- }
- }
- }
- }
- }
-
- if (fn_out) {
- if (fn_out[0] == '-' && fn_out[1] == 0)
- outf = stdout;
- else if (fn_out[0] == '.' && fn_out[1] == 0)
- outf = NULL;
- else {
- outf = fopen(fn_out, "wb");
- if (!outf) {
- fprintf(stderr, "Unable to open %s for writing!\n", fn_out);
- duh_end_sigrenderer(sr);
- unload_duh(duh);
- return 1;
- }
- }
- } else {
- char *extptr = NULL, *p;
- char *fn_out = malloc(strlen(fn)+5);
- if (!fn_out) {
- fprintf(stderr, "Out of memory!\n");
- duh_end_sigrenderer(sr);
- unload_duh(duh);
- return 1;
- }
- strcpy(fn_out, fn);
- for (p = fn_out; *p; p++)
- if (*p == '.') extptr = p;
- if (!extptr) extptr = p;
- strcpy(extptr, ".wav");
- outf = fopen(fn_out, "wb");
- if (!outf) {
- fprintf(stderr, "Unable to open %s for writing!\n", fn_out);
- free(fn_out);
- duh_end_sigrenderer(sr);
- unload_duh(duh);
- return 1;
- }
- free(fn_out);
- }
-
- {
- DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sr);
- dumb_it_set_ramp_style(itsr, 2);
- dumb_it_set_loop_callback(itsr, loop_callback, NULL);
- dumb_it_set_xm_speed_zero_callback(itsr, &dumb_it_callback_terminate, NULL);
- dumb_it_set_global_volume_zero_callback(itsr, &dumb_it_callback_terminate, NULL);
- }
-
-
- if (outf) {
- /* write RIFF header: fill file length later */
- fwrite("RIFF", 1, 4, outf);
- fwrite(" ", 1, 4, outf);
- fwrite("WAVE", 1, 4, outf);
-
- /* write format chunk */
- fwrite("fmt ", 1, 4, outf);
-
- if (depth == 32)
- {
- write32_le(outf, 18);
- write16_le(outf, 3);
- }
- else
- {
- write32_le(outf, 16); /* header length */
- write16_le(outf, 1); /* WAVE_FORMAT_PCM */
- }
- write16_le(outf, n_channels); /* channel count */
- write32_le(outf, freq); /* frequency */
- write32_le(outf, freq * n_channels * depth / 8); /*bytes/sec*/
- write16_le(outf, n_channels * depth / 8); /* block alignment */
- write16_le(outf, depth); /* bits per sample */
-
- if (depth == 32)
- {
- write16_le(outf, 0);
- }
-
- /* start data chunk */
- fwrite("data", 1, 4, outf);
- fwrite(" ", 1, 4, outf); /* fill in later */
- }
-
- length = (LONG_LONG)_dumb_it_build_checkpoints(duh_get_it_sigdata(duh), 0) * freq >> 16;
- done = 0;
- dots = 0;
- delta = 65536.0f / freq;
- bufsize = sizeof(buffer);
- if (depth == 32) bufsize /= sizeof(*buffer.s32);
- else if (depth == 16) bufsize /= sizeof(*buffer.s16);
- bufsize /= n_channels;
-
- if (depth == 32) {
- internal_buffer = create_sample_buffer(n_channels, bufsize);
- if (!internal_buffer) {
- fprintf(stderr, "Out of memory!\n");
- duh_end_sigrenderer(sr);
- unload_duh(duh);
- }
- }
-
- {
- long l = (long)floor(delay * freq + 0.5f);
- l *= n_channels * (depth >> 3);
- if (l) {
- if (unsign && depth != 32) {
- if (depth == 16) {
- for (i = 0; i < 8192; i++) {
- buffer.s8[i*2] = 0x00;
- buffer.s8[i*2+1] = 0x80;
- }
- } else
- memset(buffer.s8, 0x80, 16384);
- } else
- memset(buffer.s8, 0, 16384);
- while (l >= 16384) {
- if (outf) fwrite(buffer.s8, 1, 16384, outf);
- l -= 16384;
- data_written += 16384;
- }
- if (l) {
- if (outf) fwrite(buffer.s8, 1, l, outf);
- data_written += 1;
- }
- }
- }
-
- start = clock();
-
- fprintf(stderr, "................................................................\n");
- for (;;) {
- int write_size;
- int l;
-
- if (depth != 32) {
- l = duh_render(sr, depth, unsign, volume, delta, bufsize, &buffer);
- if (depth == 16) {
- for (i = 0; i < l * n_channels; i++) {
- short val = buffer.s16[i];
- buffer.s8[i*2] = val;
- buffer.s8[i*2+1] = val >> 8;
- }
- }
- } else {
- int j;
- dumb_silence(internal_buffer[0], bufsize * n_channels);
- l = duh_sigrenderer_get_samples(sr, volume, delta, bufsize, internal_buffer);
- for (i = 0; i < n_channels; i++) {
- for (j = 0; j < l; j++) {
- buffer.s32[j * n_channels + i] = (float)((double)internal_buffer[i][j] * (1.0 / (double)(0x800000)));
- }
- }
- }
- write_size = l * n_channels * (depth >> 3);
- if (outf) fwrite(buffer.s8, 1, write_size, outf);
- data_written += write_size;
- if (l < bufsize) break;
- done += l;
- l = done * 64 / length;
- while (dots < 64 && l > dots) {
- fprintf(stderr, "|");
- dots++;
- }
- if (dots >= 64) {
- putchar('\n');
- dots = 0;
- done = 0;
- }
- }
-
- while (64 > dots) {
- fprintf(stderr, "|");
- dots++;
- }
- fprintf(stderr, "\n");
-
- end = clock();
-
- if (depth == 32) destroy_sample_buffer(internal_buffer);
-
- /* fill in blanks we left in WAVE file */
- if (outf) {
- /* file size, not including RIFF header */
- const int fmt_size = 8 + ((depth == 32) ? 18 : 16);
- const int data_size = 8 + data_written;
- const int file_size = fmt_size + data_size;
-
- /* can we seek stdout? */
- fseek(outf, 4, SEEK_SET);
- write32_le(outf, file_size);
-
- fseek(outf, 12 + fmt_size + 4, SEEK_SET);
- write32_le(outf, data_written);
- }
-
-
- duh_end_sigrenderer(sr);
- unload_duh(duh);
- if (outf && outf != stdout) fclose(outf);
-
- fprintf(stderr, "Elapsed time: %f seconds\n", (end - start) / (float)CLOCKS_PER_SEC);
-
- return 0;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * dumb2wav.c - Utility to convert DUH to WAV. / / \ \
+ * | < / \_
+ * By Chad Austin, based on dumbout.c by entheh. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+#include <string.h>
+#include <dumb.h>
+
+#include <internal/it.h>
+
+union {
+ float s32[4096];
+ short s16[8192];
+ char s8[16384];
+} buffer;
+
+sample_t ** internal_buffer;
+
+int loop_count = 1;
+
+
+static int write32_le(FILE* outf, unsigned int value) {
+ int total = 0;
+ total += fputc(value & 0xFF, outf);
+ total += fputc((value >> 8) & 0xFF, outf);
+ total += fputc((value >> 16) & 0xFF, outf);
+ total += fputc((value >> 24) & 0xFF, outf);
+ return total;
+}
+
+static int write16_le(FILE* outf, unsigned int value) {
+ int total = 0;
+ total += fputc(value & 0xFF, outf);
+ total += fputc((value >> 8) & 0xFF, outf);
+ return total;
+}
+
+
+static int loop_callback(void* data) {
+ return (--loop_count <= 0 ? -1 : 0);
+}
+
+
+int main(int argc, const char *argv[])
+{
+ DUH *duh;
+ DUH_SIGRENDERER *sr;
+
+ const char *fn = NULL;
+ const char *fn_out = NULL;
+ FILE *outf;
+
+ int depth = 16;
+ int unsign = 0;
+ int freq = 44100;
+ int n_channels = 2;
+ int solo = -1;
+ float volume = 1.0f;
+ float delay = 0.0f;
+ float delta;
+ int bufsize;
+ clock_t start, end;
+ int data_written = 0; /* total bytes written to data chunk */
+
+ int i = 1;
+
+ LONG_LONG length;
+ LONG_LONG done;
+ int dots;
+
+ while (i < argc) {
+ const char *arg = argv[i++];
+ if (*arg != '-') {
+ if (fn) {
+ fprintf(stderr,
+ "Cannot specify multiple filenames!\n"
+ "Second filename found: \"%s\"\n", arg);
+ return 1;
+ }
+ fn = arg;
+ continue;
+ }
+ arg++;
+ while (*arg) {
+ char *endptr;
+ switch (*arg++) {
+ case 'o':
+ case 'O':
+ if (i >= argc) {
+ fprintf(stderr, "Out of arguments; output filename expected!\n");
+ return 1;
+ }
+ fn_out = argv[i++];
+ break;
+ case 'd':
+ case 'D':
+ if (i >= argc) {
+ fprintf(stderr, "Out of arguments; delay expected!\n");
+ return 1;
+ }
+ delay = (float)strtod(argv[i++], &endptr);
+ if (*endptr != 0 || delay < 0.0f || delay > 64.0f) {
+ fprintf(stderr, "Invalid delay!\n");
+ return 1;
+ }
+ break;
+ case 'v':
+ case 'V':
+ if (i >= argc) {
+ fprintf(stderr, "Out of arguments; volume expected!\n");
+ return 1;
+ }
+ volume = (float)strtod(argv[i++], &endptr);
+ if (*endptr != 0 || volume < -8.0f || volume > 8.0f) {
+ fprintf(stderr, "Invalid volume!\n");
+ return 1;
+ }
+ break;
+ case 's':
+ case 'S':
+ if (i >= argc) {
+ fprintf(stderr, "Out of arguments; sampling rate expected!\n");
+ return 1;
+ }
+ freq = strtol(argv[i++], &endptr, 10);
+ if (*endptr != 0 || freq < 1 || freq > 960000) {
+ fprintf(stderr, "Invalid sampling rate!\n");
+ return 1;
+ }
+ break;
+ case 'f':
+ depth = 32;
+ break;
+ case '8':
+ depth = 8;
+ break;
+ case 'l':
+ case 'L':
+ if (i >= argc) {
+ fprintf(stderr, "Out of arguments: loop count expected!\n");
+ return 1;
+ }
+ loop_count = strtol(argv[i++], &endptr, 10);
+ break;
+ case 'm':
+ case 'M':
+ n_channels = 1;
+ break;
+ case 'u':
+ case 'U':
+ unsign = 1;
+ break;
+ case 'r':
+ case 'R':
+ if (i >= argc) {
+ fprintf(stderr, "Out of arguments; resampling quality expected!\n");
+ return 1;
+ }
+ dumb_resampling_quality = strtol(argv[i++], &endptr, 10);
+ if (*endptr != 0 || dumb_resampling_quality < 0 || dumb_resampling_quality > 2) {
+ fprintf(stderr, "Invalid resampling quality!\n");
+ return 1;
+ }
+ break;
+ case 'c':
+ case 'C':
+ if (i >= argc) {
+ fprintf(stderr, "Out of arguments; channel number expected!\n");
+ return 1;
+ }
+ solo = strtol(argv[i++], &endptr, 10);
+ if (*endptr != 0 || solo < 0 || solo >= DUMB_IT_N_CHANNELS) {
+ fprintf(stderr, "Invalid channel number!\n");
+ return 1;
+ }
+ break;
+ default:
+ fprintf(stderr, "Invalid switch - '%c'!\n", isprint(arg[-1]) ? arg[-1] : '?');
+ return 1;
+ }
+ }
+ }
+
+ if (!fn) {
+ fprintf(stderr,
+ "Usage: dumb2wav [options] module [more-options]\n"
+ "\n"
+ "The module can be any IT, XM, S3M or MOD file. It will be rendered to a .wav\n"
+ "file of the same name, unless you specify otherwise with the -o option.\n"
+ "\n"
+ "The valid options are:\n"
+ "-o <file> specify the output filename (defaults to the input filename with\n"
+ " the extension replaced with .wav); use - to write to standard\n"
+ " output or . to write nowhere (useful for measuring DUMB's\n"
+ " performance, and DOS and Windows don't have /dev/null!)\n"
+ "-d <delay> set the initial delay, in seconds (default 0.0)\n"
+ "-v <volume> adjust the volume (default 1.0)\n"
+ "-s <freq> set the sampling rate in Hz (default 44100)\n"
+ "-8 generate 8-bit instead of 16-bit\n"
+ "-f generate floating point samples instead of 16-bit\n"
+ "-m generate mono output instead of stereo left/right pairs\n"
+ "-u generated unsigned output instead of signed\n"
+ "-r <value> specify the resampling quality to use\n"
+ "-l <value> specify the number of times to loop (default 1)\n"
+ "-c <value> specify a channel number to solo\n");
+ return 1;
+ }
+
+ atexit(&dumb_exit);
+ dumb_register_stdfiles();
+
+ dumb_it_max_to_mix = 256;
+
+ duh = load_duh(fn);
+ if (!duh) {
+ duh = dumb_load_it(fn);
+ if (!duh) {
+ duh = dumb_load_xm(fn);
+ if (!duh) {
+ duh = dumb_load_s3m(fn);
+ if (!duh) {
+ duh = dumb_load_mod(fn);
+ if (!duh) {
+ fprintf(stderr, "Unable to open %s!\n", fn);
+ return 1;
+ }
+ }
+ }
+ }
+ }
+
+ sr = duh_start_sigrenderer(duh, 0, n_channels, 0);
+ if (!sr) {
+ unload_duh(duh);
+ fprintf(stderr, "Unable to play file!\n");
+ return 1;
+ }
+
+ if (solo >= 0) {
+ DUMB_IT_SIGRENDERER * itsr = duh_get_it_sigrenderer(sr);
+ if (itsr) {
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
+ if (i != solo) {
+ IT_CHANNEL * channel = &itsr->channel[i];
+ IT_PLAYING * playing = channel->playing;
+ channel->flags |= IT_CHANNEL_MUTED;
+ /* start_sigrenderer leaves me all of the channels the first tick triggered */
+ if (playing) {
+ playing->ramp_volume[0] = 0;
+ playing->ramp_volume[1] = 0;
+ playing->ramp_delta[0] = 0;
+ playing->ramp_delta[1] = 0;
+ }
+ }
+ }
+ }
+ }
+
+ if (fn_out) {
+ if (fn_out[0] == '-' && fn_out[1] == 0)
+ outf = stdout;
+ else if (fn_out[0] == '.' && fn_out[1] == 0)
+ outf = NULL;
+ else {
+ outf = fopen(fn_out, "wb");
+ if (!outf) {
+ fprintf(stderr, "Unable to open %s for writing!\n", fn_out);
+ duh_end_sigrenderer(sr);
+ unload_duh(duh);
+ return 1;
+ }
+ }
+ } else {
+ char *extptr = NULL, *p;
+ char *fn_out = malloc(strlen(fn)+5);
+ if (!fn_out) {
+ fprintf(stderr, "Out of memory!\n");
+ duh_end_sigrenderer(sr);
+ unload_duh(duh);
+ return 1;
+ }
+ strcpy(fn_out, fn);
+ for (p = fn_out; *p; p++)
+ if (*p == '.') extptr = p;
+ if (!extptr) extptr = p;
+ strcpy(extptr, ".wav");
+ outf = fopen(fn_out, "wb");
+ if (!outf) {
+ fprintf(stderr, "Unable to open %s for writing!\n", fn_out);
+ free(fn_out);
+ duh_end_sigrenderer(sr);
+ unload_duh(duh);
+ return 1;
+ }
+ free(fn_out);
+ }
+
+ {
+ DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sr);
+ dumb_it_set_ramp_style(itsr, 2);
+ dumb_it_set_loop_callback(itsr, loop_callback, NULL);
+ dumb_it_set_xm_speed_zero_callback(itsr, &dumb_it_callback_terminate, NULL);
+ dumb_it_set_global_volume_zero_callback(itsr, &dumb_it_callback_terminate, NULL);
+ }
+
+
+ if (outf) {
+ /* write RIFF header: fill file length later */
+ fwrite("RIFF", 1, 4, outf);
+ fwrite(" ", 1, 4, outf);
+ fwrite("WAVE", 1, 4, outf);
+
+ /* write format chunk */
+ fwrite("fmt ", 1, 4, outf);
+
+ if (depth == 32)
+ {
+ write32_le(outf, 18);
+ write16_le(outf, 3);
+ }
+ else
+ {
+ write32_le(outf, 16); /* header length */
+ write16_le(outf, 1); /* WAVE_FORMAT_PCM */
+ }
+ write16_le(outf, n_channels); /* channel count */
+ write32_le(outf, freq); /* frequency */
+ write32_le(outf, freq * n_channels * depth / 8); /*bytes/sec*/
+ write16_le(outf, n_channels * depth / 8); /* block alignment */
+ write16_le(outf, depth); /* bits per sample */
+
+ if (depth == 32)
+ {
+ write16_le(outf, 0);
+ }
+
+ /* start data chunk */
+ fwrite("data", 1, 4, outf);
+ fwrite(" ", 1, 4, outf); /* fill in later */
+ }
+
+ length = (LONG_LONG)_dumb_it_build_checkpoints(duh_get_it_sigdata(duh), 0) * freq >> 16;
+ done = 0;
+ dots = 0;
+ delta = 65536.0f / freq;
+ bufsize = sizeof(buffer);
+ if (depth == 32) bufsize /= sizeof(*buffer.s32);
+ else if (depth == 16) bufsize /= sizeof(*buffer.s16);
+ bufsize /= n_channels;
+
+ if (depth == 32) {
+ internal_buffer = create_sample_buffer(n_channels, bufsize);
+ if (!internal_buffer) {
+ fprintf(stderr, "Out of memory!\n");
+ duh_end_sigrenderer(sr);
+ unload_duh(duh);
+ }
+ }
+
+ {
+ long l = (long)floor(delay * freq + 0.5f);
+ l *= n_channels * (depth >> 3);
+ if (l) {
+ if (unsign && depth != 32) {
+ if (depth == 16) {
+ for (i = 0; i < 8192; i++) {
+ buffer.s8[i*2] = 0x00;
+ buffer.s8[i*2+1] = 0x80;
+ }
+ } else
+ memset(buffer.s8, 0x80, 16384);
+ } else
+ memset(buffer.s8, 0, 16384);
+ while (l >= 16384) {
+ if (outf) fwrite(buffer.s8, 1, 16384, outf);
+ l -= 16384;
+ data_written += 16384;
+ }
+ if (l) {
+ if (outf) fwrite(buffer.s8, 1, l, outf);
+ data_written += 1;
+ }
+ }
+ }
+
+ start = clock();
+
+ fprintf(stderr, "................................................................\n");
+ for (;;) {
+ int write_size;
+ int l;
+
+ if (depth != 32) {
+ l = duh_render(sr, depth, unsign, volume, delta, bufsize, &buffer);
+ if (depth == 16) {
+ for (i = 0; i < l * n_channels; i++) {
+ short val = buffer.s16[i];
+ buffer.s8[i*2] = val;
+ buffer.s8[i*2+1] = val >> 8;
+ }
+ }
+ } else {
+ int j;
+ dumb_silence(internal_buffer[0], bufsize * n_channels);
+ l = duh_sigrenderer_get_samples(sr, volume, delta, bufsize, internal_buffer);
+ for (i = 0; i < n_channels; i++) {
+ for (j = 0; j < l; j++) {
+ buffer.s32[j * n_channels + i] = (float)((double)internal_buffer[i][j] * (1.0 / (double)(0x800000)));
+ }
+ }
+ }
+ write_size = l * n_channels * (depth >> 3);
+ if (outf) fwrite(buffer.s8, 1, write_size, outf);
+ data_written += write_size;
+ if (l < bufsize) break;
+ done += l;
+ l = done * 64 / length;
+ while (dots < 64 && l > dots) {
+ fprintf(stderr, "|");
+ dots++;
+ }
+ if (dots >= 64) {
+ putchar('\n');
+ dots = 0;
+ done = 0;
+ }
+ }
+
+ while (64 > dots) {
+ fprintf(stderr, "|");
+ dots++;
+ }
+ fprintf(stderr, "\n");
+
+ end = clock();
+
+ if (depth == 32) destroy_sample_buffer(internal_buffer);
+
+ /* fill in blanks we left in WAVE file */
+ if (outf) {
+ /* file size, not including RIFF header */
+ const int fmt_size = 8 + ((depth == 32) ? 18 : 16);
+ const int data_size = 8 + data_written;
+ const int file_size = fmt_size + data_size;
+
+ /* can we seek stdout? */
+ fseek(outf, 4, SEEK_SET);
+ write32_le(outf, file_size);
+
+ fseek(outf, 12 + fmt_size + 4, SEEK_SET);
+ write32_le(outf, data_written);
+ }
+
+
+ duh_end_sigrenderer(sr);
+ unload_duh(duh);
+ if (outf && outf != stdout) fclose(outf);
+
+ fprintf(stderr, "Elapsed time: %f seconds\n", (end - start) / (float)CLOCKS_PER_SEC);
+
+ return 0;
+}
diff --git a/plugins/dumb/dumb-kode54/examples/dumbout.c b/plugins/dumb/dumb-kode54/examples/dumbout.c
index 3082b3b4..1ca85adf 100644
--- a/plugins/dumb/dumb-kode54/examples/dumbout.c
+++ b/plugins/dumb/dumb-kode54/examples/dumbout.c
@@ -12,8 +12,8 @@
* | < / \_
* By entheh. | \/ /\ /
* \_ / > /
- * | \ / /
- * | ' /
+ * This example demonstrates how to use DUMB without | \ / /
+ * using Allegro. | ' /
* \__/
*/
@@ -25,15 +25,12 @@
#include <string.h>
#include <dumb.h>
-#include <internal/it.h>
union {
- float s32[4096];
short s16[8192];
char s8[16384];
} buffer;
-sample_t ** internal_buffer;
int main(int argc, const char *const *argv) /* I'm const-crazy! */
{
@@ -49,7 +46,6 @@ int main(int argc, const char *const *argv) /* I'm const-crazy! */
int unsign = 0;
int freq = 44100;
int n_channels = 2;
- int solo = -1;
float volume = 1.0f;
float delay = 0.0f;
float delta;
@@ -69,7 +65,7 @@ int main(int argc, const char *const *argv) /* I'm const-crazy! */
fprintf(stderr,
"Cannot specify multiple filenames!\n"
"Second filename found: \"%s\"\n", arg);
- return 1;
+ return EXIT_FAILURE;
}
fn = arg;
continue;
@@ -82,7 +78,7 @@ int main(int argc, const char *const *argv) /* I'm const-crazy! */
case 'O':
if (i >= argc) {
fprintf(stderr, "Out of arguments; output filename expected!\n");
- return 1;
+ return EXIT_FAILURE;
}
fn_out = argv[i++];
break;
@@ -90,41 +86,38 @@ int main(int argc, const char *const *argv) /* I'm const-crazy! */
case 'D':
if (i >= argc) {
fprintf(stderr, "Out of arguments; delay expected!\n");
- return 1;
+ return EXIT_FAILURE;
}
delay = (float)strtod(argv[i++], &endptr);
if (*endptr != 0 || delay < 0.0f || delay > 64.0f) {
fprintf(stderr, "Invalid delay!\n");
- return 1;
+ return EXIT_FAILURE;
}
break;
case 'v':
case 'V':
if (i >= argc) {
fprintf(stderr, "Out of arguments; volume expected!\n");
- return 1;
+ return EXIT_FAILURE;
}
volume = (float)strtod(argv[i++], &endptr);
if (*endptr != 0 || volume < -8.0f || volume > 8.0f) {
fprintf(stderr, "Invalid volume!\n");
- return 1;
+ return EXIT_FAILURE;
}
break;
case 's':
case 'S':
if (i >= argc) {
fprintf(stderr, "Out of arguments; sampling rate expected!\n");
- return 1;
+ return EXIT_FAILURE;
}
freq = strtol(argv[i++], &endptr, 10);
if (*endptr != 0 || freq < 1 || freq > 960000) {
fprintf(stderr, "Invalid sampling rate!\n");
- return 1;
+ return EXIT_FAILURE;
}
break;
- case 'f':
- depth = 32;
- break;
case '8':
depth = 8;
break;
@@ -144,29 +137,17 @@ int main(int argc, const char *const *argv) /* I'm const-crazy! */
case 'R':
if (i >= argc) {
fprintf(stderr, "Out of arguments; resampling quality expected!\n");
- return 1;
+ return EXIT_FAILURE;
}
dumb_resampling_quality = strtol(argv[i++], &endptr, 10);
if (*endptr != 0 || dumb_resampling_quality < 0 || dumb_resampling_quality > 2) {
fprintf(stderr, "Invalid resampling quality!\n");
- return 1;
- }
- break;
- case 'c':
- case 'C':
- if (i >= argc) {
- fprintf(stderr, "Out of arguments; channel number expected!\n");
- return 1;
- }
- solo = strtol(argv[i++], &endptr, 10);
- if (*endptr != 0 || solo < 0 || solo >= DUMB_IT_N_CHANNELS) {
- fprintf(stderr, "Invalid channel number!\n");
- return 1;
+ return EXIT_FAILURE;
}
break;
default:
fprintf(stderr, "Invalid switch - '%c'!\n", isprint(arg[-1]) ? arg[-1] : '?');
- return 1;
+ return EXIT_FAILURE;
}
}
}
@@ -187,21 +168,28 @@ int main(int argc, const char *const *argv) /* I'm const-crazy! */
"-v <volume> adjust the volume (default 1.0)\n"
"-s <freq> set the sampling rate in Hz (default 44100)\n"
"-8 generate 8-bit instead of 16-bit\n"
- "-f generate 32-bit floating point data instead of 16-bit\n"
"-b generate big-endian data instead of little-endian (meaningless when\n"
" using -8)\n"
"-m generate mono output instead of stereo left/right pairs\n"
"-u generated unsigned output instead of signed\n"
- "-r <value> specify the resampling quality to use\n"
- "-c <value> specify a channel number to solo\n");
- return 1;
+ "-r <value> specify the resampling quality to use\n");
+ return EXIT_FAILURE;
}
+ /* Initialisation, as in dumbplay.c, except this time we have to
+ * register stdio files since we're not using Allegro.
+ */
atexit(&dumb_exit);
dumb_register_stdfiles();
+ /* Mix as many voices as possible. DUMB only maintains state for 256
+ * of them.
+ */
dumb_it_max_to_mix = 256;
+ /* We may as well try and load a .duh file too, even though that file
+ * format will probably never materialise. :)
+ */
duh = load_duh(fn);
if (!duh) {
duh = dumb_load_it(fn);
@@ -213,38 +201,22 @@ int main(int argc, const char *const *argv) /* I'm const-crazy! */
duh = dumb_load_mod(fn);
if (!duh) {
fprintf(stderr, "Unable to open %s!\n", fn);
- return 1;
+ return EXIT_FAILURE;
}
}
}
}
}
+ /* This is equivalent to al_start_duh(), except the object returned
+ * contains playback state alone and no Allegro audio stream. We can
+ * get samples from it on demand.
+ */
sr = duh_start_sigrenderer(duh, 0, n_channels, 0);
if (!sr) {
unload_duh(duh);
fprintf(stderr, "Unable to play file!\n");
- return 1;
- }
-
- if (solo >= 0) {
- DUMB_IT_SIGRENDERER * itsr = duh_get_it_sigrenderer(sr);
- if (itsr) {
- for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
- if (i != solo) {
- IT_CHANNEL * channel = &itsr->channel[i];
- IT_PLAYING * playing = channel->playing;
- channel->flags |= IT_CHANNEL_MUTED;
- /* start_sigrenderer leaves me all of the channels the first tick triggered */
- if (playing) {
- playing->ramp_volume[0] = 0;
- playing->ramp_volume[1] = 0;
- playing->ramp_delta[0] = 0;
- playing->ramp_delta[1] = 0;
- }
- }
- }
- }
+ return EXIT_FAILURE;
}
if (fn_out) {
@@ -258,7 +230,7 @@ int main(int argc, const char *const *argv) /* I'm const-crazy! */
fprintf(stderr, "Unable to open %s for writing!\n", fn_out);
duh_end_sigrenderer(sr);
unload_duh(duh);
- return 1;
+ return EXIT_FAILURE;
}
}
} else {
@@ -268,7 +240,7 @@ int main(int argc, const char *const *argv) /* I'm const-crazy! */
fprintf(stderr, "Out of memory!\n");
duh_end_sigrenderer(sr);
unload_duh(duh);
- return 1;
+ return EXIT_FAILURE;
}
strcpy(fn_out, fn);
for (p = fn_out; *p; p++)
@@ -281,52 +253,48 @@ int main(int argc, const char *const *argv) /* I'm const-crazy! */
free(fn_out);
duh_end_sigrenderer(sr);
unload_duh(duh);
- return 1;
+ return EXIT_FAILURE;
}
free(fn_out);
}
+ /* Install dumb_it_callback_terminate() as the loop and XM speed zero
+ * callbacks. That means DUMB will stop generating samples
+ * immediately upon either of these events occurring.
+ * The callback function itself is provided by DUMB.
+ */
{
DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sr);
- dumb_it_set_ramp_style(itsr, 2);
dumb_it_set_loop_callback(itsr, &dumb_it_callback_terminate, NULL);
dumb_it_set_xm_speed_zero_callback(itsr, &dumb_it_callback_terminate, NULL);
- dumb_it_set_global_volume_zero_callback(itsr, &dumb_it_callback_terminate, NULL);
}
- length = (LONG_LONG)_dumb_it_build_checkpoints(duh_get_it_sigdata(duh), 0) * freq >> 16;
+ /* This length value is not accurate. It is only used for the
+ * progress bar.
+ */
+ length = (LONG_LONG)duh_get_length(duh) * freq >> 16;
done = 0;
dots = 0;
delta = 65536.0f / freq;
- bufsize = sizeof(buffer);
- if (depth == 32) bufsize /= sizeof(*buffer.s32);
- else if (depth == 16) bufsize /= sizeof(*buffer.s16);
+ bufsize = depth == 16 ? 8192 : 16384;
bufsize /= n_channels;
- if (depth == 32) {
- internal_buffer = create_sample_buffer(n_channels, bufsize);
- if (!internal_buffer) {
- fprintf(stderr, "Out of memory!\n");
- duh_end_sigrenderer(sr);
- unload_duh(duh);
- }
- }
-
+ /* Write the initial delay to the file if one was requested. */
{
long l = (long)floor(delay * freq + 0.5f);
l *= n_channels * (depth >> 3);
if (l) {
- if (unsign && depth != 32) {
+ if (unsign) {
if (depth == 16) {
if (bigendian) {
for (i = 0; i < 8192; i++) {
- buffer.s8[i*2] = 0x80;
- buffer.s8[i*2+1] = 0x00;
+ buffer.s8[i*2] = (char)0x80;
+ buffer.s8[i*2+1] = (char)0x00;
}
} else {
for (i = 0; i < 8192; i++) {
- buffer.s8[i*2] = 0x00;
- buffer.s8[i*2+1] = 0x80;
+ buffer.s8[i*2] = (char)0x00;
+ buffer.s8[i*2+1] = (char)0x80;
}
}
} else
@@ -341,43 +309,43 @@ int main(int argc, const char *const *argv) /* I'm const-crazy! */
}
}
+ /* On Linux, clock() is a measure of how much processing time was
+ * used by the program.
+ */
start = clock();
fprintf(stderr, "................................................................\n");
for (;;) {
- int l;
-
- if (depth != 32) {
- l = duh_render(sr, depth, unsign, volume, delta, bufsize, &buffer);
- if (depth == 16) {
- if (bigendian) {
- for (i = 0; i < l * n_channels; i++) {
- short val = buffer.s16[i];
- buffer.s8[i*2] = val >> 8;
- buffer.s8[i*2+1] = val;
- }
- } else {
- for (i = 0; i < l * n_channels; i++) {
- short val = buffer.s16[i];
- buffer.s8[i*2] = val;
- buffer.s8[i*2+1] = val >> 8;
- }
+ /* This is the function that generates samples. It is all
+ * explained in docs/dumb.txt. The return value is the number
+ * of samples generated. If it's less than the buffer size,
+ * we known that it's finished.
+ */
+ int l = duh_render(sr, depth, unsign, volume, delta, bufsize, &buffer);
+ if (depth == 16) {
+ /* If you are only targeting platforms of a specific
+ * endianness or you can find out what endianness the
+ * target platform is, you should be able to
+ * eliminate one case here.
+ */
+ if (bigendian) {
+ for (i = 0; i < l * n_channels; i++) {
+ short val = buffer.s16[i];
+ buffer.s8[i*2] = (char)(val >> 8);
+ buffer.s8[i*2+1] = (char)val;
}
- }
- } else {
- int j;
- dumb_silence(internal_buffer[0], bufsize * n_channels);
- l = duh_sigrenderer_get_samples(sr, volume, delta, bufsize, internal_buffer);
- for (i = 0; i < n_channels; i++) {
- for (j = i; j < l; j++) {
- buffer.s32[j * n_channels] = (float)((double)internal_buffer[i][j] * (1.0 / (double)(0x800000)));
+ } else {
+ for (i = 0; i < l * n_channels; i++) {
+ short val = buffer.s16[i];
+ buffer.s8[i*2] = (char)val;
+ buffer.s8[i*2+1] = (char)(val >> 8);
}
}
}
if (outf) fwrite(buffer.s8, 1, l * n_channels * (depth >> 3), outf);
if (l < bufsize) break;
done += l;
- l = done * 64 / length;
+ l = (int)(done * 64 / length);
while (dots < 64 && l > dots) {
fprintf(stderr, "|");
dots++;
@@ -392,13 +360,12 @@ int main(int argc, const char *const *argv) /* I'm const-crazy! */
end = clock();
- if (depth == 32) destroy_sample_buffer(internal_buffer);
-
+ /* Deallocate stuff and close the output file. */
duh_end_sigrenderer(sr);
unload_duh(duh);
if (outf && outf != stdout) fclose(outf);
fprintf(stderr, "Elapsed time: %f seconds\n", (end - start) / (float)CLOCKS_PER_SEC);
- return 0;
+ return EXIT_SUCCESS;
}
diff --git a/plugins/dumb/dumb-kode54/examples/dumbplay.c b/plugins/dumb/dumb-kode54/examples/dumbplay.c
index 521113f6..c097ea80 100644
--- a/plugins/dumb/dumb-kode54/examples/dumbplay.c
+++ b/plugins/dumb/dumb-kode54/examples/dumbplay.c
@@ -1,238 +1,339 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * dumbplay.c - Not-so-simple program to play / / \ \
- * music. It used to be simpler! | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * IMPORTANT NOTE: This file is not very friendly. | ' /
- * I strongly recommend AGAINST using it as a \__/
- * reference for writing your own code. If you would
- * like to write a program that uses DUMB, or add DUMB to an existing
- * project, please use docs/howto.txt. It will help you a lot more than this
- * file can. (If you have difficulty reading documentation, you are lacking
- * an important coding skill, and now is as good a time as any to learn.)
- */
-
-#include <stdlib.h>
-#include <allegro.h>
-
-#ifndef ALLEGRO_DOS
-#include <string.h>
-#endif
-
-/* Note that your own programs should use <aldumb.h> not "aldumb.h". <> tells
- * the compiler to look in the compiler's default header directory, which is
- * where DUMB should be installed before you use it (make install does this).
- * Use "" when it is your own header file. This example uses "" because DUMB
- * might not have been installed yet when the makefile builds it.
- */
-#include "aldumb.h"
-
-
-
-#ifndef ALLEGRO_DOS
-static volatile int closed = 0;
-static void closehook(void) { closed = 1; }
-#else
-#define closed 0
-#endif
-
-#ifdef ALLEGRO_WINDOWS
-#define GFX_DUMB_MODE GFX_GDI
-#include <winalleg.h>
-#define YIELD() Sleep(1)
-#else
-#define GFX_DUMB_MODE GFX_AUTODETECT_WINDOWED
-#ifdef ALLEGRO_UNIX
-#include <sys/time.h>
-static void YIELD(void)
-{
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 1;
- select(0, NULL, NULL, NULL, &tv);
-}
-#else
-#define YIELD() yield_timeslice()
-#endif
-#endif
-
-
-
-#ifdef ALLEGRO_DOS
-static int loop_callback(void *data)
-{
- (void)data;
- printf("Music has looped.\n");
- return 0;
-}
-
-static int xm_speed_zero_callback(void *data)
-{
- (void)data;
- printf("Music has stopped.\n");
- return 0;
-}
-#else
-static int gfx_half_width;
-
-static int loop_callback(void *data)
-{
- (void)data;
- if (gfx_half_width) {
- acquire_screen();
- textout_centre(screen, font, "Music has looped.", gfx_half_width, 36, 10);
- release_screen();
- }
- return 0;
-}
-
-static int xm_speed_zero_callback(void *data)
-{
- (void)data;
- if (gfx_half_width) {
- text_mode(0); /* In case this is overwriting "Music has looped." */
- acquire_screen();
- textout_centre(screen, font, "Music has stopped.", gfx_half_width, 36, 10);
- release_screen();
- }
- return 0;
-}
-#endif
-
-
-
-static void usage(const char *exename)
-{
- allegro_message(
-#ifdef ALLEGRO_WINDOWS
- "Usage:\n"
- " At the command line: %s file\n"
- " In Windows Explorer: drag a file on to this program's icon.\n"
-#else
- "Usage: %s file\n"
-#endif
- "This will play the music file specified.\n"
- "File formats supported: IT XM S3M MOD.\n"
- "You can control playback quality by editing dumb.ini.\n", exename);
-
- exit(1);
-}
-
-
-
-int main(int argc, const char *const *argv) /* I'm const-crazy! */
-{
- DUH *duh;
- AL_DUH_PLAYER *dp;
-
- if (allegro_init())
- return 1;
-
- if (argc != 2)
- usage(argv[0]);
-
- set_config_file("dumb.ini");
-
- if (install_keyboard()) {
- allegro_message("Failed to initialise keyboard driver!\n");
- return 1;
- }
-
- set_volume_per_voice(0);
-
- if (install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL)) {
- allegro_message("Failed to initialise sound driver!\n%s\n", allegro_error);
- return 1;
- }
-
- atexit(&dumb_exit);
-
- dumb_register_packfiles();
-
- duh = dumb_load_it(argv[1]);
- if (!duh) {
- duh = dumb_load_xm(argv[1]);
- if (!duh) {
- duh = dumb_load_s3m(argv[1]);
- if (!duh) {
- duh = dumb_load_mod(argv[1]);
- if (!duh) {
- allegro_message("Failed to load %s!\n", argv[1]);
- return 1;
- }
- }
- }
- }
-
- dumb_resampling_quality = get_config_int("sound", "dumb_resampling_quality", 4);
- dumb_it_max_to_mix = get_config_int("sound", "dumb_it_max_to_mix", 128);
-
-#ifndef ALLEGRO_DOS
- {
- const char *fn = get_filename(argv[1]);
- gfx_half_width = strlen(fn);
- if (gfx_half_width < 22) gfx_half_width = 22;
- gfx_half_width = (gfx_half_width + 2) * 4;
-
- /* set_window_title() is not const-correct (yet). */
- set_window_title((char *)"DUMB Music Player");
-
- if (set_gfx_mode(GFX_DUMB_MODE, gfx_half_width*2, 80, 0, 0) == 0) {
- acquire_screen();
- textout_centre(screen, font, fn, gfx_half_width, 20, 14);
- textout_centre(screen, font, "Press any key to exit.", gfx_half_width, 52, 11);
- release_screen();
- } else
- gfx_half_width = 0;
- }
-
-#if ALLEGRO_VERSION*10000 + ALLEGRO_SUB_VERSION*100 + ALLEGRO_WIP_VERSION >= 40105
- set_close_button_callback(&closehook);
-#else
- set_window_close_hook(&closehook);
-#endif
-
-#endif
-
- set_display_switch_mode(SWITCH_BACKGROUND);
-
- dp = al_start_duh(duh, 2, 0, 1.0f,
- get_config_int("sound", "buffer_size", 4096),
- get_config_int("sound", "sound_freq", 44100));
-
- {
- DUH_SIGRENDERER *sr = al_duh_get_sigrenderer(dp);
- DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sr);
- dumb_it_set_loop_callback(itsr, &loop_callback, NULL);
- dumb_it_set_xm_speed_zero_callback(itsr, &xm_speed_zero_callback, NULL);
- }
-
- for (;;) {
- if (keypressed()) {
- readkey();
- break;
- }
-
- if (al_poll_duh(dp) || closed)
- break;
-
- YIELD();
- }
-
- al_stop_duh(dp);
-
- unload_duh(duh);
-
- return 0;
-}
-END_OF_MAIN();
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * dumbplay.c - Not-so-simple program to play / / \ \
+ * music. It used to be simpler! | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * If this example does not explain everything you | ' /
+ * need to know, or you write your own code and it \__/
+ * doesn't work, please refer to docs/howto.txt for
+ * step-by-step instructions or docs/dumb.txt for a detailed description of
+ * each of DUMB's functions.
+ */
+
+#include <stdlib.h>
+#include <allegro.h>
+
+#ifndef ALLEGRO_DOS
+#include <string.h>
+#endif
+
+/* Note that your own programs should use <aldumb.h> not "aldumb.h". <> tells
+ * the compiler to look in the compiler's default header directory, which is
+ * where DUMB should be installed before you use it (make install does this).
+ * Use "" when it is your own header file. This example uses "" because DUMB
+ * might not have been installed yet when the makefile builds it.
+ */
+#include "aldumb.h"
+
+
+
+/* Hook function to be called when the close button is clicked. If the
+ * variable is set, the program will exit. Not needed in DOS.
+ */
+#ifndef ALLEGRO_DOS
+ static volatile int closed = 0;
+ static void closehook(void) { closed = 1; }
+#else
+# define closed 0
+#endif
+
+
+/* Platform-specific code. We use GDI in Windows since there's no point in
+ * using an accelerated graphics driver. If we can, we define our own YIELD()
+ * function that allows the system to sleep when it has nothing to do. This
+ * may now be part of Allegro, but I haven't kept up with it. You can ignore
+ * this stuff.
+ */
+#ifdef ALLEGRO_WINDOWS
+# define GFX_DUMB_MODE GFX_GDI
+# include <winalleg.h>
+# define YIELD() Sleep(1)
+#else
+# define GFX_DUMB_MODE GFX_AUTODETECT_WINDOWED
+# ifdef ALLEGRO_UNIX
+# include <sys/time.h>
+ static void YIELD(void)
+ {
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 1;
+ select(0, NULL, NULL, NULL, &tv);
+ }
+# else
+# define YIELD() yield_timeslice()
+# endif
+#endif
+
+
+
+/* Playback flow callback functions. In DOS we don't set a graphics mode, so
+ * we can print a message to the console when a callback is invoked. On other
+ * platforms, we add a message to the window the program has created.
+ */
+#ifdef ALLEGRO_DOS
+ static int loop_callback(void *data)
+ {
+ (void)data;
+ printf("Music has looped.\n");
+ return 0;
+ }
+
+ static int xm_speed_zero_callback(void *data)
+ {
+ (void)data;
+ printf("Music has stopped.\n");
+ return 0;
+ }
+#else
+ static int gfx_half_width;
+
+ static int loop_callback(void *data)
+ {
+ (void)data;
+ if (gfx_half_width) {
+ acquire_screen();
+ textout_centre(screen, font, "Music has looped.", gfx_half_width, 36, 10);
+ release_screen();
+ }
+ return 0;
+ }
+
+ static int xm_speed_zero_callback(void *data)
+ {
+ (void)data;
+ if (gfx_half_width) {
+ text_mode(0); /* In case this is overwriting "Music has looped." */
+ acquire_screen();
+ textout_centre(screen, font, "Music has stopped.", gfx_half_width, 36, 10);
+ release_screen();
+ }
+ return 0;
+ }
+#endif
+
+
+
+static void usage(const char *exename)
+{
+ allegro_message(
+#ifdef ALLEGRO_WINDOWS
+ "Usage:\n"
+ " At the command line: %s file\n"
+ " In Windows Explorer: drag a file on to this program's icon.\n"
+#else
+ "Usage: %s file\n"
+#endif
+ "This will play the music file specified.\n"
+ "File formats supported: IT XM S3M MOD.\n"
+ "You can control playback quality by editing dumb.ini.\n", exename);
+
+ exit(1);
+}
+
+
+
+int main(int argc, const char *const *argv) /* I'm const-crazy! */
+{
+ DUH *duh; /* Encapsulates the music file. */
+ AL_DUH_PLAYER *dp; /* Holds the current playback state. */
+
+ /* Initialise Allegro */
+ if (allegro_init())
+ return EXIT_FAILURE;
+
+ /* Check that we have one argument (plus the executable name). */
+ if (argc != 2)
+ usage(argv[0]);
+
+ /* Tell Allegro where to find configuration data. This means you can
+ * put any settings for Allegro in dumb.ini. See Allegro's
+ * documentation for more information.
+ */
+ set_config_file("dumb.ini");
+
+ /* Initialise Allegro's keyboard input. */
+ if (install_keyboard()) {
+ allegro_message("Failed to initialise keyboard driver!\n");
+ return EXIT_FAILURE;
+ }
+
+ /* This function call is appropriate for a program that will play one
+ * sample or one audio stream at a time. If you have sound effects
+ * too, you may want to increase the parameter. See Allegro's
+ * documentation for details on what the parameter means. Note that
+ * newer versions of Allegro act as if set_volume_per_voice() was
+ * called with parameter 1 initially, while older versions behave as
+ * if -1 was passed, so you should call the function if you want
+ * consistent behaviour.
+ */
+ set_volume_per_voice(0);
+
+ /* Initialise Allegro's sound output system. */
+ if (install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL)) {
+ allegro_message("Failed to initialise sound driver!\n%s\n", allegro_error);
+ return EXIT_FAILURE;
+ }
+
+ /* dumb_exit() is a function defined by DUMB. This operation arranges
+ * for dumb_exit() to be called last thing before the program exits.
+ * dumb_exit() does a bit of cleaning up for you. atexit() is
+ * declared in stdlib.h.
+ */
+ atexit(&dumb_exit);
+
+ /* DUMB defines its own wrappers for file input. There is a struct
+ * called DUMBFILE that holds function pointers for the various file
+ * operations needed by DUMB. You can decide whether to use stdio
+ * FILE objects, Allegro's PACKFILEs or something else entirely. No
+ * wrapper is installed initially, so you must call this or
+ * dumb_register_stdfiles() or set up your own before trying to load
+ * modules by file name. (If you are using another method, such as
+ * loading an Allegro datafile with modules embedded in it, then DUMB
+ * never opens a file by file name so this doesn't apply.)
+ */
+ dumb_register_packfiles();
+
+ /* Load the module file into a DUH object. Quick and dirty: try the
+ * loader for each format until one succeeds. Note that 15-sample
+ * mods have no identifying features, so dumb_load_mod() may succeed
+ * on files that aren't mods at all. We therefore try that one last.
+ */
+ duh = dumb_load_it(argv[1]);
+ if (!duh) {
+ duh = dumb_load_xm(argv[1]);
+ if (!duh) {
+ duh = dumb_load_s3m(argv[1]);
+ if (!duh) {
+ duh = dumb_load_mod(argv[1]);
+ if (!duh) {
+ allegro_message("Failed to load %s!\n", argv[1]);
+ return EXIT_FAILURE;
+ }
+ }
+ }
+ }
+
+ /* Read the quality values from the config file we told Allegro to
+ * use. You may want to hardcode these or provide a more elaborate
+ * interface via which the user can control them.
+ */
+ dumb_resampling_quality = get_config_int("sound", "dumb_resampling_quality", 4);
+ dumb_it_max_to_mix = get_config_int("sound", "dumb_it_max_to_mix", 128);
+
+ /* If we're not in DOS, show a window and register our close hook
+ * function.
+ */
+# ifndef ALLEGRO_DOS
+ {
+ const char *fn = get_filename(argv[1]);
+ gfx_half_width = strlen(fn);
+ if (gfx_half_width < 22) gfx_half_width = 22;
+ gfx_half_width = (gfx_half_width + 2) * 4;
+
+ /* set_window_title() is not const-correct (yet). */
+ set_window_title((char *)"DUMB Music Player");
+
+ if (set_gfx_mode(GFX_DUMB_MODE, gfx_half_width*2, 80, 0, 0) == 0) {
+ acquire_screen();
+ textout_centre(screen, font, fn, gfx_half_width, 20, 14);
+ textout_centre(screen, font, "Press any key to exit.", gfx_half_width, 52, 11);
+ release_screen();
+ } else
+ gfx_half_width = 0;
+ }
+
+ /* Silly check to get around the fact that someone stupidly removed
+ * an old function from Allegro instead of deprecating it. The old
+ * function was put back a version later, but we may as well use the
+ * new one if it's there!
+ */
+# if ALLEGRO_VERSION*10000 + ALLEGRO_SUB_VERSION*100 + ALLEGRO_WIP_VERSION >= 40105
+ set_close_button_callback(&closehook);
+# else
+ set_window_close_hook(&closehook);
+# endif
+
+# endif
+
+ /* We want to continue running if the user switches to another
+ * application.
+ */
+ set_display_switch_mode(SWITCH_BACKGROUND);
+
+ /* We have the music loaded, but it isn't playing yet. This starts it
+ * playing. We construct a second object, the AL_DUH_PLAYER, to
+ * represent the playing music. This means you can play the music
+ * twice at the same time should you want to!
+ *
+ * Specify the number of channels (2 for stereo), which 'signal' to
+ * play (always 0 for modules), the volume (1.0f for default), the
+ * buffer size (4096 generally works well) and the sampling frequency
+ * (ideally match the final output frequency Allegro is using). An
+ * Allegro audio stream will be started.
+ */
+ dp = al_start_duh(duh, 2, 0, 1.0f,
+ get_config_int("sound", "buffer_size", 4096),
+ get_config_int("sound", "sound_freq", 44100));
+
+ /* Register our callback functions so that they are called when the
+ * music loops or stops. See docs/howto.txt for more information.
+ * There is no threading issue: DUMB will only process playback
+ * in al_poll_duh(), which we call below.
+ */
+ {
+ DUH_SIGRENDERER *sr = al_duh_get_sigrenderer(dp);
+ DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sr);
+ dumb_it_set_loop_callback(itsr, &loop_callback, NULL);
+ dumb_it_set_xm_speed_zero_callback(itsr, &xm_speed_zero_callback, NULL);
+ }
+
+ /* Main loop. */
+ for (;;) {
+ /* Check for keys in the buffer. If we get one, discard it
+ * and exit the main loop.
+ */
+ if (keypressed()) {
+ readkey();
+ break;
+ }
+
+ /* Poll the music. We exit the loop if al_poll_duh() has
+ * returned nonzero (music finished) or the window has been
+ * closed. al_poll_duh() might return nonzero if you have set
+ * up a callback that tells the music to stop.
+ */
+ if (al_poll_duh(dp) || closed)
+ break;
+
+ /* Give other threads a look-in, or allow the processor to
+ * sleep for a bit. YIELD() is defined further up in this
+ * file.
+ */
+ YIELD();
+ }
+
+ /* Remove the audio stream and deallocate the memory being used for
+ * the playback state. We set dp to NULL to emphasise that the object
+ * has gone.
+ */
+ al_stop_duh(dp);
+ dp = NULL;
+
+ /* Free the DUH object containing the actual music data. */
+ unload_duh(duh);
+ duh = NULL;
+
+ /* All done! */
+ return EXIT_SUCCESS;
+}
+END_OF_MAIN();
diff --git a/plugins/dumb/dumb-kode54/examples/playduh.c b/plugins/dumb/dumb-kode54/examples/playduh.c
index 31d7b619..0fb33607 100644
--- a/plugins/dumb/dumb-kode54/examples/playduh.c
+++ b/plugins/dumb/dumb-kode54/examples/playduh.c
@@ -1,169 +1,169 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * playduh.c - Simple program to play DUH files. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <allegro.h>
-
-#ifndef ALLEGRO_DOS
-#include <string.h>
-#endif
-
-/* Note that your own programs should use <aldumb.h> not "aldumb.h". <> tells
- * the compiler to look in the compiler's default header directory, which is
- * where DUMB should be installed before you use it (make install does this).
- * Use "" when it is your own header file. This example uses "" because DUMB
- * might not have been installed yet when the makefile builds it.
- */
-#include "aldumb.h"
-
-
-
-#ifndef ALLEGRO_DOS
-static int closed = 0;
-static void closehook(void) { closed = 1; }
-#else
-#define closed 0
-#endif
-
-#ifdef ALLEGRO_WINDOWS
-#define GFX_DUMB_MODE GFX_GDI
-#include <winalleg.h>
-#define YIELD() Sleep(1)
-#else
-#define GFX_DUMB_MODE GFX_AUTODETECT_WINDOWED
-#ifdef ALLEGRO_UNIX
-#include <sys/time.h>
-static void YIELD(void)
-{
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 1;
- select(0, NULL, NULL, NULL, &tv);
-}
-#else
-#define YIELD() yield_timeslice()
-#endif
-#endif
-
-
-
-static void usage(void)
-{
- allegro_message(
- "Usage: playduh file.duh\n"
- "This will play the .duh file specified.\n"
- "You can control playback quality by editing dumb.ini.\n"
- );
-
- exit(1);
-}
-
-
-
-int main(int argc, char *argv[])
-{
- DUH *duh;
- AL_DUH_PLAYER *dp;
-
- if (allegro_init())
- return 1;
-
- if (argc != 2)
- usage();
-
- set_config_file("dumb.ini");
-
- if (install_keyboard()) {
- allegro_message("Failed to initialise keyboard driver!\n");
- return 1;
- }
-
- set_volume_per_voice(0);
-
- if (install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL)) {
- allegro_message("Failed to initialise sound driver!\n%s\n", allegro_error);
- return 1;
- }
-
- atexit(&dumb_exit);
-
- dumb_register_stdfiles();
-
-/*
- dumb_register_sigtype_sample();
- dumb_register_sigtype_combining();
- dumb_register_sigtype_stereopan();
- dumb_register_sigtype_sequence();
-*/
-
- duh = load_duh(argv[1]);
- if (!duh) {
- allegro_message("Failed to load %s!\n", argv[1]);
- return 1;
- }
-
- dumb_resampling_quality = get_config_int("sound", "dumb_resampling_quality", 4);
- // Are we sure dumb_it_max_to_mix will be unused? Can decide when editor matures...
-
-#ifndef ALLEGRO_DOS
- {
- const char *fn = get_filename(argv[1]);
- int w = strlen(fn);
- if (w < 22) w = 22;
- w = (w + 2) * 4;
-
- set_window_title("DUMB - IT player");
-
- if (set_gfx_mode(GFX_DUMB_MODE, w*2, 80, 0, 0) == 0) {
- acquire_screen();
- textout_centre(screen, font, fn, w, 28, 14);
- textout_centre(screen, font, "Press any key to exit.", w, 44, 11);
- release_screen();
- }
- }
-
- //set_window_close_hook(&closehook);
-#endif
-
- set_display_switch_mode(SWITCH_BACKGROUND);
-
- dp = al_start_duh(duh, 2, 0, 1.0,
- get_config_int("sound", "buffer_size", 4096),
- get_config_int("sound", "sound_freq", 44100));
-
- for (;;) {
- if (keypressed()) {
- readkey();
- break;
- }
-
- if (al_poll_duh(dp) || closed)
- break;
-
- YIELD();
- }
-
- al_stop_duh(dp);
-
- unload_duh(duh);
-
- return 0;
-}
-END_OF_MAIN();
-
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * playduh.c - Simple program to play DUH files. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <allegro.h>
+
+#ifndef ALLEGRO_DOS
+#include <string.h>
+#endif
+
+/* Note that your own programs should use <aldumb.h> not "aldumb.h". <> tells
+ * the compiler to look in the compiler's default header directory, which is
+ * where DUMB should be installed before you use it (make install does this).
+ * Use "" when it is your own header file. This example uses "" because DUMB
+ * might not have been installed yet when the makefile builds it.
+ */
+#include "aldumb.h"
+
+
+
+#ifndef ALLEGRO_DOS
+static int closed = 0;
+static void closehook(void) { closed = 1; }
+#else
+#define closed 0
+#endif
+
+#ifdef ALLEGRO_WINDOWS
+#define GFX_DUMB_MODE GFX_GDI
+#include <winalleg.h>
+#define YIELD() Sleep(1)
+#else
+#define GFX_DUMB_MODE GFX_AUTODETECT_WINDOWED
+#ifdef ALLEGRO_UNIX
+#include <sys/time.h>
+static void YIELD(void)
+{
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 1;
+ select(0, NULL, NULL, NULL, &tv);
+}
+#else
+#define YIELD() yield_timeslice()
+#endif
+#endif
+
+
+
+static void usage(void)
+{
+ allegro_message(
+ "Usage: playduh file.duh\n"
+ "This will play the .duh file specified.\n"
+ "You can control playback quality by editing dumb.ini.\n"
+ );
+
+ exit(1);
+}
+
+
+
+int main(int argc, char *argv[])
+{
+ DUH *duh;
+ AL_DUH_PLAYER *dp;
+
+ if (allegro_init())
+ return 1;
+
+ if (argc != 2)
+ usage();
+
+ set_config_file("dumb.ini");
+
+ if (install_keyboard()) {
+ allegro_message("Failed to initialise keyboard driver!\n");
+ return 1;
+ }
+
+ set_volume_per_voice(0);
+
+ if (install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL)) {
+ allegro_message("Failed to initialise sound driver!\n%s\n", allegro_error);
+ return 1;
+ }
+
+ atexit(&dumb_exit);
+
+ dumb_register_stdfiles();
+
+/*
+ dumb_register_sigtype_sample();
+ dumb_register_sigtype_combining();
+ dumb_register_sigtype_stereopan();
+ dumb_register_sigtype_sequence();
+*/
+
+ duh = load_duh(argv[1]);
+ if (!duh) {
+ allegro_message("Failed to load %s!\n", argv[1]);
+ return 1;
+ }
+
+ dumb_resampling_quality = get_config_int("sound", "dumb_resampling_quality", 4);
+ // Are we sure dumb_it_max_to_mix will be unused? Can decide when editor matures...
+
+#ifndef ALLEGRO_DOS
+ {
+ const char *fn = get_filename(argv[1]);
+ int w = strlen(fn);
+ if (w < 22) w = 22;
+ w = (w + 2) * 4;
+
+ set_window_title("DUMB - IT player");
+
+ if (set_gfx_mode(GFX_DUMB_MODE, w*2, 80, 0, 0) == 0) {
+ acquire_screen();
+ textout_centre(screen, font, fn, w, 28, 14);
+ textout_centre(screen, font, "Press any key to exit.", w, 44, 11);
+ release_screen();
+ }
+ }
+
+ //set_window_close_hook(&closehook);
+#endif
+
+ set_display_switch_mode(SWITCH_BACKGROUND);
+
+ dp = al_start_duh(duh, 2, 0, 1.0,
+ get_config_int("sound", "buffer_size", 4096),
+ get_config_int("sound", "sound_freq", 44100));
+
+ for (;;) {
+ if (keypressed()) {
+ readkey();
+ break;
+ }
+
+ if (al_poll_duh(dp) || closed)
+ break;
+
+ YIELD();
+ }
+
+ al_stop_duh(dp);
+
+ unload_duh(duh);
+
+ return 0;
+}
+END_OF_MAIN();
+
diff --git a/plugins/dumb/dumb-kode54/include/aldumb.h b/plugins/dumb/dumb-kode54/include/aldumb.h
index 015ff946..75262508 100644
--- a/plugins/dumb/dumb-kode54/include/aldumb.h
+++ b/plugins/dumb/dumb-kode54/include/aldumb.h
@@ -1,94 +1,98 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * aldumb.h - The user header file for DUMB with / / \ \
- * Allegro. | < / \_
- * | \/ /\ /
- * Include this file if you wish to use DUMB \_ / > /
- * with Allegro. It will include dumb.h for you, | \ / /
- * and provide extra functionality such as audio | ' /
- * stream and datafile integration. \__/
- */
-
-#ifndef ALDUMB_H
-#define ALDUMB_H
-
-
-#include <allegro.h>
-
-#include "dumb.h"
-
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-
-/* Packfile Support */
-
-void dumb_register_packfiles(void);
-
-DUMBFILE *dumbfile_open_packfile(PACKFILE *p);
-DUMBFILE *dumbfile_from_packfile(PACKFILE *p);
-
-
-/* Datafile Registration Functions */
-
-#define DUMB_DAT_DUH DAT_ID('D','U','H',' ')
-#define DUMB_DAT_IT DAT_ID('I','T',' ',' ')
-#define DUMB_DAT_XM DAT_ID('X','M',' ',' ')
-#define DUMB_DAT_S3M DAT_ID('S','3','M',' ')
-#define DUMB_DAT_MOD DAT_ID('M','O','D',' ')
-
-void dumb_register_dat_duh(long type);
-void dumb_register_dat_it(long type);
-void dumb_register_dat_xm(long type);
-void dumb_register_dat_s3m(long type);
-void dumb_register_dat_mod(long type);
-
-
-/* DUH Playing Functions */
-
-typedef struct AL_DUH_PLAYER AL_DUH_PLAYER;
-
-AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos, float volume, long bufsize, int freq);
-void al_stop_duh(AL_DUH_PLAYER *dp);
-void al_pause_duh(AL_DUH_PLAYER *dp);
-void al_resume_duh(AL_DUH_PLAYER *dp);
-void al_duh_set_priority(AL_DUH_PLAYER *dp, int priority);
-void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume);
-float al_duh_get_volume(AL_DUH_PLAYER *dp);
-int al_poll_duh(AL_DUH_PLAYER *dp);
-long al_duh_get_position(AL_DUH_PLAYER *dp);
-
-AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq);
-DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp);
-
-/* IMPORTANT: This function will return NULL if the music has ended. */
-DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp);
-
-#ifdef DUMB_DECLARE_DEPRECATED
-
-AL_DUH_PLAYER *al_duh_encapsulate_renderer(DUH_SIGRENDERER *dr, float volume, long bufsize, int freq) DUMB_DEPRECATED;
-DUH_SIGRENDERER *al_duh_get_renderer(AL_DUH_PLAYER *dp) DUMB_DEPRECATED;
-DUH_SIGRENDERER *al_duh_decompose_to_renderer(AL_DUH_PLAYER *dp) DUMB_DEPRECATED;
-/* Replace 'renderer' with 'sigrenderer' in each case where you called one of
- * these functions.
- */
-
-#endif
-
-
-#ifdef __cplusplus
- }
-#endif
-
-
-#endif /* ALDUMB_H */
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * aldumb.h - The user header file for DUMB with / / \ \
+ * Allegro. | < / \_
+ * | \/ /\ /
+ * Include this file if you wish to use DUMB \_ / > /
+ * with Allegro. It will include dumb.h for you, | \ / /
+ * and provide extra functionality such as audio | ' /
+ * stream and datafile integration. \__/
+ */
+
+#ifndef ALDUMB_H
+#define ALDUMB_H
+
+
+#include <allegro.h>
+
+#include "dumb.h"
+
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+/* Packfile Support */
+
+void dumb_register_packfiles(void);
+
+DUMBFILE *dumbfile_open_packfile(PACKFILE *p);
+DUMBFILE *dumbfile_from_packfile(PACKFILE *p);
+
+
+/* Datafile Registration Functions */
+
+#define DUMB_DAT_DUH DAT_ID('D','U','H',' ')
+#define DUMB_DAT_IT DAT_ID('I','T',' ',' ')
+#define DUMB_DAT_XM DAT_ID('X','M',' ',' ')
+#define DUMB_DAT_S3M DAT_ID('S','3','M',' ')
+#define DUMB_DAT_MOD DAT_ID('M','O','D',' ')
+
+void dumb_register_dat_duh(long type);
+void dumb_register_dat_it(long type);
+void dumb_register_dat_xm(long type);
+void dumb_register_dat_s3m(long type);
+void dumb_register_dat_mod(long type);
+void dumb_register_dat_it_quick(long type);
+void dumb_register_dat_xm_quick(long type);
+void dumb_register_dat_s3m_quick(long type);
+void dumb_register_dat_mod_quick(long type);
+
+
+/* DUH Playing Functions */
+
+typedef struct AL_DUH_PLAYER AL_DUH_PLAYER;
+
+AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos, float volume, long bufsize, int freq);
+void al_stop_duh(AL_DUH_PLAYER *dp);
+void al_pause_duh(AL_DUH_PLAYER *dp);
+void al_resume_duh(AL_DUH_PLAYER *dp);
+void al_duh_set_priority(AL_DUH_PLAYER *dp, int priority);
+void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume);
+float al_duh_get_volume(AL_DUH_PLAYER *dp);
+int al_poll_duh(AL_DUH_PLAYER *dp);
+long al_duh_get_position(AL_DUH_PLAYER *dp);
+
+AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq);
+DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp);
+
+/* IMPORTANT: This function will return NULL if the music has ended. */
+DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp);
+
+#ifdef DUMB_DECLARE_DEPRECATED
+
+AL_DUH_PLAYER *al_duh_encapsulate_renderer(DUH_SIGRENDERER *dr, float volume, long bufsize, int freq) DUMB_DEPRECATED;
+DUH_SIGRENDERER *al_duh_get_renderer(AL_DUH_PLAYER *dp) DUMB_DEPRECATED;
+DUH_SIGRENDERER *al_duh_decompose_to_renderer(AL_DUH_PLAYER *dp) DUMB_DEPRECATED;
+/* Replace 'renderer' with 'sigrenderer' in each case where you called one of
+ * these functions.
+ */
+
+#endif
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+#endif /* ALDUMB_H */
diff --git a/plugins/dumb/dumb-kode54/include/dumb.h b/plugins/dumb/dumb-kode54/include/dumb.h
index 63718e1e..55391605 100644
--- a/plugins/dumb/dumb-kode54/include/dumb.h
+++ b/plugins/dumb/dumb-kode54/include/dumb.h
@@ -1,744 +1,770 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * dumb.h - The user header file for DUMB. / / \ \
- * | < / \_
- * Include this file in any of your files in | \/ /\ /
- * which you wish to use the DUMB functions \_ / > /
- * and variables. | \ / /
- * | ' /
- * Allegro users, you will probably want aldumb.h. \__/
- */
-
-#ifndef DUMB_H
-#define DUMB_H
-
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#ifdef _DEBUG
-#define _CRTDBG_MAP_ALLOC
-#include <crtdbg.h>
-#endif
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-
-#define DUMB_MAJOR_VERSION 0
-#define DUMB_MINOR_VERSION 9
-#define DUMB_REVISION_VERSION 3
-
-#define DUMB_VERSION (DUMB_MAJOR_VERSION*10000 + DUMB_MINOR_VERSION*100 + DUMB_REVISION_VERSION)
-
-#define DUMB_VERSION_STR "0.9.3"
-
-#define DUMB_NAME "DUMB v"DUMB_VERSION_STR
-
-#define DUMB_YEAR 2005
-#define DUMB_MONTH 8
-#define DUMB_DAY 7
-
-#define DUMB_YEAR_STR2 "05"
-#define DUMB_YEAR_STR4 "2005"
-#define DUMB_MONTH_STR1 "8"
-#define DUMB_DAY_STR1 "7"
-
-#if DUMB_MONTH < 10
-#define DUMB_MONTH_STR2 "0"DUMB_MONTH_STR1
-#else
-#define DUMB_MONTH_STR2 DUMB_MONTH_STR1
-#endif
-
-#if DUMB_DAY < 10
-#define DUMB_DAY_STR2 "0"DUMB_DAY_STR1
-#else
-#define DUMB_DAY_STR2 DUMB_DAY_STR1
-#endif
-
-
-/* WARNING: The month and day were inadvertently swapped in the v0.8 release.
- * Please do not compare this constant against any date in 2002. In
- * any case, DUMB_VERSION is probably more useful for this purpose.
- */
-#define DUMB_DATE (DUMB_YEAR*10000 + DUMB_MONTH*100 + DUMB_DAY)
-
-#define DUMB_DATE_STR DUMB_DAY_STR1"."DUMB_MONTH_STR1"."DUMB_YEAR_STR4
-
-
-#undef MIN
-#undef MAX
-#undef MID
-
-#define MIN(x,y) (((x) < (y)) ? (x) : (y))
-#define MAX(x,y) (((x) > (y)) ? (x) : (y))
-#define MID(x,y,z) MAX((x), MIN((y), (z)))
-
-#undef ABS
-#define ABS(x) (((x) >= 0) ? (x) : (-(x)))
-
-
-#ifdef DEBUGMODE
-
-#ifndef ASSERT
-#include <assert.h>
-#define ASSERT(n) assert(n)
-#endif
-#ifndef TRACE
-// it would be nice if this did actually trace ...
-#define TRACE 1 ? (void)0 : (void)printf
-#endif
-
-#else
-
-#ifndef ASSERT
-#define ASSERT(n)
-#endif
-#ifndef TRACE
-#define TRACE 1 ? (void)0 : (void)printf
-#endif
-
-#endif
-
-
-#define DUMB_ID(a,b,c,d) (((unsigned int)(a) << 24) | \
- ((unsigned int)(b) << 16) | \
- ((unsigned int)(c) << 8) | \
- ((unsigned int)(d) ))
-
-
-
-#ifndef LONG_LONG
-#if defined __GNUC__ || defined __INTEL_COMPILER || defined __MWERKS__
-#define LONG_LONG long long
-#elif defined _MSC_VER || defined __WATCOMC__
-#define LONG_LONG __int64
-#elif defined __sgi
-#define LONG_LONG long long
-#else
-#error 64-bit integer type unknown
-#endif
-#endif
-
-#if __GNUC__ * 100 + __GNUC_MINOR__ >= 301 /* GCC 3.1+ */
-#ifndef DUMB_DECLARE_DEPRECATED
-#define DUMB_DECLARE_DEPRECATED
-#endif
-#define DUMB_DEPRECATED __attribute__((__deprecated__))
-#else
-#define DUMB_DEPRECATED
-#endif
-
-
-/* Basic Sample Type. Normal range is -0x800000 to 0x7FFFFF. */
-
-typedef int sample_t;
-
-
-/* Library Clean-up Management */
-
-int dumb_atexit(void (*proc)(void));
-
-void dumb_exit(void);
-
-
-/* File Input Functions */
-
-typedef struct DUMBFILE_SYSTEM
-{
- void *(*open)(const char *filename);
- int (*skip)(void *f, long n);
- int (*getc)(void *f);
- long (*getnc)(char *ptr, long n, void *f);
- void (*close)(void *f);
-}
-DUMBFILE_SYSTEM;
-
-typedef struct DUMBFILE DUMBFILE;
-
-void register_dumbfile_system(DUMBFILE_SYSTEM *dfs);
-
-DUMBFILE *dumbfile_open(const char *filename);
-DUMBFILE *dumbfile_open_ex(void *file, DUMBFILE_SYSTEM *dfs);
-
-long dumbfile_pos(DUMBFILE *f);
-int dumbfile_skip(DUMBFILE *f, long n);
-
-int dumbfile_getc(DUMBFILE *f);
-
-int dumbfile_igetw(DUMBFILE *f);
-int dumbfile_mgetw(DUMBFILE *f);
-
-long dumbfile_igetl(DUMBFILE *f);
-long dumbfile_mgetl(DUMBFILE *f);
-
-unsigned long dumbfile_cgetul(DUMBFILE *f);
-signed long dumbfile_cgetsl(DUMBFILE *f);
-
-long dumbfile_getnc(char *ptr, long n, DUMBFILE *f);
-
-int dumbfile_error(DUMBFILE *f);
-int dumbfile_close(DUMBFILE *f);
-
-
-/* stdio File Input Module */
-
-void dumb_register_stdfiles(void);
-
-DUMBFILE *dumbfile_open_stdfile(FILE *p);
-
-
-/* Memory File Input Module */
-
-DUMBFILE *dumbfile_open_memory(const char *data, long size);
-
-
-/* DUH Management */
-
-typedef struct DUH DUH;
-
-#define DUH_SIGNATURE DUMB_ID('D','U','H','!')
-
-void unload_duh(DUH *duh);
-
-DUH *load_duh(const char *filename);
-DUH *read_duh(DUMBFILE *f);
-
-long duh_get_length(DUH *duh);
-
-const char *duh_get_tag(DUH *duh, const char *key);
-
-
-/* Signal Rendering Functions */
-
-typedef struct DUH_SIGRENDERER DUH_SIGRENDERER;
-
-DUH_SIGRENDERER *duh_start_sigrenderer(DUH *duh, int sig, int n_channels, long pos);
-
-#ifdef DUMB_DECLARE_DEPRECATED
-typedef void (*DUH_SIGRENDERER_CALLBACK)(void *data, sample_t **samples, int n_channels, long length);
-/* This is deprecated, but is not marked as such because GCC tends to
- * complain spuriously when the typedef is used later. See comments below.
- */
-
-void duh_sigrenderer_set_callback(
- DUH_SIGRENDERER *sigrenderer,
- DUH_SIGRENDERER_CALLBACK callback, void *data
-) DUMB_DEPRECATED;
-/* The 'callback' argument's type has changed for const-correctness. See the
- * DUH_SIGRENDERER_CALLBACK definition just above. Also note that the samples
- * in the buffer are now 256 times as large; the normal range is -0x800000 to
- * 0x7FFFFF. The function has been renamed partly because its functionality
- * has changed slightly and partly so that its name is more meaningful. The
- * new one is duh_sigrenderer_set_analyser_callback(), and the typedef for
- * the function pointer has also changed, from DUH_SIGRENDERER_CALLBACK to
- * DUH_SIGRENDERER_ANALYSER_CALLBACK. (If you wanted to use this callback to
- * apply a DSP effect, don't worry; there is a better way of doing this. It
- * is undocumented, so contact me and I shall try to help. Contact details
- * are in readme.txt.)
- */
-
-typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data, const sample_t *const *samples, int n_channels, long length);
-/* This is deprecated, but is not marked as such because GCC tends to
- * complain spuriously when the typedef is used later. See comments below.
- */
-
-void duh_sigrenderer_set_analyser_callback(
- DUH_SIGRENDERER *sigrenderer,
- DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data
-) DUMB_DEPRECATED;
-/* This is deprecated because the meaning of the 'samples' parameter in the
- * callback needed to change. For stereo applications, the array used to be
- * indexed with samples[channel][pos]. It is now indexed with
- * samples[0][pos*2+channel]. Mono sample data are still indexed with
- * samples[0][pos]. The array is still 2D because samples will probably only
- * ever be interleaved in twos. In order to fix your code, adapt it to the
- * new sample layout and then call
- * duh_sigrenderer_set_sample_analyser_callback below instead of this
- * function.
- */
-#endif
-
-typedef void (*DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK)(void *data, const sample_t *const *samples, int n_channels, long length);
-
-void duh_sigrenderer_set_sample_analyser_callback(
- DUH_SIGRENDERER *sigrenderer,
- DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data
-);
-
-int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer);
-long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer);
-
-void duh_sigrenderer_set_sigparam(DUH_SIGRENDERER *sigrenderer, unsigned char id, long value);
-
-#ifdef DUMB_DECLARE_DEPRECATED
-long duh_sigrenderer_get_samples(
- DUH_SIGRENDERER *sigrenderer,
- float volume, float delta,
- long size, sample_t **samples
-) DUMB_DEPRECATED;
-/* The sample format has changed, so if you were using this function,
- * you should switch to duh_sigrenderer_generate_samples() and change
- * how you interpret the samples array. See the comments for
- * duh_sigrenderer_set_analyser_callback().
- */
-#endif
-
-long duh_sigrenderer_generate_samples(
- DUH_SIGRENDERER *sigrenderer,
- float volume, float delta,
- long size, sample_t **samples
-);
-
-void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, float volume, sample_t *samples);
-
-void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer);
-
-
-/* DUH Rendering Functions */
-
-long duh_render(
- DUH_SIGRENDERER *sigrenderer,
- int bits, int unsign,
- float volume, float delta,
- long size, void *sptr
-);
-
-#ifdef DUMB_DECLARE_DEPRECATED
-
-long duh_render_signal(
- DUH_SIGRENDERER *sigrenderer,
- float volume, float delta,
- long size, sample_t **samples
-) DUMB_DEPRECATED;
-/* Please use duh_sigrenderer_generate_samples(), and see the
- * comments for the deprecated duh_sigrenderer_get_samples() too.
- */
-
-typedef DUH_SIGRENDERER DUH_RENDERER DUMB_DEPRECATED;
-/* Please use DUH_SIGRENDERER instead of DUH_RENDERER. */
-
-DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos) DUMB_DEPRECATED;
-/* Please use duh_start_sigrenderer() instead. Pass 0 for 'sig'. */
-
-int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
-long duh_renderer_get_position(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
-/* Please use the duh_sigrenderer_*() equivalents of these two functions. */
-
-void duh_end_renderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
-/* Please use duh_end_sigrenderer() instead. */
-
-DUH_SIGRENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer) DUMB_DEPRECATED;
-DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
-DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
-/* These functions have become no-ops that just return the parameter.
- * So, for instance, replace
- * duh_renderer_encapsulate_sigrenderer(my_sigrenderer)
- * with
- * my_sigrenderer
- */
-
-#endif
-
-
-/* Impulse Tracker Support */
-
-extern int dumb_it_max_to_mix;
-
-typedef struct DUMB_IT_SIGDATA DUMB_IT_SIGDATA;
-typedef struct DUMB_IT_SIGRENDERER DUMB_IT_SIGRENDERER;
-
-DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh);
-DUH_SIGRENDERER *duh_encapsulate_it_sigrenderer(DUMB_IT_SIGRENDERER *it_sigrenderer, int n_channels, long pos);
-DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer);
-
-int dumb_it_trim_silent_patterns(DUH * duh);
-
-typedef int (*dumb_scan_callback)(void *, int, long);
-int dumb_it_scan_for_playable_orders(DUMB_IT_SIGDATA *sigdata, dumb_scan_callback callback, void * callback_data);
-
-DUH_SIGRENDERER *dumb_it_start_at_order(DUH *duh, int n_channels, int startorder);
-
-void dumb_it_set_resampling_quality(DUMB_IT_SIGRENDERER * sigrenderer, int quality);
-
-void dumb_it_set_ramp_style(DUMB_IT_SIGRENDERER * sigrenderer, int ramp_style);
-
-void dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data);
-void dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data);
-void dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data, int channel, unsigned char midi_byte), void *data);
-void dumb_it_set_global_volume_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data);
-
-int dumb_it_callback_terminate(void *data);
-int dumb_it_callback_midi_block(void *data, int channel, unsigned char midi_byte);
-
-DUH *dumb_load_it(const char *filename);
-DUH *dumb_load_xm(const char *filename);
-DUH *dumb_load_s3m(const char *filename);
-DUH *dumb_load_stm(const char *filename);
-DUH *dumb_load_mod(const char *filename, int restr);
-DUH *dumb_load_ptm(const char *filename);
-DUH *dumb_load_669(const char *filename);
-DUH *dumb_load_psm(const char *filename, int subsong);
-DUH *dumb_load_old_psm(const char * filename);
-DUH *dumb_load_mtm(const char *filename);
-DUH *dumb_load_riff(const char *filename);
-DUH *dumb_load_asy(const char *filename);
-
-DUH *dumb_read_it(DUMBFILE *f);
-DUH *dumb_read_xm(DUMBFILE *f);
-DUH *dumb_read_s3m(DUMBFILE *f);
-DUH *dumb_read_stm(DUMBFILE *f);
-DUH *dumb_read_mod(DUMBFILE *f, int restr);
-DUH *dumb_read_ptm(DUMBFILE *f);
-DUH *dumb_read_669(DUMBFILE *f);
-DUH *dumb_read_psm(DUMBFILE *f, int subsong);
-DUH *dumb_read_old_psm(DUMBFILE *f);
-DUH *dumb_read_mtm(DUMBFILE *f);
-DUH *dumb_read_riff(DUMBFILE *f);
-DUH *dumb_read_asy(DUMBFILE *f);
-
-DUH *dumb_load_it_quick(const char *filename);
-DUH *dumb_load_xm_quick(const char *filename);
-DUH *dumb_load_s3m_quick(const char *filename);
-DUH *dumb_load_stm_quick(const char *filename);
-DUH *dumb_load_mod_quick(const char *filename, int restr);
-DUH *dumb_load_ptm_quick(const char *filename);
-DUH *dumb_load_669_quick(const char *filename);
-DUH *dumb_load_psm_quick(const char *filename, int subsong);
-DUH *dumb_load_old_psm_quick(const char * filename);
-DUH *dumb_load_mtm_quick(const char *filename);
-DUH *dumb_load_riff_quick(const char *filename);
-DUH *dumb_load_asy_quick(const char *filename);
-
-DUH *dumb_read_it_quick(DUMBFILE *f);
-DUH *dumb_read_xm_quick(DUMBFILE *f);
-DUH *dumb_read_s3m_quick(DUMBFILE *f);
-DUH *dumb_read_stm_quick(DUMBFILE *f);
-DUH *dumb_read_mod_quick(DUMBFILE *f, int restr);
-DUH *dumb_read_ptm_quick(DUMBFILE *f);
-DUH *dumb_read_669_quick(DUMBFILE *f);
-DUH *dumb_read_psm_quick(DUMBFILE *f, int subsong);
-DUH *dumb_read_old_psm_quick(DUMBFILE *f);
-DUH *dumb_read_mtm_quick(DUMBFILE *f);
-DUH *dumb_read_riff_quick(DUMBFILE *f);
-DUH *dumb_read_asy_quick(DUMBFILE *f);
-
-long dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata, int startorder);
-void dumb_it_do_initial_runthrough(DUH *duh);
-
-int dumb_get_psm_subsong_count(DUMBFILE *f);
-
-const unsigned char *dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd);
-
-int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd);
-int dumb_it_sd_get_n_samples(DUMB_IT_SIGDATA *sd);
-int dumb_it_sd_get_n_instruments(DUMB_IT_SIGDATA *sd);
-
-const unsigned char *dumb_it_sd_get_sample_name(DUMB_IT_SIGDATA *sd, int i);
-const unsigned char *dumb_it_sd_get_sample_filename(DUMB_IT_SIGDATA *sd, int i);
-const unsigned char *dumb_it_sd_get_instrument_name(DUMB_IT_SIGDATA *sd, int i);
-const unsigned char *dumb_it_sd_get_instrument_filename(DUMB_IT_SIGDATA *sd, int i);
-
-int dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd);
-void dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv);
-
-int dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd);
-void dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv);
-
-int dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd);
-void dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed);
-
-int dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd);
-void dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo);
-
-int dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel);
-void dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel, int volume);
-
-int dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr);
-int dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr);
-
-int dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr);
-void dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv);
-
-int dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr);
-void dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo);
-
-int dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr);
-void dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed);
-
-#define DUMB_IT_N_CHANNELS 64
-#define DUMB_IT_N_NNA_CHANNELS 192
-#define DUMB_IT_TOTAL_CHANNELS (DUMB_IT_N_CHANNELS + DUMB_IT_N_NNA_CHANNELS)
-
-/* Channels passed to any of these functions are 0-based */
-int dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel);
-void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, int volume);
-
-int dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel);
-void dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel, int muted);
-
-typedef struct DUMB_IT_CHANNEL_STATE DUMB_IT_CHANNEL_STATE;
-
-struct DUMB_IT_CHANNEL_STATE
-{
- int channel; /* 0-based; meaningful for NNA channels */
- int sample; /* 1-based; 0 if nothing playing, then other fields undef */
- int freq; /* in Hz */
- float volume; /* 1.0 maximum; affected by ALL factors, inc. mixing vol */
- unsigned char pan; /* 0-64, 100 for surround */
- signed char subpan; /* use (pan + subpan/256.0f) or ((pan<<8)+subpan) */
- unsigned char filter_cutoff; /* 0-127 cutoff=127 AND resonance=0 */
- unsigned char filter_subcutoff; /* 0-255 -> no filters (subcutoff */
- unsigned char filter_resonance; /* 0-127 always 0 in this case) */
- /* subcutoff only changes from zero if filter envelopes are in use. The
- * calculation (filter_cutoff + filter_subcutoff/256.0f) gives a more
- * accurate filter cutoff measurement as a float. It would often be more
- * useful to use a scaled int such as ((cutoff<<8) + subcutoff).
- */
-};
-
-/* Values of 64 or more will access NNA channels here. */
-void dumb_it_sr_get_channel_state(DUMB_IT_SIGRENDERER *sr, int channel, DUMB_IT_CHANNEL_STATE *state);
-
-
-/* Signal Design Helper Values */
-
-/* Use pow(DUMB_SEMITONE_BASE, n) to get the 'delta' value to transpose up by
- * n semitones. To transpose down, use negative n.
- */
-#define DUMB_SEMITONE_BASE 1.059463094359295309843105314939748495817
-
-/* Use pow(DUMB_QUARTERTONE_BASE, n) to get the 'delta' value to transpose up
- * by n quartertones. To transpose down, use negative n.
- */
-#define DUMB_QUARTERTONE_BASE 1.029302236643492074463779317738953977823
-
-/* Use pow(DUMB_PITCH_BASE, n) to get the 'delta' value to transpose up by n
- * units. In this case, 256 units represent one semitone; 3072 units
- * represent one octave. These units are used by the sequence signal (SEQU).
- */
-#define DUMB_PITCH_BASE 1.000225659305069791926712241547647863626
-
-
-/* Signal Design Function Types */
-
-typedef void sigdata_t;
-typedef void sigrenderer_t;
-
-typedef sigdata_t *(*DUH_LOAD_SIGDATA)(DUH *duh, DUMBFILE *file);
-
-typedef sigrenderer_t *(*DUH_START_SIGRENDERER)(
- DUH *duh,
- sigdata_t *sigdata,
- int n_channels,
- long pos
-);
-
-typedef void (*DUH_SIGRENDERER_SET_SIGPARAM)(
- sigrenderer_t *sigrenderer,
- unsigned char id, long value
-);
-
-typedef long (*DUH_SIGRENDERER_GENERATE_SAMPLES)(
- sigrenderer_t *sigrenderer,
- float volume, float delta,
- long size, sample_t **samples
-);
-
-typedef void (*DUH_SIGRENDERER_GET_CURRENT_SAMPLE)(
- sigrenderer_t *sigrenderer,
- float volume,
- sample_t *samples
-);
-
-typedef void (*DUH_END_SIGRENDERER)(sigrenderer_t *sigrenderer);
-
-typedef void (*DUH_UNLOAD_SIGDATA)(sigdata_t *sigdata);
-
-
-/* Signal Design Function Registration */
-
-typedef struct DUH_SIGTYPE_DESC
-{
- long type;
- DUH_LOAD_SIGDATA load_sigdata;
- DUH_START_SIGRENDERER start_sigrenderer;
- DUH_SIGRENDERER_SET_SIGPARAM sigrenderer_set_sigparam;
- DUH_SIGRENDERER_GENERATE_SAMPLES sigrenderer_generate_samples;
- DUH_SIGRENDERER_GET_CURRENT_SAMPLE sigrenderer_get_current_sample;
- DUH_END_SIGRENDERER end_sigrenderer;
- DUH_UNLOAD_SIGDATA unload_sigdata;
-}
-DUH_SIGTYPE_DESC;
-
-void dumb_register_sigtype(DUH_SIGTYPE_DESC *desc);
-
-
-// Decide where to put these functions; new heading?
-
-sigdata_t *duh_get_raw_sigdata(DUH *duh, int sig, long type);
-
-DUH_SIGRENDERER *duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, long pos);
-sigrenderer_t *duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type);
-
-
-/* Standard Signal Types */
-
-//void dumb_register_sigtype_sample(void);
-
-
-/* Sample Buffer Allocation Helpers */
-
-#ifdef DUMB_DECLARE_DEPRECATED
-sample_t **create_sample_buffer(int n_channels, long length) DUMB_DEPRECATED;
-/* DUMB has been changed to interleave stereo samples. Use
- * allocate_sample_buffer() instead, and see the comments for
- * duh_sigrenderer_set_analyser_callback().
- */
-#endif
-sample_t **allocate_sample_buffer(int n_channels, long length);
-void destroy_sample_buffer(sample_t **samples);
-
-
-/* Silencing Helper */
-
-void dumb_silence(sample_t *samples, long length);
-
-
-/* Click Removal Helpers */
-
-typedef struct DUMB_CLICK_REMOVER DUMB_CLICK_REMOVER;
-
-DUMB_CLICK_REMOVER *dumb_create_click_remover(void);
-void dumb_record_click(DUMB_CLICK_REMOVER *cr, long pos, sample_t step);
-void dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, long length, int step, float halflife);
-sample_t dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr);
-void dumb_destroy_click_remover(DUMB_CLICK_REMOVER *cr);
-
-DUMB_CLICK_REMOVER **dumb_create_click_remover_array(int n);
-void dumb_record_click_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step);
-void dumb_record_click_negative_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step);
-void dumb_remove_clicks_array(int n, DUMB_CLICK_REMOVER **cr, sample_t **samples, long length, float halflife);
-void dumb_click_remover_get_offset_array(int n, DUMB_CLICK_REMOVER **cr, sample_t *offset);
-void dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr);
-
-
-/* Resampling Helpers */
-
-#define DUMB_RQ_ALIASING 0
-#define DUMB_RQ_LINEAR 1
-#define DUMB_RQ_CUBIC 2
-#define DUMB_RQ_N_LEVELS 3
-extern int dumb_resampling_quality;
-
-typedef struct DUMB_RESAMPLER DUMB_RESAMPLER;
-
-typedef struct DUMB_VOLUME_RAMP_INFO DUMB_VOLUME_RAMP_INFO;
-
-typedef void (*DUMB_RESAMPLE_PICKUP)(DUMB_RESAMPLER *resampler, void *data);
-
-struct DUMB_RESAMPLER
-{
- void *src;
- long pos;
- int subpos;
- long start, end;
- int dir;
- DUMB_RESAMPLE_PICKUP pickup;
- void *pickup_data;
- int quality;
- /* Everything below this point is internal: do not use. */
- union {
- sample_t x24[3*2];
- short x16[3*2];
- signed char x8[3*2];
- } x;
- int overshot;
-};
-
-struct DUMB_VOLUME_RAMP_INFO
-{
- float volume;
- float delta;
- float target;
- float mix;
-};
-
-void dumb_reset_resampler(DUMB_RESAMPLER *resampler, sample_t *src, int src_channels, long pos, long start, long end, int quality);
-DUMB_RESAMPLER *dumb_start_resampler(sample_t *src, int src_channels, long pos, long start, long end, int quality);
-long dumb_resample_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta);
-long dumb_resample_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
-long dumb_resample_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
-long dumb_resample_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
-void dumb_resample_get_current_sample_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
-void dumb_resample_get_current_sample_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
-void dumb_resample_get_current_sample_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
-void dumb_resample_get_current_sample_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
-void dumb_end_resampler(DUMB_RESAMPLER *resampler);
-
-void dumb_reset_resampler_16(DUMB_RESAMPLER *resampler, short *src, int src_channels, long pos, long start, long end, int quality);
-DUMB_RESAMPLER *dumb_start_resampler_16(short *src, int src_channels, long pos, long start, long end, int quality);
-long dumb_resample_16_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta);
-long dumb_resample_16_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
-long dumb_resample_16_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
-long dumb_resample_16_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
-void dumb_resample_get_current_sample_16_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
-void dumb_resample_get_current_sample_16_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
-void dumb_resample_get_current_sample_16_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
-void dumb_resample_get_current_sample_16_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
-void dumb_end_resampler_16(DUMB_RESAMPLER *resampler);
-
-void dumb_reset_resampler_8(DUMB_RESAMPLER *resampler, signed char *src, int src_channels, long pos, long start, long end, int quality);
-DUMB_RESAMPLER *dumb_start_resampler_8(signed char *src, int src_channels, long pos, long start, long end, int quality);
-long dumb_resample_8_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta);
-long dumb_resample_8_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
-long dumb_resample_8_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
-long dumb_resample_8_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
-void dumb_resample_get_current_sample_8_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
-void dumb_resample_get_current_sample_8_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
-void dumb_resample_get_current_sample_8_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
-void dumb_resample_get_current_sample_8_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
-void dumb_end_resampler_8(DUMB_RESAMPLER *resampler);
-
-void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, int src_channels, long pos, long start, long end, int quality);
-DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels, long pos, long start, long end, int quality);
-long dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta);
-long dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
-long dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
-long dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
-void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
-void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
-void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
-void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
-void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler);
-
-
-/* DUH Construction */
-
-DUH *make_duh(
- long length,
- int n_tags,
- const char *const tag[][2],
- int n_signals,
- DUH_SIGTYPE_DESC *desc[],
- sigdata_t *sigdata[]
-);
-
-void duh_set_length(DUH *duh, long length);
-
-
-#ifdef __cplusplus
- }
-#endif
-
-
-#endif /* DUMB_H */
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * dumb.h - The user header file for DUMB. / / \ \
+ * | < / \_
+ * Include this file in any of your files in | \/ /\ /
+ * which you wish to use the DUMB functions \_ / > /
+ * and variables. | \ / /
+ * | ' /
+ * Allegro users, you will probably want aldumb.h. \__/
+ */
+
+#ifndef DUMB_H
+#define DUMB_H
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef _DEBUG
+#define _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+#define DUMB_MAJOR_VERSION 0
+#define DUMB_MINOR_VERSION 9
+#define DUMB_REVISION_VERSION 3
+
+#define DUMB_VERSION (DUMB_MAJOR_VERSION*10000 + DUMB_MINOR_VERSION*100 + DUMB_REVISION_VERSION)
+
+#define DUMB_VERSION_STR "0.9.3"
+
+#define DUMB_NAME "DUMB v"DUMB_VERSION_STR
+
+#define DUMB_YEAR 2005
+#define DUMB_MONTH 8
+#define DUMB_DAY 7
+
+#define DUMB_YEAR_STR2 "05"
+#define DUMB_YEAR_STR4 "2005"
+#define DUMB_MONTH_STR1 "8"
+#define DUMB_DAY_STR1 "7"
+
+#define DUMB_YEAR_STR2 "05"
+#define DUMB_YEAR_STR4 "2005"
+#define DUMB_MONTH_STR1 "8"
+#define DUMB_DAY_STR1 "7"
+
+#if DUMB_MONTH < 10
+#define DUMB_MONTH_STR2 "0"DUMB_MONTH_STR1
+#else
+#define DUMB_MONTH_STR2 DUMB_MONTH_STR1
+#endif
+
+#if DUMB_DAY < 10
+#define DUMB_DAY_STR2 "0"DUMB_DAY_STR1
+#else
+#define DUMB_DAY_STR2 DUMB_DAY_STR1
+#endif
+
+
+/* WARNING: The month and day were inadvertently swapped in the v0.8 release.
+ * Please do not compare this constant against any date in 2002. In
+ * any case, DUMB_VERSION is probably more useful for this purpose.
+ */
+#define DUMB_DATE (DUMB_YEAR*10000 + DUMB_MONTH*100 + DUMB_DAY)
+
+#define DUMB_DATE_STR DUMB_DAY_STR1"."DUMB_MONTH_STR1"."DUMB_YEAR_STR4
+
+
+#undef MIN
+#undef MAX
+#undef MID
+
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+#define MID(x,y,z) MAX((x), MIN((y), (z)))
+
+#undef ABS
+#define ABS(x) (((x) >= 0) ? (x) : (-(x)))
+
+
+#ifdef DEBUGMODE
+
+#ifndef ASSERT
+#include <assert.h>
+#define ASSERT(n) assert(n)
+#endif
+#ifndef TRACE
+// it would be nice if this did actually trace ...
+#define TRACE 1 ? (void)0 : (void)printf
+#endif
+
+#else
+
+#ifndef ASSERT
+#define ASSERT(n)
+#endif
+#ifndef TRACE
+#define TRACE 1 ? (void)0 : (void)printf
+#endif
+
+#endif
+
+
+#define DUMB_ID(a,b,c,d) (((unsigned int)(a) << 24) | \
+ ((unsigned int)(b) << 16) | \
+ ((unsigned int)(c) << 8) | \
+ ((unsigned int)(d) ))
+
+
+
+#ifndef LONG_LONG
+#if defined __GNUC__ || defined __INTEL_COMPILER || defined __MWERKS__
+#define LONG_LONG long long
+#elif defined _MSC_VER || defined __WATCOMC__
+#define LONG_LONG __int64
+#elif defined __sgi
+#define LONG_LONG long long
+#else
+#error 64-bit integer type unknown
+#endif
+#endif
+
+#if __GNUC__ * 100 + __GNUC_MINOR__ >= 301 /* GCC 3.1+ */
+#ifndef DUMB_DECLARE_DEPRECATED
+#define DUMB_DECLARE_DEPRECATED
+#endif
+#define DUMB_DEPRECATED __attribute__((__deprecated__))
+#else
+#define DUMB_DEPRECATED
+#endif
+
+
+/* Basic Sample Type. Normal range is -0x800000 to 0x7FFFFF. */
+
+typedef int sample_t;
+
+
+/* Library Clean-up Management */
+
+int dumb_atexit(void (*proc)(void));
+
+void dumb_exit(void);
+
+
+/* File Input Functions */
+
+typedef struct DUMBFILE_SYSTEM
+{
+ void *(*open)(const char *filename);
+ int (*skip)(void *f, long n);
+ int (*getc)(void *f);
+ long (*getnc)(char *ptr, long n, void *f);
+ void (*close)(void *f);
+}
+DUMBFILE_SYSTEM;
+
+typedef struct DUMBFILE DUMBFILE;
+
+void register_dumbfile_system(DUMBFILE_SYSTEM *dfs);
+
+DUMBFILE *dumbfile_open(const char *filename);
+DUMBFILE *dumbfile_open_ex(void *file, DUMBFILE_SYSTEM *dfs);
+
+long dumbfile_pos(DUMBFILE *f);
+int dumbfile_skip(DUMBFILE *f, long n);
+
+int dumbfile_getc(DUMBFILE *f);
+
+int dumbfile_igetw(DUMBFILE *f);
+int dumbfile_mgetw(DUMBFILE *f);
+
+long dumbfile_igetl(DUMBFILE *f);
+long dumbfile_mgetl(DUMBFILE *f);
+
+unsigned long dumbfile_cgetul(DUMBFILE *f);
+signed long dumbfile_cgetsl(DUMBFILE *f);
+
+long dumbfile_getnc(char *ptr, long n, DUMBFILE *f);
+
+int dumbfile_error(DUMBFILE *f);
+int dumbfile_close(DUMBFILE *f);
+
+
+/* stdio File Input Module */
+
+void dumb_register_stdfiles(void);
+
+DUMBFILE *dumbfile_open_stdfile(FILE *p);
+
+
+/* Memory File Input Module */
+
+DUMBFILE *dumbfile_open_memory(const char *data, long size);
+
+
+/* DUH Management */
+
+typedef struct DUH DUH;
+
+#define DUH_SIGNATURE DUMB_ID('D','U','H','!')
+
+void unload_duh(DUH *duh);
+
+DUH *load_duh(const char *filename);
+DUH *read_duh(DUMBFILE *f);
+
+long duh_get_length(DUH *duh);
+
+const char *duh_get_tag(DUH *duh, const char *key);
+
+const char *duh_get_tag(DUH *duh, const char *key);
+
+
+/* Signal Rendering Functions */
+
+typedef struct DUH_SIGRENDERER DUH_SIGRENDERER;
+
+DUH_SIGRENDERER *duh_start_sigrenderer(DUH *duh, int sig, int n_channels, long pos);
+
+#ifdef DUMB_DECLARE_DEPRECATED
+typedef void (*DUH_SIGRENDERER_CALLBACK)(void *data, sample_t **samples, int n_channels, long length);
+/* This is deprecated, but is not marked as such because GCC tends to
+ * complain spuriously when the typedef is used later. See comments below.
+ */
+
+void duh_sigrenderer_set_callback(
+ DUH_SIGRENDERER *sigrenderer,
+ DUH_SIGRENDERER_CALLBACK callback, void *data
+) DUMB_DEPRECATED;
+/* The 'callback' argument's type has changed for const-correctness. See the
+ * DUH_SIGRENDERER_CALLBACK definition just above. Also note that the samples
+ * in the buffer are now 256 times as large; the normal range is -0x800000 to
+ * 0x7FFFFF. The function has been renamed partly because its functionality
+ * has changed slightly and partly so that its name is more meaningful. The
+ * new one is duh_sigrenderer_set_analyser_callback(), and the typedef for
+ * the function pointer has also changed, from DUH_SIGRENDERER_CALLBACK to
+ * DUH_SIGRENDERER_ANALYSER_CALLBACK. (If you wanted to use this callback to
+ * apply a DSP effect, don't worry; there is a better way of doing this. It
+ * is undocumented, so contact me and I shall try to help. Contact details
+ * are in readme.txt.)
+ */
+
+typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data, const sample_t *const *samples, int n_channels, long length);
+/* This is deprecated, but is not marked as such because GCC tends to
+ * complain spuriously when the typedef is used later. See comments below.
+ */
+
+void duh_sigrenderer_set_analyser_callback(
+ DUH_SIGRENDERER *sigrenderer,
+ DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data
+) DUMB_DEPRECATED;
+/* This is deprecated because the meaning of the 'samples' parameter in the
+ * callback needed to change. For stereo applications, the array used to be
+ * indexed with samples[channel][pos]. It is now indexed with
+ * samples[0][pos*2+channel]. Mono sample data are still indexed with
+ * samples[0][pos]. The array is still 2D because samples will probably only
+ * ever be interleaved in twos. In order to fix your code, adapt it to the
+ * new sample layout and then call
+ * duh_sigrenderer_set_sample_analyser_callback below instead of this
+ * function.
+ */
+#endif
+
+typedef void (*DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK)(void *data, const sample_t *const *samples, int n_channels, long length);
+
+void duh_sigrenderer_set_sample_analyser_callback(
+ DUH_SIGRENDERER *sigrenderer,
+ DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data
+);
+
+int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer);
+long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer);
+
+void duh_sigrenderer_set_sigparam(DUH_SIGRENDERER *sigrenderer, unsigned char id, long value);
+
+#ifdef DUMB_DECLARE_DEPRECATED
+long duh_sigrenderer_get_samples(
+ DUH_SIGRENDERER *sigrenderer,
+ float volume, float delta,
+ long size, sample_t **samples
+) DUMB_DEPRECATED;
+/* The sample format has changed, so if you were using this function,
+ * you should switch to duh_sigrenderer_generate_samples() and change
+ * how you interpret the samples array. See the comments for
+ * duh_sigrenderer_set_analyser_callback().
+ */
+#endif
+
+long duh_sigrenderer_generate_samples(
+ DUH_SIGRENDERER *sigrenderer,
+ float volume, float delta,
+ long size, sample_t **samples
+);
+
+void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, float volume, sample_t *samples);
+
+void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer);
+
+
+/* DUH Rendering Functions */
+
+long duh_render(
+ DUH_SIGRENDERER *sigrenderer,
+ int bits, int unsign,
+ float volume, float delta,
+ long size, void *sptr
+);
+
+#ifdef DUMB_DECLARE_DEPRECATED
+
+long duh_render_signal(
+ DUH_SIGRENDERER *sigrenderer,
+ float volume, float delta,
+ long size, sample_t **samples
+) DUMB_DEPRECATED;
+/* Please use duh_sigrenderer_generate_samples(), and see the
+ * comments for the deprecated duh_sigrenderer_get_samples() too.
+ */
+
+typedef DUH_SIGRENDERER DUH_RENDERER DUMB_DEPRECATED;
+/* Please use DUH_SIGRENDERER instead of DUH_RENDERER. */
+
+DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos) DUMB_DEPRECATED;
+/* Please use duh_start_sigrenderer() instead. Pass 0 for 'sig'. */
+
+int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
+long duh_renderer_get_position(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
+/* Please use the duh_sigrenderer_*() equivalents of these two functions. */
+
+void duh_end_renderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
+/* Please use duh_end_sigrenderer() instead. */
+
+DUH_SIGRENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer) DUMB_DEPRECATED;
+DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
+DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED;
+/* These functions have become no-ops that just return the parameter.
+ * So, for instance, replace
+ * duh_renderer_encapsulate_sigrenderer(my_sigrenderer)
+ * with
+ * my_sigrenderer
+ */
+
+#endif
+
+
+/* Impulse Tracker Support */
+
+extern int dumb_it_max_to_mix;
+
+typedef struct DUMB_IT_SIGDATA DUMB_IT_SIGDATA;
+typedef struct DUMB_IT_SIGRENDERER DUMB_IT_SIGRENDERER;
+
+DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh);
+DUH_SIGRENDERER *duh_encapsulate_it_sigrenderer(DUMB_IT_SIGRENDERER *it_sigrenderer, int n_channels, long pos);
+DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer);
+
+int dumb_it_trim_silent_patterns(DUH * duh);
+
+typedef int (*dumb_scan_callback)(void *, int, long);
+int dumb_it_scan_for_playable_orders(DUMB_IT_SIGDATA *sigdata, dumb_scan_callback callback, void * callback_data);
+
+DUH_SIGRENDERER *dumb_it_start_at_order(DUH *duh, int n_channels, int startorder);
+
+void dumb_it_set_resampling_quality(DUMB_IT_SIGRENDERER * sigrenderer, int quality);
+
+void dumb_it_set_ramp_style(DUMB_IT_SIGRENDERER * sigrenderer, int ramp_style);
+
+void dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data);
+void dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data);
+void dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data, int channel, unsigned char midi_byte), void *data);
+void dumb_it_set_global_volume_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data);
+
+int dumb_it_callback_terminate(void *data);
+int dumb_it_callback_midi_block(void *data, int channel, unsigned char midi_byte);
+
+DUH *dumb_load_it(const char *filename);
+DUH *dumb_load_xm(const char *filename);
+DUH *dumb_load_s3m(const char *filename);
+DUH *dumb_load_stm(const char *filename);
+DUH *dumb_load_mod(const char *filename, int restr);
+DUH *dumb_load_ptm(const char *filename);
+DUH *dumb_load_669(const char *filename);
+DUH *dumb_load_psm(const char *filename, int subsong);
+DUH *dumb_load_old_psm(const char * filename);
+DUH *dumb_load_mtm(const char *filename);
+DUH *dumb_load_riff(const char *filename);
+DUH *dumb_load_asy(const char *filename);
+
+DUH *dumb_read_it(DUMBFILE *f);
+DUH *dumb_read_xm(DUMBFILE *f);
+DUH *dumb_read_s3m(DUMBFILE *f);
+DUH *dumb_read_stm(DUMBFILE *f);
+DUH *dumb_read_mod(DUMBFILE *f, int restr);
+DUH *dumb_read_ptm(DUMBFILE *f);
+DUH *dumb_read_669(DUMBFILE *f);
+DUH *dumb_read_psm(DUMBFILE *f, int subsong);
+DUH *dumb_read_old_psm(DUMBFILE *f);
+DUH *dumb_read_mtm(DUMBFILE *f);
+DUH *dumb_read_riff(DUMBFILE *f);
+DUH *dumb_read_asy(DUMBFILE *f);
+
+DUH *dumb_load_it_quick(const char *filename);
+DUH *dumb_load_xm_quick(const char *filename);
+DUH *dumb_load_s3m_quick(const char *filename);
+DUH *dumb_load_stm_quick(const char *filename);
+DUH *dumb_load_mod_quick(const char *filename, int restr);
+DUH *dumb_load_ptm_quick(const char *filename);
+DUH *dumb_load_669_quick(const char *filename);
+DUH *dumb_load_psm_quick(const char *filename, int subsong);
+DUH *dumb_load_old_psm_quick(const char * filename);
+DUH *dumb_load_mtm_quick(const char *filename);
+DUH *dumb_load_riff_quick(const char *filename);
+DUH *dumb_load_asy_quick(const char *filename);
+
+DUH *dumb_read_it_quick(DUMBFILE *f);
+DUH *dumb_read_xm_quick(DUMBFILE *f);
+DUH *dumb_read_s3m_quick(DUMBFILE *f);
+DUH *dumb_read_stm_quick(DUMBFILE *f);
+DUH *dumb_read_mod_quick(DUMBFILE *f, int restr);
+DUH *dumb_read_ptm_quick(DUMBFILE *f);
+DUH *dumb_read_669_quick(DUMBFILE *f);
+DUH *dumb_read_psm_quick(DUMBFILE *f, int subsong);
+DUH *dumb_read_old_psm_quick(DUMBFILE *f);
+DUH *dumb_read_mtm_quick(DUMBFILE *f);
+DUH *dumb_read_riff_quick(DUMBFILE *f);
+DUH *dumb_read_asy_quick(DUMBFILE *f);
+
+long dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata, int startorder);
+void dumb_it_do_initial_runthrough(DUH *duh);
+
+int dumb_get_psm_subsong_count(DUMBFILE *f);
+
+const unsigned char *dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd);
+
+int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd);
+int dumb_it_sd_get_n_samples(DUMB_IT_SIGDATA *sd);
+int dumb_it_sd_get_n_instruments(DUMB_IT_SIGDATA *sd);
+
+const unsigned char *dumb_it_sd_get_sample_name(DUMB_IT_SIGDATA *sd, int i);
+const unsigned char *dumb_it_sd_get_sample_filename(DUMB_IT_SIGDATA *sd, int i);
+const unsigned char *dumb_it_sd_get_instrument_name(DUMB_IT_SIGDATA *sd, int i);
+const unsigned char *dumb_it_sd_get_instrument_filename(DUMB_IT_SIGDATA *sd, int i);
+
+int dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd);
+void dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv);
+
+int dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd);
+void dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv);
+
+int dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd);
+void dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed);
+
+int dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd);
+void dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo);
+
+int dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel);
+void dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel, int volume);
+
+int dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr);
+int dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr);
+
+int dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr);
+void dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv);
+
+int dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr);
+void dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo);
+
+int dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr);
+void dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed);
+
+#define DUMB_IT_N_CHANNELS 64
+#define DUMB_IT_N_NNA_CHANNELS 192
+#define DUMB_IT_TOTAL_CHANNELS (DUMB_IT_N_CHANNELS + DUMB_IT_N_NNA_CHANNELS)
+
+/* Channels passed to any of these functions are 0-based */
+int dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel);
+void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, int volume);
+
+int dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel);
+void dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel, int muted);
+
+int dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel);
+void dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel, int muted);
+
+typedef struct DUMB_IT_CHANNEL_STATE DUMB_IT_CHANNEL_STATE;
+
+struct DUMB_IT_CHANNEL_STATE
+{
+ int channel; /* 0-based; meaningful for NNA channels */
+ int sample; /* 1-based; 0 if nothing playing, then other fields undef */
+ int freq; /* in Hz */
+ float volume; /* 1.0 maximum; affected by ALL factors, inc. mixing vol */
+ unsigned char pan; /* 0-64, 100 for surround */
+ signed char subpan; /* use (pan + subpan/256.0f) or ((pan<<8)+subpan) */
+ unsigned char filter_cutoff; /* 0-127 cutoff=127 AND resonance=0 */
+ unsigned char filter_subcutoff; /* 0-255 -> no filters (subcutoff */
+ unsigned char filter_resonance; /* 0-127 always 0 in this case) */
+ /* subcutoff only changes from zero if filter envelopes are in use. The
+ * calculation (filter_cutoff + filter_subcutoff/256.0f) gives a more
+ * accurate filter cutoff measurement as a float. It would often be more
+ * useful to use a scaled int such as ((cutoff<<8) + subcutoff).
+ */
+};
+
+/* Values of 64 or more will access NNA channels here. */
+void dumb_it_sr_get_channel_state(DUMB_IT_SIGRENDERER *sr, int channel, DUMB_IT_CHANNEL_STATE *state);
+
+
+/* Signal Design Helper Values */
+
+/* Use pow(DUMB_SEMITONE_BASE, n) to get the 'delta' value to transpose up by
+ * n semitones. To transpose down, use negative n.
+ */
+#define DUMB_SEMITONE_BASE 1.059463094359295309843105314939748495817
+
+/* Use pow(DUMB_QUARTERTONE_BASE, n) to get the 'delta' value to transpose up
+ * by n quartertones. To transpose down, use negative n.
+ */
+#define DUMB_QUARTERTONE_BASE 1.029302236643492074463779317738953977823
+
+/* Use pow(DUMB_PITCH_BASE, n) to get the 'delta' value to transpose up by n
+ * units. In this case, 256 units represent one semitone; 3072 units
+ * represent one octave. These units are used by the sequence signal (SEQU).
+ */
+#define DUMB_PITCH_BASE 1.000225659305069791926712241547647863626
+
+
+/* Signal Design Function Types */
+
+typedef void sigdata_t;
+typedef void sigrenderer_t;
+
+typedef sigdata_t *(*DUH_LOAD_SIGDATA)(DUH *duh, DUMBFILE *file);
+
+typedef sigrenderer_t *(*DUH_START_SIGRENDERER)(
+ DUH *duh,
+ sigdata_t *sigdata,
+ int n_channels,
+ long pos
+);
+
+typedef void (*DUH_SIGRENDERER_SET_SIGPARAM)(
+ sigrenderer_t *sigrenderer,
+ unsigned char id, long value
+);
+
+typedef long (*DUH_SIGRENDERER_GENERATE_SAMPLES)(
+ sigrenderer_t *sigrenderer,
+ float volume, float delta,
+ long size, sample_t **samples
+);
+
+typedef void (*DUH_SIGRENDERER_GET_CURRENT_SAMPLE)(
+ sigrenderer_t *sigrenderer,
+ float volume,
+ sample_t *samples
+);
+
+typedef void (*DUH_END_SIGRENDERER)(sigrenderer_t *sigrenderer);
+
+typedef void (*DUH_UNLOAD_SIGDATA)(sigdata_t *sigdata);
+
+
+/* Signal Design Function Registration */
+
+typedef struct DUH_SIGTYPE_DESC
+{
+ long type;
+ DUH_LOAD_SIGDATA load_sigdata;
+ DUH_START_SIGRENDERER start_sigrenderer;
+ DUH_SIGRENDERER_SET_SIGPARAM sigrenderer_set_sigparam;
+ DUH_SIGRENDERER_GENERATE_SAMPLES sigrenderer_generate_samples;
+ DUH_SIGRENDERER_GET_CURRENT_SAMPLE sigrenderer_get_current_sample;
+ DUH_END_SIGRENDERER end_sigrenderer;
+ DUH_UNLOAD_SIGDATA unload_sigdata;
+}
+DUH_SIGTYPE_DESC;
+
+void dumb_register_sigtype(DUH_SIGTYPE_DESC *desc);
+
+
+// Decide where to put these functions; new heading?
+
+sigdata_t *duh_get_raw_sigdata(DUH *duh, int sig, long type);
+
+DUH_SIGRENDERER *duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, long pos);
+sigrenderer_t *duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type);
+
+
+/* Standard Signal Types */
+
+//void dumb_register_sigtype_sample(void);
+
+
+/* Sample Buffer Allocation Helpers */
+
+#ifdef DUMB_DECLARE_DEPRECATED
+sample_t **create_sample_buffer(int n_channels, long length) DUMB_DEPRECATED;
+/* DUMB has been changed to interleave stereo samples. Use
+ * allocate_sample_buffer() instead, and see the comments for
+ * duh_sigrenderer_set_analyser_callback().
+ */
+#endif
+sample_t **allocate_sample_buffer(int n_channels, long length);
+void destroy_sample_buffer(sample_t **samples);
+
+
+/* Sample Buffer Allocation Helpers */
+
+#ifdef DUMB_DECLARE_DEPRECATED
+sample_t **create_sample_buffer(int n_channels, long length) DUMB_DEPRECATED;
+/* DUMB has been changed to interleave stereo samples. Use
+ * allocate_sample_buffer() instead, and see the comments for
+ * duh_sigrenderer_set_analyser_callback().
+ */
+#endif
+sample_t **allocate_sample_buffer(int n_channels, long length);
+void destroy_sample_buffer(sample_t **samples);
+
+
+/* Silencing Helper */
+
+void dumb_silence(sample_t *samples, long length);
+
+
+/* Click Removal Helpers */
+
+typedef struct DUMB_CLICK_REMOVER DUMB_CLICK_REMOVER;
+
+DUMB_CLICK_REMOVER *dumb_create_click_remover(void);
+void dumb_record_click(DUMB_CLICK_REMOVER *cr, long pos, sample_t step);
+void dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, long length, int step, float halflife);
+sample_t dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr);
+void dumb_destroy_click_remover(DUMB_CLICK_REMOVER *cr);
+
+DUMB_CLICK_REMOVER **dumb_create_click_remover_array(int n);
+void dumb_record_click_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step);
+void dumb_record_click_negative_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step);
+void dumb_remove_clicks_array(int n, DUMB_CLICK_REMOVER **cr, sample_t **samples, long length, float halflife);
+void dumb_click_remover_get_offset_array(int n, DUMB_CLICK_REMOVER **cr, sample_t *offset);
+void dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr);
+
+
+/* Resampling Helpers */
+
+#define DUMB_RQ_ALIASING 0
+#define DUMB_RQ_LINEAR 1
+#define DUMB_RQ_CUBIC 2
+#define DUMB_RQ_N_LEVELS 3
+extern int dumb_resampling_quality;
+
+typedef struct DUMB_RESAMPLER DUMB_RESAMPLER;
+
+typedef struct DUMB_VOLUME_RAMP_INFO DUMB_VOLUME_RAMP_INFO;
+
+typedef void (*DUMB_RESAMPLE_PICKUP)(DUMB_RESAMPLER *resampler, void *data);
+
+struct DUMB_RESAMPLER
+{
+ void *src;
+ long pos;
+ int subpos;
+ long start, end;
+ int dir;
+ DUMB_RESAMPLE_PICKUP pickup;
+ void *pickup_data;
+ int quality;
+ /* Everything below this point is internal: do not use. */
+ union {
+ sample_t x24[3*2];
+ short x16[3*2];
+ signed char x8[3*2];
+ } x;
+ int overshot;
+};
+
+struct DUMB_VOLUME_RAMP_INFO
+{
+ float volume;
+ float delta;
+ float target;
+ float mix;
+};
+
+void dumb_reset_resampler(DUMB_RESAMPLER *resampler, sample_t *src, int src_channels, long pos, long start, long end, int quality);
+DUMB_RESAMPLER *dumb_start_resampler(sample_t *src, int src_channels, long pos, long start, long end, int quality);
+long dumb_resample_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta);
+long dumb_resample_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+void dumb_resample_get_current_sample_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
+void dumb_resample_get_current_sample_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_end_resampler(DUMB_RESAMPLER *resampler);
+
+void dumb_reset_resampler_16(DUMB_RESAMPLER *resampler, short *src, int src_channels, long pos, long start, long end, int quality);
+DUMB_RESAMPLER *dumb_start_resampler_16(short *src, int src_channels, long pos, long start, long end, int quality);
+long dumb_resample_16_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta);
+long dumb_resample_16_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_16_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_16_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+void dumb_resample_get_current_sample_16_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
+void dumb_resample_get_current_sample_16_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_16_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_16_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_end_resampler_16(DUMB_RESAMPLER *resampler);
+
+void dumb_reset_resampler_8(DUMB_RESAMPLER *resampler, signed char *src, int src_channels, long pos, long start, long end, int quality);
+DUMB_RESAMPLER *dumb_start_resampler_8(signed char *src, int src_channels, long pos, long start, long end, int quality);
+long dumb_resample_8_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta);
+long dumb_resample_8_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_8_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_8_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+void dumb_resample_get_current_sample_8_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
+void dumb_resample_get_current_sample_8_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_8_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_8_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_end_resampler_8(DUMB_RESAMPLER *resampler);
+
+
+void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, int src_channels, long pos, long start, long end, int quality);
+DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels, long pos, long start, long end, int quality);
+long dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta);
+long dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
+void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler);
+
+
+/* DUH Construction */
+
+DUH *make_duh(
+ long length,
+ int n_tags,
+ const char *const tag[][2],
+ int n_signals,
+ DUH_SIGTYPE_DESC *desc[],
+ sigdata_t *sigdata[]
+);
+
+void duh_set_length(DUH *duh, long length);
+
+void duh_set_length(DUH *duh, long length);
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+#endif /* DUMB_H */
diff --git a/plugins/dumb/dumb-kode54/include/internal/aldumb.h b/plugins/dumb/dumb-kode54/include/internal/aldumb.h
index 9c02c01f..833ec7b9 100644
--- a/plugins/dumb/dumb-kode54/include/internal/aldumb.h
+++ b/plugins/dumb/dumb-kode54/include/internal/aldumb.h
@@ -1,27 +1,34 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * internal/aldumb.h - The internal header file / / \ \
- * for DUMB with Allegro. | < / \_
- * | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#ifndef INTERNAL_ALDUMB_H
-#define INTERNAL_ALDUMB_H
-
-
-void _dat_unload_duh(void *duh);
-
-
-#endif /* INTERNAL_DUMB_H */
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * internal/aldumb.h - The internal header file / / \ \
+ * for DUMB with Allegro. | < / \_
+ * | \/ /\ /
+ * This header file provides access to the \_ / > /
+ * internal structure of DUMB, and is liable | \ / /
+ * to change, mutate or cease to exist at any | ' /
+ * moment. Include it at your own peril. \__/
+ *
+ * ...
+ *
+ * Seriously. You don't need access to anything in this file. All right, you
+ * probably do actually. But if you use it, you will be relying on a specific
+ * version of DUMB, so please check DUMB_VERSION defined in dumb.h. Please
+ * contact the authors so that we can provide a public API for what you need.
+ */
+
+#ifndef INTERNAL_ALDUMB_H
+#define INTERNAL_ALDUMB_H
+
+
+void _dat_unload_duh(void *duh);
+
+
+#endif /* INTERNAL_DUMB_H */
diff --git a/plugins/dumb/dumb-kode54/include/internal/barray.h b/plugins/dumb/dumb-kode54/include/internal/barray.h
index 53c9a6cf..ab6984da 100644
--- a/plugins/dumb/dumb-kode54/include/internal/barray.h
+++ b/plugins/dumb/dumb-kode54/include/internal/barray.h
@@ -1,20 +1,20 @@
-#ifndef _B_ARRAY_H_
-#define _B_ARRAY_H_
-
-#include <stdlib.h>
-
-void * bit_array_create(size_t size);
-void bit_array_destroy(void * array);
-void * bit_array_dup(void * array);
-
-void bit_array_reset(void * array);
-
-void bit_array_set(void * array, size_t bit);
-int bit_array_test(void * array, size_t bit);
-int bit_array_test_range(void * array, size_t bit, size_t count);
-void bit_array_clear(void * array, size_t bit);
-
-void bit_array_merge(void * array, void * source, size_t offset);
-void bit_array_mask(void * array, void * source, size_t offset);
-
-#endif
+#ifndef _B_ARRAY_H_
+#define _B_ARRAY_H_
+
+#include <stdlib.h>
+
+void * bit_array_create(size_t size);
+void bit_array_destroy(void * array);
+void * bit_array_dup(void * array);
+
+void bit_array_reset(void * array);
+
+void bit_array_set(void * array, size_t bit);
+int bit_array_test(void * array, size_t bit);
+int bit_array_test_range(void * array, size_t bit, size_t count);
+void bit_array_clear(void * array, size_t bit);
+
+void bit_array_merge(void * array, void * source, size_t offset);
+void bit_array_mask(void * array, void * source, size_t offset);
+
+#endif
diff --git a/plugins/dumb/dumb-kode54/include/internal/dumb.h b/plugins/dumb/dumb-kode54/include/internal/dumb.h
index bed59566..99823f15 100644
--- a/plugins/dumb/dumb-kode54/include/internal/dumb.h
+++ b/plugins/dumb/dumb-kode54/include/internal/dumb.h
@@ -1,61 +1,61 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * internal/dumb.h - DUMB's internal declarations. / / \ \
- * | < / \_
- * This header file provides access to the | \/ /\ /
- * internal structure of DUMB, and is liable \_ / > /
- * to change, mutate or cease to exist at any | \ / /
- * moment. Include it at your own peril. | ' /
- * \__/
- * ...
- *
- * Seriously. You don't need access to anything in this file. All right, you
- * probably do actually. But if you use it, you will be relying on a specific
- * version of DUMB, so please check DUMB_VERSION defined in dumb.h. Please
- * contact the authors so that we can provide a public API for what you need.
- */
-
-#ifndef INTERNAL_DUMB_H
-#define INTERNAL_DUMB_H
-
-
-typedef struct DUH_SIGTYPE_DESC_LINK
-{
- struct DUH_SIGTYPE_DESC_LINK *next;
- DUH_SIGTYPE_DESC *desc;
-}
-DUH_SIGTYPE_DESC_LINK;
-
-
-typedef struct DUH_SIGNAL
-{
- sigdata_t *sigdata;
- DUH_SIGTYPE_DESC *desc;
-}
-DUH_SIGNAL;
-
-
-struct DUH
-{
- long length;
-
- int n_tags;
- char *(*tag)[2];
-
- int n_signals;
- DUH_SIGNAL **signal;
-};
-
-
-DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(long type);
-
-
-#endif /* INTERNAL_DUMB_H */
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * internal/dumb.h - DUMB's internal declarations. / / \ \
+ * | < / \_
+ * This header file provides access to the | \/ /\ /
+ * internal structure of DUMB, and is liable \_ / > /
+ * to change, mutate or cease to exist at any | \ / /
+ * moment. Include it at your own peril. | ' /
+ * \__/
+ * ...
+ *
+ * Seriously. You don't need access to anything in this file. All right, you
+ * probably do actually. But if you use it, you will be relying on a specific
+ * version of DUMB, so please check DUMB_VERSION defined in dumb.h. Please
+ * contact the authors so that we can provide a public API for what you need.
+ */
+
+#ifndef INTERNAL_DUMB_H
+#define INTERNAL_DUMB_H
+
+
+typedef struct DUH_SIGTYPE_DESC_LINK
+{
+ struct DUH_SIGTYPE_DESC_LINK *next;
+ DUH_SIGTYPE_DESC *desc;
+}
+DUH_SIGTYPE_DESC_LINK;
+
+
+typedef struct DUH_SIGNAL
+{
+ sigdata_t *sigdata;
+ DUH_SIGTYPE_DESC *desc;
+}
+DUH_SIGNAL;
+
+
+struct DUH
+{
+ long length;
+
+ int n_tags;
+ char *(*tag)[2];
+
+ int n_signals;
+ DUH_SIGNAL **signal;
+};
+
+
+DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(long type);
+
+
+#endif /* INTERNAL_DUMB_H */
diff --git a/plugins/dumb/dumb-kode54/include/internal/it.h b/plugins/dumb/dumb-kode54/include/internal/it.h
index fd7cb8b5..7f066882 100644
--- a/plugins/dumb/dumb-kode54/include/internal/it.h
+++ b/plugins/dumb/dumb-kode54/include/internal/it.h
@@ -1,882 +1,892 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * internal/it.h - Internal stuff for IT playback / / \ \
- * and MOD/XM/S3M conversion. | < / \_
- * | \/ /\ /
- * This header file provides access to the \_ / > /
- * internal structure of DUMB, and is liable | \ / /
- * to change, mutate or cease to exist at any | ' /
- * moment. Include it at your own peril. \__/
- *
- * ...
- *
- * Seriously. You don't need access to anything in this file. All right, you
- * probably do actually. But if you use it, you will be relying on a specific
- * version of DUMB, so please check DUMB_VERSION defined in dumb.h. Please
- * contact the authors so that we can provide a public API for what you need.
- */
-
-#ifndef INTERNAL_IT_H
-#define INTERNAL_IT_H
-
-
-#define BIT_ARRAY_BULLSHIT
-
-#include <stddef.h>
-
-#include "barray.h"
-
-
-/** TO DO: THINK ABOUT THE FOLLOWING:
-
-sigdata->flags & IT_COMPATIBLE_GXX
-
- Bit 5: On = Link Effect G's memory with Effect E/F. Also
- Gxx with an instrument present will cause the
- envelopes to be retriggered. If you change a
- sample on a row with Gxx, it'll adjust the
- frequency of the current note according to:
-
- NewFrequency = OldFrequency * NewC5 / OldC5;
-*/
-
-
-
-/* These #defines are TEMPORARY. They are used to write alternative code to
- * handle ambiguities in the format specification. The correct code in each
- * case will be determined most likely by experimentation.
- */
-#define STEREO_SAMPLES_COUNT_AS_TWO
-#define INVALID_ORDERS_END_SONG
-#define INVALID_NOTES_CAUSE_NOTE_CUT
-#define SUSTAIN_LOOP_OVERRIDES_NORMAL_LOOP
-#define VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
-
-
-
-#define SIGTYPE_IT DUMB_ID('I', 'T', ' ', ' ')
-
-#define IT_SIGNATURE DUMB_ID('I', 'M', 'P', 'M')
-#define IT_INSTRUMENT_SIGNATURE DUMB_ID('I', 'M', 'P', 'I')
-#define IT_SAMPLE_SIGNATURE DUMB_ID('I', 'M', 'P', 'S')
-
-// olivier sux
-#define IT_MPTX_SIGNATURE DUMB_ID('X', 'T', 'P', 'M')
-#define IT_INSM_SIGNATURE DUMB_ID('M', 'S', 'N', 'I')
-
-
-/* 1 minute per 4 rows, each row 6 ticks; this is divided by the tempo to get
- * the interval between ticks.
- */
-#define TICK_TIME_DIVIDEND ((65536 * 60) / (4 * 6))
-
-
-
-/* I'm not going to try to explain this, because I didn't derive it very
- * formally ;)
- */
-/* #define AMIGA_DIVISOR ((float)(4.0 * 14317056.0)) */
-/* I believe the following one to be more accurate. */
-//#define AMIGA_DIVISOR ((float)(8.0 * 7159090.5))
-#define AMIGA_CLOCK 3546895
-#define AMIGA_DIVISOR ((float)(16.0 * AMIGA_CLOCK))
-
-
-
-typedef struct IT_MIDI IT_MIDI;
-typedef struct IT_FILTER_STATE IT_FILTER_STATE;
-typedef struct IT_ENVELOPE IT_ENVELOPE;
-typedef struct IT_INSTRUMENT IT_INSTRUMENT;
-typedef struct IT_SAMPLE IT_SAMPLE;
-typedef struct IT_ENTRY IT_ENTRY;
-typedef struct IT_PATTERN IT_PATTERN;
-typedef struct IT_PLAYING_ENVELOPE IT_PLAYING_ENVELOPE;
-typedef struct IT_PLAYING IT_PLAYING;
-typedef struct IT_CHANNEL IT_CHANNEL;
-typedef struct IT_CHECKPOINT IT_CHECKPOINT;
-typedef struct IT_CALLBACKS IT_CALLBACKS;
-
-
-
-struct IT_MIDI
-{
- unsigned char SFmacro[16][16]; // read these from 0x120
- unsigned char SFmacrolen[16];
- unsigned short SFmacroz[16]; /* Bitfield; bit 0 set = z in first position */
- unsigned char Zmacro[128][16]; // read these from 0x320
- unsigned char Zmacrolen[128];
-};
-
-
-
-struct IT_FILTER_STATE
-{
- sample_t currsample, prevsample;
-};
-
-
-
-#define IT_ENVELOPE_ON 1
-#define IT_ENVELOPE_LOOP_ON 2
-#define IT_ENVELOPE_SUSTAIN_LOOP 4
-#define IT_ENVELOPE_CARRY 8
-#define IT_ENVELOPE_PITCH_IS_FILTER 128
-
-struct IT_ENVELOPE
-{
- unsigned char flags;
- unsigned char n_nodes;
- unsigned char loop_start;
- unsigned char loop_end;
- unsigned char sus_loop_start;
- unsigned char sus_loop_end;
- signed char node_y[25];
- unsigned short node_t[25];
-};
-
-
-
-#define NNA_NOTE_CUT 0
-#define NNA_NOTE_CONTINUE 1
-#define NNA_NOTE_OFF 2
-#define NNA_NOTE_FADE 3
-
-#define DCT_OFF 0
-#define DCT_NOTE 1
-#define DCT_SAMPLE 2
-#define DCT_INSTRUMENT 3
-
-#define DCA_NOTE_CUT 0
-#define DCA_NOTE_OFF 1
-#define DCA_NOTE_FADE 2
-
-struct IT_INSTRUMENT
-{
- unsigned char name[27];
- unsigned char filename[14];
-
- int fadeout;
-
- IT_ENVELOPE volume_envelope;
- IT_ENVELOPE pan_envelope;
- IT_ENVELOPE pitch_envelope;
-
- unsigned char new_note_action;
- unsigned char dup_check_type;
- unsigned char dup_check_action;
- signed char pp_separation;
- unsigned char pp_centre;
- unsigned char global_volume;
- unsigned char default_pan;
- unsigned char random_volume;
- unsigned char random_pan;
-
- unsigned char filter_cutoff;
- unsigned char filter_resonance;
-
- unsigned char map_note[120];
- unsigned short map_sample[120];
-
- //int output;
-};
-
-
-
-#define IT_SAMPLE_EXISTS 1
-#define IT_SAMPLE_16BIT 2
-#define IT_SAMPLE_STEREO 4
-#define IT_SAMPLE_LOOP 16
-#define IT_SAMPLE_SUS_LOOP 32
-#define IT_SAMPLE_PINGPONG_LOOP 64
-#define IT_SAMPLE_PINGPONG_SUS_LOOP 128
-
-#define IT_VIBRATO_SINE 0
-#define IT_VIBRATO_SAWTOOTH 1
-#define IT_VIBRATO_SQUARE 2
-#define IT_VIBRATO_RANDOM 3
-#define IT_VIBRATO_XM_SQUARE 4
-#define IT_VIBRATO_RAMP_DOWN 5
-#define IT_VIBRATO_RAMP_UP 6
-
-struct IT_SAMPLE
-{
- unsigned char name[35];
- unsigned char filename[14];
- unsigned char flags;
- unsigned char global_volume;
- unsigned char default_volume;
- unsigned char default_pan;
- /* default_pan:
- * 0-255 for XM
- * ignored for MOD
- * otherwise, 0-64, and add 128 to enable
- */
-
- long length;
- long loop_start;
- long loop_end;
- long C5_speed;
- long sus_loop_start;
- long sus_loop_end;
-
- unsigned char vibrato_speed;
- unsigned char vibrato_depth;
- unsigned char vibrato_rate;
- unsigned char vibrato_waveform;
-
- signed short finetune;
-
- void *data;
-
- int max_resampling_quality;
-};
-
-
-
-#define IT_ENTRY_NOTE 1
-#define IT_ENTRY_INSTRUMENT 2
-#define IT_ENTRY_VOLPAN 4
-#define IT_ENTRY_EFFECT 8
-
-#define IT_SET_END_ROW(entry) ((entry)->channel = 255)
-#define IT_IS_END_ROW(entry) ((entry)->channel >= DUMB_IT_N_CHANNELS)
-
-#define IT_NOTE_OFF 255
-#define IT_NOTE_CUT 254
-
-#define IT_ENVELOPE_SHIFT 8
-
-#define IT_SURROUND 100
-#define IT_IS_SURROUND(pan) ((pan) > 64)
-#define IT_IS_SURROUND_SHIFTED(pan) ((pan) > 64 << IT_ENVELOPE_SHIFT)
-
-#define IT_SET_SPEED 1
-#define IT_JUMP_TO_ORDER 2
-#define IT_BREAK_TO_ROW 3
-#define IT_VOLUME_SLIDE 4
-#define IT_PORTAMENTO_DOWN 5
-#define IT_PORTAMENTO_UP 6
-#define IT_TONE_PORTAMENTO 7
-#define IT_VIBRATO 8
-#define IT_TREMOR 9
-#define IT_ARPEGGIO 10
-#define IT_VOLSLIDE_VIBRATO 11
-#define IT_VOLSLIDE_TONEPORTA 12
-#define IT_SET_CHANNEL_VOLUME 13
-#define IT_CHANNEL_VOLUME_SLIDE 14
-#define IT_SET_SAMPLE_OFFSET 15
-#define IT_PANNING_SLIDE 16
-#define IT_RETRIGGER_NOTE 17
-#define IT_TREMOLO 18
-#define IT_S 19
-#define IT_SET_SONG_TEMPO 20
-#define IT_FINE_VIBRATO 21
-#define IT_SET_GLOBAL_VOLUME 22
-#define IT_GLOBAL_VOLUME_SLIDE 23
-#define IT_SET_PANNING 24
-#define IT_PANBRELLO 25
-#define IT_MIDI_MACRO 26 //see MIDI.TXT
-
-/* Some effects needed for XM compatibility */
-#define IT_XM_PORTAMENTO_DOWN 27
-#define IT_XM_PORTAMENTO_UP 28
-#define IT_XM_FINE_VOLSLIDE_DOWN 29
-#define IT_XM_FINE_VOLSLIDE_UP 30
-#define IT_XM_RETRIGGER_NOTE 31
-#define IT_XM_KEY_OFF 32
-#define IT_XM_SET_ENVELOPE_POSITION 33
-
-/* More effects needed for PTM compatibility */
-#define IT_PTM_NOTE_SLIDE_DOWN 34
-#define IT_PTM_NOTE_SLIDE_UP 35
-#define IT_PTM_NOTE_SLIDE_DOWN_RETRIG 36
-#define IT_PTM_NOTE_SLIDE_UP_RETRIG 37
-
-#define IT_N_EFFECTS 38
-
-/* These represent the top nibble of the command value. */
-#define IT_S_SET_FILTER 0 /* Greyed out in IT... */
-#define IT_S_SET_GLISSANDO_CONTROL 1 /* Greyed out in IT... */
-#define IT_S_FINETUNE 2 /* Greyed out in IT... */
-#define IT_S_SET_VIBRATO_WAVEFORM 3
-#define IT_S_SET_TREMOLO_WAVEFORM 4
-#define IT_S_SET_PANBRELLO_WAVEFORM 5
-#define IT_S_FINE_PATTERN_DELAY 6
-#define IT_S7 7
-#define IT_S_SET_PAN 8
-#define IT_S_SET_SURROUND_SOUND 9
-#define IT_S_SET_HIGH_OFFSET 10
-#define IT_S_PATTERN_LOOP 11
-#define IT_S_DELAYED_NOTE_CUT 12
-#define IT_S_NOTE_DELAY 13
-#define IT_S_PATTERN_DELAY 14
-#define IT_S_SET_MIDI_MACRO 15
-
-/*
-S0x Set filter
-S1x Set glissando control
-S2x Set finetune
-
-
-S3x Set vibrato waveform to type x
-S4x Set tremelo waveform to type x
-S5x Set panbrello waveform to type x
- Waveforms for commands S3x, S4x and S5x:
- 0: Sine wave
- 1: Ramp down
- 2: Square wave
- 3: Random wave
-S6x Pattern delay for x ticks
-S70 Past note cut
-S71 Past note off
-S72 Past note fade
-S73 Set NNA to note cut
-S74 Set NNA to continue
-S75 Set NNA to note off
-S76 Set NNA to note fade
-S77 Turn off volume envelope
-S78 Turn on volume envelope
-S79 Turn off panning envelope
-S7A Turn on panning envelope
-S7B Turn off pitch envelope
-S7C Turn on pitch envelope
-S8x Set panning position
-S91 Set surround sound
-SAy Set high value of sample offset yxx00h
-SB0 Set loopback point
-SBx Loop x times to loopback point
-SCx Note cut after x ticks
-SDx Note delay for x ticks
-SEx Pattern delay for x rows
-SFx Set parameterised MIDI Macro
-*/
-
-struct IT_ENTRY
-{
- unsigned char channel; /* End of row if channel >= DUMB_IT_N_CHANNELS */
- unsigned char mask;
- unsigned char note;
- unsigned char instrument;
- unsigned char volpan;
- unsigned char effect;
- unsigned char effectvalue;
-};
-
-
-
-struct IT_PATTERN
-{
- int n_rows;
- int n_entries;
- IT_ENTRY *entry;
-};
-
-
-
-#define IT_STEREO 1
-#define IT_USE_INSTRUMENTS 4
-#define IT_LINEAR_SLIDES 8 /* If not set, use Amiga slides */
-#define IT_OLD_EFFECTS 16
-#define IT_COMPATIBLE_GXX 32
-
-/* Make sure IT_WAS_AN_XM and IT_WAS_A_MOD aren't set accidentally */
-#define IT_REAL_FLAGS 63
-
-#define IT_WAS_AN_XM 64 /* Set for both XMs and MODs */
-#define IT_WAS_A_MOD 128
-
-#define IT_WAS_AN_S3M 256
-
-#define IT_WAS_A_PTM 512
-
-#define IT_WAS_A_669 1024
-
-#define IT_ORDER_END 255
-#define IT_ORDER_SKIP 254
-
-struct DUMB_IT_SIGDATA
-{
- unsigned char name[65];
-
- unsigned char *song_message;
-
- int n_orders;
- int n_instruments;
- int n_samples;
- int n_patterns;
- int n_pchannels;
-
- int flags;
-
- int global_volume;
- int mixing_volume;
- int speed;
- int tempo;
- int pan_separation;
-
- unsigned char channel_pan[DUMB_IT_N_CHANNELS];
- unsigned char channel_volume[DUMB_IT_N_CHANNELS];
-
- unsigned char *order;
- unsigned char restart_position; /* for XM compatiblity */
-
- IT_INSTRUMENT *instrument;
- IT_SAMPLE *sample;
- IT_PATTERN *pattern;
-
- IT_MIDI *midi;
-
- IT_CHECKPOINT *checkpoint;
-};
-
-
-
-struct IT_PLAYING_ENVELOPE
-{
- int next_node;
- int tick;
- int value;
-};
-
-
-
-#define IT_PLAYING_BACKGROUND 1
-#define IT_PLAYING_SUSTAINOFF 2
-#define IT_PLAYING_FADING 4
-#define IT_PLAYING_DEAD 8
-
-struct IT_PLAYING
-{
- int flags;
-
- int resampling_quality;
-
- IT_CHANNEL *channel;
- IT_SAMPLE *sample;
- IT_INSTRUMENT *instrument;
- IT_INSTRUMENT *env_instrument;
-
- unsigned short sampnum;
- unsigned char instnum;
-
- unsigned char declick_stage;
- float declick_volume;
-
- float float_volume[2];
- float ramp_volume[2];
- float ramp_delta[2];
-
- unsigned char channel_volume;
-
- unsigned char volume;
- unsigned short pan;
-
- signed char volume_offset, panning_offset;
-
- unsigned char note;
-
- unsigned char enabled_envelopes;
-
- unsigned char filter_cutoff;
- unsigned char filter_resonance;
-
- unsigned short true_filter_cutoff; /* These incorporate the filter envelope, and will not */
- unsigned char true_filter_resonance; /* be changed if they would be set to 127<<8 and 0. */
-
- unsigned char vibrato_speed;
- unsigned char vibrato_depth;
- unsigned char vibrato_n; /* May be specified twice: volpan & effect. */
- unsigned char vibrato_time;
- unsigned char vibrato_waveform;
-
- unsigned char tremolo_speed;
- unsigned char tremolo_depth;
- unsigned char tremolo_time;
- unsigned char tremolo_waveform;
-
- unsigned char panbrello_speed;
- unsigned char panbrello_depth;
- unsigned char panbrello_time;
- unsigned char panbrello_waveform;
- signed char panbrello_random;
-
- unsigned char sample_vibrato_time;
- unsigned char sample_vibrato_waveform;
- int sample_vibrato_depth; /* Starts at rate?0:depth, increases by rate */
-
- int slide;
- float delta;
- int finetune;
-
- IT_PLAYING_ENVELOPE volume_envelope;
- IT_PLAYING_ENVELOPE pan_envelope;
- IT_PLAYING_ENVELOPE pitch_envelope;
-
- int fadeoutcount;
-
- IT_FILTER_STATE filter_state[2]; /* Left and right */
-
- DUMB_RESAMPLER resampler;
-
- /* time_lost is used to emulate Impulse Tracker's sample looping
- * characteristics. When time_lost is added to pos, the result represents
- * the position in the theoretical version of the sample where all loops
- * have been expanded. If this is stored, the resampling helpers will
- * safely convert it for use with new loop boundaries. The situation is
- * slightly more complicated if dir == -1 when the change takes place; we
- * must reflect pos off the loop end point and set dir to 1 before
- * proceeding.
- */
- long time_lost;
-
- //int output;
-};
-
-
-
-#define IT_CHANNEL_MUTED 1
-
-#define IT_ENV_VOLUME 1
-#define IT_ENV_PANNING 2
-#define IT_ENV_PITCH 4
-
-struct IT_CHANNEL
-{
- int flags;
-
- unsigned char volume;
- signed char volslide;
- signed char xm_volslide;
- signed char panslide;
-
- /* xm_volslide is used for volume slides done in the volume column in an
- * XM file, since it seems the volume column slide is applied first,
- * followed by clamping, followed by the effects column slide. IT does
- * not exhibit this behaviour, so xm_volslide is maintained at zero.
- */
-
- unsigned char pan;
- unsigned short truepan;
-
- unsigned char channelvolume;
- signed char channelvolslide;
-
- unsigned char instrument;
- unsigned char note;
-
- unsigned char SFmacro;
-
- unsigned char filter_cutoff;
- unsigned char filter_resonance;
-
- unsigned char key_off_count;
- unsigned char note_cut_count;
- unsigned char note_delay_count;
- IT_ENTRY *note_delay_entry;
-
- unsigned char new_note_action;
-
- int arpeggio;
- unsigned char retrig;
- unsigned char xm_retrig;
- int retrig_tick;
-
- unsigned char tremor;
- unsigned char tremor_time; /* Bit 6 set if note on; bit 7 set if tremor active. */
-
- unsigned char vibrato_waveform;
- unsigned char tremolo_waveform;
- unsigned char panbrello_waveform;
-
- int portamento;
- int toneporta;
- int toneslide;
- unsigned char toneslide_tick, last_toneslide_tick, ptm_toneslide, ptm_last_toneslide;
- unsigned char destnote;
- unsigned char toneslide_retrig;
-
- unsigned char glissando;
-
- /** WARNING - for neatness, should one or both of these be in the IT_PLAYING struct? */
- unsigned short sample;
- unsigned char truenote;
-
- unsigned char midi_state;
-
- signed char lastvolslide;
- unsigned char lastDKL;
- unsigned char lastEF; /* Doubles as last portamento up for XM files */
- unsigned char lastG;
- unsigned char lastHspeed;
- unsigned char lastHdepth;
- unsigned char lastRspeed;
- unsigned char lastRdepth;
- unsigned char lastYspeed;
- unsigned char lastYdepth;
- unsigned char lastI;
- unsigned char lastJ; /* Doubles as last portamento down for XM files */
- unsigned char lastN;
- unsigned char lastO;
- unsigned char high_offset;
- unsigned char lastP;
- unsigned char lastQ;
- unsigned char lastS;
- unsigned char pat_loop_row;
- unsigned char pat_loop_count;
- unsigned char pat_loop_end_row; /* Used to catch infinite pattern loops */
- unsigned char lastW;
-
- unsigned char xm_lastE1;
- unsigned char xm_lastE2;
- unsigned char xm_lastEA;
- unsigned char xm_lastEB;
- unsigned char xm_lastX1;
- unsigned char xm_lastX2;
-
- IT_PLAYING *playing;
-
-#ifdef BIT_ARRAY_BULLSHIT
- void * played_patjump;
- int played_patjump_order;
-#endif
-
- //int output;
-};
-
-
-
-struct DUMB_IT_SIGRENDERER
-{
- DUMB_IT_SIGDATA *sigdata;
-
- int n_channels;
-
- int resampling_quality;
-
- unsigned char globalvolume;
- signed char globalvolslide;
-
- int tempo;
- signed char temposlide;
-
- IT_CHANNEL channel[DUMB_IT_N_CHANNELS];
-
- IT_PLAYING *playing[DUMB_IT_N_NNA_CHANNELS];
-
- int tick;
- int speed;
- int rowcount;
-
- int order; /* Set to -1 if the song is terminated by a callback. */
- int row;
- int processorder;
- int processrow;
- int breakrow;
-
- int restart_position;
-
- int n_rows;
-
- IT_ENTRY *entry_start;
- IT_ENTRY *entry;
- IT_ENTRY *entry_end;
-
- long time_left; /* Time before the next tick is processed */
- int sub_time_left;
-
- DUMB_CLICK_REMOVER **click_remover;
-
- IT_CALLBACKS *callbacks;
-
-#ifdef BIT_ARRAY_BULLSHIT
- /* bit array, which rows are played, only checked by pattern break or loop commands */
- void * played;
-#endif
-
- long gvz_time;
- int gvz_sub_time;
-
- int ramp_style;
-
- //int max_output;
-};
-
-
-
-struct IT_CHECKPOINT
-{
- IT_CHECKPOINT *next;
- long time;
- DUMB_IT_SIGRENDERER *sigrenderer;
-};
-
-
-
-struct IT_CALLBACKS
-{
- int (*loop)(void *data);
- void *loop_data;
- /* Return 1 to prevent looping; the music will terminate abruptly. If you
- * want to make the music stop but allow samples to fade (beware, as they
- * might not fade at all!), use dumb_it_sr_set_speed() and set the speed
- * to 0. Note that xm_speed_zero() will not be called if you set the
- * speed manually, and also that this will work for IT and S3M files even
- * though the music can't stop in this way by itself.
- */
-
- int (*xm_speed_zero)(void *data);
- void *xm_speed_zero_data;
- /* Return 1 to terminate the mod, without letting samples fade. */
-
- int (*midi)(void *data, int channel, unsigned char byte);
- void *midi_data;
- /* Return 1 to prevent DUMB from subsequently interpreting the MIDI bytes
- * itself. In other words, return 1 if the Zxx macros in an IT file are
- * controlling filters and shouldn't be.
- */
-
- int (*global_volume_zero)(void *data);
- void *global_volume_zero_data;
- /* Return 1 to terminate the module when global volume is set to zero. */
-};
-
-
-
-void _dumb_it_end_sigrenderer(sigrenderer_t *sigrenderer);
-void _dumb_it_unload_sigdata(sigdata_t *vsigdata);
-
-extern DUH_SIGTYPE_DESC _dumb_sigtype_it;
-
-
-
-#define XM_APPREGIO 0
-#define XM_PORTAMENTO_UP 1
-#define XM_PORTAMENTO_DOWN 2
-#define XM_TONE_PORTAMENTO 3
-#define XM_VIBRATO 4
-#define XM_VOLSLIDE_TONEPORTA 5
-#define XM_VOLSLIDE_VIBRATO 6
-#define XM_TREMOLO 7
-#define XM_SET_PANNING 8
-#define XM_SAMPLE_OFFSET 9
-#define XM_VOLUME_SLIDE 10 /* A */
-#define XM_POSITION_JUMP 11 /* B */
-#define XM_SET_CHANNEL_VOLUME 12 /* C */
-#define XM_PATTERN_BREAK 13 /* D */
-#define XM_E 14 /* E */
-#define XM_SET_TEMPO_BPM 15 /* F */
-#define XM_SET_GLOBAL_VOLUME 16 /* G */
-#define XM_GLOBAL_VOLUME_SLIDE 17 /* H */
-#define XM_KEY_OFF 20 /* K (undocumented) */
-#define XM_SET_ENVELOPE_POSITION 21 /* L */
-#define XM_PANNING_SLIDE 25 /* P */
-#define XM_MULTI_RETRIG 27 /* R */
-#define XM_TREMOR 29 /* T */
-#define XM_X 33 /* X */
-#define XM_N_EFFECTS (10+26)
-
-#define XM_E_SET_FILTER 0x0
-#define XM_E_FINE_PORTA_UP 0x1
-#define XM_E_FINE_PORTA_DOWN 0x2
-#define XM_E_SET_GLISSANDO_CONTROL 0x3
-#define XM_E_SET_VIBRATO_CONTROL 0x4
-#define XM_E_SET_FINETUNE 0x5
-#define XM_E_SET_LOOP 0x6
-#define XM_E_SET_TREMOLO_CONTROL 0x7
-#define XM_E_SET_PANNING 0x8
-#define XM_E_RETRIG_NOTE 0x9
-#define XM_E_FINE_VOLSLIDE_UP 0xA
-#define XM_E_FINE_VOLSLIDE_DOWN 0xB
-#define XM_E_NOTE_CUT 0xC
-#define XM_E_NOTE_DELAY 0xD
-#define XM_E_PATTERN_DELAY 0xE
-
-#define XM_X_EXTRAFINE_PORTA_UP 1
-#define XM_X_EXTRAFINE_PORTA_DOWN 2
-
-/* To make my life a bit simpler during conversion, effect E:xy is converted
- * to effect number EBASE+x:y. The same applies to effect X, and IT's S. That
- * way, these effects can be manipulated like regular effects.
- */
-#define EBASE (XM_N_EFFECTS)
-#define XBASE (EBASE+16)
-#define SBASE (IT_N_EFFECTS)
-
-#define EFFECT_VALUE(x, y) (((x)<<4)|(y))
-#define HIGH(v) ((v)>>4)
-#define LOW(v) ((v)&0x0F)
-#define SET_HIGH(v, x) v = (((x)<<4)|((v)&0x0F))
-#define SET_LOW(v, y) v = (((v)&0xF0)|(y))
-#define BCD_TO_NORMAL(v) (HIGH(v)*10+LOW(v))
-
-
-
-#if 0
-unsigned char **_dumb_malloc2(int w, int h);
-void _dumb_free2(unsigned char **line);
-#endif
-
-void _dumb_it_xm_convert_effect(int effect, int value, IT_ENTRY *entry, int mod);
-int _dumb_it_fix_invalid_orders(DUMB_IT_SIGDATA *sigdata);
-
-
-#define PTM_APPREGIO 0
-#define PTM_PORTAMENTO_UP 1
-#define PTM_PORTAMENTO_DOWN 2
-#define PTM_TONE_PORTAMENTO 3
-#define PTM_VIBRATO 4
-#define PTM_VOLSLIDE_TONEPORTA 5
-#define PTM_VOLSLIDE_VIBRATO 6
-#define PTM_TREMOLO 7
-#define PTM_SAMPLE_OFFSET 9
-#define PTM_VOLUME_SLIDE 10 /* A */
-#define PTM_POSITION_JUMP 11 /* B */
-#define PTM_SET_CHANNEL_VOLUME 12 /* C */
-#define PTM_PATTERN_BREAK 13 /* D */
-#define PTM_E 14 /* E */
-#define PTM_SET_TEMPO_BPM 15 /* F */
-#define PTM_SET_GLOBAL_VOLUME 16 /* G */
-#define PTM_RETRIGGER 17 /* H */
-#define PTM_FINE_VIBRATO 18 /* I */
-#define PTM_NOTE_SLIDE_UP 19 /* J */
-#define PTM_NOTE_SLIDE_DOWN 20 /* K */
-#define PTM_NOTE_SLIDE_UP_RETRIG 21 /* L */
-#define PTM_NOTE_SLIDE_DOWN_RETRIG 22 /* M */
-#define PTM_N_EFFECTS 23
-
-#define PTM_E_FINE_PORTA_DOWN 0x1
-#define PTM_E_FINE_PORTA_UP 0x2
-#define PTM_E_SET_VIBRATO_CONTROL 0x4
-#define PTM_E_SET_FINETUNE 0x5
-#define PTM_E_SET_LOOP 0x6
-#define PTM_E_SET_TREMOLO_CONTROL 0x7
-#define PTM_E_SET_PANNING 0x8
-#define PTM_E_RETRIG_NOTE 0x9
-#define PTM_E_FINE_VOLSLIDE_UP 0xA
-#define PTM_E_FINE_VOLSLIDE_DOWN 0xB
-#define PTM_E_NOTE_CUT 0xC
-#define PTM_E_NOTE_DELAY 0xD
-#define PTM_E_PATTERN_DELAY 0xE
-
-/* To make my life a bit simpler during conversion, effect E:xy is converted
- * to effect number EBASE+x:y. The same applies to effect X, and IT's S. That
- * way, these effects can be manipulated like regular effects.
- */
-#define PTM_EBASE (PTM_N_EFFECTS)
-
-void _dumb_it_ptm_convert_effect(int effect, int value, IT_ENTRY *entry);
-
-long _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f);
-
-#define min(x,y) ((x)<(y)?(x):(y))
-#define max(x,y) ((x)>(y)?(x):(y))
-
-#endif /* INTERNAL_IT_H */
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * internal/it.h - Internal stuff for IT playback / / \ \
+ * and MOD/XM/S3M conversion. | < / \_
+ * | \/ /\ /
+ * This header file provides access to the \_ / > /
+ * internal structure of DUMB, and is liable | \ / /
+ * to change, mutate or cease to exist at any | ' /
+ * moment. Include it at your own peril. \__/
+ *
+ * ...
+ *
+ * Seriously. You don't need access to anything in this file. All right, you
+ * probably do actually. But if you use it, you will be relying on a specific
+ * version of DUMB, so please check DUMB_VERSION defined in dumb.h. Please
+ * contact the authors so that we can provide a public API for what you need.
+ */
+
+#ifndef INTERNAL_IT_H
+#define INTERNAL_IT_H
+
+
+#define BIT_ARRAY_BULLSHIT
+
+#include <stddef.h>
+
+#include "barray.h"
+
+
+/** TO DO: THINK ABOUT THE FOLLOWING:
+
+sigdata->flags & IT_COMPATIBLE_GXX
+
+ Bit 5: On = Link Effect G's memory with Effect E/F. Also
+ Gxx with an instrument present will cause the
+ envelopes to be retriggered. If you change a
+ sample on a row with Gxx, it'll adjust the
+ frequency of the current note according to:
+
+ NewFrequency = OldFrequency * NewC5 / OldC5;
+*/
+
+
+
+/* These #defines are TEMPORARY. They are used to write alternative code to
+ * handle ambiguities in the format specification. The correct code in each
+ * case will be determined most likely by experimentation.
+ */
+#define STEREO_SAMPLES_COUNT_AS_TWO
+#define INVALID_ORDERS_END_SONG
+#define INVALID_NOTES_CAUSE_NOTE_CUT
+#define SUSTAIN_LOOP_OVERRIDES_NORMAL_LOOP
+#define VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
+
+
+
+#define SIGTYPE_IT DUMB_ID('I', 'T', ' ', ' ')
+
+#define IT_SIGNATURE DUMB_ID('I', 'M', 'P', 'M')
+#define IT_INSTRUMENT_SIGNATURE DUMB_ID('I', 'M', 'P', 'I')
+#define IT_SAMPLE_SIGNATURE DUMB_ID('I', 'M', 'P', 'S')
+
+// olivier sux
+#define IT_MPTX_SIGNATURE DUMB_ID('X', 'T', 'P', 'M')
+#define IT_INSM_SIGNATURE DUMB_ID('M', 'S', 'N', 'I')
+
+
+/* 1 minute per 4 rows, each row 6 ticks; this is divided by the tempo to get
+ * the interval between ticks.
+ */
+#define TICK_TIME_DIVIDEND ((65536 * 60) / (4 * 6))
+
+
+
+/* I'm not going to try to explain this, because I didn't derive it very
+ * formally ;)
+ */
+/* #define AMIGA_DIVISOR ((float)(4.0 * 14317056.0)) */
+/* I believe the following one to be more accurate. */
+//#define AMIGA_DIVISOR ((float)(8.0 * 7159090.5))
+#define AMIGA_CLOCK 3546895
+#define AMIGA_DIVISOR ((float)(16.0 * AMIGA_CLOCK))
+
+
+
+typedef struct IT_MIDI IT_MIDI;
+typedef struct IT_FILTER_STATE IT_FILTER_STATE;
+typedef struct IT_ENVELOPE IT_ENVELOPE;
+typedef struct IT_INSTRUMENT IT_INSTRUMENT;
+typedef struct IT_SAMPLE IT_SAMPLE;
+typedef struct IT_ENTRY IT_ENTRY;
+typedef struct IT_PATTERN IT_PATTERN;
+typedef struct IT_PLAYING_ENVELOPE IT_PLAYING_ENVELOPE;
+typedef struct IT_PLAYING IT_PLAYING;
+typedef struct IT_CHANNEL IT_CHANNEL;
+typedef struct IT_CHECKPOINT IT_CHECKPOINT;
+typedef struct IT_CALLBACKS IT_CALLBACKS;
+
+
+
+struct IT_MIDI
+{
+ unsigned char SFmacro[16][16]; // read these from 0x120
+ unsigned char SFmacrolen[16];
+ unsigned short SFmacroz[16]; /* Bitfield; bit 0 set = z in first position */
+ unsigned char Zmacro[128][16]; // read these from 0x320
+ unsigned char Zmacrolen[128];
+};
+
+
+
+struct IT_FILTER_STATE
+{
+ sample_t currsample, prevsample;
+};
+
+
+
+#define IT_ENVELOPE_ON 1
+#define IT_ENVELOPE_LOOP_ON 2
+#define IT_ENVELOPE_SUSTAIN_LOOP 4
+#define IT_ENVELOPE_CARRY 8
+#define IT_ENVELOPE_PITCH_IS_FILTER 128
+
+struct IT_ENVELOPE
+{
+ unsigned char flags;
+ unsigned char n_nodes;
+ unsigned char loop_start;
+ unsigned char loop_end;
+ unsigned char sus_loop_start;
+ unsigned char sus_loop_end;
+ signed char node_y[25];
+ unsigned short node_t[25];
+};
+
+
+
+#define NNA_NOTE_CUT 0
+#define NNA_NOTE_CONTINUE 1
+#define NNA_NOTE_OFF 2
+#define NNA_NOTE_FADE 3
+
+#define DCT_OFF 0
+#define DCT_NOTE 1
+#define DCT_SAMPLE 2
+#define DCT_INSTRUMENT 3
+
+#define DCA_NOTE_CUT 0
+#define DCA_NOTE_OFF 1
+#define DCA_NOTE_FADE 2
+
+struct IT_INSTRUMENT
+{
+ unsigned char name[27];
+ unsigned char filename[14];
+
+ int fadeout;
+
+ IT_ENVELOPE volume_envelope;
+ IT_ENVELOPE pan_envelope;
+ IT_ENVELOPE pitch_envelope;
+
+ unsigned char new_note_action;
+ unsigned char dup_check_type;
+ unsigned char dup_check_action;
+ signed char pp_separation;
+ unsigned char pp_centre;
+ unsigned char global_volume;
+ unsigned char default_pan;
+ unsigned char random_volume;
+ unsigned char random_pan;
+
+ unsigned char filter_cutoff;
+ unsigned char filter_resonance;
+
+ unsigned char map_note[120];
+ unsigned short map_sample[120];
+
+ //int output;
+};
+
+
+
+#define IT_SAMPLE_EXISTS 1
+#define IT_SAMPLE_16BIT 2
+#define IT_SAMPLE_STEREO 4
+#define IT_SAMPLE_LOOP 16
+#define IT_SAMPLE_SUS_LOOP 32
+#define IT_SAMPLE_PINGPONG_LOOP 64
+#define IT_SAMPLE_PINGPONG_SUS_LOOP 128
+
+#define IT_VIBRATO_SINE 0
+#define IT_VIBRATO_SAWTOOTH 1
+#define IT_VIBRATO_SQUARE 2
+#define IT_VIBRATO_RANDOM 3
+#define IT_VIBRATO_XM_SQUARE 4
+#define IT_VIBRATO_RAMP_DOWN 5
+#define IT_VIBRATO_RAMP_UP 6
+
+struct IT_SAMPLE
+{
+ unsigned char name[35];
+ unsigned char filename[14];
+ unsigned char flags;
+ unsigned char global_volume;
+ unsigned char default_volume;
+ unsigned char default_pan;
+ /* default_pan:
+ * 0-255 for XM
+ * ignored for MOD
+ * otherwise, 0-64, and add 128 to enable
+ */
+
+ long length;
+ long loop_start;
+ long loop_end;
+ long C5_speed;
+ long sus_loop_start;
+ long sus_loop_end;
+
+ unsigned char vibrato_speed;
+ unsigned char vibrato_depth;
+ unsigned char vibrato_rate;
+ unsigned char vibrato_waveform;
+
+ signed short finetune;
+
+ void *data;
+
+ int max_resampling_quality;
+};
+
+
+
+#define IT_ENTRY_NOTE 1
+#define IT_ENTRY_INSTRUMENT 2
+#define IT_ENTRY_VOLPAN 4
+#define IT_ENTRY_EFFECT 8
+
+#define IT_SET_END_ROW(entry) ((entry)->channel = 255)
+#define IT_IS_END_ROW(entry) ((entry)->channel >= DUMB_IT_N_CHANNELS)
+
+#define IT_NOTE_OFF 255
+#define IT_NOTE_CUT 254
+
+#define IT_ENVELOPE_SHIFT 8
+
+#define IT_SURROUND 100
+#define IT_IS_SURROUND(pan) ((pan) > 64)
+#define IT_IS_SURROUND_SHIFTED(pan) ((pan) > 64 << IT_ENVELOPE_SHIFT)
+
+#define IT_SET_SPEED 1
+#define IT_JUMP_TO_ORDER 2
+#define IT_BREAK_TO_ROW 3
+#define IT_VOLUME_SLIDE 4
+#define IT_PORTAMENTO_DOWN 5
+#define IT_PORTAMENTO_UP 6
+#define IT_TONE_PORTAMENTO 7
+#define IT_VIBRATO 8
+#define IT_TREMOR 9
+#define IT_ARPEGGIO 10
+#define IT_VOLSLIDE_VIBRATO 11
+#define IT_VOLSLIDE_TONEPORTA 12
+#define IT_SET_CHANNEL_VOLUME 13
+#define IT_CHANNEL_VOLUME_SLIDE 14
+#define IT_SET_SAMPLE_OFFSET 15
+#define IT_PANNING_SLIDE 16
+#define IT_RETRIGGER_NOTE 17
+#define IT_TREMOLO 18
+#define IT_S 19
+#define IT_SET_SONG_TEMPO 20
+#define IT_FINE_VIBRATO 21
+#define IT_SET_GLOBAL_VOLUME 22
+#define IT_GLOBAL_VOLUME_SLIDE 23
+#define IT_SET_PANNING 24
+#define IT_PANBRELLO 25
+#define IT_MIDI_MACRO 26 //see MIDI.TXT
+
+/* Some effects needed for XM compatibility */
+#define IT_XM_PORTAMENTO_DOWN 27
+#define IT_XM_PORTAMENTO_UP 28
+#define IT_XM_FINE_VOLSLIDE_DOWN 29
+#define IT_XM_FINE_VOLSLIDE_UP 30
+#define IT_XM_RETRIGGER_NOTE 31
+#define IT_XM_KEY_OFF 32
+#define IT_XM_SET_ENVELOPE_POSITION 33
+
+/* More effects needed for PTM compatibility */
+#define IT_PTM_NOTE_SLIDE_DOWN 34
+#define IT_PTM_NOTE_SLIDE_UP 35
+#define IT_PTM_NOTE_SLIDE_DOWN_RETRIG 36
+#define IT_PTM_NOTE_SLIDE_UP_RETRIG 37
+#define IT_MIDI_MACRO 26 //see MIDI.TXT
+
+/* Some effects needed for XM compatibility */
+#define IT_XM_PORTAMENTO_DOWN 27
+#define IT_XM_PORTAMENTO_UP 28
+#define IT_XM_FINE_VOLSLIDE_DOWN 29
+#define IT_XM_FINE_VOLSLIDE_UP 30
+#define IT_XM_RETRIGGER_NOTE 31
+#define IT_XM_KEY_OFF 32
+#define IT_XM_SET_ENVELOPE_POSITION 33
+
+#define IT_N_EFFECTS 38
+
+/* These represent the top nibble of the command value. */
+#define IT_S_SET_FILTER 0 /* Greyed out in IT... */
+#define IT_S_SET_GLISSANDO_CONTROL 1 /* Greyed out in IT... */
+#define IT_S_FINETUNE 2 /* Greyed out in IT... */
+#define IT_S_SET_VIBRATO_WAVEFORM 3
+#define IT_S_SET_TREMOLO_WAVEFORM 4
+#define IT_S_SET_PANBRELLO_WAVEFORM 5
+#define IT_S_FINE_PATTERN_DELAY 6
+#define IT_S7 7
+#define IT_S_SET_PAN 8
+#define IT_S_SET_SURROUND_SOUND 9
+#define IT_S_SET_HIGH_OFFSET 10
+#define IT_S_PATTERN_LOOP 11
+#define IT_S_DELAYED_NOTE_CUT 12
+#define IT_S_NOTE_DELAY 13
+#define IT_S_PATTERN_DELAY 14
+#define IT_S_SET_MIDI_MACRO 15
+
+/*
+S0x Set filter
+S1x Set glissando control
+S2x Set finetune
+
+
+S3x Set vibrato waveform to type x
+S4x Set tremelo waveform to type x
+S5x Set panbrello waveform to type x
+ Waveforms for commands S3x, S4x and S5x:
+ 0: Sine wave
+ 1: Ramp down
+ 2: Square wave
+ 3: Random wave
+S6x Pattern delay for x ticks
+S70 Past note cut
+S71 Past note off
+S72 Past note fade
+S73 Set NNA to note cut
+S74 Set NNA to continue
+S75 Set NNA to note off
+S76 Set NNA to note fade
+S77 Turn off volume envelope
+S78 Turn on volume envelope
+S79 Turn off panning envelope
+S7A Turn on panning envelope
+S7B Turn off pitch envelope
+S7C Turn on pitch envelope
+S8x Set panning position
+S91 Set surround sound
+SAy Set high value of sample offset yxx00h
+SB0 Set loopback point
+SBx Loop x times to loopback point
+SCx Note cut after x ticks
+SDx Note delay for x ticks
+SEx Pattern delay for x rows
+SFx Set parameterised MIDI Macro
+*/
+
+struct IT_ENTRY
+{
+ unsigned char channel; /* End of row if channel >= DUMB_IT_N_CHANNELS */
+ unsigned char mask;
+ unsigned char note;
+ unsigned char instrument;
+ unsigned char volpan;
+ unsigned char effect;
+ unsigned char effectvalue;
+};
+
+
+
+struct IT_PATTERN
+{
+ int n_rows;
+ int n_entries;
+ IT_ENTRY *entry;
+};
+
+
+
+#define IT_STEREO 1
+#define IT_USE_INSTRUMENTS 4
+#define IT_LINEAR_SLIDES 8 /* If not set, use Amiga slides */
+#define IT_OLD_EFFECTS 16
+#define IT_COMPATIBLE_GXX 32
+
+/* Make sure IT_WAS_AN_XM and IT_WAS_A_MOD aren't set accidentally */
+#define IT_REAL_FLAGS 63
+
+#define IT_WAS_AN_XM 64 /* Set for both XMs and MODs */
+#define IT_WAS_A_MOD 128
+
+#define IT_WAS_AN_S3M 256
+
+#define IT_WAS_A_PTM 512
+
+#define IT_WAS_A_669 1024
+
+#define IT_ORDER_END 255
+#define IT_ORDER_SKIP 254
+
+struct DUMB_IT_SIGDATA
+{
+ unsigned char name[65];
+
+ unsigned char *song_message;
+
+ int n_orders;
+ int n_instruments;
+ int n_samples;
+ int n_patterns;
+ int n_pchannels;
+
+ int flags;
+
+ int global_volume;
+ int mixing_volume;
+ int speed;
+ int tempo;
+ int pan_separation;
+
+ unsigned char channel_pan[DUMB_IT_N_CHANNELS];
+ unsigned char channel_volume[DUMB_IT_N_CHANNELS];
+
+ unsigned char *order;
+ unsigned char restart_position; /* for XM compatiblity */
+
+ IT_INSTRUMENT *instrument;
+ IT_SAMPLE *sample;
+ IT_PATTERN *pattern;
+
+ IT_MIDI *midi;
+
+ IT_CHECKPOINT *checkpoint;
+};
+
+
+
+struct IT_PLAYING_ENVELOPE
+{
+ int next_node;
+ int tick;
+ int value;
+};
+
+
+
+#define IT_PLAYING_BACKGROUND 1
+#define IT_PLAYING_SUSTAINOFF 2
+#define IT_PLAYING_FADING 4
+#define IT_PLAYING_DEAD 8
+
+struct IT_PLAYING
+{
+ int flags;
+
+ int resampling_quality;
+
+ IT_CHANNEL *channel;
+ IT_SAMPLE *sample;
+ IT_INSTRUMENT *instrument;
+ IT_INSTRUMENT *env_instrument;
+
+ unsigned short sampnum;
+ unsigned char instnum;
+
+ unsigned char declick_stage;
+ float declick_volume;
+
+ float float_volume[2];
+ float ramp_volume[2];
+ float ramp_delta[2];
+
+ unsigned char channel_volume;
+
+ unsigned char volume;
+ unsigned short pan;
+
+ signed char volume_offset, panning_offset;
+
+ unsigned char note;
+
+ unsigned char enabled_envelopes;
+
+ unsigned char filter_cutoff;
+ unsigned char filter_resonance;
+
+ unsigned short true_filter_cutoff; /* These incorporate the filter envelope, and will not */
+ unsigned char true_filter_resonance; /* be changed if they would be set to 127<<8 and 0. */
+
+ unsigned char vibrato_speed;
+ unsigned char vibrato_depth;
+ unsigned char vibrato_n; /* May be specified twice: volpan & effect. */
+ unsigned char vibrato_time;
+ unsigned char vibrato_waveform;
+
+ unsigned char tremolo_speed;
+ unsigned char tremolo_depth;
+ unsigned char tremolo_time;
+ unsigned char tremolo_waveform;
+
+ unsigned char panbrello_speed;
+ unsigned char panbrello_depth;
+ unsigned char panbrello_time;
+ unsigned char panbrello_waveform;
+ signed char panbrello_random;
+
+ unsigned char sample_vibrato_time;
+ unsigned char sample_vibrato_waveform;
+ int sample_vibrato_depth; /* Starts at rate?0:depth, increases by rate */
+
+ int slide;
+ float delta;
+ int finetune;
+
+ IT_PLAYING_ENVELOPE volume_envelope;
+ IT_PLAYING_ENVELOPE pan_envelope;
+ IT_PLAYING_ENVELOPE pitch_envelope;
+
+ int fadeoutcount;
+
+ IT_FILTER_STATE filter_state[2]; /* Left and right */
+
+ DUMB_RESAMPLER resampler;
+
+ /* time_lost is used to emulate Impulse Tracker's sample looping
+ * characteristics. When time_lost is added to pos, the result represents
+ * the position in the theoretical version of the sample where all loops
+ * have been expanded. If this is stored, the resampling helpers will
+ * safely convert it for use with new loop boundaries. The situation is
+ * slightly more complicated if dir == -1 when the change takes place; we
+ * must reflect pos off the loop end point and set dir to 1 before
+ * proceeding.
+ */
+ long time_lost;
+
+ //int output;
+};
+
+
+
+#define IT_CHANNEL_MUTED 1
+
+#define IT_ENV_VOLUME 1
+#define IT_ENV_PANNING 2
+#define IT_ENV_PITCH 4
+
+struct IT_CHANNEL
+{
+ int flags;
+
+ unsigned char volume;
+ signed char volslide;
+ signed char xm_volslide;
+ signed char panslide;
+
+ /* xm_volslide is used for volume slides done in the volume column in an
+ * XM file, since it seems the volume column slide is applied first,
+ * followed by clamping, followed by the effects column slide. IT does
+ * not exhibit this behaviour, so xm_volslide is maintained at zero.
+ */
+
+ unsigned char pan;
+ unsigned short truepan;
+
+ unsigned char channelvolume;
+ signed char channelvolslide;
+
+ unsigned char instrument;
+ unsigned char note;
+
+ unsigned char SFmacro;
+
+ unsigned char filter_cutoff;
+ unsigned char filter_resonance;
+
+ unsigned char key_off_count;
+ unsigned char note_cut_count;
+ unsigned char note_delay_count;
+ IT_ENTRY *note_delay_entry;
+
+ unsigned char new_note_action;
+
+ int arpeggio;
+ unsigned char retrig;
+ unsigned char xm_retrig;
+ int retrig_tick;
+
+ unsigned char tremor;
+ unsigned char tremor_time; /* Bit 6 set if note on; bit 7 set if tremor active. */
+
+ unsigned char vibrato_waveform;
+ unsigned char tremolo_waveform;
+ unsigned char panbrello_waveform;
+
+ int portamento;
+ int toneporta;
+ int toneslide;
+ unsigned char toneslide_tick, last_toneslide_tick, ptm_toneslide, ptm_last_toneslide;
+ unsigned char destnote;
+ unsigned char toneslide_retrig;
+
+ unsigned char glissando;
+
+ /** WARNING - for neatness, should one or both of these be in the IT_PLAYING struct? */
+ unsigned short sample;
+ unsigned char truenote;
+
+ unsigned char midi_state;
+
+ signed char lastvolslide;
+ unsigned char lastDKL;
+ unsigned char lastEF; /* Doubles as last portamento up for XM files */
+ unsigned char lastG;
+ unsigned char lastHspeed;
+ unsigned char lastHdepth;
+ unsigned char lastRspeed;
+ unsigned char lastRdepth;
+ unsigned char lastYspeed;
+ unsigned char lastYdepth;
+ unsigned char lastI;
+ unsigned char lastJ; /* Doubles as last portamento down for XM files */
+ unsigned char lastN;
+ unsigned char lastO;
+ unsigned char high_offset;
+ unsigned char lastP;
+ unsigned char lastQ;
+ unsigned char lastS;
+ unsigned char pat_loop_row;
+ unsigned char pat_loop_count;
+ unsigned char pat_loop_end_row; /* Used to catch infinite pattern loops */
+ unsigned char lastW;
+
+ unsigned char xm_lastE1;
+ unsigned char xm_lastE2;
+ unsigned char xm_lastEA;
+ unsigned char xm_lastEB;
+ unsigned char xm_lastX1;
+ unsigned char xm_lastX2;
+
+ IT_PLAYING *playing;
+
+#ifdef BIT_ARRAY_BULLSHIT
+ void * played_patjump;
+ int played_patjump_order;
+#endif
+
+ //int output;
+};
+
+
+
+struct DUMB_IT_SIGRENDERER
+{
+ DUMB_IT_SIGDATA *sigdata;
+
+ int n_channels;
+
+ int resampling_quality;
+
+ unsigned char globalvolume;
+ signed char globalvolslide;
+
+ int tempo;
+ signed char temposlide;
+
+ IT_CHANNEL channel[DUMB_IT_N_CHANNELS];
+
+ IT_PLAYING *playing[DUMB_IT_N_NNA_CHANNELS];
+
+ int tick;
+ int speed;
+ int rowcount;
+
+ int order; /* Set to -1 if the song is terminated by a callback. */
+ int row;
+ int processorder;
+ int processrow;
+ int breakrow;
+
+ int restart_position;
+
+ int n_rows;
+
+ IT_ENTRY *entry_start;
+ IT_ENTRY *entry;
+ IT_ENTRY *entry_end;
+
+ long time_left; /* Time before the next tick is processed */
+ int sub_time_left;
+
+ DUMB_CLICK_REMOVER **click_remover;
+
+ IT_CALLBACKS *callbacks;
+
+#ifdef BIT_ARRAY_BULLSHIT
+ /* bit array, which rows are played, only checked by pattern break or loop commands */
+ void * played;
+#endif
+
+ long gvz_time;
+ int gvz_sub_time;
+
+ int ramp_style;
+
+ //int max_output;
+};
+
+
+
+struct IT_CHECKPOINT
+{
+ IT_CHECKPOINT *next;
+ long time;
+ DUMB_IT_SIGRENDERER *sigrenderer;
+};
+
+
+
+struct IT_CALLBACKS
+{
+ int (*loop)(void *data);
+ void *loop_data;
+ /* Return 1 to prevent looping; the music will terminate abruptly. If you
+ * want to make the music stop but allow samples to fade (beware, as they
+ * might not fade at all!), use dumb_it_sr_set_speed() and set the speed
+ * to 0. Note that xm_speed_zero() will not be called if you set the
+ * speed manually, and also that this will work for IT and S3M files even
+ * though the music can't stop in this way by itself.
+ */
+
+ int (*xm_speed_zero)(void *data);
+ void *xm_speed_zero_data;
+ /* Return 1 to terminate the mod, without letting samples fade. */
+
+ int (*midi)(void *data, int channel, unsigned char byte);
+ void *midi_data;
+ /* Return 1 to prevent DUMB from subsequently interpreting the MIDI bytes
+ * itself. In other words, return 1 if the Zxx macros in an IT file are
+ * controlling filters and shouldn't be.
+ */
+
+ int (*global_volume_zero)(void *data);
+ void *global_volume_zero_data;
+ /* Return 1 to terminate the module when global volume is set to zero. */
+};
+
+
+
+void _dumb_it_end_sigrenderer(sigrenderer_t *sigrenderer);
+void _dumb_it_unload_sigdata(sigdata_t *vsigdata);
+
+extern DUH_SIGTYPE_DESC _dumb_sigtype_it;
+
+
+
+#define XM_APPREGIO 0
+#define XM_PORTAMENTO_UP 1
+#define XM_PORTAMENTO_DOWN 2
+#define XM_TONE_PORTAMENTO 3
+#define XM_VIBRATO 4
+#define XM_VOLSLIDE_TONEPORTA 5
+#define XM_VOLSLIDE_VIBRATO 6
+#define XM_TREMOLO 7
+#define XM_SET_PANNING 8
+#define XM_SAMPLE_OFFSET 9
+#define XM_VOLUME_SLIDE 10 /* A */
+#define XM_POSITION_JUMP 11 /* B */
+#define XM_SET_CHANNEL_VOLUME 12 /* C */
+#define XM_PATTERN_BREAK 13 /* D */
+#define XM_E 14 /* E */
+#define XM_SET_TEMPO_BPM 15 /* F */
+#define XM_SET_GLOBAL_VOLUME 16 /* G */
+#define XM_GLOBAL_VOLUME_SLIDE 17 /* H */
+#define XM_KEY_OFF 20 /* K (undocumented) */
+#define XM_SET_ENVELOPE_POSITION 21 /* L */
+#define XM_PANNING_SLIDE 25 /* P */
+#define XM_MULTI_RETRIG 27 /* R */
+#define XM_TREMOR 29 /* T */
+#define XM_X 33 /* X */
+#define XM_N_EFFECTS (10+26)
+
+#define XM_E_SET_FILTER 0x0
+#define XM_E_FINE_PORTA_UP 0x1
+#define XM_E_FINE_PORTA_DOWN 0x2
+#define XM_E_SET_GLISSANDO_CONTROL 0x3
+#define XM_E_SET_VIBRATO_CONTROL 0x4
+#define XM_E_SET_FINETUNE 0x5
+#define XM_E_SET_LOOP 0x6
+#define XM_E_SET_TREMOLO_CONTROL 0x7
+#define XM_E_SET_PANNING 0x8
+#define XM_E_RETRIG_NOTE 0x9
+#define XM_E_FINE_VOLSLIDE_UP 0xA
+#define XM_E_FINE_VOLSLIDE_DOWN 0xB
+#define XM_E_NOTE_CUT 0xC
+#define XM_E_NOTE_DELAY 0xD
+#define XM_E_PATTERN_DELAY 0xE
+
+#define XM_X_EXTRAFINE_PORTA_UP 1
+#define XM_X_EXTRAFINE_PORTA_DOWN 2
+
+/* To make my life a bit simpler during conversion, effect E:xy is converted
+ * to effect number EBASE+x:y. The same applies to effect X, and IT's S. That
+ * way, these effects can be manipulated like regular effects.
+ */
+#define EBASE (XM_N_EFFECTS)
+#define XBASE (EBASE+16)
+#define SBASE (IT_N_EFFECTS)
+
+#define EFFECT_VALUE(x, y) (((x)<<4)|(y))
+#define HIGH(v) ((v)>>4)
+#define LOW(v) ((v)&0x0F)
+#define SET_HIGH(v, x) v = (((x)<<4)|((v)&0x0F))
+#define SET_LOW(v, y) v = (((v)&0xF0)|(y))
+#define BCD_TO_NORMAL(v) (HIGH(v)*10+LOW(v))
+
+
+
+#if 0
+unsigned char **_dumb_malloc2(int w, int h);
+void _dumb_free2(unsigned char **line);
+#endif
+
+void _dumb_it_xm_convert_effect(int effect, int value, IT_ENTRY *entry, int mod);
+int _dumb_it_fix_invalid_orders(DUMB_IT_SIGDATA *sigdata);
+
+
+#define PTM_APPREGIO 0
+#define PTM_PORTAMENTO_UP 1
+#define PTM_PORTAMENTO_DOWN 2
+#define PTM_TONE_PORTAMENTO 3
+#define PTM_VIBRATO 4
+#define PTM_VOLSLIDE_TONEPORTA 5
+#define PTM_VOLSLIDE_VIBRATO 6
+#define PTM_TREMOLO 7
+#define PTM_SAMPLE_OFFSET 9
+#define PTM_VOLUME_SLIDE 10 /* A */
+#define PTM_POSITION_JUMP 11 /* B */
+#define PTM_SET_CHANNEL_VOLUME 12 /* C */
+#define PTM_PATTERN_BREAK 13 /* D */
+#define PTM_E 14 /* E */
+#define PTM_SET_TEMPO_BPM 15 /* F */
+#define PTM_SET_GLOBAL_VOLUME 16 /* G */
+#define PTM_RETRIGGER 17 /* H */
+#define PTM_FINE_VIBRATO 18 /* I */
+#define PTM_NOTE_SLIDE_UP 19 /* J */
+#define PTM_NOTE_SLIDE_DOWN 20 /* K */
+#define PTM_NOTE_SLIDE_UP_RETRIG 21 /* L */
+#define PTM_NOTE_SLIDE_DOWN_RETRIG 22 /* M */
+#define PTM_N_EFFECTS 23
+
+#define PTM_E_FINE_PORTA_DOWN 0x1
+#define PTM_E_FINE_PORTA_UP 0x2
+#define PTM_E_SET_VIBRATO_CONTROL 0x4
+#define PTM_E_SET_FINETUNE 0x5
+#define PTM_E_SET_LOOP 0x6
+#define PTM_E_SET_TREMOLO_CONTROL 0x7
+#define PTM_E_SET_PANNING 0x8
+#define PTM_E_RETRIG_NOTE 0x9
+#define PTM_E_FINE_VOLSLIDE_UP 0xA
+#define PTM_E_FINE_VOLSLIDE_DOWN 0xB
+#define PTM_E_NOTE_CUT 0xC
+#define PTM_E_NOTE_DELAY 0xD
+#define PTM_E_PATTERN_DELAY 0xE
+
+/* To make my life a bit simpler during conversion, effect E:xy is converted
+ * to effect number EBASE+x:y. The same applies to effect X, and IT's S. That
+ * way, these effects can be manipulated like regular effects.
+ */
+#define PTM_EBASE (PTM_N_EFFECTS)
+
+void _dumb_it_ptm_convert_effect(int effect, int value, IT_ENTRY *entry);
+
+long _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f);
+
+#define min(x,y) ((x)<(y)?(x):(y))
+#define max(x,y) ((x)>(y)?(x):(y))
+
+#endif /* INTERNAL_IT_H */
diff --git a/plugins/dumb/dumb-kode54/include/internal/riff.h b/plugins/dumb/dumb-kode54/include/internal/riff.h
index 344a24ea..3dd7547b 100644
--- a/plugins/dumb/dumb-kode54/include/internal/riff.h
+++ b/plugins/dumb/dumb-kode54/include/internal/riff.h
@@ -1,21 +1,21 @@
-#ifndef RIFF_H
-#define RIFF_H
-
-struct riff_chunk
-{
- unsigned type;
- void * data;
- unsigned size;
-};
-
-struct riff
-{
- unsigned type;
- unsigned chunk_count;
- struct riff_chunk * chunks;
-};
-
-struct riff * riff_parse( unsigned char *, unsigned size, unsigned proper );
-void riff_free( struct riff * );
-
-#endif
+#ifndef RIFF_H
+#define RIFF_H
+
+struct riff_chunk
+{
+ unsigned type;
+ void * data;
+ unsigned size;
+};
+
+struct riff
+{
+ unsigned type;
+ unsigned chunk_count;
+ struct riff_chunk * chunks;
+};
+
+struct riff * riff_parse( unsigned char *, unsigned size, unsigned proper );
+void riff_free( struct riff * );
+
+#endif
diff --git a/plugins/dumb/dumb-kode54/licence.txt b/plugins/dumb/dumb-kode54/licence.txt
index 506ec17b..70de9198 100644
--- a/plugins/dumb/dumb-kode54/licence.txt
+++ b/plugins/dumb/dumb-kode54/licence.txt
@@ -18,9 +18,9 @@
*/
-Dynamic Universal Music Bibliotheque
+Dynamic Universal Music Bibliotheque, Version 0.9.3
-Copyright (C) 2001-2003 Ben Davis, Robert J Ohannessian and Julien Cugniere
+Copyright (C) 2001-2005 Ben Davis, Robert J Ohannessian and Julien Cugniere
This software is provided 'as-is', without any express or implied warranty.
In no event shall the authors be held liable for any damages arising from the
@@ -39,16 +39,39 @@ freely, subject to the following restrictions:
[Note that the above point asks for a link to DUMB, not just a mention.
Googling for DUMB doesn't help much! The URL is "http://dumb.sf.net/".]
- [The only reason why the link is not strictly required is that such a
- requirement prevents DUMB from being used in projects with certain other
- licences, notably the GPL. See http://www.gnu.org/philosophy/bsd.html .]
+ [The link was originally strictly required. This was changed for two
+ reasons. Firstly, if many projects request an acknowledgement, the list of
+ acknowledgements can become quite unmanageable. Secondly, DUMB was placing
+ a restriction on the code using it, preventing people from using the GNU
+ General Public Licence which disallows any such restrictions. See
+ http://www.gnu.org/philosophy/bsd.html for more information on this
+ subject. However, if DUMB plays a significant part in your project, we do
+ urge you to acknowledge its use.]
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed from or altered in any source distribution.
-4. If you are using the Program in someone else's bedroom at any Monday
- 3:05 PM, you are not allowed to modify the Program for ten minutes. [This
+4. If you are using the Program in someone else's bedroom on any Monday at
+ 3:05 pm, you are not allowed to modify the Program for ten minutes. [This
clause provided by Inphernic; every licence should contain at least one
clause, the reasoning behind which is far from obvious.]
+
+5. Users who wish to use DUMB for the specific purpose of playing music are
+ required to feed their dog on every full moon (if deemed appropriate).
+ [This clause provided by Allefant, who couldn't remember what Inphernic's
+ clause was.]
+
+6. No clause in this licence shall prevent this software from being depended
+ upon by a product licensed under the GNU General Public Licence. If such a
+ clause is deemed to exist, Debian, then it shall be respected in spirit as
+ far as possible and all other clauses shall continue to apply in full
+ force.
+
+We regret that we cannot provide any warranty, not even the implied warranty
+of merchantability or fitness for a particular purpose.
+
+Some files generated or copied by automake, autoconf and friends are
+available in an extra download. These fall under separate licences but are
+all free to distribute. Please check their licences as necessary.
diff --git a/plugins/dumb/dumb-kode54/make/Makefile.inc b/plugins/dumb/dumb-kode54/make/Makefile.inc
index d7e276cd..3aa94e9c 100644
--- a/plugins/dumb/dumb-kode54/make/Makefile.inc
+++ b/plugins/dumb/dumb-kode54/make/Makefile.inc
@@ -20,7 +20,7 @@ $(OBJDIR)/%.o: src/core/%.c include/dumb.h include/internal/dumb.h
$(OBJDIR)/%.o: src/helpers/%.c include/dumb.h
$(CC) $(CFLAGS) -c -o $@ $<
-$(OBJDIR)/resample.o: src/helpers/resample.inc
+$(OBJDIR)/resample.o: src/helpers/resample.inc src/helpers/resamp2.inc src/helpers/resamp3.inc
$(OBJDIR)/%.o: src/it/%.c include/dumb.h include/internal/it.h
$(CC) $(CFLAGS) -c -o $@ $<
diff --git a/plugins/dumb/dumb-kode54/make/config.sh b/plugins/dumb/dumb-kode54/make/config.sh
index 923b3ccc..9be5e49c 100644
--- a/plugins/dumb/dumb-kode54/make/config.sh
+++ b/plugins/dumb/dumb-kode54/make/config.sh
@@ -5,7 +5,7 @@
# should be run indirectly through the 'make config' target (or the 'make'
# target the first time).
-if [ ! -e make/dumbask ]; then
+if [ ! -f make/dumbask ]; then
echo "You should not be running this directly! Use 'make' or 'make config'."
exit
fi
@@ -24,7 +24,9 @@ echo "Please specify an installation prefix (default $DEFAULT_PREFIX)."
echo -n '> '
read PREFIX
if [ -z $PREFIX ]; then PREFIX=$DEFAULT_PREFIX; fi
-echo "PREFIX := $PREFIX" >> make/config.tmp
+echo "PREFIX := `echo "$PREFIX" | \
+ sed -e 's/\${\([A-Za-z_][A-Za-z0-9_]*\)}/$(\1)/g' \
+ -e 's/\$\([A-Za-z_][A-Za-z0-9_]*\)/$(\1)/g'`" >> make/config.tmp
fi
mv -f make/config.tmp make/config.txt
diff --git a/plugins/dumb/dumb-kode54/make/djgpp.inc b/plugins/dumb/dumb-kode54/make/djgpp.inc
index 009533ce..6f61553c 100644
--- a/plugins/dumb/dumb-kode54/make/djgpp.inc
+++ b/plugins/dumb/dumb-kode54/make/djgpp.inc
@@ -12,6 +12,7 @@ ECHO = @$(COMSPEC) /C ECHO $(1)
# Note: the following two macros only work for single files!
DELETE = $(COMSPEC) /C DEL $(call FIX,$(1))
COPY = $(COMSPEC) /C COPY $(call FIX,$(1)) $(call FIX,$(2))
+MKDIR = $(COMSPEC) /C MKDIR $(call FIX,$(1))
EXE_SUFFIX := .exe
diff --git a/plugins/dumb/dumb-kode54/make/dumbask.c b/plugins/dumb/dumb-kode54/make/dumbask.c
index 8c1b3757..728e8e60 100644
--- a/plugins/dumb/dumb-kode54/make/dumbask.c
+++ b/plugins/dumb/dumb-kode54/make/dumbask.c
@@ -21,7 +21,9 @@ int main(int argc, const char *const argv[])
printf("%s", argv[1]);
for (;;) {
- char c = toupper(getchar());
+ char c = getchar();
+ if (c == EOF) return 0;
+ c = toupper(c);
int i;
for (i = 0; options[i]; i++)
if (c == toupper(options[i]))
diff --git a/plugins/dumb/dumb-kode54/make/mingw.inc b/plugins/dumb/dumb-kode54/make/mingw.inc
index 065f2e5f..d6c665e5 100644
--- a/plugins/dumb/dumb-kode54/make/mingw.inc
+++ b/plugins/dumb/dumb-kode54/make/mingw.inc
@@ -12,6 +12,7 @@ ECHO = @$(COMSPEC) /C ECHO $(1)
# Note: the following two macros only work for single files!
DELETE = $(COMSPEC) /C DEL $(call FIX,$(1))
COPY = $(COMSPEC) /C COPY $(call FIX,$(1)) $(call FIX,$(2))
+MKDIR = $(COMSPEC) /C MKDIR $(call FIX,$(1))
EXE_SUFFIX := .exe
diff --git a/plugins/dumb/dumb-kode54/make/unix.inc b/plugins/dumb/dumb-kode54/make/unix.inc
index 2ab5259a..9345e891 100644
--- a/plugins/dumb/dumb-kode54/make/unix.inc
+++ b/plugins/dumb/dumb-kode54/make/unix.inc
@@ -11,6 +11,7 @@ FIX = $(1)
ECHO = @echo $(1)
DELETE = rm -f $(1)
COPY = cp $(1) $(2)
+MKDIR = mkdir $(1)
EXE_SUFFIX :=
diff --git a/plugins/dumb/dumb-kode54/readme.txt b/plugins/dumb/dumb-kode54/readme.txt
index f8517bac..7a13df96 100644
--- a/plugins/dumb/dumb-kode54/readme.txt
+++ b/plugins/dumb/dumb-kode54/readme.txt
@@ -1,3 +1,7 @@
+NOTICE: this is not the original DUMB-0.9.3,
+it is a modified code based on DUMB-0.9.2 fork from http://kode54.foobar2000.org/
+relevant parts of 0.9.3 were merged on top of that
+
/* _______ ____ __ ___ ___
* \ _ \ \ / \ / \ \ / / ' ' '
* | | \ \ | | || | \/ | . .
@@ -23,7 +27,8 @@
********************
-Thank you for downloading DUMB! You should have the following documentation:
+Thank you for downloading DUMB v0.9.3! You should have the following
+documentation:
readme.txt - This file
licence.txt - Conditions for the use of this software
@@ -75,21 +80,26 @@ Here is the statutory feature list:
- All notes will be present and correct even if you start a piece of music in
the middle
-- Fast seeking to any point before the music first loops (seeking time
- increases beyond this point)
+- Option to take longer loading but seek fast to any point before the music
+ first loops (seeking time increases beyond this point)
- Audio generated can be used in any way; DUMB does not necessarily send it
straight to a sound output system
-- Makefile provided for DJGPP, MinGW, Linux, BeOS and Mac OS X; project file
- provided for MSVC 6 (please contact me if you'd like to submit or request
- support for a new platform; the code itself should port anywhere that has a
- 32-bit C compiler)
-
- Can be used with Allegro, can be used without (if you'd like to help make
DUMB more approachable to people who aren't using Allegro, please contact
me)
+- Makefile provided for DJGPP, MinGW, Linux, BeOS and Mac OS X
+
+- Project files provided for MSVC 6
+
+- Autotools-based configure script available as a separate download for
+ masochists
+
+- Code should port anywhere that has a 32-bit C compiler; instructions on
+ compiling it manually are available further down
+
*********************
*** What you need ***
@@ -104,10 +114,6 @@ Allegro.
Allegro - http://alleg.sf.net/
-Neil Walker has kindly uploaded some DUMB binaries at
-http://retrospec.sgn.net/allegro/ . They may not always be up to date, so you
-should try to compile it yourself first.
-
**********************************************
*** How to set DUMB up with DJGPP or MinGW ***
@@ -117,9 +123,10 @@ should try to compile it yourself first.
You should have got the .zip version. If for some reason you got the .tar.gz
version instead, you may have to convert make/config.bat to DOS text file
format. WinZip does this automatically by default. Otherwise, loading it into
-MS EDIT and saving it again should do the trick. You will have to do the same
-for any files you want to view in Windows Notepad. If you have problems, just
-go and download the .zip instead.
+MS EDIT and saving it again should do the trick (but do not do this to the
+Makefiles as it destroys tabs). You will have to do the same for any files
+you want to view in Windows Notepad. If you have problems, just go and
+download the .zip instead.
Make sure you preserved the directory structure when you extracted DUMB from
the archive. Most unzipping programs will do this by default, but pkunzip
@@ -129,7 +136,11 @@ properly.
If you are using Windows, open an MS-DOS Prompt or a Windows Command Line.
Change to the directory into which you unzipped DUMB.
-Type the following:
+If you are using MinGW (and you haven't renamed 'mingw32-make'), type:
+
+ mingw32-make
+
+Otherwise, type the following:
make
@@ -137,23 +148,35 @@ DUMB will ask you whether you wish to compile for DJGPP or MinGW. Then it
will ask you whether you want support for Allegro. (You have to have made and
installed Allegro's optimised library for this to work.) Finally, it will
compile optimised and debugging builds of DUMB, along with the example
-programs. When it has finished, run the following to install the libraries:
+programs. When it has finished, run one of the following to install the
+libraries:
make install
+ mingw32-make install
All done! If you ever need the configuration again (e.g. if you compiled for
-DJGPP before and you want to compile for MinGW now), run the following:
+DJGPP before and you want to compile for MinGW now), run one of the
+following:
make config
+ mingw32-make config
-See the comments in the makefile for other targets.
+See the comments in the Makefile for other targets.
-Note: the makefile will only work properly if you have COMSPEC or ComSpec set
+Note: the Makefile will only work properly if you have COMSPEC or ComSpec set
to point to command.com or cmd.exe. If you set it to point to a Unix-style
-shell, the makefile won't work.
+shell, the Makefile won't work.
Please let me know if you have any trouble.
+As an alternative, MSYS users may attempt to use the configure script,
+available in dumb-0.9.3-autotools.tar.gz. This has been found to work without
+Allegro, and is untested with Allegro. I should appreciate feedback from
+anyone else who tries this. I do not recommend its use, partly because it
+creates dynamically linked libraries and I don't know how to stop it from
+doing that (see the section on compiling DUMB manually), and partly because
+autotools are plain evil.
+
Scroll down for information on the example programs. Refer to docs/howto.txt
when you are ready to start programming with DUMB. If you use DUMB in a game,
let me know - I might decide to place a link to your game on DUMB's website!
@@ -164,6 +187,9 @@ let me know - I might decide to place a link to your game on DUMB's website!
******************************************************
+If you have a newer version of Microsoft Visual C++ or Visual Something that
+supports C++, please try these instructions and let me know if it works.
+
You should have got the .zip version. If for some reason you got the .tar.gz
version instead, you may have to convert some files to DOS text file format.
WinZip does this automatically by default. Otherwise, loading such files into
@@ -176,12 +202,22 @@ the archive. Most unzipping programs will do this by default, but pkunzip
requires you to pass -d. If not, please delete DUMB and extract it again
properly.
-DUMB now comes with a project file for Microsoft Visual C++ 6. To add DUMB to
-your project:
+DUMB comes with a workspace Microsoft Visual C++ 6, containing projects for
+the DUMB core, the Allegro interface library and each of the examples. The
+first thing you might want to do is load the workspace up and have a look
+around. You will find it in the dumb\vc6 directory under the name dumb.dsw.
+Note that the aldumb and dumbplay projects require Allegro, so they won't
+work if you don't have Allegro. Nevertheless, dumbplay is the best-commented
+of the examples, so do have a look.
+
+When you are ready to add DUMB to your project, follow these instructions:
1. Open your project in VC++.
2. Select Project|Insert Project into Workspace...
-3. Navigate to the dumb\vc6 directory, and select dumb.dsp.
+3. Navigate to the dumb\vc6\dumb directory and select dumb.dsp.
+ Alternatively, if you know that you are statically linking with a library
+ that uses the statically linked multithreaded runtime (/MT), you may wish
+ to select dumb_static.dsp in the dumb_static subdirectory instead.
4. Select Build|Set Active Configuration..., and reselect one of your
project's configurations.
5. Select Project|Dependencies... and ensure your project is dependent on
@@ -196,37 +232,63 @@ your project:
separate, so you'll have to change them one at a time. Exactly which run-
time library you use will depend on what you need; it doesn't appear that
DUMB has any particular requirements, so set it to whatever you're using
- now.
+ now. (It will have to be /MD, the multithreaded DLL library, if you are
+ statically linking with Allegro. If you are dynamically linking with
+ Allegro than it doesn't matter.)
+8. If you are using Allegro, do some or all of the above for the aldumb.dsp
+ project in the aldumb directory too.
-Good thing you only have to do all that once ...
+Good thing you only have to do all that once ... or twice ...
If you have the Intel compiler installed, it will - well, should - be used to
-compile DUMB. The only setting I added is /QxiM. This allows the compiler to
-use PPro and MMX instructions, and so when compiling with Intel the resultant
-EXE will require a Pentium II or greater. I don't think this is unreasonable.
-After all, it is 2003 :)
+compile DUMB. The only setting I [Tom Seddon] added is /QxiM. This allows the
+compiler to use PPro and MMX instructions, and so when compiling with Intel
+the resultant EXE will require a Pentium II or greater. I don't think this is
+unreasonable. After all, it is 2003 :)
+
+[Note from Ben: the Intel compiler is evil! It makes AMD processors look bad!
+Patch it or boycott it or something!]
If you don't have the Intel compiler, VC will compile DUMB as normal.
This project file and these instructions were provided by Tom Seddon (I hope
-I got his name right; I had to guess it from his e-mail address!). They are
-untested by me. If you have problems, check the download page at
-http://dumb.sf.net/ to see if they are addressed; failing that, direct
-queries to me and I'll try to figure them out.
+I got his name right; I had to guess it from his e-mail address!). Chad
+Austin has since changed the project files around, and I've just attempted to
+hack them to incorporate new source files. I've also tried to update the
+instructions using guesswork and some knowledge of Visual J++ (you heard me).
+The instructions and the project files are to this day untested by me. If you
+have problems, check the download page at http://dumb.sf.net/ to see if they
+are addressed; failing that, direct queries to me and I'll try to figure them
+out.
-When you are ready to start using DUMB, refer to docs/howto.txt. If you use
-DUMB in a game, let me know - I might decide to place a link to your game on
-DUMB's website!
+If you have any comments at all on how the VC6 projects are laid out, or how
+the instructions could be improved, I should be really grateful to hear them.
+I am a perfectionist, after all. :)
+Scroll down for information on the example programs. When you are ready to
+start using DUMB, refer to docs/howto.txt. If you use DUMB in a game, let me
+know - I might decide to place a link to your game on DUMB's website!
-********************************************************************
-*** How to set DUMB up on Linux, BeOS and possibly even Mac OS X ***
-********************************************************************
+
+******************************************************
+*** How to set DUMB up on Linux, BeOS and Mac OS X ***
+******************************************************
You should have got the .tar.gz version. If for some reason you got the .zip
-version instead, you may have to use dtou on some or all of the text files.
-If you have problems, just go and download the .tar.gz instead.
+version instead, you may have to strip all characters with ASCII code 13 from
+some of the text files. If you have problems, just go and download the
+.tar.gz instead.
+
+You have two options. There is a Makefile which should cope with most
+systems. The first option is to use this default Makefile, and the procedure
+is explained below. The second option is to download
+dumb-0.9.3-autotools.tar.gz, extract it over the installation, run
+./configure and use the generated Makefile. Users who choose to do this are
+left to their own devices but advised to read the information at the end of
+this section. I strongly recommend the first option.
+
+If you are not using the configure script, the procedure is as follows.
First, run the following command as a normal user:
@@ -236,31 +298,105 @@ You will be asked whether you want Allegro support. Then, unless you are on
BeOS, you will be asked where you'd like DUMB to install its headers,
libraries and examples (which will go in the include/, lib/ and bin/
subdirectories of the prefix you specify). BeOS has fixed locations for these
-files. Once you have specified these pieces of information, the optimised and
-debugging builds of DUMB will be compiled, along with the examples. When it
-has finished, you can install them with:
+files. You may use shell variables here, e.g. $HOME or ${HOME}, but ~ will
+not work. Once you have specified these pieces of information, the optimised
+and debugging builds of DUMB will be compiled, along with the examples. When
+it has finished, you can install them with:
make install
You may need to be root for this to work. It depends on the prefix you chose.
-Note: the makefile will only work if COMSPEC and ComSpec are both undefined.
-If either of these is defined, the makefile will try to build for a Windows
+Note: the Makefile will only work if COMSPEC and ComSpec are both undefined.
+If either of these is defined, the Makefile will try to build for a Windows
system, and will fail.
Please let me know if you have any trouble.
-Information on the example programs is just below. Refer to docs/howto.txt
+Scroll down for information on the example programs. Refer to docs/howto.txt
when you are ready to start programming with DUMB. If you use DUMB in a game,
let me know - I might decide to place a link to your game on DUMB's website!
+Important information for users of the configure script follows.
+
+The Makefile generated by the configure script creates dynamically linked
+libraries, and I don't know how to stop it from doing so. See the section
+below on building DUMB manually for why I recommend linking DUMB statically.
+However, if you choose to use the configure script, note the following.
+
+The default Makefile is a copy of Makefile.rdy (short for 'ready'), and it
+must exist with the name Makefile.rdy in order to work. The configure script
+will overwrite Makefile, so if you want the default Makefile back, just run:
+
+ cp Makefile.rdy Makefile
+
+Do not use a symlink, as that would result in Makefile.rdy getting
+overwritten next time the configure script is run!
+
+You can also access the usual build system by passing '-f Makefile.rdy' to
+Make.
+
+
+********************************************************
+*** How to build DUMB manually if nothing else works ***
+********************************************************
+
+
+Those porting to platforms without floating point support should be aware
+that DUMB does use floating point operations but not in the inner loops. They
+are used for volume and note pitch calculations, and they are used when
+initialising the filter algorithm for given cut-off and resonance values.
+Please let me know if this is a problem for you. If there is enough demand, I
+may be able to eliminate one or both of these cases.
+
+All of the library source code may be found in the src/ subdirectory. There
+are headers in the include/ subdirectory, and src/helpers/resample.c also
+#includes some .inc files in its own directory.
+
+There are four subdirectories under src/. For projects not using Allegro, you
+will need all the files in src/core/, src/helpers/ and src/it/. If you are
+using Allegro, you will want the src/allegro/ subdirectory too. For
+consistency with the other build systems, the contents of src/allegro/ should
+be compiled into a separate library.
+
+I recommend static-linking DUMB, since the version information is done via
+macros and the API has a tendency to change. If you static-link, then once
+your program is in binary form, you can be sure that changes to the installed
+version of DUMB won't cause it to malfuction. It is my fault that the API has
+been so unstable. Sorry!
+
+Compile each .c file separately. As mentioned above, you will need to specify
+two places to look for #include files: the include/ directory and the source
+file's own directory. You will also need to define the symbol
+DUMB_DECLARE_DEPRECATED on the command line.
+
+Do not compile the .inc files separately.
+
+You may need to edit dumb.h and add your own definition for LONG_LONG. It
+should be a 64-bit integer. If you do this, please see if you can add a check
+for your compiler so that it still works with other compilers.
+
+DUMB has two build modes. If you define the symbol DEBUGMODE, some checks for
+programmer error will be incorporated into the library. Otherwise it will be
+built without any such checks. (DUMB will however always thoroughly check the
+validity of files it is loading. If you ever find a module file that crashes
+DUMB, please let me know!)
+
+I recommend building two versions of the library, one with DEBUGMODE defined
+and debugging information included, and the other with compiler optimisation
+enabled. If you can install DUMB system-wide so that your projects, and other
+people's, can simply #include <dumb.h> or <aldumb.h> and link with libraries
+by simple name with no path, then that is ideal.
+
+If you successfully port DUMB to a new platform, please let me know!
+
****************************
*** The example programs ***
****************************
-Two example programs are provided. On DOS and Windows, you can find them in
+Three example programs are provided. On DOS and Windows, you can find them in
the examples subdirectory. On other systems they will be installed system-
wide.
@@ -278,11 +414,14 @@ dumbout
This program does not need Allegro. You can use it to stream an IT, XM,
S3M or MOD file to raw PCM. This can be used as input to an encoder like
oggenc (with appropriate command-line options), or it can be sent to a
- .pcm file which can be read by any respectable waveform editor. No .wav
- support yet, sorry. This program is also convenient for timing DUMB.
- Compare the time it takes to render a module with the module's playing
- time! dumbout doesn't try to read any configuration file; the options are
- set on the command line.
+ .pcm file which can be read by any respectable waveform editor. This
+ program is also convenient for timing DUMB. Compare the time it takes to
+ render a module with the module's playing time! dumbout doesn't try to
+ read any configuration file; the options are set on the command line.
+
+dumb2wav
+ This program is much the same as dumbout, but it writes a .wav file with
+ the appropriate header. Thanks go to Chad Austin for this useful tool.
*********************************************
@@ -290,29 +429,27 @@ dumbout
*********************************************
-If you would like to compose your own music modules, then first I must offer
-a word of warning: not everyone is capable of composing music. Do not assume
-you will be able to learn the art. By all means have a go; if you can learn
-to play tunes on the computer keyboard, you're well on the way to being a
-composer!
+If you would like to compose your own music modules, then this section should
+help get you started.
The best programs for the job are the trackers that pioneered the file
formats:
- Impulse Tracker - IT files - http://www.noisemusic.org/it/
- Fast Tracker II - XM files - http://www.gwinternet.com/music/ft2/
- Scream Tracker 3 - S3M files -
- http://www.united-trackers.org/resources/software/screamtracker.htm
+ Impulse Tracker - IT files - http://www.lim.com.au/ImpulseTracker/
+ Fast Tracker II - XM files - http://www.fasttracker2.com/
+ Scream Tracker 3 - S3M files - No official site known, please use Google
MOD files come from the Amiga; I do not know what PC tracker to recommend for
editing these. If you know of one, let me know! In the meantime, I would
recommend using a more advanced file format. However, don't convert your
existing MODs just for the sake of it.
-Note that Fast Tracker II is Shareware. It arguably offers the best
-interface, but the IT file format is more powerful and better defined.
-Impulse Tracker and Scream Tracker 3 are Freeware. DUMB is likely to be at
-its best with IT files.
+Fast Tracker II is Shareware. It offers a very flashy interface and has a
+game embedded, but the IT file format is more powerful and better defined. By
+all means try them both and see which you prefer; it is largely a matter of
+taste (and, in some cases, religion). Impulse Tracker and Scream Tracker 3
+are Freeware, although you can donate to Impulse Tracker and receive a
+slightly upgraded version. DUMB is likely to be at its best with IT files.
These editors are DOS programs. Users of DOS-incapable operating systems may
like to try ModPlug Tracker, but should read docs/modplug.txt before using it
@@ -322,16 +459,34 @@ trackers' playback, please give me some links so I can put them here!
ModPlug Tracker - http://www.modplug.com/
+If you have an x86 Linux system with VGA-compatible hardware (which covers
+all PC graphics cards I've ever seen), you should be able to get Impulse
+Tracker running with DOSEMU. You will have to give it access to the VGA ports
+and run it in a true console, as it will not work with the X-based VGA
+emulation. I personally added the SB16 emulation to DOSEMU, so you can even
+use filters! However, it corrupts samples alarmingly often when saving on my
+system - probably a DOSEMU issue. If you set this up, I am curious to know
+whether it works for you.
+
+ DOSEMU - http://www.dosemu.org/
+
BEWARE OF WINAMP! Although it's excellent for MP3s, it is notorious for being
-one of the worst module players in existence; very few modules play correctly
+one of the worst module players in existence; very many modules play wrongly
with it. There are plug-ins available to improve Winamp's module support, for
example WSP.
Winamp - http://www.winamp.com/
WSP - http://www.spytech.cz/index.php?sec=demo
+(There is a Winamp plug-in that uses DUMB, but it is unreliable. If anyone
+would like to work on it, please get in touch.)
+
+While I am at it I should also point out that Winamp is notorious for
+containing security flaws. Install it at your own risk, and if it is your
+work computer, check with your boss first!
+
Samples and instruments are the building blocks of music modules. You can
-download samples at:
+download samples at
http://www.tump.net/
@@ -350,14 +505,14 @@ available for download, please let me know.
If you wish to use someone's music in your game, please respect the
composer's wishes. In general, you should ask the composer. Music that has
been placed in the Public Domain can be used by anyone for anything, but it
-wouldn't do any harm to ask anyway if you know who the author is. In most
+wouldn't do any harm to ask anyway if you know who the author is. In many
cases the author will be thrilled, so don't hesitate!
-A note about converting modules from one format to another: don't do it,
-unless you are a musician and are prepared to go through the file and make
-sure everything sounds the way it should! The module formats are all slightly
-different, and converting from one format to another will usually do some
-damage.
+A note about converting modules from one format to another, or converting
+from MIDI: don't do it, unless you are a musician and are prepared to go
+through the file and make sure everything sounds the way it should! The
+module formats are all slightly different, and MIDI is very different;
+converting from one format to another will usually do some damage.
Instead, it is recommended that you allow DUMB to interpret the original file
as it sees fit. DUMB may make mistakes (it does a lot of conversion on
@@ -371,41 +526,11 @@ On the other hand, if you convert the file, the damage is permanent.
If you have trouble with DUMB, or want to contact me for any other reason, my
-e-mail address is given below. However, I may be able to help more if you
-come on to IRC EFnet #dumb.
-
-IRC stands for Internet Relay Chat, and is a type of chat network. Several
-such networks exist, and EFnet is a popular one. In order to connect to an
-IRC network, you first need an IRC client. Here are some:
-
- http://www.xchat.org/
- http://www.visualirc.net/beta.php
- http://www.mirc.com/
-
-Getting on to IRC can be a steep cliff, but it is not insurmountable, and
-it's well worth it. Once you have set up the client software, you need to
-connect to a server. Here is a list of EFnet servers I have had success with.
-Type "/server" (without quotes), then a space, then the name of a server.
-
- irc.homelien.no
- irc.webgiro.se
- efnet.vuurwerk.nl
- efnet.demon.co.uk
- irc.isdnet.fr
- irc.prison.net
-
-If these servers do not work, visit http://efnet.org/ircdb/servers.php for a
-huge list of other EFnet servers to try.
-
-Once you're connected, type the following:
-
- /join #dumb
+e-mail address is given below. Please do get in touch, even if I appear to
+have disappeared!
-A window will appear, and you can ask your question. It should be clear
-what's going on from this point onwards. I am 'entheh'. Note that unlike many
-other nerds I am not always at my computer, so if I don't answer your
-question, don't take it personally! I will usually be able to read your
-question when I come back.
+If you wish to chat online about something, perhaps on IRC, that can most
+likely be arranged. Send me an e-mail.
******************
@@ -418,4 +543,3 @@ This is the conclusion.
Ben Davis
entheh@users.sf.net
-IRC EFnet #dumb
diff --git a/plugins/dumb/dumb-kode54/release.txt b/plugins/dumb/dumb-kode54/release.txt
index cd164887..5334b763 100644
--- a/plugins/dumb/dumb-kode54/release.txt
+++ b/plugins/dumb/dumb-kode54/release.txt
@@ -18,6 +18,161 @@
*/
+*******************************************
+*** DUMB v0.9.3, released 7 August 2005 ***
+*******************************************
+
+Hello! Welcome to a long-awaited-or-probably-just-given-up-on-by-everybody
+release! New to this release are lower memory usage, faster mixing loops,
+loading of text fields in the module files, and faster load functions for
+projects that don't need to seek within the module or know its length.
+Additionally, Chad Austin has contributed a dumb2wav tool for converting
+modules to .wav files and updated the Visual Studio 6 project files to
+compile all the examples as well as the library. Users of Unix-like systems
+will be pleased to know that on Chad's suggestion I have made the build
+system cope with variables such as $HOME or ${HOME} in the prefix.
+
+Chad has also contributed an Autotools build system, but neither of us
+recommends its use. The Autotools are an evil black box, we haven't quite
+managed to get it right, and goodness help you if it happens not to work for
+you. The files are available in a separate download if you absolutely need
+them. Notice that that download is almost twice as large as the rest of DUMB!
+
+Maybe we'll do SCons next time.
+
+Thanks to Chad for all his work. Chad is the author of Audiere, a portable
+sound library which has started using DUMB for its module playback! Wahoo!
+
+ http://audiere.sf.net/
+
+There are three main optimisations that went into the mixing loops.
+
+First, I downloaded ModPlugXMMS and had a peek at the mixing code, which is
+Public Domain. It uses look-up tables for the cubic mixing. I pinched the
+idea, and that sped DUMB's cubic (best quality) resamplers up by a factor of
+two or three.
+
+Secondly, the samples loaded from the file are now kept in 8-bit or 16-bit
+format, whereas previously they were being converted to 24-bit-in-32-bit on
+loading. This means the samples occupy a half or a quarter of the memory they
+used to occupy. It also had the side-effect of speeding up the mixing loops,
+but it meant I had to duplicate the resampling code. (It is all done with
+macros in the source code, but it becomes two copies on the binary level.)
+
+Secondly, stereo samples and stereo mixing buffers are now kept in
+interleaved format, where previously the two channels were done separately to
+keep the code simpler. This change has made the library quite a bit bigger,
+but has made the code run almost twice as fast for stereo output (tested for
+modules whose samples are mostly mono)!
+
+DUMB is now as fast as ModPlugXMMS on my system.
+
+Some people have also commented that DUMB seems to take a long time loading
+files. This is because immediately upon loading the file it runs the playback
+engine over it up as far as the point of first loop, taking snapshots at 30-
+second intervals to be used as references for fast seeking and finally
+storing the playback time. Of course, most games don't need this. You can now
+skip it by calling the _quick versions of the dumb_load_*(), dumb_read_*() or
+dumb_register_dat_*() functions. Should you need the data later, you can call
+dumb_it_do_initial_runthrough() to calculate it. Please note that this cannot
+currently be done safely from a concurrent thread while the music is playing.
+
+As mentioned, DUMB loads the text fields in module files now. You can
+retrieve the song title with duh_get_tag(). Sample names and file names and
+instrument names and filenames, and the song message for IT files, are
+available with a call to duh_get_it_sigdata() and various dumb_it_sd_*()
+functions. Please note that text fields added as extensions by ModPlug
+Tracker are not supported.
+
+DUMB's timing is ever so slightly more accurate. This is hardly noticeable,
+but it has meant that the length computed will increase very slightly.
+
+There are many small playback fixes in this release:
+
+* The Lxx effect in XM files (set envelope position) is now supported.
+
+* Pattern looping is now correct for XM files. Bizarrely, an ordinary pattern
+ loop whose start point isn't the first row seems to cause the next pattern
+ to start at the row corresponding to the loop start point. That must have
+ been a headache for people creating XM files! Nevertheless, DUMB now
+ emulates this behaviour. If you have an XM file that was written in a
+ tracker other than Fast Tracker II and breaks in DUMB, you can get around
+ it by putting a D00 effect (break to row 0) right at the end of the pattern
+ containing the loop.
+
+* XM pattern looping can be infinite. DUMB should detect this and call the
+ loop callback when it happens. Specifically, it has a loop counter for each
+ channel, so each time it sets or decrements that counter, it remembers the
+ loop end point for that channel. When the loop terminates, the loop end
+ point is reset to 0. If the loop end point ever decreases during a loop,
+ the loop callback is called. If anyone manages to get around this check and
+ prevent DUMB from calling the callback, please let me know and send me an
+ illustrative XM file!
+
+* For IT files, notes are now removed from channels if they have faded out,
+ even if they are still in the foreground. After this has happened, a row
+ with a note and Gxx (tone portamento) specified will cause a new note to
+ start playing, which is what Impulse Tracker does in this scenario.
+ (Normally, Gxx prevents the new note from playing and instead causes the
+ old note to start sliding towards the new note.)
+
+* If a tone portamento command occurred when no note was playing, the effect
+ value wasn't stored. This has been fixed. Thanks to Maim from #trax on
+ EFnet for discovering this bug.
+
+* DUMB now treats the parameter to the undocumented XM key off effect Kxx as
+ a delay, consistent with Fast Tracker II's behaviour. It has also been made
+ not to clear the note, so a subsequent volume command will restore it, as
+ in Fast Tracker II.
+
+* DUMB used to process the first row when you created the
+ DUMB_IT_SIGRENDERER. This happened before you had a chance to install any
+ callbacks. If an F00 effect occurred on the first row, the music would stop
+ immediately and the xm_speed_zero callback would be called if it were
+ present. Unfortunately, it wasn't present, and the algorithm for
+ calculating the length subsequently went into an endless loop while waiting
+ for it. Worse still, the same algorithm accumulated data for fast seeking,
+ and never stopped, so it pretty quickly consumed all the resources. DUMB
+ will now not process the first row until you first request some samples,
+ provided you pass zero for pos. Of course, any MOD or XM file with F00 in
+ the very first row won't do much anyway, but such files won't crash the
+ library now.
+
+* There was a subtle bug that affected a few XM files. For instruments with
+ no associated samples, the array mapping notes to samples is uninitialised.
+ This became a problem if such instruments were then used, which does happen
+ sometimes. On many systems, memory is initialised to zero when first given
+ to a program (for security reasons), so the problem didn't come up most of
+ the time. However, on platforms like DOS where memory isn't initialised, or
+ in programs that reuse memory later on (this includes the XMMS plug-in with
+ which I discovered the bug), a rogue note would occasionally play. This has
+ now been fixed.
+
+* DUMB's envelope handling for IT files was subtly wrong. Upon note off, it
+ stopped obeying the sustain loop points one tick too early. Notes were
+ often shorter than they should have been, and in pathological cases a whole
+ extra iteration of the sustain loop section might have been skipped. The
+ envelope code has now been rewritten. Thanks go to Allefant for Valgrinding
+ the new code!
+
+Finally, there were two build problems in the last version, which were fixed
+in the download marked with -fixed. They are of course correct in this
+version. For the record:
+
+* The make/config.bat file, responsible for generating make/config.txt, wrote
+ a crucial line to the wrong place, causing it to be left out of the file.
+ As a result, the makefile would fail to install everything for Allegro
+ users, and enter infinite recursion for other users. This applied to people
+ using DJGPP and MinGW.
+
+* DUMB's Makefile was supposed to install the example programs on Unix-based
+ platforms, but it wasn't doing. The fix was to edit Makefile and change the
+ one occurrence of $COMSPEC to $(COMSPEC).
+
+That's it! I hope you enjoy this long-awaited-or-probably-just-given-up-on-
+by-everybody release of DUMB!
+
+
******************************************
*** DUMB v
******************************************
diff --git a/plugins/dumb/dumb-kode54/src/allegro/alplay.c b/plugins/dumb/dumb-kode54/src/allegro/alplay.c
index 85e2079a..761ae36a 100644
--- a/plugins/dumb/dumb-kode54/src/allegro/alplay.c
+++ b/plugins/dumb/dumb-kode54/src/allegro/alplay.c
@@ -1,277 +1,284 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * alplay.c - Functions to play a DUH through / / \ \
- * an Allegro audio stream. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include <allegro.h>
-
-#include "aldumb.h"
-
-
-
-#define ADP_PLAYING 1
-
-struct AL_DUH_PLAYER
-{
- int flags;
- long bufsize;
- int freq;
- AUDIOSTREAM *stream;
- DUH_SIGRENDERER *sigrenderer; /* If this is NULL, stream is invalid. */
- float volume;
- int silentcount;
-};
-
-
-
-AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos, float volume, long bufsize, int freq)
-{
- AL_DUH_PLAYER *dp;
-
- /* This restriction is imposed by Allegro. */
- ASSERT(n_channels > 0);
- ASSERT(n_channels <= 2);
-
- if (!duh)
- return NULL;
-
- dp = malloc(sizeof(*dp));
- if (!dp)
- return NULL;
-
- dp->flags = ADP_PLAYING;
- dp->bufsize = bufsize;
- dp->freq = freq;
-
- dp->stream = play_audio_stream(bufsize, 16, n_channels - 1, freq, 255, 128);
-
- if (!dp->stream) {
- free(dp);
- return NULL;
- }
-
- voice_set_priority(dp->stream->voice, 255);
-
- dp->sigrenderer = duh_start_sigrenderer(duh, 0, n_channels, pos);
-
- if (!dp->sigrenderer) {
- stop_audio_stream(dp->stream);
- free(dp);
- return NULL;
- }
-
- dp->volume = volume;
- dp->silentcount = 0;
-
- return dp;
-}
-
-
-
-void al_stop_duh(AL_DUH_PLAYER *dp)
-{
- if (dp) {
- if (dp->sigrenderer) {
- duh_end_sigrenderer(dp->sigrenderer);
- stop_audio_stream(dp->stream);
- }
- free(dp);
- }
-}
-
-
-
-void al_pause_duh(AL_DUH_PLAYER *dp)
-{
- if (dp && dp->sigrenderer && (dp->flags & ADP_PLAYING)) {
- voice_stop(dp->stream->voice);
- dp->flags &= ~ADP_PLAYING;
- }
-}
-
-
-
-void al_resume_duh(AL_DUH_PLAYER *dp)
-{
- if (dp && dp->sigrenderer && !(dp->flags & ADP_PLAYING)) {
- voice_start(dp->stream->voice);
- dp->flags |= ADP_PLAYING;
- }
-}
-
-
-
-void al_duh_set_priority(AL_DUH_PLAYER *dp, int priority)
-{
- if (dp && dp->sigrenderer)
- voice_set_priority(dp->stream->voice, priority);
-}
-
-
-
-void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume)
-{
- if (dp)
- dp->volume = volume;
-}
-
-
-
-float al_duh_get_volume(AL_DUH_PLAYER *dp)
-{
- return dp ? dp->volume : 0;
-}
-
-
-
-int al_poll_duh(AL_DUH_PLAYER *dp)
-{
- unsigned short *sptr;
- long n;
- long size;
- int n_channels;
-
- if (!dp || !dp->sigrenderer)
- return 1;
-
- if (!(dp->flags & ADP_PLAYING))
- return 0;
-
- sptr = get_audio_stream_buffer(dp->stream);
-
- if (!sptr)
- return 0;
-
- n = duh_render(dp->sigrenderer, 16, 1, dp->volume, 65536.0 / dp->freq, dp->bufsize, sptr);
-
- if (n == 0) {
- if (++dp->silentcount >= 2) {
- duh_end_sigrenderer(dp->sigrenderer);
- free_audio_stream_buffer(dp->stream);
- stop_audio_stream(dp->stream);
- dp->sigrenderer = NULL;
- return 1;
- }
- }
-
- n_channels = duh_sigrenderer_get_n_channels(dp->sigrenderer);
- n *= n_channels;
- size = dp->bufsize * n_channels;
- for (; n < size; n++)
- sptr[n] = 0x8000;
-
- free_audio_stream_buffer(dp->stream);
-
- return 0;
-}
-
-
-
-long al_duh_get_position(AL_DUH_PLAYER *dp)
-{
- return dp ? duh_sigrenderer_get_position(dp->sigrenderer) : -1;
-}
-
-
-
-AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq)
-{
- AL_DUH_PLAYER *dp;
- int n_channels;
-
- if (!sigrenderer)
- return NULL;
-
- dp = malloc(sizeof(*dp));
- if (!dp)
- return NULL;
-
- n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
-
- /* This restriction is imposed by Allegro. */
- ASSERT(n_channels > 0);
- ASSERT(n_channels <= 2);
-
- dp->flags = ADP_PLAYING;
- dp->bufsize = bufsize;
- dp->freq = freq;
-
- dp->stream = play_audio_stream(bufsize, 16, n_channels - 1, freq, 255, 128);
-
- if (!dp->stream) {
- free(dp);
- return NULL;
- }
-
- voice_set_priority(dp->stream->voice, 255);
-
- dp->sigrenderer = sigrenderer;
-
- dp->volume = volume;
- dp->silentcount = 0;
-
- return dp;
-}
-
-
-
-DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp)
-{
- return dp ? dp->sigrenderer : NULL;
-}
-
-
-
-/* IMPORTANT: This function will return NULL if the music has ended. */
-// Should this be changed? User might want to hack the underlying SIGRENDERER
-// and resurrect it (e.g. change pattern number), before it gets destroyed...
-DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp)
-{
- if (dp) {
- DUH_SIGRENDERER *sigrenderer = dp->sigrenderer;
- if (sigrenderer) stop_audio_stream(dp->stream);
- free(dp);
- return sigrenderer;
- }
- return NULL;
-}
-
-
-
-/* DEPRECATED */
-AL_DUH_PLAYER *al_duh_encapsulate_renderer(DUH_SIGRENDERER *dr, float volume, long bufsize, int freq)
-{
- return al_duh_encapsulate_sigrenderer(dr, volume, bufsize, freq);
-}
-
-
-
-/* DEPRECATED */
-DUH_SIGRENDERER *al_duh_get_renderer(AL_DUH_PLAYER *dp)
-{
- return al_duh_get_sigrenderer(dp);
-}
-
-
-
-/* DEPRECATED */
-DUH_SIGRENDERER *al_duh_decompose_to_renderer(AL_DUH_PLAYER *dp)
-{
- return al_duh_decompose_to_sigrenderer(dp);
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * alplay.c - Functions to play a DUH through / / \ \
+ * an Allegro audio stream. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include <allegro.h>
+
+#include "aldumb.h"
+
+
+
+#define ADP_PLAYING 1
+
+struct AL_DUH_PLAYER
+{
+ int flags;
+ long bufsize;
+ int freq;
+ AUDIOSTREAM *stream;
+ DUH_SIGRENDERER *sigrenderer; /* If this is NULL, stream is invalid. */
+ float volume;
+ int silentcount;
+};
+
+
+
+AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos, float volume, long bufsize, int freq)
+{
+ AL_DUH_PLAYER *dp;
+
+ /* This restriction is imposed by Allegro. */
+ ASSERT(n_channels > 0);
+ ASSERT(n_channels <= 2);
+
+ if (!duh)
+ return NULL;
+
+ dp = malloc(sizeof(*dp));
+ if (!dp)
+ return NULL;
+
+ dp->flags = ADP_PLAYING;
+ dp->bufsize = bufsize;
+ dp->freq = freq;
+
+ dp->stream = play_audio_stream(bufsize, 16, n_channels - 1, freq, 255, 128);
+
+ if (!dp->stream) {
+ free(dp);
+ return NULL;
+ }
+
+ voice_set_priority(dp->stream->voice, 255);
+
+ dp->sigrenderer = duh_start_sigrenderer(duh, 0, n_channels, pos);
+
+ if (!dp->sigrenderer) {
+ stop_audio_stream(dp->stream);
+ free(dp);
+ return NULL;
+ }
+
+ dp->volume = volume;
+ dp->silentcount = 0;
+
+ return dp;
+}
+
+
+
+void al_stop_duh(AL_DUH_PLAYER *dp)
+{
+ if (dp) {
+ if (dp->sigrenderer) {
+ duh_end_sigrenderer(dp->sigrenderer);
+ stop_audio_stream(dp->stream);
+ }
+ free(dp);
+ }
+}
+
+
+
+void al_pause_duh(AL_DUH_PLAYER *dp)
+{
+ if (dp && dp->sigrenderer && (dp->flags & ADP_PLAYING)) {
+ voice_stop(dp->stream->voice);
+ dp->flags &= ~ADP_PLAYING;
+ }
+}
+
+
+
+void al_resume_duh(AL_DUH_PLAYER *dp)
+{
+ if (dp && dp->sigrenderer && !(dp->flags & ADP_PLAYING)) {
+ voice_start(dp->stream->voice);
+ dp->flags |= ADP_PLAYING;
+ }
+}
+
+
+
+void al_duh_set_priority(AL_DUH_PLAYER *dp, int priority)
+{
+ if (dp && dp->sigrenderer)
+ voice_set_priority(dp->stream->voice, priority);
+}
+
+
+
+void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume)
+{
+ if (dp)
+ dp->volume = volume;
+}
+
+
+
+float al_duh_get_volume(AL_DUH_PLAYER *dp)
+{
+ return dp ? dp->volume : 0;
+}
+
+
+
+float al_duh_get_volume(AL_DUH_PLAYER *dp)
+{
+ return dp ? dp->volume : 0;
+}
+
+
+
+int al_poll_duh(AL_DUH_PLAYER *dp)
+{
+ unsigned short *sptr;
+ long n;
+ long size;
+ int n_channels;
+
+ if (!dp || !dp->sigrenderer)
+ return 1;
+
+ if (!(dp->flags & ADP_PLAYING))
+ return 0;
+
+ sptr = get_audio_stream_buffer(dp->stream);
+
+ if (!sptr)
+ return 0;
+
+ n = duh_render(dp->sigrenderer, 16, 1, dp->volume, 65536.0 / dp->freq, dp->bufsize, sptr);
+
+ if (n == 0) {
+ if (++dp->silentcount >= 2) {
+ duh_end_sigrenderer(dp->sigrenderer);
+ free_audio_stream_buffer(dp->stream);
+ stop_audio_stream(dp->stream);
+ dp->sigrenderer = NULL;
+ return 1;
+ }
+ }
+
+ n_channels = duh_sigrenderer_get_n_channels(dp->sigrenderer);
+ n *= n_channels;
+ size = dp->bufsize * n_channels;
+ for (; n < size; n++)
+ sptr[n] = 0x8000;
+
+ free_audio_stream_buffer(dp->stream);
+
+ return 0;
+}
+
+
+
+long al_duh_get_position(AL_DUH_PLAYER *dp)
+{
+ return dp ? duh_sigrenderer_get_position(dp->sigrenderer) : -1;
+}
+
+
+
+AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq)
+{
+ AL_DUH_PLAYER *dp;
+ int n_channels;
+
+ if (!sigrenderer)
+ return NULL;
+
+ dp = malloc(sizeof(*dp));
+ if (!dp)
+ return NULL;
+
+ n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
+
+ /* This restriction is imposed by Allegro. */
+ ASSERT(n_channels > 0);
+ ASSERT(n_channels <= 2);
+
+ dp->flags = ADP_PLAYING;
+ dp->bufsize = bufsize;
+ dp->freq = freq;
+
+ dp->stream = play_audio_stream(bufsize, 16, n_channels - 1, freq, 255, 128);
+
+ if (!dp->stream) {
+ free(dp);
+ return NULL;
+ }
+
+ voice_set_priority(dp->stream->voice, 255);
+
+ dp->sigrenderer = sigrenderer;
+
+ dp->volume = volume;
+ dp->silentcount = 0;
+
+ return dp;
+}
+
+
+
+DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp)
+{
+ return dp ? dp->sigrenderer : NULL;
+}
+
+
+
+/* IMPORTANT: This function will return NULL if the music has ended. */
+// Should this be changed? User might want to hack the underlying SIGRENDERER
+// and resurrect it (e.g. change pattern number), before it gets destroyed...
+DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp)
+{
+ if (dp) {
+ DUH_SIGRENDERER *sigrenderer = dp->sigrenderer;
+ if (sigrenderer) stop_audio_stream(dp->stream);
+ free(dp);
+ return sigrenderer;
+ }
+ return NULL;
+}
+
+
+
+/* DEPRECATED */
+AL_DUH_PLAYER *al_duh_encapsulate_renderer(DUH_SIGRENDERER *dr, float volume, long bufsize, int freq)
+{
+ return al_duh_encapsulate_sigrenderer(dr, volume, bufsize, freq);
+}
+
+
+
+/* DEPRECATED */
+DUH_SIGRENDERER *al_duh_get_renderer(AL_DUH_PLAYER *dp)
+{
+ return al_duh_get_sigrenderer(dp);
+}
+
+
+
+/* DEPRECATED */
+DUH_SIGRENDERER *al_duh_decompose_to_renderer(AL_DUH_PLAYER *dp)
+{
+ return al_duh_decompose_to_sigrenderer(dp);
+}
diff --git a/plugins/dumb/dumb-kode54/src/allegro/datduh.c b/plugins/dumb/dumb-kode54/src/allegro/datduh.c
index 5dec3975..672e3c82 100644
--- a/plugins/dumb/dumb-kode54/src/allegro/datduh.c
+++ b/plugins/dumb/dumb-kode54/src/allegro/datduh.c
@@ -1,60 +1,60 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * datduh.c - Integration with Allegro's / / \ \
- * datafiles. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <allegro.h>
-
-#include "aldumb.h"
-#include "internal/aldumb.h"
-
-
-
-static void *dat_read_duh(PACKFILE *f, long size)
-{
- DUMBFILE *df;
- DUH *duh;
-
- (void)size;
-
- df = dumbfile_open_packfile(f);
-
- if (!df)
- return NULL;
-
- duh = read_duh(df);
-
- dumbfile_close(df);
-
- return duh;
-}
-
-
-
-/* dumb_register_dat_duh(): tells Allegro about the DUH datafile object. If
- * you intend to load a datafile containing a DUH object, you must call this
- * function first. It is recommended you pass DAT_DUH, but you may have a
- * reason to use a different type (apart from pride, that doesn't count).
- */
-void dumb_register_dat_duh(long type)
-{
- register_datafile_object(
- type,
- &dat_read_duh,
- &_dat_unload_duh
- );
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * datduh.c - Integration with Allegro's / / \ \
+ * datafiles. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <allegro.h>
+
+#include "aldumb.h"
+#include "internal/aldumb.h"
+
+
+
+static void *dat_read_duh(PACKFILE *f, long size)
+{
+ DUMBFILE *df;
+ DUH *duh;
+
+ (void)size;
+
+ df = dumbfile_open_packfile(f);
+
+ if (!df)
+ return NULL;
+
+ duh = read_duh(df);
+
+ dumbfile_close(df);
+
+ return duh;
+}
+
+
+
+/* dumb_register_dat_duh(): tells Allegro about the DUH datafile object. If
+ * you intend to load a datafile containing a DUH object, you must call this
+ * function first. It is recommended you pass DAT_DUH, but you may have a
+ * reason to use a different type (apart from pride, that doesn't count).
+ */
+void dumb_register_dat_duh(long type)
+{
+ register_datafile_object(
+ type,
+ &dat_read_duh,
+ &_dat_unload_duh
+ );
+}
diff --git a/plugins/dumb/dumb-kode54/src/allegro/datit.c b/plugins/dumb/dumb-kode54/src/allegro/datit.c
index 1a6ce2f6..8f58f142 100644
--- a/plugins/dumb/dumb-kode54/src/allegro/datit.c
+++ b/plugins/dumb/dumb-kode54/src/allegro/datit.c
@@ -1,62 +1,62 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * datit.c - Integration of IT files with / / \ \
- * Allegro's datafiles. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <allegro.h>
-
-#include "aldumb.h"
-#include "internal/aldumb.h"
-
-
-
-static void *dat_read_it(PACKFILE *f, long size)
-{
- DUMBFILE *df;
- DUH *duh;
-
- (void)size;
-
- df = dumbfile_open_packfile(f);
-
- if (!df)
- return NULL;
-
- duh = dumb_read_it(df);
-
- dumbfile_close(df);
-
- return duh;
-}
-
-
-
-/* dumb_register_dat_it(): tells Allegro about the IT datafile object. If you
- * intend to load a datafile containing an IT object, you must call this
- * function first. It is recommended you pass DUMB_DAT_IT, but you may have a
- * reason to use a different type (perhaps you already have a datafile with
- * IT files in and they use a different type).
- */
-void dumb_register_dat_it(long type)
-{
- register_datafile_object(
- type,
- &dat_read_it,
- &_dat_unload_duh
- );
-}
-
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * datit.c - Integration of IT files with / / \ \
+ * Allegro's datafiles. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <allegro.h>
+
+#include "aldumb.h"
+#include "internal/aldumb.h"
+
+
+
+static void *dat_read_it(PACKFILE *f, long size)
+{
+ DUMBFILE *df;
+ DUH *duh;
+
+ (void)size;
+
+ df = dumbfile_open_packfile(f);
+
+ if (!df)
+ return NULL;
+
+ duh = dumb_read_it(df);
+
+ dumbfile_close(df);
+
+ return duh;
+}
+
+
+
+/* dumb_register_dat_it(): tells Allegro about the IT datafile object. If you
+ * intend to load a datafile containing an IT object, you must call this
+ * function first. It is recommended you pass DUMB_DAT_IT, but you may have a
+ * reason to use a different type (perhaps you already have a datafile with
+ * IT files in and they use a different type).
+ */
+void dumb_register_dat_it(long type)
+{
+ register_datafile_object(
+ type,
+ &dat_read_it,
+ &_dat_unload_duh
+ );
+}
+
diff --git a/plugins/dumb/dumb-kode54/src/allegro/datmod.c b/plugins/dumb/dumb-kode54/src/allegro/datmod.c
index abbc1d9a..850b17b4 100644
--- a/plugins/dumb/dumb-kode54/src/allegro/datmod.c
+++ b/plugins/dumb/dumb-kode54/src/allegro/datmod.c
@@ -1,61 +1,61 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * datmod.c - Integration of MOD files with / / \ \
- * Allegro's datafiles. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <allegro.h>
-
-#include "aldumb.h"
-#include "internal/aldumb.h"
-
-
-
-static void *dat_read_mod(PACKFILE *f, long size)
-{
- DUMBFILE *df;
- DUH *duh;
-
- (void)size;
-
- df = dumbfile_open_packfile(f);
-
- if (!df)
- return NULL;
-
- duh = dumb_read_mod(df);
-
- dumbfile_close(df);
-
- return duh;
-}
-
-
-
-/* dumb_register_dat_mod(): tells Allegro about the MOD datafile object. If
- * you intend to load a datafile containing a MOD object, you must call this
- * function first. It is recommended you pass DUMB_DAT_MOD, but you may have
- * a reason to use a different type (perhaps you already have a datafile with
- * MOD files in and they use a different type).
- */
-void dumb_register_dat_mod(long type)
-{
- register_datafile_object(
- type,
- &dat_read_mod,
- &_dat_unload_duh
- );
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * datmod.c - Integration of MOD files with / / \ \
+ * Allegro's datafiles. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <allegro.h>
+
+#include "aldumb.h"
+#include "internal/aldumb.h"
+
+
+
+static void *dat_read_mod(PACKFILE *f, long size)
+{
+ DUMBFILE *df;
+ DUH *duh;
+
+ (void)size;
+
+ df = dumbfile_open_packfile(f);
+
+ if (!df)
+ return NULL;
+
+ duh = dumb_read_mod(df);
+
+ dumbfile_close(df);
+
+ return duh;
+}
+
+
+
+/* dumb_register_dat_mod(): tells Allegro about the MOD datafile object. If
+ * you intend to load a datafile containing a MOD object, you must call this
+ * function first. It is recommended you pass DUMB_DAT_MOD, but you may have
+ * a reason to use a different type (perhaps you already have a datafile with
+ * MOD files in and they use a different type).
+ */
+void dumb_register_dat_mod(long type)
+{
+ register_datafile_object(
+ type,
+ &dat_read_mod,
+ &_dat_unload_duh
+ );
+}
diff --git a/plugins/dumb/dumb-kode54/src/allegro/dats3m.c b/plugins/dumb/dumb-kode54/src/allegro/dats3m.c
index 8fe21666..a0fc7442 100644
--- a/plugins/dumb/dumb-kode54/src/allegro/dats3m.c
+++ b/plugins/dumb/dumb-kode54/src/allegro/dats3m.c
@@ -1,61 +1,61 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * dats3m.c - Integration of S3M files with / / \ \
- * Allegro's datafiles. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <allegro.h>
-
-#include "aldumb.h"
-#include "internal/aldumb.h"
-
-
-
-static void *dat_read_s3m(PACKFILE *f, long size)
-{
- DUMBFILE *df;
- DUH *duh;
-
- (void)size;
-
- df = dumbfile_open_packfile(f);
-
- if (!df)
- return NULL;
-
- duh = dumb_read_s3m(df);
-
- dumbfile_close(df);
-
- return duh;
-}
-
-
-
-/* dumb_register_dat_s3m(): tells Allegro about the S3M datafile object. If
- * you intend to load a datafile containing an S3M object, you must call this
- * function first. It is recommended you pass DUMB_DAT_S3M, but you may have
- * a reason to use a different type (perhaps you already have a datafile with
- * S3M files in and they use a different type).
- */
-void dumb_register_dat_s3m(long type)
-{
- register_datafile_object(
- type,
- &dat_read_s3m,
- &_dat_unload_duh
- );
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * dats3m.c - Integration of S3M files with / / \ \
+ * Allegro's datafiles. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <allegro.h>
+
+#include "aldumb.h"
+#include "internal/aldumb.h"
+
+
+
+static void *dat_read_s3m(PACKFILE *f, long size)
+{
+ DUMBFILE *df;
+ DUH *duh;
+
+ (void)size;
+
+ df = dumbfile_open_packfile(f);
+
+ if (!df)
+ return NULL;
+
+ duh = dumb_read_s3m(df);
+
+ dumbfile_close(df);
+
+ return duh;
+}
+
+
+
+/* dumb_register_dat_s3m(): tells Allegro about the S3M datafile object. If
+ * you intend to load a datafile containing an S3M object, you must call this
+ * function first. It is recommended you pass DUMB_DAT_S3M, but you may have
+ * a reason to use a different type (perhaps you already have a datafile with
+ * S3M files in and they use a different type).
+ */
+void dumb_register_dat_s3m(long type)
+{
+ register_datafile_object(
+ type,
+ &dat_read_s3m,
+ &_dat_unload_duh
+ );
+}
diff --git a/plugins/dumb/dumb-kode54/src/allegro/datunld.c b/plugins/dumb/dumb-kode54/src/allegro/datunld.c
index 68d359fb..71906445 100644
--- a/plugins/dumb/dumb-kode54/src/allegro/datunld.c
+++ b/plugins/dumb/dumb-kode54/src/allegro/datunld.c
@@ -1,31 +1,31 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * datunld.c - Unload function for integration / / \ \
- * with Allegro's datafiles. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <allegro.h>
-
-#include "aldumb.h"
-#include "internal/aldumb.h"
-
-
-
-void _dat_unload_duh(void *duh)
-{
- unload_duh(duh);
-}
-
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * datunld.c - Unload function for integration / / \ \
+ * with Allegro's datafiles. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <allegro.h>
+
+#include "aldumb.h"
+#include "internal/aldumb.h"
+
+
+
+void _dat_unload_duh(void *duh)
+{
+ unload_duh(duh);
+}
+
diff --git a/plugins/dumb/dumb-kode54/src/allegro/datxm.c b/plugins/dumb/dumb-kode54/src/allegro/datxm.c
index ff3ff25a..6cb98d87 100644
--- a/plugins/dumb/dumb-kode54/src/allegro/datxm.c
+++ b/plugins/dumb/dumb-kode54/src/allegro/datxm.c
@@ -1,62 +1,62 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * datxm.c - Integration of XM files with / / \ \
- * Allegro's datafiles. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <allegro.h>
-
-#include "aldumb.h"
-#include "internal/aldumb.h"
-
-
-
-static void *dat_read_xm(PACKFILE *f, long size)
-{
- DUMBFILE *df;
- DUH *duh;
-
- (void)size;
-
- df = dumbfile_open_packfile(f);
-
- if (!df)
- return NULL;
-
- duh = dumb_read_xm(df);
-
- dumbfile_close(df);
-
- return duh;
-}
-
-
-
-/* dumb_register_dat_xm(): tells Allegro about the XM datafile object. If you
- * intend to load a datafile containing an XM object, you must call this
- * function first. It is recommended you pass DUMB_DAT_XM, but you may have a
- * reason to use a different type (perhaps you already have a datafile with
- * XM files in and they use a different type).
- */
-void dumb_register_dat_xm(long type)
-{
- register_datafile_object(
- type,
- &dat_read_xm,
- &_dat_unload_duh
- );
-}
-
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * datxm.c - Integration of XM files with / / \ \
+ * Allegro's datafiles. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <allegro.h>
+
+#include "aldumb.h"
+#include "internal/aldumb.h"
+
+
+
+static void *dat_read_xm(PACKFILE *f, long size)
+{
+ DUMBFILE *df;
+ DUH *duh;
+
+ (void)size;
+
+ df = dumbfile_open_packfile(f);
+
+ if (!df)
+ return NULL;
+
+ duh = dumb_read_xm(df);
+
+ dumbfile_close(df);
+
+ return duh;
+}
+
+
+
+/* dumb_register_dat_xm(): tells Allegro about the XM datafile object. If you
+ * intend to load a datafile containing an XM object, you must call this
+ * function first. It is recommended you pass DUMB_DAT_XM, but you may have a
+ * reason to use a different type (perhaps you already have a datafile with
+ * XM files in and they use a different type).
+ */
+void dumb_register_dat_xm(long type)
+{
+ register_datafile_object(
+ type,
+ &dat_read_xm,
+ &_dat_unload_duh
+ );
+}
+
diff --git a/plugins/dumb/dumb-kode54/src/allegro/packfile.c b/plugins/dumb/dumb-kode54/src/allegro/packfile.c
index 5a07bdb5..525baebd 100644
--- a/plugins/dumb/dumb-kode54/src/allegro/packfile.c
+++ b/plugins/dumb/dumb-kode54/src/allegro/packfile.c
@@ -1,98 +1,98 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * packfile.c - Packfile input module. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * Note that this does not use file compression; | \ / /
- * for that you must open the file yourself and | ' /
- * then use dumbfile_open_packfile(). \__/
- */
-
-#include <allegro.h>
-
-#include "aldumb.h"
-
-
-
-static void *dumb_packfile_open(const char *filename)
-{
- return pack_fopen(filename, F_READ);
-}
-
-
-
-static int dumb_packfile_skip(void *f, long n)
-{
- return pack_fseek(f, n);
-}
-
-
-
-static int dumb_packfile_getc(void *f)
-{
- return pack_getc(f);
-}
-
-
-
-static long dumb_packfile_getnc(char *ptr, long n, void *f)
-{
- return pack_fread(ptr, n, f);
-}
-
-
-
-static void dumb_packfile_close(void *f)
-{
- pack_fclose(f);
-}
-
-
-
-static DUMBFILE_SYSTEM packfile_dfs = {
- &dumb_packfile_open,
- &dumb_packfile_skip,
- &dumb_packfile_getc,
- &dumb_packfile_getnc,
- &dumb_packfile_close
-};
-
-
-
-void dumb_register_packfiles(void)
-{
- register_dumbfile_system(&packfile_dfs);
-}
-
-
-
-static DUMBFILE_SYSTEM packfile_dfs_leave_open = {
- NULL,
- &dumb_packfile_skip,
- &dumb_packfile_getc,
- &dumb_packfile_getnc,
- NULL
-};
-
-
-
-DUMBFILE *dumbfile_open_packfile(PACKFILE *p)
-{
- return dumbfile_open_ex(p, &packfile_dfs_leave_open);
-}
-
-
-
-DUMBFILE *dumbfile_from_packfile(PACKFILE *p)
-{
- return p ? dumbfile_open_ex(p, &packfile_dfs) : NULL;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * packfile.c - Packfile input module. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * Note that this does not use file compression; | \ / /
+ * for that you must open the file yourself and | ' /
+ * then use dumbfile_open_packfile(). \__/
+ */
+
+#include <allegro.h>
+
+#include "aldumb.h"
+
+
+
+static void *dumb_packfile_open(const char *filename)
+{
+ return pack_fopen(filename, F_READ);
+}
+
+
+
+static int dumb_packfile_skip(void *f, long n)
+{
+ return pack_fseek(f, n);
+}
+
+
+
+static int dumb_packfile_getc(void *f)
+{
+ return pack_getc(f);
+}
+
+
+
+static long dumb_packfile_getnc(char *ptr, long n, void *f)
+{
+ return pack_fread(ptr, n, f);
+}
+
+
+
+static void dumb_packfile_close(void *f)
+{
+ pack_fclose(f);
+}
+
+
+
+static DUMBFILE_SYSTEM packfile_dfs = {
+ &dumb_packfile_open,
+ &dumb_packfile_skip,
+ &dumb_packfile_getc,
+ &dumb_packfile_getnc,
+ &dumb_packfile_close
+};
+
+
+
+void dumb_register_packfiles(void)
+{
+ register_dumbfile_system(&packfile_dfs);
+}
+
+
+
+static DUMBFILE_SYSTEM packfile_dfs_leave_open = {
+ NULL,
+ &dumb_packfile_skip,
+ &dumb_packfile_getc,
+ &dumb_packfile_getnc,
+ NULL
+};
+
+
+
+DUMBFILE *dumbfile_open_packfile(PACKFILE *p)
+{
+ return dumbfile_open_ex(p, &packfile_dfs_leave_open);
+}
+
+
+
+DUMBFILE *dumbfile_from_packfile(PACKFILE *p)
+{
+ return p ? dumbfile_open_ex(p, &packfile_dfs) : NULL;
+}
diff --git a/plugins/dumb/dumb-kode54/src/core/atexit.c b/plugins/dumb/dumb-kode54/src/core/atexit.c
index 64814efd..16c6abdb 100644
--- a/plugins/dumb/dumb-kode54/src/core/atexit.c
+++ b/plugins/dumb/dumb-kode54/src/core/atexit.c
@@ -1,71 +1,71 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * atexit.c - Library Clean-up Management. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-typedef struct DUMB_ATEXIT_PROC
-{
- struct DUMB_ATEXIT_PROC *next;
- void (*proc)(void);
-}
-DUMB_ATEXIT_PROC;
-
-
-
-static DUMB_ATEXIT_PROC *dumb_atexit_proc = NULL;
-
-
-
-int dumb_atexit(void (*proc)(void))
-{
- DUMB_ATEXIT_PROC *dap = dumb_atexit_proc;
-
- while (dap) {
- if (dap->proc == proc) return 0;
- dap = dap->next;
- }
-
- dap = malloc(sizeof(*dap));
-
- if (!dap)
- return -1;
-
- dap->next = dumb_atexit_proc;
- dap->proc = proc;
- dumb_atexit_proc = dap;
-
- return 0;
-}
-
-
-
-void dumb_exit(void)
-{
- while (dumb_atexit_proc) {
- DUMB_ATEXIT_PROC *next = dumb_atexit_proc->next;
- (*dumb_atexit_proc->proc)();
- free(dumb_atexit_proc);
- dumb_atexit_proc = next;
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * atexit.c - Library Clean-up Management. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+typedef struct DUMB_ATEXIT_PROC
+{
+ struct DUMB_ATEXIT_PROC *next;
+ void (*proc)(void);
+}
+DUMB_ATEXIT_PROC;
+
+
+
+static DUMB_ATEXIT_PROC *dumb_atexit_proc = NULL;
+
+
+
+int dumb_atexit(void (*proc)(void))
+{
+ DUMB_ATEXIT_PROC *dap = dumb_atexit_proc;
+
+ while (dap) {
+ if (dap->proc == proc) return 0;
+ dap = dap->next;
+ }
+
+ dap = malloc(sizeof(*dap));
+
+ if (!dap)
+ return -1;
+
+ dap->next = dumb_atexit_proc;
+ dap->proc = proc;
+ dumb_atexit_proc = dap;
+
+ return 0;
+}
+
+
+
+void dumb_exit(void)
+{
+ while (dumb_atexit_proc) {
+ DUMB_ATEXIT_PROC *next = dumb_atexit_proc->next;
+ (*dumb_atexit_proc->proc)();
+ free(dumb_atexit_proc);
+ dumb_atexit_proc = next;
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/core/duhlen.c b/plugins/dumb/dumb-kode54/src/core/duhlen.c
index 2c3a3576..3cfa8d88 100644
--- a/plugins/dumb/dumb-kode54/src/core/duhlen.c
+++ b/plugins/dumb/dumb-kode54/src/core/duhlen.c
@@ -1,42 +1,45 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * duhlen.c - Functions to set and return the / / \ \
- * length of a DUH. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * Note that the length of a DUH is a constant | ' /
- * stored in the DUH struct and in the DUH disk \__/
- * format. It will be calculated on loading for
- * other formats in which the length is not explicitly stored. Also note that
- * it does not necessarily correspond to the length of time for which the DUH
- * will generate samples. Rather it represents a suitable point for a player
- * such as Winamp to stop, and in any good DUH it will allow for any final
- * flourish to fade out and be appreciated.
- */
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-long duh_get_length(DUH *duh)
-{
- return duh ? duh->length : 0;
-}
-
-
-
-void duh_set_length(DUH *duh, long length)
-{
- if (duh)
- duh->length = length;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * duhlen.c - Functions to set and return the / / \ \
+ * length of a DUH. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * Note that the length of a DUH is a constant | ' /
+ * stored in the DUH struct and in the DUH disk \__/
+ * format. It will be calculated on loading for
+ * other formats in which the length is not explicitly stored. Also note that
+ * it does not necessarily correspond to the length of time for which the DUH
+ * will generate samples. Rather it represents a suitable point for a player
+ * such as Winamp to stop, and in any good DUH it will allow for any final
+ * flourish to fade out and be appreciated.
+ */
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+long duh_get_length(DUH *duh)
+{
+ return duh ? duh->length : 0;
+}
+
+
+
+void duh_set_length(DUH *duh, long length)
+{
+ if (duh)
+ duh->length = length;
+}
+
+
+
diff --git a/plugins/dumb/dumb-kode54/src/core/duhtag.c b/plugins/dumb/dumb-kode54/src/core/duhtag.c
index 77061094..b150467d 100644
--- a/plugins/dumb/dumb-kode54/src/core/duhtag.c
+++ b/plugins/dumb/dumb-kode54/src/core/duhtag.c
@@ -1,38 +1,38 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * duhtag.c - Function to return the tags stored / / \ \
- * in a DUH struct (typically author | < / \_
- * information). | \/ /\ /
- * \_ / > /
- * By entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-const char *duh_get_tag(DUH *duh, const char *key)
-{
- int i;
- ASSERT(key);
- if (!duh || !duh->tag) return NULL;
-
- for (i = 0; i < duh->n_tags; i++)
- if (strcmp(key, duh->tag[i][0]) == 0)
- return duh->tag[i][1];
-
- return NULL;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * duhtag.c - Function to return the tags stored / / \ \
+ * in a DUH struct (typically author | < / \_
+ * information). | \/ /\ /
+ * \_ / > /
+ * By entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <string.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+const char *duh_get_tag(DUH *duh, const char *key)
+{
+ int i;
+ ASSERT(key);
+ if (!duh || !duh->tag) return NULL;
+
+ for (i = 0; i < duh->n_tags; i++)
+ if (strcmp(key, duh->tag[i][0]) == 0)
+ return duh->tag[i][1];
+
+ return NULL;
+}
diff --git a/plugins/dumb/dumb-kode54/src/core/dumbfile.c b/plugins/dumb/dumb-kode54/src/core/dumbfile.c
index ae738bf7..71108c0c 100644
--- a/plugins/dumb/dumb-kode54/src/core/dumbfile.c
+++ b/plugins/dumb/dumb-kode54/src/core/dumbfile.c
@@ -1,401 +1,401 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * dumbfile.c - Hookable, strictly sequential / / \ \
- * file input functions. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-
-
-
-static DUMBFILE_SYSTEM *the_dfs = NULL;
-
-
-
-void register_dumbfile_system(DUMBFILE_SYSTEM *dfs)
-{
- ASSERT(dfs);
- ASSERT(dfs->open);
- ASSERT(dfs->getc);
- ASSERT(dfs->close);
- the_dfs = dfs;
-}
-
-
-
-struct DUMBFILE
-{
- DUMBFILE_SYSTEM *dfs;
- void *file;
- long pos;
-};
-
-
-
-DUMBFILE *dumbfile_open(const char *filename)
-{
- DUMBFILE *f;
-
- ASSERT(the_dfs);
-
- f = malloc(sizeof(*f));
-
- if (!f)
- return NULL;
-
- f->dfs = the_dfs;
-
- f->file = (*the_dfs->open)(filename);
-
- if (!f->file) {
- free(f);
- return NULL;
- }
-
- f->pos = 0;
-
- return f;
-}
-
-
-
-DUMBFILE *dumbfile_open_ex(void *file, DUMBFILE_SYSTEM *dfs)
-{
- DUMBFILE *f;
-
- ASSERT(dfs);
- ASSERT(dfs->getc);
- ASSERT(file);
-
- f = malloc(sizeof(*f));
-
- if (!f) {
- if (dfs->close)
- (*dfs->close)(file);
- return NULL;
- }
-
- f->dfs = dfs;
- f->file = file;
-
- f->pos = 0;
-
- return f;
-}
-
-
-
-long dumbfile_pos(DUMBFILE *f)
-{
- ASSERT(f);
-
- return f->pos;
-}
-
-
-
-int dumbfile_skip(DUMBFILE *f, long n)
-{
- int rv;
-
- ASSERT(f);
- ASSERT(n >= 0);
-
- if (f->pos < 0)
- return -1;
-
- f->pos += n;
-
- if (f->dfs->skip) {
- rv = (*f->dfs->skip)(f->file, n);
- if (rv) {
- f->pos = -1;
- return rv;
- }
- } else {
- while (n) {
- rv = (*f->dfs->getc)(f->file);
- if (rv < 0) {
- f->pos = -1;
- return rv;
- }
- n--;
- }
- }
-
- return 0;
-}
-
-
-
-int dumbfile_getc(DUMBFILE *f)
-{
- int rv;
-
- ASSERT(f);
-
- if (f->pos < 0)
- return -1;
-
- rv = (*f->dfs->getc)(f->file);
-
- if (rv < 0) {
- f->pos = -1;
- return rv;
- }
-
- f->pos++;
-
- return rv;
-}
-
-
-
-int dumbfile_igetw(DUMBFILE *f)
-{
- int l, h;
-
- ASSERT(f);
-
- if (f->pos < 0)
- return -1;
-
- l = (*f->dfs->getc)(f->file);
- if (l < 0) {
- f->pos = -1;
- return l;
- }
-
- h = (*f->dfs->getc)(f->file);
- if (h < 0) {
- f->pos = -1;
- return h;
- }
-
- f->pos += 2;
-
- return l | (h << 8);
-}
-
-
-
-int dumbfile_mgetw(DUMBFILE *f)
-{
- int l, h;
-
- ASSERT(f);
-
- if (f->pos < 0)
- return -1;
-
- h = (*f->dfs->getc)(f->file);
- if (h < 0) {
- f->pos = -1;
- return h;
- }
-
- l = (*f->dfs->getc)(f->file);
- if (l < 0) {
- f->pos = -1;
- return l;
- }
-
- f->pos += 2;
-
- return l | (h << 8);
-}
-
-
-
-long dumbfile_igetl(DUMBFILE *f)
-{
- unsigned long rv, b;
-
- ASSERT(f);
-
- if (f->pos < 0)
- return -1;
-
- rv = (*f->dfs->getc)(f->file);
- if ((signed long)rv < 0) {
- f->pos = -1;
- return rv;
- }
-
- b = (*f->dfs->getc)(f->file);
- if ((signed long)b < 0) {
- f->pos = -1;
- return b;
- }
- rv |= b << 8;
-
- b = (*f->dfs->getc)(f->file);
- if ((signed long)b < 0) {
- f->pos = -1;
- return b;
- }
- rv |= b << 16;
-
- b = (*f->dfs->getc)(f->file);
- if ((signed long)b < 0) {
- f->pos = -1;
- return b;
- }
- rv |= b << 24;
-
- f->pos += 4;
-
- return rv;
-}
-
-
-
-long dumbfile_mgetl(DUMBFILE *f)
-{
- unsigned long rv, b;
-
- ASSERT(f);
-
- if (f->pos < 0)
- return -1;
-
- rv = (*f->dfs->getc)(f->file);
- if ((signed long)rv < 0) {
- f->pos = -1;
- return rv;
- }
- rv <<= 24;
-
- b = (*f->dfs->getc)(f->file);
- if ((signed long)b < 0) {
- f->pos = -1;
- return b;
- }
- rv |= b << 16;
-
- b = (*f->dfs->getc)(f->file);
- if ((signed long)b < 0) {
- f->pos = -1;
- return b;
- }
- rv |= b << 8;
-
- b = (*f->dfs->getc)(f->file);
- if ((signed long)b < 0) {
- f->pos = -1;
- return b;
- }
- rv |= b;
-
- f->pos += 4;
-
- return rv;
-}
-
-
-
-unsigned long dumbfile_cgetul(DUMBFILE *f)
-{
- unsigned long rv = 0;
- int v;
-
- do {
- v = dumbfile_getc(f);
-
- if (v < 0)
- return v;
-
- rv <<= 7;
- rv |= v & 0x7F;
- } while (v & 0x80);
-
- return rv;
-}
-
-
-
-signed long dumbfile_cgetsl(DUMBFILE *f)
-{
- unsigned long rv = dumbfile_cgetul(f);
-
- if (f->pos < 0)
- return rv;
-
- return (rv >> 1) | (rv << 31);
-}
-
-
-
-long dumbfile_getnc(char *ptr, long n, DUMBFILE *f)
-{
- long rv;
-
- ASSERT(f);
- ASSERT(n >= 0);
-
- if (f->pos < 0)
- return -1;
-
- if (f->dfs->getnc) {
- rv = (*f->dfs->getnc)(ptr, n, f->file);
- if (rv < n) {
- f->pos = -1;
- return MAX(rv, 0);
- }
- } else {
- for (rv = 0; rv < n; rv++) {
- int c = (*f->dfs->getc)(f->file);
- if (c < 0) {
- f->pos = -1;
- return rv;
- }
- *ptr++ = c;
- }
- }
-
- f->pos += rv;
-
- return rv;
-}
-
-
-
-int dumbfile_error(DUMBFILE *f)
-{
- ASSERT(f);
-
- return f->pos < 0;
-}
-
-
-
-int dumbfile_close(DUMBFILE *f)
-{
- int rv;
-
- ASSERT(f);
-
- rv = f->pos < 0;
-
- if (f->dfs->close)
- (*f->dfs->close)(f->file);
-
- free(f);
-
- return rv;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * dumbfile.c - Hookable, strictly sequential / / \ \
+ * file input functions. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+
+
+
+static DUMBFILE_SYSTEM *the_dfs = NULL;
+
+
+
+void register_dumbfile_system(DUMBFILE_SYSTEM *dfs)
+{
+ ASSERT(dfs);
+ ASSERT(dfs->open);
+ ASSERT(dfs->getc);
+ ASSERT(dfs->close);
+ the_dfs = dfs;
+}
+
+
+
+struct DUMBFILE
+{
+ DUMBFILE_SYSTEM *dfs;
+ void *file;
+ long pos;
+};
+
+
+
+DUMBFILE *dumbfile_open(const char *filename)
+{
+ DUMBFILE *f;
+
+ ASSERT(the_dfs);
+
+ f = malloc(sizeof(*f));
+
+ if (!f)
+ return NULL;
+
+ f->dfs = the_dfs;
+
+ f->file = (*the_dfs->open)(filename);
+
+ if (!f->file) {
+ free(f);
+ return NULL;
+ }
+
+ f->pos = 0;
+
+ return f;
+}
+
+
+
+DUMBFILE *dumbfile_open_ex(void *file, DUMBFILE_SYSTEM *dfs)
+{
+ DUMBFILE *f;
+
+ ASSERT(dfs);
+ ASSERT(dfs->getc);
+ ASSERT(file);
+
+ f = malloc(sizeof(*f));
+
+ if (!f) {
+ if (dfs->close)
+ (*dfs->close)(file);
+ return NULL;
+ }
+
+ f->dfs = dfs;
+ f->file = file;
+
+ f->pos = 0;
+
+ return f;
+}
+
+
+
+long dumbfile_pos(DUMBFILE *f)
+{
+ ASSERT(f);
+
+ return f->pos;
+}
+
+
+
+int dumbfile_skip(DUMBFILE *f, long n)
+{
+ int rv;
+
+ ASSERT(f);
+ ASSERT(n >= 0);
+
+ if (f->pos < 0)
+ return -1;
+
+ f->pos += n;
+
+ if (f->dfs->skip) {
+ rv = (*f->dfs->skip)(f->file, n);
+ if (rv) {
+ f->pos = -1;
+ return rv;
+ }
+ } else {
+ while (n) {
+ rv = (*f->dfs->getc)(f->file);
+ if (rv < 0) {
+ f->pos = -1;
+ return rv;
+ }
+ n--;
+ }
+ }
+
+ return 0;
+}
+
+
+
+int dumbfile_getc(DUMBFILE *f)
+{
+ int rv;
+
+ ASSERT(f);
+
+ if (f->pos < 0)
+ return -1;
+
+ rv = (*f->dfs->getc)(f->file);
+
+ if (rv < 0) {
+ f->pos = -1;
+ return rv;
+ }
+
+ f->pos++;
+
+ return rv;
+}
+
+
+
+int dumbfile_igetw(DUMBFILE *f)
+{
+ int l, h;
+
+ ASSERT(f);
+
+ if (f->pos < 0)
+ return -1;
+
+ l = (*f->dfs->getc)(f->file);
+ if (l < 0) {
+ f->pos = -1;
+ return l;
+ }
+
+ h = (*f->dfs->getc)(f->file);
+ if (h < 0) {
+ f->pos = -1;
+ return h;
+ }
+
+ f->pos += 2;
+
+ return l | (h << 8);
+}
+
+
+
+int dumbfile_mgetw(DUMBFILE *f)
+{
+ int l, h;
+
+ ASSERT(f);
+
+ if (f->pos < 0)
+ return -1;
+
+ h = (*f->dfs->getc)(f->file);
+ if (h < 0) {
+ f->pos = -1;
+ return h;
+ }
+
+ l = (*f->dfs->getc)(f->file);
+ if (l < 0) {
+ f->pos = -1;
+ return l;
+ }
+
+ f->pos += 2;
+
+ return l | (h << 8);
+}
+
+
+
+long dumbfile_igetl(DUMBFILE *f)
+{
+ unsigned long rv, b;
+
+ ASSERT(f);
+
+ if (f->pos < 0)
+ return -1;
+
+ rv = (*f->dfs->getc)(f->file);
+ if ((signed long)rv < 0) {
+ f->pos = -1;
+ return rv;
+ }
+
+ b = (*f->dfs->getc)(f->file);
+ if ((signed long)b < 0) {
+ f->pos = -1;
+ return b;
+ }
+ rv |= b << 8;
+
+ b = (*f->dfs->getc)(f->file);
+ if ((signed long)b < 0) {
+ f->pos = -1;
+ return b;
+ }
+ rv |= b << 16;
+
+ b = (*f->dfs->getc)(f->file);
+ if ((signed long)b < 0) {
+ f->pos = -1;
+ return b;
+ }
+ rv |= b << 24;
+
+ f->pos += 4;
+
+ return rv;
+}
+
+
+
+long dumbfile_mgetl(DUMBFILE *f)
+{
+ unsigned long rv, b;
+
+ ASSERT(f);
+
+ if (f->pos < 0)
+ return -1;
+
+ rv = (*f->dfs->getc)(f->file);
+ if ((signed long)rv < 0) {
+ f->pos = -1;
+ return rv;
+ }
+ rv <<= 24;
+
+ b = (*f->dfs->getc)(f->file);
+ if ((signed long)b < 0) {
+ f->pos = -1;
+ return b;
+ }
+ rv |= b << 16;
+
+ b = (*f->dfs->getc)(f->file);
+ if ((signed long)b < 0) {
+ f->pos = -1;
+ return b;
+ }
+ rv |= b << 8;
+
+ b = (*f->dfs->getc)(f->file);
+ if ((signed long)b < 0) {
+ f->pos = -1;
+ return b;
+ }
+ rv |= b;
+
+ f->pos += 4;
+
+ return rv;
+}
+
+
+
+unsigned long dumbfile_cgetul(DUMBFILE *f)
+{
+ unsigned long rv = 0;
+ int v;
+
+ do {
+ v = dumbfile_getc(f);
+
+ if (v < 0)
+ return v;
+
+ rv <<= 7;
+ rv |= v & 0x7F;
+ } while (v & 0x80);
+
+ return rv;
+}
+
+
+
+signed long dumbfile_cgetsl(DUMBFILE *f)
+{
+ unsigned long rv = dumbfile_cgetul(f);
+
+ if (f->pos < 0)
+ return rv;
+
+ return (rv >> 1) | (rv << 31);
+}
+
+
+
+long dumbfile_getnc(char *ptr, long n, DUMBFILE *f)
+{
+ long rv;
+
+ ASSERT(f);
+ ASSERT(n >= 0);
+
+ if (f->pos < 0)
+ return -1;
+
+ if (f->dfs->getnc) {
+ rv = (*f->dfs->getnc)(ptr, n, f->file);
+ if (rv < n) {
+ f->pos = -1;
+ return MAX(rv, 0);
+ }
+ } else {
+ for (rv = 0; rv < n; rv++) {
+ int c = (*f->dfs->getc)(f->file);
+ if (c < 0) {
+ f->pos = -1;
+ return rv;
+ }
+ *ptr++ = c;
+ }
+ }
+
+ f->pos += rv;
+
+ return rv;
+}
+
+
+
+int dumbfile_error(DUMBFILE *f)
+{
+ ASSERT(f);
+
+ return f->pos < 0;
+}
+
+
+
+int dumbfile_close(DUMBFILE *f)
+{
+ int rv;
+
+ ASSERT(f);
+
+ rv = f->pos < 0;
+
+ if (f->dfs->close)
+ (*f->dfs->close)(f->file);
+
+ free(f);
+
+ return rv;
+}
diff --git a/plugins/dumb/dumb-kode54/src/core/loadduh.c b/plugins/dumb/dumb-kode54/src/core/loadduh.c
index e954fe24..7dfe5cc1 100644
--- a/plugins/dumb/dumb-kode54/src/core/loadduh.c
+++ b/plugins/dumb/dumb-kode54/src/core/loadduh.c
@@ -1,42 +1,42 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadduh.c - Code to read a DUH from a file, / / \ \
- * opening and closing the file for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-/* load_duh(): loads a .duh file, returning a pointer to a DUH struct.
- * When you have finished with it, you must pass the pointer to unload_duh()
- * so that the memory can be freed.
- */
-DUH *load_duh(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = read_duh(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadduh.c - Code to read a DUH from a file, / / \ \
+ * opening and closing the file for | < / \_
+ * you. | \/ /\ /
+ * \_ / > /
+ * By entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+/* load_duh(): loads a .duh file, returning a pointer to a DUH struct.
+ * When you have finished with it, you must pass the pointer to unload_duh()
+ * so that the memory can be freed.
+ */
+DUH *load_duh(const char *filename)
+{
+ DUH *duh;
+ DUMBFILE *f = dumbfile_open(filename);
+
+ if (!f)
+ return NULL;
+
+ duh = read_duh(f);
+
+ dumbfile_close(f);
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/core/makeduh.c b/plugins/dumb/dumb-kode54/src/core/makeduh.c
index 1edf2b1f..e52b86bc 100644
--- a/plugins/dumb/dumb-kode54/src/core/makeduh.c
+++ b/plugins/dumb/dumb-kode54/src/core/makeduh.c
@@ -1,132 +1,135 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * makeduh.c - Function to construct a DUH from / / \ \
- * its components. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-static DUH_SIGNAL *make_signal(DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata)
-{
- DUH_SIGNAL *signal;
-
- ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer));
- ASSERT(desc->sigrenderer_generate_samples && desc->sigrenderer_get_current_sample);
-
- signal = malloc(sizeof(*signal));
-
- if (!signal) {
- if (desc->unload_sigdata)
- if (sigdata)
- (*desc->unload_sigdata)(sigdata);
- return NULL;
- }
-
- signal->desc = desc;
- signal->sigdata = sigdata;
-
- return signal;
-}
-
-
-
-DUH *make_duh(
- long length,
- int n_tags,
- const char *const tags[][2],
- int n_signals,
- DUH_SIGTYPE_DESC *desc[],
- sigdata_t *sigdata[]
-)
-{
- DUH *duh = malloc(sizeof(*duh));
- int i;
- int fail;
-
- if (duh) {
- duh->n_signals = n_signals;
-
- duh->signal = malloc(n_signals * sizeof(*duh->signal));
-
- if (!duh->signal) {
- free(duh);
- duh = NULL;
- }
- }
-
- if (!duh) {
- for (i = 0; i < n_signals; i++)
- if (desc[i]->unload_sigdata)
- if (sigdata[i])
- (*desc[i]->unload_sigdata)(sigdata[i]);
- return NULL;
- }
-
- duh->n_tags = 0;
- duh->tag = NULL;
-
- fail = 0;
-
- for (i = 0; i < n_signals; i++) {
- duh->signal[i] = make_signal(desc[i], sigdata[i]);
- if (!duh->signal[i])
- fail = 1;
- }
-
- if (fail) {
- unload_duh(duh);
- return NULL;
- }
-
- duh->length = length;
-
- {
- int mem = n_tags * 2; /* account for NUL terminators here */
- char *ptr;
-
- for (i = 0; i < n_tags; i++)
- mem += strlen(tags[i][0]) + strlen(tags[i][1]);
-
- if (mem <= 0) return duh;
-
- duh->tag = malloc(n_tags * sizeof(*duh->tag));
- if (!duh->tag) return duh;
- duh->tag[0][0] = malloc(mem);
- if (!duh->tag[0][0]) {
- free(duh->tag);
- duh->tag = NULL;
- return duh;
- }
- duh->n_tags = n_tags;
- ptr = duh->tag[0][0];
- for (i = 0; i < n_tags; i++) {
- duh->tag[i][0] = ptr;
- strcpy(ptr, tags[i][0]);
- ptr += strlen(tags[i][0]) + 1;
- duh->tag[i][1] = ptr;
- strcpy(ptr, tags[i][1]);
- ptr += strlen(tags[i][1]) + 1;
- }
- }
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * makeduh.c - Function to construct a DUH from / / \ \
+ * its components. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+static DUH_SIGNAL *make_signal(DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata)
+{
+ DUH_SIGNAL *signal;
+
+ ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer));
+ ASSERT(desc->sigrenderer_generate_samples && desc->sigrenderer_get_current_sample);
+
+ signal = malloc(sizeof(*signal));
+
+ if (!signal) {
+ if (desc->unload_sigdata)
+ if (sigdata)
+ (*desc->unload_sigdata)(sigdata);
+ return NULL;
+ }
+
+ signal->desc = desc;
+ signal->sigdata = sigdata;
+
+ return signal;
+}
+
+
+
+DUH *make_duh(
+ long length,
+ int n_tags,
+ const char *const tags[][2],
+ int n_signals,
+ DUH_SIGTYPE_DESC *desc[],
+ sigdata_t *sigdata[]
+)
+{
+ DUH *duh = malloc(sizeof(*duh));
+ int i;
+ int fail;
+
+ if (duh) {
+ duh->n_signals = n_signals;
+
+ duh->signal = malloc(n_signals * sizeof(*duh->signal));
+
+ if (!duh->signal) {
+ free(duh);
+ duh = NULL;
+ }
+ }
+
+ if (!duh) {
+ for (i = 0; i < n_signals; i++)
+ if (desc[i]->unload_sigdata)
+ if (sigdata[i])
+ (*desc[i]->unload_sigdata)(sigdata[i]);
+ return NULL;
+ }
+
+ duh->n_tags = 0;
+ duh->tag = NULL;
+
+ duh->n_tags = 0;
+ duh->tag = NULL;
+
+ fail = 0;
+
+ for (i = 0; i < n_signals; i++) {
+ duh->signal[i] = make_signal(desc[i], sigdata[i]);
+ if (!duh->signal[i])
+ fail = 1;
+ }
+
+ if (fail) {
+ unload_duh(duh);
+ return NULL;
+ }
+
+ duh->length = length;
+
+ {
+ int mem = n_tags * 2; /* account for NUL terminators here */
+ char *ptr;
+
+ for (i = 0; i < n_tags; i++)
+ mem += strlen(tags[i][0]) + strlen(tags[i][1]);
+
+ if (mem <= 0) return duh;
+
+ duh->tag = malloc(n_tags * sizeof(*duh->tag));
+ if (!duh->tag) return duh;
+ duh->tag[0][0] = malloc(mem);
+ if (!duh->tag[0][0]) {
+ free(duh->tag);
+ duh->tag = NULL;
+ return duh;
+ }
+ duh->n_tags = n_tags;
+ ptr = duh->tag[0][0];
+ for (i = 0; i < n_tags; i++) {
+ duh->tag[i][0] = ptr;
+ strcpy(ptr, tags[i][0]);
+ ptr += strlen(tags[i][0]) + 1;
+ duh->tag[i][1] = ptr;
+ strcpy(ptr, tags[i][1]);
+ ptr += strlen(tags[i][1]) + 1;
+ }
+ }
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/core/rawsig.c b/plugins/dumb/dumb-kode54/src/core/rawsig.c
index 75c41eb0..926c9906 100644
--- a/plugins/dumb/dumb-kode54/src/core/rawsig.c
+++ b/plugins/dumb/dumb-kode54/src/core/rawsig.c
@@ -1,44 +1,44 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * rawsig.c - Function to retrieve raw signal / / \ \
- * data from a DUH provided you know | < / \_
- * what type of signal it is. | \/ /\ /
- * \_ / > /
- * By entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-/* You have to specify the type of sigdata, proving you know what to do with
- * the pointer. If you get it wrong, you can expect NULL back.
- */
-sigdata_t *duh_get_raw_sigdata(DUH *duh, int sig, long type)
-{
- DUH_SIGNAL *signal;
-
- if (!duh) return NULL;
-
- if ((unsigned int)sig >= (unsigned int)duh->n_signals) return NULL;
-
- signal = duh->signal[sig];
-
- if (signal && signal->desc->type == type)
- return signal->sigdata;
-
- return NULL;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * rawsig.c - Function to retrieve raw signal / / \ \
+ * data from a DUH provided you know | < / \_
+ * what type of signal it is. | \/ /\ /
+ * \_ / > /
+ * By entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+/* You have to specify the type of sigdata, proving you know what to do with
+ * the pointer. If you get it wrong, you can expect NULL back.
+ */
+sigdata_t *duh_get_raw_sigdata(DUH *duh, int sig, long type)
+{
+ DUH_SIGNAL *signal;
+
+ if (!duh) return NULL;
+
+ if ((unsigned int)sig >= (unsigned int)duh->n_signals) return NULL;
+
+ signal = duh->signal[sig];
+
+ if (signal && signal->desc->type == type)
+ return signal->sigdata;
+
+ return NULL;
+}
diff --git a/plugins/dumb/dumb-kode54/src/core/readduh.c b/plugins/dumb/dumb-kode54/src/core/readduh.c
index 0fb775b2..514b04a0 100644
--- a/plugins/dumb/dumb-kode54/src/core/readduh.c
+++ b/plugins/dumb/dumb-kode54/src/core/readduh.c
@@ -1,107 +1,107 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readduh.c - Code to read a DUH from an open / / \ \
- * file. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-static DUH_SIGNAL *read_signal(DUH *duh, DUMBFILE *f)
-{
- DUH_SIGNAL *signal;
- long type;
-
- signal = malloc(sizeof(*signal));
-
- if (!signal)
- return NULL;
-
- type = dumbfile_mgetl(f);
- if (dumbfile_error(f)) {
- free(signal);
- return NULL;
- }
-
- signal->desc = _dumb_get_sigtype_desc(type);
- if (!signal->desc) {
- free(signal);
- return NULL;
- }
-
- if (signal->desc->load_sigdata) {
- signal->sigdata = (*signal->desc->load_sigdata)(duh, f);
- if (!signal->sigdata) {
- free(signal);
- return NULL;
- }
- } else
- signal->sigdata = NULL;
-
- return signal;
-}
-
-
-
-/* read_duh(): reads a DUH from an already open DUMBFILE, and returns its
- * pointer, or null on error. The file is not closed.
- */
-DUH *read_duh(DUMBFILE *f)
-{
- DUH *duh;
- int i;
-
- if (dumbfile_mgetl(f) != DUH_SIGNATURE)
- return NULL;
-
- duh = malloc(sizeof(*duh));
- if (!duh)
- return NULL;
-
- duh->length = dumbfile_igetl(f);
- if (dumbfile_error(f) || duh->length <= 0) {
- free(duh);
- return NULL;
- }
-
- duh->n_signals = dumbfile_igetl(f);
- if (dumbfile_error(f) || duh->n_signals <= 0) {
- free(duh);
- return NULL;
- }
-
- duh->signal = malloc(sizeof(*duh->signal) * duh->n_signals);
- if (!duh->signal) {
- free(duh);
- return NULL;
- }
-
- for (i = 0; i < duh->n_signals; i++)
- duh->signal[i] = NULL;
-
- for (i = 0; i < duh->n_signals; i++) {
- if (!(duh->signal[i] = read_signal(duh, f))) {
- unload_duh(duh);
- return NULL;
- }
- }
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readduh.c - Code to read a DUH from an open / / \ \
+ * file. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+static DUH_SIGNAL *read_signal(DUH *duh, DUMBFILE *f)
+{
+ DUH_SIGNAL *signal;
+ long type;
+
+ signal = malloc(sizeof(*signal));
+
+ if (!signal)
+ return NULL;
+
+ type = dumbfile_mgetl(f);
+ if (dumbfile_error(f)) {
+ free(signal);
+ return NULL;
+ }
+
+ signal->desc = _dumb_get_sigtype_desc(type);
+ if (!signal->desc) {
+ free(signal);
+ return NULL;
+ }
+
+ if (signal->desc->load_sigdata) {
+ signal->sigdata = (*signal->desc->load_sigdata)(duh, f);
+ if (!signal->sigdata) {
+ free(signal);
+ return NULL;
+ }
+ } else
+ signal->sigdata = NULL;
+
+ return signal;
+}
+
+
+
+/* read_duh(): reads a DUH from an already open DUMBFILE, and returns its
+ * pointer, or null on error. The file is not closed.
+ */
+DUH *read_duh(DUMBFILE *f)
+{
+ DUH *duh;
+ int i;
+
+ if (dumbfile_mgetl(f) != DUH_SIGNATURE)
+ return NULL;
+
+ duh = malloc(sizeof(*duh));
+ if (!duh)
+ return NULL;
+
+ duh->length = dumbfile_igetl(f);
+ if (dumbfile_error(f) || duh->length <= 0) {
+ free(duh);
+ return NULL;
+ }
+
+ duh->n_signals = dumbfile_igetl(f);
+ if (dumbfile_error(f) || duh->n_signals <= 0) {
+ free(duh);
+ return NULL;
+ }
+
+ duh->signal = malloc(sizeof(*duh->signal) * duh->n_signals);
+ if (!duh->signal) {
+ free(duh);
+ return NULL;
+ }
+
+ for (i = 0; i < duh->n_signals; i++)
+ duh->signal[i] = NULL;
+
+ for (i = 0; i < duh->n_signals; i++) {
+ if (!(duh->signal[i] = read_signal(duh, f))) {
+ unload_duh(duh);
+ return NULL;
+ }
+ }
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/core/register.c b/plugins/dumb/dumb-kode54/src/core/register.c
index 2e16c9a7..66dd4524 100644
--- a/plugins/dumb/dumb-kode54/src/core/register.c
+++ b/plugins/dumb/dumb-kode54/src/core/register.c
@@ -1,104 +1,104 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * register.c - Signal type registration. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-static DUH_SIGTYPE_DESC_LINK *sigtype_desc = NULL;
-static DUH_SIGTYPE_DESC_LINK **sigtype_desc_tail = &sigtype_desc;
-
-
-
-/* destroy_sigtypes(): frees all memory allocated while registering signal
- * types. This function is set up to be called by dumb_exit().
- */
-static void destroy_sigtypes(void)
-{
- DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc, *next;
- sigtype_desc = NULL;
- sigtype_desc_tail = &sigtype_desc;
-
- while (desc_link) {
- next = desc_link->next;
- free(desc_link);
- desc_link = next;
- }
-}
-
-
-
-/* dumb_register_sigtype(): registers a new signal type with DUMB. The signal
- * type is identified by a four-character string (e.g. "WAVE"), which you can
- * encode using the the DUMB_ID() macro (e.g. DUMB_ID('W','A','V','E')). The
- * signal's behaviour is defined by four functions, whose pointers you pass
- * here. See the documentation for details.
- *
- * If a DUH tries to use a signal that has not been registered using this
- * function, then the library will fail to load the DUH.
- */
-void dumb_register_sigtype(DUH_SIGTYPE_DESC *desc)
-{
- DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
-
- ASSERT((desc->load_sigdata && desc->unload_sigdata) || (!desc->load_sigdata && !desc->unload_sigdata));
- ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer));
- ASSERT(desc->sigrenderer_generate_samples && desc->sigrenderer_get_current_sample);
-
- if (desc_link) {
- do {
- if (desc_link->desc->type == desc->type) {
- desc_link->desc = desc;
- return;
- }
- desc_link = desc_link->next;
- } while (desc_link);
- } else
- dumb_atexit(&destroy_sigtypes);
-
- desc_link = *sigtype_desc_tail = malloc(sizeof(DUH_SIGTYPE_DESC_LINK));
-
- if (!desc_link)
- return;
-
- desc_link->next = NULL;
- sigtype_desc_tail = &desc_link->next;
-
- desc_link->desc = desc;
-}
-
-
-
-/* _dumb_get_sigtype_desc(): searches the registered functions for a signal
- * type matching the parameter. If such a sigtype is found, it returns a
- * pointer to a sigtype descriptor containing the necessary functions to
- * manage the signal. If none is found, it returns NULL.
- */
-DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(long type)
-{
- DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
-
- while (desc_link && desc_link->desc->type != type)
- desc_link = desc_link->next;
-
- return desc_link ? desc_link->desc : NULL;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * register.c - Signal type registration. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+static DUH_SIGTYPE_DESC_LINK *sigtype_desc = NULL;
+static DUH_SIGTYPE_DESC_LINK **sigtype_desc_tail = &sigtype_desc;
+
+
+
+/* destroy_sigtypes(): frees all memory allocated while registering signal
+ * types. This function is set up to be called by dumb_exit().
+ */
+static void destroy_sigtypes(void)
+{
+ DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc, *next;
+ sigtype_desc = NULL;
+ sigtype_desc_tail = &sigtype_desc;
+
+ while (desc_link) {
+ next = desc_link->next;
+ free(desc_link);
+ desc_link = next;
+ }
+}
+
+
+
+/* dumb_register_sigtype(): registers a new signal type with DUMB. The signal
+ * type is identified by a four-character string (e.g. "WAVE"), which you can
+ * encode using the the DUMB_ID() macro (e.g. DUMB_ID('W','A','V','E')). The
+ * signal's behaviour is defined by four functions, whose pointers you pass
+ * here. See the documentation for details.
+ *
+ * If a DUH tries to use a signal that has not been registered using this
+ * function, then the library will fail to load the DUH.
+ */
+void dumb_register_sigtype(DUH_SIGTYPE_DESC *desc)
+{
+ DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
+
+ ASSERT((desc->load_sigdata && desc->unload_sigdata) || (!desc->load_sigdata && !desc->unload_sigdata));
+ ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer));
+ ASSERT(desc->sigrenderer_generate_samples && desc->sigrenderer_get_current_sample);
+
+ if (desc_link) {
+ do {
+ if (desc_link->desc->type == desc->type) {
+ desc_link->desc = desc;
+ return;
+ }
+ desc_link = desc_link->next;
+ } while (desc_link);
+ } else
+ dumb_atexit(&destroy_sigtypes);
+
+ desc_link = *sigtype_desc_tail = malloc(sizeof(DUH_SIGTYPE_DESC_LINK));
+
+ if (!desc_link)
+ return;
+
+ desc_link->next = NULL;
+ sigtype_desc_tail = &desc_link->next;
+
+ desc_link->desc = desc;
+}
+
+
+
+/* _dumb_get_sigtype_desc(): searches the registered functions for a signal
+ * type matching the parameter. If such a sigtype is found, it returns a
+ * pointer to a sigtype descriptor containing the necessary functions to
+ * manage the signal. If none is found, it returns NULL.
+ */
+DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(long type)
+{
+ DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
+
+ while (desc_link && desc_link->desc->type != type)
+ desc_link = desc_link->next;
+
+ return desc_link ? desc_link->desc : NULL;
+}
diff --git a/plugins/dumb/dumb-kode54/src/core/rendduh.c b/plugins/dumb/dumb-kode54/src/core/rendduh.c
index 1effa3eb..1639b938 100644
--- a/plugins/dumb/dumb-kode54/src/core/rendduh.c
+++ b/plugins/dumb/dumb-kode54/src/core/rendduh.c
@@ -1,184 +1,184 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * rendduh.c - Functions for rendering a DUH into / / \ \
- * an end-user sample format. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <limits.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-/* On the x86, we can use some tricks to speed stuff up */
-#if (defined _MSC_VER) || (defined __DJGPP__) || (defined __MINGW__)
-// Can't we detect Linux and other x86 platforms here? :/
-
-#define FAST_MID(var, min, max) { \
- var -= (min); \
- var &= (~var) >> (sizeof(var) * CHAR_BIT - 1); \
- var += (min); \
- var -= (max); \
- var &= var >> (sizeof(var) * CHAR_BIT - 1); \
- var += (max); \
-}
-
-#define CONVERT8(src, pos, signconv) { \
- signed int f = (src + 0x8000) >> 16; \
- FAST_MID(f, -128, 127); \
- ((char*)sptr)[pos] = (char)f ^ signconv; \
-}
-
-#define CONVERT16(src, pos, signconv) { \
- signed int f = (src + 0x80) >> 8; \
- FAST_MID(f, -32768, 32767); \
- ((short*)sptr)[pos] = (short)(f ^ signconv); \
-}
-
-#else
-
-#define CONVERT8(src, pos, signconv) \
-{ \
- signed int f = (src + 0x8000) >> 16; \
- f = MID(-128, f, 127); \
- ((char *)sptr)[pos] = (char)f ^ signconv; \
-}
-
-
-
-#define CONVERT16(src, pos, signconv) \
-{ \
- signed int f = (src + 0x80) >> 8; \
- f = MID(-32768, f, 32767); \
- ((short *)sptr)[pos] = (short)(f ^ signconv); \
-}
-
-#endif
-
-
-
-/* DEPRECATED */
-DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos)
-{
- return duh_start_sigrenderer(duh, 0, n_channels, pos);
-}
-
-
-
-long duh_render(
- DUH_SIGRENDERER *sigrenderer,
- int bits, int unsign,
- float volume, float delta,
- long size, void *sptr
-)
-{
- long n;
-
- sample_t **sampptr;
-
- int n_channels;
-
- ASSERT(bits == 8 || bits == 16);
- ASSERT(sptr);
-
- if (!sigrenderer)
- return 0;
-
- n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
-
- ASSERT(n_channels > 0);
- /* This restriction will be removed when need be. At the moment, tightly
- * optimised loops exist for exactly one or two channels.
- */
- ASSERT(n_channels <= 2);
-
- sampptr = allocate_sample_buffer(n_channels, size);
-
- if (!sampptr)
- return 0;
-
- dumb_silence(sampptr[0], n_channels * size);
-
- size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, sampptr);
-
- if (bits == 16) {
- int signconv = unsign ? 0x8000 : 0x0000;
-
- for (n = 0; n < size * n_channels; n++) {
- CONVERT16(sampptr[0][n], n, signconv);
- }
- } else {
- char signconv = unsign ? 0x80 : 0x00;
-
- for (n = 0; n < size * n_channels; n++) {
- CONVERT8(sampptr[0][n], n, signconv);
- }
- }
-
- destroy_sample_buffer(sampptr);
-
- return size;
-}
-
-
-
-/* DEPRECATED */
-int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr)
-{
- return duh_sigrenderer_get_n_channels(dr);
-}
-
-
-
-/* DEPRECATED */
-long duh_renderer_get_position(DUH_SIGRENDERER *dr)
-{
- return duh_sigrenderer_get_position(dr);
-}
-
-
-
-/* DEPRECATED */
-void duh_end_renderer(DUH_SIGRENDERER *dr)
-{
- duh_end_sigrenderer(dr);
-}
-
-
-
-/* DEPRECATED */
-DUH_SIGRENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer)
-{
- return sigrenderer;
-}
-
-
-
-/* DEPRECATED */
-DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_SIGRENDERER *dr)
-{
- return dr;
-}
-
-
-
-/* DEPRECATED */
-DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_SIGRENDERER *dr)
-{
- return dr;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * rendduh.c - Functions for rendering a DUH into / / \ \
+ * an end-user sample format. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <limits.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+/* On the x86, we can use some tricks to speed stuff up */
+#if (defined _MSC_VER) || (defined __DJGPP__) || (defined __MINGW__)
+// Can't we detect Linux and other x86 platforms here? :/
+
+#define FAST_MID(var, min, max) { \
+ var -= (min); \
+ var &= (~var) >> (sizeof(var) * CHAR_BIT - 1); \
+ var += (min); \
+ var -= (max); \
+ var &= var >> (sizeof(var) * CHAR_BIT - 1); \
+ var += (max); \
+}
+
+#define CONVERT8(src, pos, signconv) { \
+ signed int f = (src + 0x8000) >> 16; \
+ FAST_MID(f, -128, 127); \
+ ((char*)sptr)[pos] = (char)f ^ signconv; \
+}
+
+#define CONVERT16(src, pos, signconv) { \
+ signed int f = (src + 0x80) >> 8; \
+ FAST_MID(f, -32768, 32767); \
+ ((short*)sptr)[pos] = (short)(f ^ signconv); \
+}
+
+#else
+
+#define CONVERT8(src, pos, signconv) \
+{ \
+ signed int f = (src + 0x8000) >> 16; \
+ f = MID(-128, f, 127); \
+ ((char *)sptr)[pos] = (char)f ^ signconv; \
+}
+
+
+
+#define CONVERT16(src, pos, signconv) \
+{ \
+ signed int f = (src + 0x80) >> 8; \
+ f = MID(-32768, f, 32767); \
+ ((short *)sptr)[pos] = (short)(f ^ signconv); \
+}
+
+#endif
+
+
+
+/* DEPRECATED */
+DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos)
+{
+ return duh_start_sigrenderer(duh, 0, n_channels, pos);
+}
+
+
+
+long duh_render(
+ DUH_SIGRENDERER *sigrenderer,
+ int bits, int unsign,
+ float volume, float delta,
+ long size, void *sptr
+)
+{
+ long n;
+
+ sample_t **sampptr;
+
+ int n_channels;
+
+ ASSERT(bits == 8 || bits == 16);
+ ASSERT(sptr);
+
+ if (!sigrenderer)
+ return 0;
+
+ n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
+
+ ASSERT(n_channels > 0);
+ /* This restriction will be removed when need be. At the moment, tightly
+ * optimised loops exist for exactly one or two channels.
+ */
+ ASSERT(n_channels <= 2);
+
+ sampptr = allocate_sample_buffer(n_channels, size);
+
+ if (!sampptr)
+ return 0;
+
+ dumb_silence(sampptr[0], n_channels * size);
+
+ size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, sampptr);
+
+ if (bits == 16) {
+ int signconv = unsign ? 0x8000 : 0x0000;
+
+ for (n = 0; n < size * n_channels; n++) {
+ CONVERT16(sampptr[0][n], n, signconv);
+ }
+ } else {
+ char signconv = unsign ? 0x80 : 0x00;
+
+ for (n = 0; n < size * n_channels; n++) {
+ CONVERT8(sampptr[0][n], n, signconv);
+ }
+ }
+
+ destroy_sample_buffer(sampptr);
+
+ return size;
+}
+
+
+
+/* DEPRECATED */
+int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr)
+{
+ return duh_sigrenderer_get_n_channels(dr);
+}
+
+
+
+/* DEPRECATED */
+long duh_renderer_get_position(DUH_SIGRENDERER *dr)
+{
+ return duh_sigrenderer_get_position(dr);
+}
+
+
+
+/* DEPRECATED */
+void duh_end_renderer(DUH_SIGRENDERER *dr)
+{
+ duh_end_sigrenderer(dr);
+}
+
+
+
+/* DEPRECATED */
+DUH_SIGRENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer)
+{
+ return sigrenderer;
+}
+
+
+
+/* DEPRECATED */
+DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_SIGRENDERER *dr)
+{
+ return dr;
+}
+
+
+
+/* DEPRECATED */
+DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_SIGRENDERER *dr)
+{
+ return dr;
+}
diff --git a/plugins/dumb/dumb-kode54/src/core/rendsig.c b/plugins/dumb/dumb-kode54/src/core/rendsig.c
index b8f866c5..4181d1cd 100644
--- a/plugins/dumb/dumb-kode54/src/core/rendsig.c
+++ b/plugins/dumb/dumb-kode54/src/core/rendsig.c
@@ -1,344 +1,346 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * rendsig.c - Wrappers to render samples from / / \ \
- * the signals in a DUH. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-struct DUH_SIGRENDERER
-{
- DUH_SIGTYPE_DESC *desc;
-
- sigrenderer_t *sigrenderer;
-
- int n_channels;
-
- long pos;
- int subpos;
-
- DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback;
- void *callback_data;
-};
-
-
-
-DUH_SIGRENDERER *duh_start_sigrenderer(DUH *duh, int sig, int n_channels, long pos)
-{
- DUH_SIGRENDERER *sigrenderer;
-
- DUH_SIGNAL *signal;
- DUH_START_SIGRENDERER proc;
-
- if (!duh)
- return NULL;
-
- if ((unsigned int)sig >= (unsigned int)duh->n_signals)
- return NULL;
-
- signal = duh->signal[sig];
- if (!signal)
- return NULL;
-
- sigrenderer = malloc(sizeof(*sigrenderer));
- if (!sigrenderer)
- return NULL;
-
- sigrenderer->desc = signal->desc;
-
- proc = sigrenderer->desc->start_sigrenderer;
-
- if (proc) {
- duh->signal[sig] = NULL;
- sigrenderer->sigrenderer = (*proc)(duh, signal->sigdata, n_channels, pos);
- duh->signal[sig] = signal;
-
- if (!sigrenderer->sigrenderer) {
- free(sigrenderer);
- return NULL;
- }
- } else
- sigrenderer->sigrenderer = NULL;
-
- sigrenderer->n_channels = n_channels;
-
- sigrenderer->pos = pos;
- sigrenderer->subpos = 0;
-
- sigrenderer->callback = NULL;
-
- return sigrenderer;
-}
-
-
-
-#include <stdio.h>
-void duh_sigrenderer_set_callback(
- DUH_SIGRENDERER *sigrenderer,
- DUH_SIGRENDERER_CALLBACK callback, void *data
-)
-{
- (void)sigrenderer;
- (void)callback;
- (void)data;
- /*fprintf(stderr,
- "Call to deprecated function duh_sigrenderer_set_callback(). The callback\n"
- "was not installed. See dumb/docs/deprec.txt for how to fix this.\n");*/
-}
-
-
-
-void duh_sigrenderer_set_analyser_callback(
- DUH_SIGRENDERER *sigrenderer,
- DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data
-)
-{
- (void)sigrenderer;
- (void)callback;
- (void)data;
- fprintf(stderr,
- "Call to deprecated function duh_sigrenderer_set_analyser_callback(). The\n"
- "callback was not installed. See dumb/docs/deprec.txt for how to fix this.\n");
-}
-
-
-
-void duh_sigrenderer_set_sample_analyser_callback(
- DUH_SIGRENDERER *sigrenderer,
- DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data
-)
-{
- if (sigrenderer) {
- sigrenderer->callback = callback;
- sigrenderer->callback_data = data;
- }
-}
-
-
-
-int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer)
-{
- return sigrenderer ? sigrenderer->n_channels : 0;
-}
-
-
-
-long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer)
-{
- return sigrenderer ? sigrenderer->pos : -1;
-}
-
-
-
-void duh_sigrenderer_set_sigparam(
- DUH_SIGRENDERER *sigrenderer,
- unsigned char id, long value
-)
-{
- DUH_SIGRENDERER_SET_SIGPARAM proc;
-
- if (!sigrenderer) return;
-
- proc = sigrenderer->desc->sigrenderer_set_sigparam;
- if (proc)
- (*proc)(sigrenderer->sigrenderer, id, value);
- else
- TRACE("Parameter #%d = %ld for signal %c%c%c%c, which does not take parameters.\n",
- (int)id,
- value,
- (int)(sigrenderer->desc->type >> 24),
- (int)(sigrenderer->desc->type >> 16),
- (int)(sigrenderer->desc->type >> 8),
- (int)(sigrenderer->desc->type));
-}
-
-
-
-long duh_sigrenderer_generate_samples(
- DUH_SIGRENDERER *sigrenderer,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
- long rendered;
- LONG_LONG t;
-
- if (!sigrenderer) return 0;
-
- rendered = (*sigrenderer->desc->sigrenderer_generate_samples)
- (sigrenderer->sigrenderer, volume, delta, size, samples);
-
- if (rendered) {
- if (sigrenderer->callback)
- (*sigrenderer->callback)(sigrenderer->callback_data,
- (const sample_t *const *)samples, sigrenderer->n_channels, rendered);
-
- t = sigrenderer->subpos + (LONG_LONG)(delta * 65536.0 + 0.5) * rendered;
-
- sigrenderer->pos += (long)(t >> 16);
- sigrenderer->subpos = (int)t & 65535;
- }
-
- return rendered;
-}
-
-
-
-/* DEPRECATED */
-long duh_sigrenderer_get_samples(
- DUH_SIGRENDERER *sigrenderer,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
- sample_t **s;
- long rendered;
- long i;
- int j;
- if (!samples) return duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, NULL);
- s = allocate_sample_buffer(sigrenderer->n_channels, size);
- if (!s) return 0;
- dumb_silence(s[0], sigrenderer->n_channels * size);
- rendered = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, s);
- for (j = 0; j < sigrenderer->n_channels; j++)
- for (i = 0; i < rendered; i++)
- samples[j][i] += s[0][i*sigrenderer->n_channels+j];
- destroy_sample_buffer(s);
- return rendered;
-}
-
-
-
-/* DEPRECATED */
-long duh_render_signal(
- DUH_SIGRENDERER *sigrenderer,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
- sample_t **s;
- long rendered;
- long i;
- int j;
- if (!samples) return duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, NULL);
- s = allocate_sample_buffer(sigrenderer->n_channels, size);
- if (!s) return 0;
- dumb_silence(s[0], sigrenderer->n_channels * size);
- rendered = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, s);
- for (j = 0; j < sigrenderer->n_channels; j++)
- for (i = 0; i < rendered; i++)
- samples[j][i] += s[0][i*sigrenderer->n_channels+j] >> 8;
- destroy_sample_buffer(s);
- return rendered;
-}
-
-
-
-void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, float volume, sample_t *samples)
-{
- if (sigrenderer)
- (*sigrenderer->desc->sigrenderer_get_current_sample)(sigrenderer->sigrenderer, volume, samples);
-}
-
-
-
-void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer)
-{
- if (sigrenderer) {
- if (sigrenderer->desc->end_sigrenderer)
- if (sigrenderer->sigrenderer)
- (*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer);
-
- free(sigrenderer);
- }
-}
-
-
-
-DUH_SIGRENDERER *duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, long pos)
-{
- DUH_SIGRENDERER *sigrenderer;
-
- if (desc->start_sigrenderer && !vsigrenderer) return NULL;
-
- sigrenderer = malloc(sizeof(*sigrenderer));
- if (!sigrenderer) {
- if (desc->end_sigrenderer)
- if (vsigrenderer)
- (*desc->end_sigrenderer)(vsigrenderer);
- return NULL;
- }
-
- sigrenderer->desc = desc;
- sigrenderer->sigrenderer = vsigrenderer;
-
- sigrenderer->n_channels = n_channels;
-
- sigrenderer->pos = pos;
- sigrenderer->subpos = 0;
-
- sigrenderer->callback = NULL;
-
- return sigrenderer;
-}
-
-
-
-sigrenderer_t *duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type)
-{
- if (sigrenderer && sigrenderer->desc->type == type)
- return sigrenderer->sigrenderer;
-
- return NULL;
-}
-
-
-
-#if 0
-// This function is disabled because we don't know whether we want to destroy
-// the sigrenderer if the type doesn't match. We don't even know if we need
-// the function at all. Who would want to keep an IT_SIGRENDERER (for
-// instance) without keeping the DUH_SIGRENDERER?
-sigrenderer_t *duh_decompose_to_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type)
-{
- if (sigrenderer && sigrenderer->desc->type == type) {
-
-
-
- if (sigrenderer) {
- if (sigrenderer->desc->end_sigrenderer)
- if (sigrenderer->sigrenderer)
- (*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer);
-
- free(sigrenderer);
- }
-
-
-
-
-
-
- return sigrenderer->sigrenderer;
- }
-
- return NULL;
-}
-#endif
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * rendsig.c - Wrappers to render samples from / / \ \
+ * the signals in a DUH. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+struct DUH_SIGRENDERER
+{
+ DUH_SIGTYPE_DESC *desc;
+
+ sigrenderer_t *sigrenderer;
+
+ int n_channels;
+
+ long pos;
+ int subpos;
+
+ DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback;
+ void *callback_data;
+};
+
+
+
+DUH_SIGRENDERER *duh_start_sigrenderer(DUH *duh, int sig, int n_channels, long pos)
+{
+ DUH_SIGRENDERER *sigrenderer;
+
+ DUH_SIGNAL *signal;
+ DUH_START_SIGRENDERER proc;
+
+ if (!duh)
+ return NULL;
+
+ if ((unsigned int)sig >= (unsigned int)duh->n_signals)
+ return NULL;
+
+ signal = duh->signal[sig];
+ if (!signal)
+ return NULL;
+
+ sigrenderer = malloc(sizeof(*sigrenderer));
+ if (!sigrenderer)
+ return NULL;
+
+ sigrenderer->desc = signal->desc;
+
+ proc = sigrenderer->desc->start_sigrenderer;
+
+ if (proc) {
+ duh->signal[sig] = NULL;
+ sigrenderer->sigrenderer = (*proc)(duh, signal->sigdata, n_channels, pos);
+ duh->signal[sig] = signal;
+
+ if (!sigrenderer->sigrenderer) {
+ free(sigrenderer);
+ return NULL;
+ }
+ } else
+ sigrenderer->sigrenderer = NULL;
+
+ sigrenderer->n_channels = n_channels;
+
+ sigrenderer->pos = pos;
+ sigrenderer->subpos = 0;
+
+ sigrenderer->callback = NULL;
+
+ return sigrenderer;
+}
+
+
+
+#include <stdio.h>
+void duh_sigrenderer_set_callback(
+ DUH_SIGRENDERER *sigrenderer,
+ DUH_SIGRENDERER_CALLBACK callback, void *data
+)
+{
+ (void)sigrenderer;
+ (void)callback;
+ (void)data;
+ /*fprintf(stderr,
+ "Call to deprecated function duh_sigrenderer_set_callback(). The callback\n"
+ "was not installed. See dumb/docs/deprec.txt for how to fix this.\n");*/
+}
+
+
+
+void duh_sigrenderer_set_analyser_callback(
+ DUH_SIGRENDERER *sigrenderer,
+ DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data
+)
+{
+ (void)sigrenderer;
+ (void)callback;
+ (void)data;
+ fprintf(stderr,
+ "Call to deprecated function duh_sigrenderer_set_analyser_callback(). The\n"
+ "callback was not installed. See dumb/docs/deprec.txt for how to fix this.\n");
+}
+
+
+
+void duh_sigrenderer_set_sample_analyser_callback(
+ DUH_SIGRENDERER *sigrenderer,
+ DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data
+)
+{
+ (void)sigrenderer;
+ (void)callback;
+ (void)data;
+ fprintf(stderr,
+ "Call to deprecated function duh_sigrenderer_set_analyser_callback(). The\n"
+ "callback was not installed. See dumb/docs/deprec.txt for how to fix this.\n");
+}
+
+
+
+int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer)
+{
+ return sigrenderer ? sigrenderer->n_channels : 0;
+}
+
+
+
+long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer)
+{
+ return sigrenderer ? sigrenderer->pos : -1;
+}
+
+
+
+void duh_sigrenderer_set_sigparam(
+ DUH_SIGRENDERER *sigrenderer,
+ unsigned char id, long value
+)
+{
+ DUH_SIGRENDERER_SET_SIGPARAM proc;
+
+ if (!sigrenderer) return;
+
+ proc = sigrenderer->desc->sigrenderer_set_sigparam;
+ if (proc)
+ (*proc)(sigrenderer->sigrenderer, id, value);
+ else
+ TRACE("Parameter #%d = %ld for signal %c%c%c%c, which does not take parameters.\n",
+ (int)id,
+ value,
+ (int)(sigrenderer->desc->type >> 24),
+ (int)(sigrenderer->desc->type >> 16),
+ (int)(sigrenderer->desc->type >> 8),
+ (int)(sigrenderer->desc->type));
+}
+
+
+
+long duh_sigrenderer_generate_samples(
+ DUH_SIGRENDERER *sigrenderer,
+ float volume, float delta,
+ long size, sample_t **samples
+)
+{
+ long rendered;
+ LONG_LONG t;
+
+ if (!sigrenderer) return 0;
+
+ rendered = (*sigrenderer->desc->sigrenderer_generate_samples)
+ (sigrenderer->sigrenderer, volume, delta, size, samples);
+
+ if (rendered) {
+ if (sigrenderer->callback)
+ (*sigrenderer->callback)(sigrenderer->callback_data,
+ (const sample_t *const *)samples, sigrenderer->n_channels, rendered);
+
+ t = sigrenderer->subpos + (LONG_LONG)(delta * 65536.0 + 0.5) * rendered;
+
+ sigrenderer->pos += (long)(t >> 16);
+ sigrenderer->subpos = (int)t & 65535;
+ }
+
+ return rendered;
+}
+
+
+
+/* DEPRECATED */
+long duh_sigrenderer_get_samples(
+ DUH_SIGRENDERER *sigrenderer,
+ float volume, float delta,
+ long size, sample_t **samples
+)
+{
+ sample_t **s;
+ long rendered;
+ long i;
+ int j;
+ if (!samples) return duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, NULL);
+ s = allocate_sample_buffer(sigrenderer->n_channels, size);
+ if (!s) return 0;
+ dumb_silence(s[0], sigrenderer->n_channels * size);
+ rendered = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, s);
+ for (j = 0; j < sigrenderer->n_channels; j++)
+ for (i = 0; i < rendered; i++)
+ samples[j][i] += s[0][i*sigrenderer->n_channels+j];
+ destroy_sample_buffer(s);
+ return rendered;
+}
+
+
+
+/* DEPRECATED */
+long duh_render_signal(
+ DUH_SIGRENDERER *sigrenderer,
+ float volume, float delta,
+ long size, sample_t **samples
+)
+{
+ sample_t **s;
+ long rendered;
+ long i;
+ int j;
+ if (!samples) return duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, NULL);
+ s = allocate_sample_buffer(sigrenderer->n_channels, size);
+ if (!s) return 0;
+ dumb_silence(s[0], sigrenderer->n_channels * size);
+ rendered = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, s);
+ for (j = 0; j < sigrenderer->n_channels; j++)
+ for (i = 0; i < rendered; i++)
+ samples[j][i] += s[0][i*sigrenderer->n_channels+j] >> 8;
+ destroy_sample_buffer(s);
+ return rendered;
+}
+
+
+
+void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, float volume, sample_t *samples)
+{
+ if (sigrenderer)
+ (*sigrenderer->desc->sigrenderer_get_current_sample)(sigrenderer->sigrenderer, volume, samples);
+}
+
+
+
+void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer)
+{
+ if (sigrenderer) {
+ if (sigrenderer->desc->end_sigrenderer)
+ if (sigrenderer->sigrenderer)
+ (*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer);
+
+ free(sigrenderer);
+ }
+}
+
+
+
+DUH_SIGRENDERER *duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, long pos)
+{
+ DUH_SIGRENDERER *sigrenderer;
+
+ if (desc->start_sigrenderer && !vsigrenderer) return NULL;
+
+ sigrenderer = malloc(sizeof(*sigrenderer));
+ if (!sigrenderer) {
+ if (desc->end_sigrenderer)
+ if (vsigrenderer)
+ (*desc->end_sigrenderer)(vsigrenderer);
+ return NULL;
+ }
+
+ sigrenderer->desc = desc;
+ sigrenderer->sigrenderer = vsigrenderer;
+
+ sigrenderer->n_channels = n_channels;
+
+ sigrenderer->pos = pos;
+ sigrenderer->subpos = 0;
+
+ sigrenderer->callback = NULL;
+
+ return sigrenderer;
+}
+
+
+
+sigrenderer_t *duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type)
+{
+ if (sigrenderer && sigrenderer->desc->type == type)
+ return sigrenderer->sigrenderer;
+
+ return NULL;
+}
+
+
+
+#if 0
+// This function is disabled because we don't know whether we want to destroy
+// the sigrenderer if the type doesn't match. We don't even know if we need
+// the function at all. Who would want to keep an IT_SIGRENDERER (for
+// instance) without keeping the DUH_SIGRENDERER?
+sigrenderer_t *duh_decompose_to_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type)
+{
+ if (sigrenderer && sigrenderer->desc->type == type) {
+
+
+
+ if (sigrenderer) {
+ if (sigrenderer->desc->end_sigrenderer)
+ if (sigrenderer->sigrenderer)
+ (*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer);
+
+ free(sigrenderer);
+ }
+
+
+
+
+
+
+ return sigrenderer->sigrenderer;
+ }
+
+ return NULL;
+}
+#endif
diff --git a/plugins/dumb/dumb-kode54/src/core/unload.c b/plugins/dumb/dumb-kode54/src/core/unload.c
index f241f718..11d81e26 100644
--- a/plugins/dumb/dumb-kode54/src/core/unload.c
+++ b/plugins/dumb/dumb-kode54/src/core/unload.c
@@ -1,64 +1,64 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * unload.c - Code to free a DUH from memory. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-static void destroy_signal(DUH_SIGNAL *signal)
-{
- if (signal) {
- if (signal->desc)
- if (signal->desc->unload_sigdata)
- if (signal->sigdata)
- (*signal->desc->unload_sigdata)(signal->sigdata);
-
- free(signal);
- }
-}
-
-
-
-/* unload_duh(): destroys a DUH struct. You must call this for every DUH
- * struct created, when you've finished with it.
- */
-void unload_duh(DUH *duh)
-{
- int i;
-
- if (duh) {
- if (duh->signal) {
- for (i = 0; i < duh->n_signals; i++)
- destroy_signal(duh->signal[i]);
-
- free(duh->signal);
- }
-
- if (duh->tag) {
- if (duh->tag[0][0])
- free(duh->tag[0][0]);
- free(duh->tag);
- }
-
- free(duh);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * unload.c - Code to free a DUH from memory. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+
+
+
+static void destroy_signal(DUH_SIGNAL *signal)
+{
+ if (signal) {
+ if (signal->desc)
+ if (signal->desc->unload_sigdata)
+ if (signal->sigdata)
+ (*signal->desc->unload_sigdata)(signal->sigdata);
+
+ free(signal);
+ }
+}
+
+
+
+/* unload_duh(): destroys a DUH struct. You must call this for every DUH
+ * struct created, when you've finished with it.
+ */
+void unload_duh(DUH *duh)
+{
+ int i;
+
+ if (duh) {
+ if (duh->signal) {
+ for (i = 0; i < duh->n_signals; i++)
+ destroy_signal(duh->signal[i]);
+
+ free(duh->signal);
+ }
+
+ if (duh->tag) {
+ if (duh->tag[0][0])
+ free(duh->tag[0][0]);
+ free(duh->tag);
+ }
+
+ free(duh);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/helpers/barray.c b/plugins/dumb/dumb-kode54/src/helpers/barray.c
index 95fe7af1..5877725c 100644
--- a/plugins/dumb/dumb-kode54/src/helpers/barray.c
+++ b/plugins/dumb/dumb-kode54/src/helpers/barray.c
@@ -1,159 +1,159 @@
-#include "internal/barray.h"
-
-#include <string.h>
-
-
-void * bit_array_create(size_t size)
-{
- size_t bsize = ((size + 7) >> 3) + sizeof(size_t);
- void * ret = calloc(1, bsize);
- if (ret) *(size_t *)ret = size;
- return ret;
-}
-
-void bit_array_destroy(void * array)
-{
- if (array) free(array);
-}
-
-void * bit_array_dup(void * array)
-{
- if (array)
- {
- size_t * size = (size_t *) array;
- size_t bsize = ((*size + 7) >> 3) + sizeof(*size);
- void * ret = malloc(bsize);
- if (ret) memcpy(ret, array, bsize);
- return ret;
- }
- return NULL;
-}
-
-void bit_array_reset(void * array)
-{
- if (array)
- {
- size_t * size = (size_t *) array;
- size_t bsize = (*size + 7) >> 3;
- memset(size + 1, 0, bsize);
- }
-}
-
-
-void bit_array_set(void * array, size_t bit)
-{
- if (array)
- {
- size_t * size = (size_t *) array;
- if (bit < *size)
- {
- unsigned char * ptr = (unsigned char *)(size + 1);
- ptr[bit >> 3] |= (1U << (bit & 7));
- }
- }
-}
-
-int bit_array_test(void * array, size_t bit)
-{
- if (array)
- {
- size_t * size = (size_t *) array;
- if (bit < *size)
- {
- unsigned char * ptr = (unsigned char *)(size + 1);
- if (ptr[bit >> 3] & (1U << (bit & 7)))
- {
- return 1;
- }
- }
- }
- return 0;
-}
-
-int bit_array_test_range(void * array, size_t bit, size_t count)
-{
- if (array)
- {
- size_t * size = (size_t *) array;
- if (bit < *size)
- {
- unsigned char * ptr = (unsigned char *)(size + 1);
- if ((bit & 7) && (count > 8))
- {
- while ((bit < *size) && count && (bit & 7))
- {
- if (ptr[bit >> 3] & (1U << (bit & 7))) return 1;
- bit++;
- count--;
- }
- }
- if (!(bit & 7))
- {
- while (((*size - bit) >= 8) && (count >= 8))
- {
- if (ptr[bit >> 3]) return 1;
- bit += 8;
- count -= 8;
- }
- }
- while ((bit < *size) && count)
- {
- if (ptr[bit >> 3] & (1U << (bit & 7))) return 1;
- bit++;
- count--;
- }
- }
- }
- return 0;
-}
-
-void bit_array_clear(void * array, size_t bit)
-{
- if (array)
- {
- size_t * size = (size_t *) array;
- if (bit < *size)
- {
- unsigned char * ptr = (unsigned char *)(size + 1);
- ptr[bit >> 3] &= ~(1U << (bit & 7));
- }
- }
-}
-
-void bit_array_merge(void * dest, void * source, size_t offset)
-{
- if (dest && source)
- {
- size_t * dsize = (size_t *) dest;
- size_t * ssize = (size_t *) source;
- size_t soffset = 0;
- while (offset < *dsize && soffset < *ssize)
- {
- if (bit_array_test(source, soffset))
- {
- bit_array_set(dest, offset);
- }
- soffset++;
- offset++;
- }
- }
-}
-
-void bit_array_mask(void * dest, void * source, size_t offset)
-{
- if (dest && source)
- {
- size_t * dsize = (size_t *) dest;
- size_t * ssize = (size_t *) source;
- size_t soffset = 0;
- while (offset < *dsize && soffset < *ssize)
- {
- if (bit_array_test(source, soffset))
- {
- bit_array_clear(dest, offset);
- }
- soffset++;
- offset++;
- }
- }
-}
+#include "internal/barray.h"
+
+#include <string.h>
+
+
+void * bit_array_create(size_t size)
+{
+ size_t bsize = ((size + 7) >> 3) + sizeof(size_t);
+ void * ret = calloc(1, bsize);
+ if (ret) *(size_t *)ret = size;
+ return ret;
+}
+
+void bit_array_destroy(void * array)
+{
+ if (array) free(array);
+}
+
+void * bit_array_dup(void * array)
+{
+ if (array)
+ {
+ size_t * size = (size_t *) array;
+ size_t bsize = ((*size + 7) >> 3) + sizeof(*size);
+ void * ret = malloc(bsize);
+ if (ret) memcpy(ret, array, bsize);
+ return ret;
+ }
+ return NULL;
+}
+
+void bit_array_reset(void * array)
+{
+ if (array)
+ {
+ size_t * size = (size_t *) array;
+ size_t bsize = (*size + 7) >> 3;
+ memset(size + 1, 0, bsize);
+ }
+}
+
+
+void bit_array_set(void * array, size_t bit)
+{
+ if (array)
+ {
+ size_t * size = (size_t *) array;
+ if (bit < *size)
+ {
+ unsigned char * ptr = (unsigned char *)(size + 1);
+ ptr[bit >> 3] |= (1U << (bit & 7));
+ }
+ }
+}
+
+int bit_array_test(void * array, size_t bit)
+{
+ if (array)
+ {
+ size_t * size = (size_t *) array;
+ if (bit < *size)
+ {
+ unsigned char * ptr = (unsigned char *)(size + 1);
+ if (ptr[bit >> 3] & (1U << (bit & 7)))
+ {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+int bit_array_test_range(void * array, size_t bit, size_t count)
+{
+ if (array)
+ {
+ size_t * size = (size_t *) array;
+ if (bit < *size)
+ {
+ unsigned char * ptr = (unsigned char *)(size + 1);
+ if ((bit & 7) && (count > 8))
+ {
+ while ((bit < *size) && count && (bit & 7))
+ {
+ if (ptr[bit >> 3] & (1U << (bit & 7))) return 1;
+ bit++;
+ count--;
+ }
+ }
+ if (!(bit & 7))
+ {
+ while (((*size - bit) >= 8) && (count >= 8))
+ {
+ if (ptr[bit >> 3]) return 1;
+ bit += 8;
+ count -= 8;
+ }
+ }
+ while ((bit < *size) && count)
+ {
+ if (ptr[bit >> 3] & (1U << (bit & 7))) return 1;
+ bit++;
+ count--;
+ }
+ }
+ }
+ return 0;
+}
+
+void bit_array_clear(void * array, size_t bit)
+{
+ if (array)
+ {
+ size_t * size = (size_t *) array;
+ if (bit < *size)
+ {
+ unsigned char * ptr = (unsigned char *)(size + 1);
+ ptr[bit >> 3] &= ~(1U << (bit & 7));
+ }
+ }
+}
+
+void bit_array_merge(void * dest, void * source, size_t offset)
+{
+ if (dest && source)
+ {
+ size_t * dsize = (size_t *) dest;
+ size_t * ssize = (size_t *) source;
+ size_t soffset = 0;
+ while (offset < *dsize && soffset < *ssize)
+ {
+ if (bit_array_test(source, soffset))
+ {
+ bit_array_set(dest, offset);
+ }
+ soffset++;
+ offset++;
+ }
+ }
+}
+
+void bit_array_mask(void * dest, void * source, size_t offset)
+{
+ if (dest && source)
+ {
+ size_t * dsize = (size_t *) dest;
+ size_t * ssize = (size_t *) source;
+ size_t soffset = 0;
+ while (offset < *dsize && soffset < *ssize)
+ {
+ if (bit_array_test(source, soffset))
+ {
+ bit_array_clear(dest, offset);
+ }
+ soffset++;
+ offset++;
+ }
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/helpers/clickrem.c b/plugins/dumb/dumb-kode54/src/helpers/clickrem.c
index 336b492d..62885e6a 100644
--- a/plugins/dumb/dumb-kode54/src/helpers/clickrem.c
+++ b/plugins/dumb/dumb-kode54/src/helpers/clickrem.c
@@ -1,281 +1,281 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * clickrem.c - Click removal helpers. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <math.h>
-#include "dumb.h"
-
-
-
-typedef struct DUMB_CLICK DUMB_CLICK;
-
-
-struct DUMB_CLICK_REMOVER
-{
- DUMB_CLICK *click;
- int n_clicks;
-
- int offset;
-};
-
-
-struct DUMB_CLICK
-{
- DUMB_CLICK *next;
- long pos;
- sample_t step;
-};
-
-
-
-DUMB_CLICK_REMOVER *dumb_create_click_remover(void)
-{
- DUMB_CLICK_REMOVER *cr = malloc(sizeof(*cr));
- if (!cr) return NULL;
-
- cr->click = NULL;
- cr->n_clicks = 0;
-
- cr->offset = 0;
-
- return cr;
-}
-
-
-
-void dumb_record_click(DUMB_CLICK_REMOVER *cr, long pos, sample_t step)
-{
- DUMB_CLICK *click;
-
- ASSERT(pos >= 0);
-
- if (!cr || !step) return;
-
- if (pos == 0) {
- cr->offset -= step;
- return;
- }
-
- click = malloc(sizeof(*click));
- if (!click) return;
-
- click->pos = pos;
- click->step = step;
-
- click->next = cr->click;
- cr->click = click;
- cr->n_clicks++;
-}
-
-
-
-static DUMB_CLICK *dumb_click_mergesort(DUMB_CLICK *click, int n_clicks)
-{
- int i;
- DUMB_CLICK *c1, *c2, **cp;
-
- if (n_clicks <= 1) return click;
-
- /* Split the list into two */
- c1 = click;
- cp = &c1;
- for (i = 0; i < n_clicks; i += 2) cp = &(*cp)->next;
- c2 = *cp;
- *cp = NULL;
-
- /* Sort the sublists */
- c1 = dumb_click_mergesort(c1, (n_clicks + 1) >> 1);
- c2 = dumb_click_mergesort(c2, n_clicks >> 1);
-
- /* Merge them */
- cp = &click;
- while (c1 && c2) {
- if (c1->pos > c2->pos) {
- *cp = c2;
- c2 = c2->next;
- } else {
- *cp = c1;
- c1 = c1->next;
- }
- cp = &(*cp)->next;
- }
- if (c2)
- *cp = c2;
- else
- *cp = c1;
-
- return click;
-}
-
-
-
-void dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, long length, int step, float halflife)
-{
- DUMB_CLICK *click;
- long pos = 0;
- int offset;
- int factor;
-
- if (!cr) return;
-
- factor = (int)floor(pow(0.5, 1.0/halflife) * (1U << 31));
-
- click = dumb_click_mergesort(cr->click, cr->n_clicks);
- cr->click = NULL;
- cr->n_clicks = 0;
-
- length *= step;
-
- while (click) {
- DUMB_CLICK *next = click->next;
- int end = click->pos * step;
- ASSERT(end <= length);
- offset = cr->offset;
- if (offset < 0) {
- offset = -offset;
- while (pos < end) {
- samples[pos] -= offset;
- offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32);
- pos += step;
- }
- offset = -offset;
- } else {
- while (pos < end) {
- samples[pos] += offset;
- offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32);
- pos += step;
- }
- }
- cr->offset = offset - click->step;
- free(click);
- click = next;
- }
-
- offset = cr->offset;
- if (offset < 0) {
- offset = -offset;
- while (pos < length) {
- samples[pos] -= offset;
- offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
- pos += step;
- }
- offset = -offset;
- } else {
- while (pos < length) {
- samples[pos] += offset;
- offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
- pos += step;
- }
- }
- cr->offset = offset;
-}
-
-
-
-sample_t dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr)
-{
- return cr ? cr->offset : 0;
-}
-
-
-
-void dumb_destroy_click_remover(DUMB_CLICK_REMOVER *cr)
-{
- if (cr) {
- DUMB_CLICK *click = cr->click;
- while (click) {
- DUMB_CLICK *next = click->next;
- free(click);
- click = next;
- }
- free(cr);
- }
-}
-
-
-
-DUMB_CLICK_REMOVER **dumb_create_click_remover_array(int n)
-{
- int i;
- DUMB_CLICK_REMOVER **cr;
- if (n <= 0) return NULL;
- cr = malloc(n * sizeof(*cr));
- if (!cr) return NULL;
- for (i = 0; i < n; i++) cr[i] = dumb_create_click_remover();
- return cr;
-}
-
-
-
-void dumb_record_click_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step)
-{
- if (cr) {
- int i;
- for (i = 0; i < n; i++)
- dumb_record_click(cr[i], pos, step[i]);
- }
-}
-
-
-
-void dumb_record_click_negative_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step)
-{
- if (cr) {
- int i;
- for (i = 0; i < n; i++)
- dumb_record_click(cr[i], pos, -step[i]);
- }
-}
-
-
-
-void dumb_remove_clicks_array(int n, DUMB_CLICK_REMOVER **cr, sample_t **samples, long length, float halflife)
-{
- if (cr) {
- int i;
- for (i = 0; i < n >> 1; i++) {
- dumb_remove_clicks(cr[i << 1], samples[i], length, 2, halflife);
- dumb_remove_clicks(cr[(i << 1) + 1], samples[i] + 1, length, 2, halflife);
- }
- if (n & 1)
- dumb_remove_clicks(cr[i << 1], samples[i], length, 1, halflife);
- }
-}
-
-
-
-void dumb_click_remover_get_offset_array(int n, DUMB_CLICK_REMOVER **cr, sample_t *offset)
-{
- if (cr) {
- int i;
- for (i = 0; i < n; i++)
- if (cr[i]) offset[i] += cr[i]->offset;
- }
-}
-
-
-
-void dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr)
-{
- if (cr) {
- int i;
- for (i = 0; i < n; i++) dumb_destroy_click_remover(cr[i]);
- free(cr);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * clickrem.c - Click removal helpers. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include "dumb.h"
+
+
+
+typedef struct DUMB_CLICK DUMB_CLICK;
+
+
+struct DUMB_CLICK_REMOVER
+{
+ DUMB_CLICK *click;
+ int n_clicks;
+
+ int offset;
+};
+
+
+struct DUMB_CLICK
+{
+ DUMB_CLICK *next;
+ long pos;
+ sample_t step;
+};
+
+
+
+DUMB_CLICK_REMOVER *dumb_create_click_remover(void)
+{
+ DUMB_CLICK_REMOVER *cr = malloc(sizeof(*cr));
+ if (!cr) return NULL;
+
+ cr->click = NULL;
+ cr->n_clicks = 0;
+
+ cr->offset = 0;
+
+ return cr;
+}
+
+
+
+void dumb_record_click(DUMB_CLICK_REMOVER *cr, long pos, sample_t step)
+{
+ DUMB_CLICK *click;
+
+ ASSERT(pos >= 0);
+
+ if (!cr || !step) return;
+
+ if (pos == 0) {
+ cr->offset -= step;
+ return;
+ }
+
+ click = malloc(sizeof(*click));
+ if (!click) return;
+
+ click->pos = pos;
+ click->step = step;
+
+ click->next = cr->click;
+ cr->click = click;
+ cr->n_clicks++;
+}
+
+
+
+static DUMB_CLICK *dumb_click_mergesort(DUMB_CLICK *click, int n_clicks)
+{
+ int i;
+ DUMB_CLICK *c1, *c2, **cp;
+
+ if (n_clicks <= 1) return click;
+
+ /* Split the list into two */
+ c1 = click;
+ cp = &c1;
+ for (i = 0; i < n_clicks; i += 2) cp = &(*cp)->next;
+ c2 = *cp;
+ *cp = NULL;
+
+ /* Sort the sublists */
+ c1 = dumb_click_mergesort(c1, (n_clicks + 1) >> 1);
+ c2 = dumb_click_mergesort(c2, n_clicks >> 1);
+
+ /* Merge them */
+ cp = &click;
+ while (c1 && c2) {
+ if (c1->pos > c2->pos) {
+ *cp = c2;
+ c2 = c2->next;
+ } else {
+ *cp = c1;
+ c1 = c1->next;
+ }
+ cp = &(*cp)->next;
+ }
+ if (c2)
+ *cp = c2;
+ else
+ *cp = c1;
+
+ return click;
+}
+
+
+
+void dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, long length, int step, float halflife)
+{
+ DUMB_CLICK *click;
+ long pos = 0;
+ int offset;
+ int factor;
+
+ if (!cr) return;
+
+ factor = (int)floor(pow(0.5, 1.0/halflife) * (1U << 31));
+
+ click = dumb_click_mergesort(cr->click, cr->n_clicks);
+ cr->click = NULL;
+ cr->n_clicks = 0;
+
+ length *= step;
+
+ while (click) {
+ DUMB_CLICK *next = click->next;
+ int end = click->pos * step;
+ ASSERT(end <= length);
+ offset = cr->offset;
+ if (offset < 0) {
+ offset = -offset;
+ while (pos < end) {
+ samples[pos] -= offset;
+ offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32);
+ pos += step;
+ }
+ offset = -offset;
+ } else {
+ while (pos < end) {
+ samples[pos] += offset;
+ offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32);
+ pos += step;
+ }
+ }
+ cr->offset = offset - click->step;
+ free(click);
+ click = next;
+ }
+
+ offset = cr->offset;
+ if (offset < 0) {
+ offset = -offset;
+ while (pos < length) {
+ samples[pos] -= offset;
+ offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
+ pos += step;
+ }
+ offset = -offset;
+ } else {
+ while (pos < length) {
+ samples[pos] += offset;
+ offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
+ pos += step;
+ }
+ }
+ cr->offset = offset;
+}
+
+
+
+sample_t dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr)
+{
+ return cr ? cr->offset : 0;
+}
+
+
+
+void dumb_destroy_click_remover(DUMB_CLICK_REMOVER *cr)
+{
+ if (cr) {
+ DUMB_CLICK *click = cr->click;
+ while (click) {
+ DUMB_CLICK *next = click->next;
+ free(click);
+ click = next;
+ }
+ free(cr);
+ }
+}
+
+
+
+DUMB_CLICK_REMOVER **dumb_create_click_remover_array(int n)
+{
+ int i;
+ DUMB_CLICK_REMOVER **cr;
+ if (n <= 0) return NULL;
+ cr = malloc(n * sizeof(*cr));
+ if (!cr) return NULL;
+ for (i = 0; i < n; i++) cr[i] = dumb_create_click_remover();
+ return cr;
+}
+
+
+
+void dumb_record_click_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step)
+{
+ if (cr) {
+ int i;
+ for (i = 0; i < n; i++)
+ dumb_record_click(cr[i], pos, step[i]);
+ }
+}
+
+
+
+void dumb_record_click_negative_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step)
+{
+ if (cr) {
+ int i;
+ for (i = 0; i < n; i++)
+ dumb_record_click(cr[i], pos, -step[i]);
+ }
+}
+
+
+
+void dumb_remove_clicks_array(int n, DUMB_CLICK_REMOVER **cr, sample_t **samples, long length, float halflife)
+{
+ if (cr) {
+ int i;
+ for (i = 0; i < n >> 1; i++) {
+ dumb_remove_clicks(cr[i << 1], samples[i], length, 2, halflife);
+ dumb_remove_clicks(cr[(i << 1) + 1], samples[i] + 1, length, 2, halflife);
+ }
+ if (n & 1)
+ dumb_remove_clicks(cr[i << 1], samples[i], length, 1, halflife);
+ }
+}
+
+
+
+void dumb_click_remover_get_offset_array(int n, DUMB_CLICK_REMOVER **cr, sample_t *offset)
+{
+ if (cr) {
+ int i;
+ for (i = 0; i < n; i++)
+ if (cr[i]) offset[i] += cr[i]->offset;
+ }
+}
+
+
+
+void dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr)
+{
+ if (cr) {
+ int i;
+ for (i = 0; i < n; i++) dumb_destroy_click_remover(cr[i]);
+ free(cr);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/helpers/memfile.c b/plugins/dumb/dumb-kode54/src/helpers/memfile.c
index 6fcbbc7c..bf6d510f 100644
--- a/plugins/dumb/dumb-kode54/src/helpers/memfile.c
+++ b/plugins/dumb/dumb-kode54/src/helpers/memfile.c
@@ -1,96 +1,96 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * memfile.c - Module for reading data from / / \ \
- * memory using a DUMBFILE. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-
-
-
-typedef struct MEMFILE MEMFILE;
-
-struct MEMFILE
-{
- const char *ptr;
- long left;
-};
-
-
-
-static int dumb_memfile_skip(void *f, long n)
-{
- MEMFILE *m = f;
- if (n > m->left) return -1;
- m->ptr += n;
- m->left -= n;
- return 0;
-}
-
-
-
-static int dumb_memfile_getc(void *f)
-{
- MEMFILE *m = f;
- if (m->left <= 0) return -1;
- m->left--;
- return *(const unsigned char *)m->ptr++;
-}
-
-
-
-static long dumb_memfile_getnc(char *ptr, long n, void *f)
-{
- MEMFILE *m = f;
- if (n > m->left) n = m->left;
- memcpy(ptr, m->ptr, n);
- m->ptr += n;
- m->left -= n;
- return n;
-}
-
-
-
-static void dumb_memfile_close(void *f)
-{
- free(f);
-}
-
-
-
-static const DUMBFILE_SYSTEM memfile_dfs = {
- NULL,
- &dumb_memfile_skip,
- &dumb_memfile_getc,
- &dumb_memfile_getnc,
- &dumb_memfile_close
-};
-
-
-
-DUMBFILE *dumbfile_open_memory(const char *data, long size)
-{
- MEMFILE *m = malloc(sizeof(*m));
- if (!m) return NULL;
-
- m->ptr = data;
- m->left = size;
-
- return dumbfile_open_ex(m, &memfile_dfs);
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * memfile.c - Module for reading data from / / \ \
+ * memory using a DUMBFILE. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dumb.h"
+
+
+
+typedef struct MEMFILE MEMFILE;
+
+struct MEMFILE
+{
+ const char *ptr;
+ long left;
+};
+
+
+
+static int dumb_memfile_skip(void *f, long n)
+{
+ MEMFILE *m = f;
+ if (n > m->left) return -1;
+ m->ptr += n;
+ m->left -= n;
+ return 0;
+}
+
+
+
+static int dumb_memfile_getc(void *f)
+{
+ MEMFILE *m = f;
+ if (m->left <= 0) return -1;
+ m->left--;
+ return *(const unsigned char *)m->ptr++;
+}
+
+
+
+static long dumb_memfile_getnc(char *ptr, long n, void *f)
+{
+ MEMFILE *m = f;
+ if (n > m->left) n = m->left;
+ memcpy(ptr, m->ptr, n);
+ m->ptr += n;
+ m->left -= n;
+ return n;
+}
+
+
+
+static void dumb_memfile_close(void *f)
+{
+ free(f);
+}
+
+
+
+static const DUMBFILE_SYSTEM memfile_dfs = {
+ NULL,
+ &dumb_memfile_skip,
+ &dumb_memfile_getc,
+ &dumb_memfile_getnc,
+ &dumb_memfile_close
+};
+
+
+
+DUMBFILE *dumbfile_open_memory(const char *data, long size)
+{
+ MEMFILE *m = malloc(sizeof(*m));
+ if (!m) return NULL;
+
+ m->ptr = data;
+ m->left = size;
+
+ return dumbfile_open_ex(m, &memfile_dfs);
+}
diff --git a/plugins/dumb/dumb-kode54/src/helpers/resample.c b/plugins/dumb/dumb-kode54/src/helpers/resample.c
index 033538c5..54b98d08 100644
--- a/plugins/dumb/dumb-kode54/src/helpers/resample.c
+++ b/plugins/dumb/dumb-kode54/src/helpers/resample.c
@@ -1,393 +1,393 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * resample.c - Resampling helpers. / / \ \
- * | < / \_
- * By Bob and entheh. | \/ /\ /
- * \_ / > /
- * In order to find a good trade-off between | \ / /
- * speed and accuracy in this code, some tests | ' /
- * were carried out regarding the behaviour of \__/
- * long long ints with gcc. The following code
- * was tested:
- *
- * int a, b, c;
- * c = ((long long)a * b) >> 16;
- *
- * DJGPP GCC Version 3.0.3 generated the following assembly language code for
- * the multiplication and scaling, leaving the 32-bit result in EAX.
- *
- * movl -8(%ebp), %eax ; read one int into EAX
- * imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX
- * shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX
- *
- * Note that a 32*32->64 multiplication is performed, allowing for high
- * accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally),
- * so it is a minor concern when four multiplications are being performed
- * (the cubic resampler). On the Pentium MMX and earlier, it takes four or
- * more cycles, so this method is unsuitable for use in the low-quality
- * resamplers.
- *
- * Since "long long" is a gcc-specific extension, we use LONG_LONG instead,
- * defined in dumb.h. We may investigate later what code MSVC generates, but
- * if it seems too slow then we suggest you use a good compiler.
- *
- * FIXME: these comments are somewhat out of date now.
- */
-
-#include <math.h>
-#include "dumb.h"
-
-
-
-/* Compile with -DHEAVYDEBUG if you want to make sure the pick-up function is
- * called when it should be. There will be a considerable performance hit,
- * since at least one condition has to be tested for every sample generated.
- */
-#ifdef HEAVYDEBUG
-#define HEAVYASSERT(cond) ASSERT(cond)
-#else
-#define HEAVYASSERT(cond)
-#endif
-
-
-
-/* Make MSVC shut the hell up about if ( upd ) UPDATE_VOLUME() conditions being constant */
-#ifdef _MSC_VER
-#pragma warning(disable:4127 4701)
-#endif
-
-
-
-/* A global variable for controlling resampling quality wherever a local
- * specification doesn't override it. The following values are valid:
- *
- * 0 - DUMB_RQ_ALIASING - fastest
- * 1 - DUMB_RQ_LINEAR
- * 2 - DUMB_RQ_CUBIC - nicest
- *
- * Values outside the range 0-2 will behave the same as the nearest
- * value within the range.
- */
-int dumb_resampling_quality = DUMB_RQ_CUBIC;
-
-
-
-//#define MULSC(a, b) ((int)((LONG_LONG)(a) * (b) >> 16))
-//#define MULSC(a, b) ((a) * ((b) >> 2) >> 14)
-#define MULSCV(a, b) ((int)((LONG_LONG)(a) * (b) >> 32))
-#define MULSC(a, b) ((int)((LONG_LONG)((a) << 4) * ((b) << 12) >> 32))
-#define MULSC16(a, b) ((int)((LONG_LONG)((a) << 12) * ((b) << 12) >> 32))
-
-
-
-/* Executes the content 'iterator' times.
- * Clobbers the 'iterator' variable.
- * The loop is unrolled by four.
- */
-#define LOOP4(iterator, CONTENT) \
-{ \
- if ((iterator) & 2) { \
- CONTENT; \
- CONTENT; \
- } \
- if ((iterator) & 1) { \
- CONTENT; \
- } \
- (iterator) >>= 2; \
- while (iterator) { \
- CONTENT; \
- CONTENT; \
- CONTENT; \
- CONTENT; \
- (iterator)--; \
- } \
-}
-
-
-
-#define PASTERAW(a, b) a ## b /* This does not expand macros in b ... */
-#define PASTE(a, b) PASTERAW(a, b) /* ... but b is expanded during this substitution. */
-
-#define X PASTE(x.x, SRCBITS)
-
-
-
-/* Cubic resampler: look-up tables
- *
- * a = 1.5*x1 - 1.5*x2 + 0.5*x3 - 0.5*x0
- * b = 2*x2 + x0 - 2.5*x1 - 0.5*x3
- * c = 0.5*x2 - 0.5*x0
- * d = x1
- *
- * x = a*t*t*t + b*t*t + c*t + d
- * = (-0.5*x0 + 1.5*x1 - 1.5*x2 + 0.5*x3) * t*t*t +
- * ( 1*x0 - 2.5*x1 + 2 *x2 - 0.5*x3) * t*t +
- * (-0.5*x0 + 0.5*x2 ) * t +
- * ( 1*x1 )
- * = (-0.5*t*t*t + 1 *t*t - 0.5*t ) * x0 +
- * ( 1.5*t*t*t - 2.5*t*t + 1) * x1 +
- * (-1.5*t*t*t + 2 *t*t + 0.5*t ) * x2 +
- * ( 0.5*t*t*t - 0.5*t*t ) * x3
- * = A0(t) * x0 + A1(t) * x1 + A2(t) * x2 + A3(t) * x3
- *
- * A0, A1, A2 and A3 stay within the range [-1,1].
- * In the tables, they are scaled with 14 fractional bits.
- *
- * Turns out we don't need to store A2 and A3; they are symmetrical to A1 and A0.
- *
- * TODO: A0 and A3 stay very small indeed. Consider different scale/resolution?
- */
-
-static short cubicA0[1025], cubicA1[1025];
-
-/*static*/ void init_cubic(void)
-{
- unsigned int t; /* 3*1024*1024*1024 is within range if it's unsigned */
- static int done = 0;
- if (done) return;
- done = 1;
- for (t = 0; t < 1025; t++) {
- /* int casts to pacify warnings about negating unsigned values */
- cubicA0[t] = -(int)( t*t*t >> 17) + (int)( t*t >> 6) - (int)(t << 3);
- cubicA1[t] = (int)(3*t*t*t >> 17) - (int)(5*t*t >> 7) + (int)(1 << 14);
- }
-}
-
-
-
-/* Create resamplers for 24-in-32-bit source samples. */
-
-/* #define SUFFIX
- * MSVC warns if we try to paste a null SUFFIX, so instead we define
- * special macros for the function names that don't bother doing the
- * corresponding paste. The more generic definitions are further down.
- */
-#define process_pickup PASTE(process_pickup, SUFFIX2)
-#define dumb_resample PASTE(PASTE(dumb_resample, SUFFIX2), SUFFIX3)
-#define dumb_resample_get_current_sample PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX2), SUFFIX3)
-
-#define SRCTYPE sample_t
-#define SRCBITS 24
-#define ALIAS(x, vol) MULSC(x, vol)
-#define LINEAR(x0, x1) (x0 + MULSC(x1 - x0, subpos))
-/*
-#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
- a = (3 * (x1 - x2) + (x3 - x0)) >> 1; \
- b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) >> 1; \
- c = (x2 - x0) >> 1; \
-}
-#define CUBIC(d) MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + d, vol)
-*/
-#define CUBIC(x0, x1, x2, x3) ( \
- MULSC(x0, cubicA0[subpos >> 6] << 2) + \
- MULSC(x1, cubicA1[subpos >> 6] << 2) + \
- MULSC(x2, cubicA1[1 + (subpos >> 6 ^ 1023)] << 2) + \
- MULSC(x3, cubicA0[1 + (subpos >> 6 ^ 1023)] << 2))
-#define CUBICVOL(x, vol) MULSC(x, vol)
-#include "resample.inc"
-
-/* Undefine the simplified macros. */
-#undef dumb_resample_get_current_sample
-#undef dumb_resample
-#undef process_pickup
-
-
-/* Now define the proper ones that use SUFFIX. */
-#define dumb_reset_resampler PASTE(dumb_reset_resampler, SUFFIX)
-#define dumb_start_resampler PASTE(dumb_start_resampler, SUFFIX)
-#define process_pickup PASTE(PASTE(process_pickup, SUFFIX), SUFFIX2)
-#define dumb_resample PASTE(PASTE(PASTE(dumb_resample, SUFFIX), SUFFIX2), SUFFIX3)
-#define dumb_resample_get_current_sample PASTE(PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX), SUFFIX2), SUFFIX3)
-#define dumb_end_resampler PASTE(dumb_end_resampler, SUFFIX)
-
-/* Create resamplers for 16-bit source samples. */
-#define SUFFIX _16
-#define SRCTYPE short
-#define SRCBITS 16
-#define ALIAS(x, vol) (x * vol >> 8)
-#define LINEAR(x0, x1) ((x0 << 8) + MULSC16(x1 - x0, subpos))
-/*
-#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
- a = (3 * (x1 - x2) + (x3 - x0)) << 7; \
- b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) << 7; \
- c = (x2 - x0) << 7; \
-}
-#define CUBIC(d) MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + (d << 8), vol)
-*/
-#define CUBIC(x0, x1, x2, x3) ( \
- x0 * cubicA0[subpos >> 6] + \
- x1 * cubicA1[subpos >> 6] + \
- x2 * cubicA1[1 + (subpos >> 6 ^ 1023)] + \
- x3 * cubicA0[1 + (subpos >> 6 ^ 1023)])
-#define CUBICVOL(x, vol) (int)((LONG_LONG)(x) * (vol << 10) >> 32)
-#include "resample.inc"
-
-/* Create resamplers for 8-bit source samples. */
-#define SUFFIX _8
-#define SRCTYPE signed char
-#define SRCBITS 8
-#define ALIAS(x, vol) (x * vol)
-#define LINEAR(x0, x1) ((x0 << 16) + (x1 - x0) * subpos)
-/*
-#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
- a = 3 * (x1 - x2) + (x3 - x0); \
- b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) << 15; \
- c = (x2 - x0) << 15; \
-}
-#define CUBIC(d) MULSC(MULSC(MULSC((a * subpos >> 1) + b, subpos) + c, subpos) + (d << 16), vol)
-*/
-#define CUBIC(x0, x1, x2, x3) (( \
- x0 * cubicA0[subpos >> 6] + \
- x1 * cubicA1[subpos >> 6] + \
- x2 * cubicA1[1 + (subpos >> 6 ^ 1023)] + \
- x3 * cubicA0[1 + (subpos >> 6 ^ 1023)]) << 6)
-#define CUBICVOL(x, vol) (int)((LONG_LONG)(x) * (vol << 12) >> 32)
-#include "resample.inc"
-
-
-#undef dumb_reset_resampler
-#undef dumb_start_resampler
-#undef process_pickup
-#undef dumb_resample
-#undef dumb_resample_get_current_sample
-#undef dumb_end_resampler
-
-
-
-void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, int src_channels, long pos, long start, long end, int quality)
-{
- if (n == 8)
- dumb_reset_resampler_8(resampler, src, src_channels, pos, start, end, quality);
- else if (n == 16)
- dumb_reset_resampler_16(resampler, src, src_channels, pos, start, end, quality);
- else
- dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality);
-}
-
-
-
-DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels, long pos, long start, long end, int quality)
-{
- if (n == 8)
- return dumb_start_resampler_8(src, src_channels, pos, start, end, quality);
- else if (n == 16)
- return dumb_start_resampler_16(src, src_channels, pos, start, end, quality);
- else
- return dumb_start_resampler(src, src_channels, pos, start, end, quality);
-}
-
-
-
-long dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta)
-{
- if (n == 8)
- return dumb_resample_8_1_1(resampler, dst, dst_size, volume, delta);
- else if (n == 16)
- return dumb_resample_16_1_1(resampler, dst, dst_size, volume, delta);
- else
- return dumb_resample_1_1(resampler, dst, dst_size, volume, delta);
-}
-
-
-
-long dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
-{
- if (n == 8)
- return dumb_resample_8_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
- else if (n == 16)
- return dumb_resample_16_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
- else
- return dumb_resample_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
-}
-
-
-
-long dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
-{
- if (n == 8)
- return dumb_resample_8_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
- else if (n == 16)
- return dumb_resample_16_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
- else
- return dumb_resample_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
-}
-
-
-
-long dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
-{
- if (n == 8)
- return dumb_resample_8_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
- else if (n == 16)
- return dumb_resample_16_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
- else
- return dumb_resample_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
-}
-
-
-
-void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst)
-{
- if (n == 8)
- dumb_resample_get_current_sample_8_1_1(resampler, volume, dst);
- else if (n == 16)
- dumb_resample_get_current_sample_16_1_1(resampler, volume, dst);
- else
- dumb_resample_get_current_sample_1_1(resampler, volume, dst);
-}
-
-
-
-void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
-{
- if (n == 8)
- dumb_resample_get_current_sample_8_1_2(resampler, volume_left, volume_right, dst);
- else if (n == 16)
- dumb_resample_get_current_sample_16_1_2(resampler, volume_left, volume_right, dst);
- else
- dumb_resample_get_current_sample_1_2(resampler, volume_left, volume_right, dst);
-}
-
-
-
-void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
-{
- if (n == 8)
- dumb_resample_get_current_sample_8_2_1(resampler, volume_left, volume_right, dst);
- else if (n == 16)
- dumb_resample_get_current_sample_16_2_1(resampler, volume_left, volume_right, dst);
- else
- dumb_resample_get_current_sample_2_1(resampler, volume_left, volume_right, dst);
-}
-
-
-
-void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
-{
- if (n == 8)
- dumb_resample_get_current_sample_8_2_2(resampler, volume_left, volume_right, dst);
- else if (n == 16)
- dumb_resample_get_current_sample_16_2_2(resampler, volume_left, volume_right, dst);
- else
- dumb_resample_get_current_sample_2_2(resampler, volume_left, volume_right, dst);
-}
-
-
-
-void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler)
-{
- if (n == 8)
- dumb_end_resampler_8(resampler);
- else if (n == 16)
- dumb_end_resampler_16(resampler);
- else
- dumb_end_resampler(resampler);
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * resample.c - Resampling helpers. / / \ \
+ * | < / \_
+ * By Bob and entheh. | \/ /\ /
+ * \_ / > /
+ * In order to find a good trade-off between | \ / /
+ * speed and accuracy in this code, some tests | ' /
+ * were carried out regarding the behaviour of \__/
+ * long long ints with gcc. The following code
+ * was tested:
+ *
+ * int a, b, c;
+ * c = ((long long)a * b) >> 16;
+ *
+ * DJGPP GCC Version 3.0.3 generated the following assembly language code for
+ * the multiplication and scaling, leaving the 32-bit result in EAX.
+ *
+ * movl -8(%ebp), %eax ; read one int into EAX
+ * imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX
+ * shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX
+ *
+ * Note that a 32*32->64 multiplication is performed, allowing for high
+ * accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally),
+ * so it is a minor concern when four multiplications are being performed
+ * (the cubic resampler). On the Pentium MMX and earlier, it takes four or
+ * more cycles, so this method is unsuitable for use in the low-quality
+ * resamplers.
+ *
+ * Since "long long" is a gcc-specific extension, we use LONG_LONG instead,
+ * defined in dumb.h. We may investigate later what code MSVC generates, but
+ * if it seems too slow then we suggest you use a good compiler.
+ *
+ * FIXME: these comments are somewhat out of date now.
+ */
+
+#include <math.h>
+#include "dumb.h"
+
+
+
+/* Compile with -DHEAVYDEBUG if you want to make sure the pick-up function is
+ * called when it should be. There will be a considerable performance hit,
+ * since at least one condition has to be tested for every sample generated.
+ */
+#ifdef HEAVYDEBUG
+#define HEAVYASSERT(cond) ASSERT(cond)
+#else
+#define HEAVYASSERT(cond)
+#endif
+
+
+
+/* Make MSVC shut the hell up about if ( upd ) UPDATE_VOLUME() conditions being constant */
+#ifdef _MSC_VER
+#pragma warning(disable:4127 4701)
+#endif
+
+
+
+/* A global variable for controlling resampling quality wherever a local
+ * specification doesn't override it. The following values are valid:
+ *
+ * 0 - DUMB_RQ_ALIASING - fastest
+ * 1 - DUMB_RQ_LINEAR
+ * 2 - DUMB_RQ_CUBIC - nicest
+ *
+ * Values outside the range 0-2 will behave the same as the nearest
+ * value within the range.
+ */
+int dumb_resampling_quality = DUMB_RQ_CUBIC;
+
+
+
+//#define MULSC(a, b) ((int)((LONG_LONG)(a) * (b) >> 16))
+//#define MULSC(a, b) ((a) * ((b) >> 2) >> 14)
+#define MULSCV(a, b) ((int)((LONG_LONG)(a) * (b) >> 32))
+#define MULSC(a, b) ((int)((LONG_LONG)((a) << 4) * ((b) << 12) >> 32))
+#define MULSC16(a, b) ((int)((LONG_LONG)((a) << 12) * ((b) << 12) >> 32))
+
+
+
+/* Executes the content 'iterator' times.
+ * Clobbers the 'iterator' variable.
+ * The loop is unrolled by four.
+ */
+#define LOOP4(iterator, CONTENT) \
+{ \
+ if ((iterator) & 2) { \
+ CONTENT; \
+ CONTENT; \
+ } \
+ if ((iterator) & 1) { \
+ CONTENT; \
+ } \
+ (iterator) >>= 2; \
+ while (iterator) { \
+ CONTENT; \
+ CONTENT; \
+ CONTENT; \
+ CONTENT; \
+ (iterator)--; \
+ } \
+}
+
+
+
+#define PASTERAW(a, b) a ## b /* This does not expand macros in b ... */
+#define PASTE(a, b) PASTERAW(a, b) /* ... but b is expanded during this substitution. */
+
+#define X PASTE(x.x, SRCBITS)
+
+
+
+/* Cubic resampler: look-up tables
+ *
+ * a = 1.5*x1 - 1.5*x2 + 0.5*x3 - 0.5*x0
+ * b = 2*x2 + x0 - 2.5*x1 - 0.5*x3
+ * c = 0.5*x2 - 0.5*x0
+ * d = x1
+ *
+ * x = a*t*t*t + b*t*t + c*t + d
+ * = (-0.5*x0 + 1.5*x1 - 1.5*x2 + 0.5*x3) * t*t*t +
+ * ( 1*x0 - 2.5*x1 + 2 *x2 - 0.5*x3) * t*t +
+ * (-0.5*x0 + 0.5*x2 ) * t +
+ * ( 1*x1 )
+ * = (-0.5*t*t*t + 1 *t*t - 0.5*t ) * x0 +
+ * ( 1.5*t*t*t - 2.5*t*t + 1) * x1 +
+ * (-1.5*t*t*t + 2 *t*t + 0.5*t ) * x2 +
+ * ( 0.5*t*t*t - 0.5*t*t ) * x3
+ * = A0(t) * x0 + A1(t) * x1 + A2(t) * x2 + A3(t) * x3
+ *
+ * A0, A1, A2 and A3 stay within the range [-1,1].
+ * In the tables, they are scaled with 14 fractional bits.
+ *
+ * Turns out we don't need to store A2 and A3; they are symmetrical to A1 and A0.
+ *
+ * TODO: A0 and A3 stay very small indeed. Consider different scale/resolution?
+ */
+
+static short cubicA0[1025], cubicA1[1025];
+
+/*static*/ void init_cubic(void)
+{
+ unsigned int t; /* 3*1024*1024*1024 is within range if it's unsigned */
+ static int done = 0;
+ if (done) return;
+ done = 1;
+ for (t = 0; t < 1025; t++) {
+ /* int casts to pacify warnings about negating unsigned values */
+ cubicA0[t] = -(int)( t*t*t >> 17) + (int)( t*t >> 6) - (int)(t << 3);
+ cubicA1[t] = (int)(3*t*t*t >> 17) - (int)(5*t*t >> 7) + (int)(1 << 14);
+ }
+}
+
+
+
+/* Create resamplers for 24-in-32-bit source samples. */
+
+/* #define SUFFIX
+ * MSVC warns if we try to paste a null SUFFIX, so instead we define
+ * special macros for the function names that don't bother doing the
+ * corresponding paste. The more generic definitions are further down.
+ */
+#define process_pickup PASTE(process_pickup, SUFFIX2)
+#define dumb_resample PASTE(PASTE(dumb_resample, SUFFIX2), SUFFIX3)
+#define dumb_resample_get_current_sample PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX2), SUFFIX3)
+
+#define SRCTYPE sample_t
+#define SRCBITS 24
+#define ALIAS(x, vol) MULSC(x, vol)
+#define LINEAR(x0, x1) (x0 + MULSC(x1 - x0, subpos))
+/*
+#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
+ a = (3 * (x1 - x2) + (x3 - x0)) >> 1; \
+ b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) >> 1; \
+ c = (x2 - x0) >> 1; \
+}
+#define CUBIC(d) MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + d, vol)
+*/
+#define CUBIC(x0, x1, x2, x3) ( \
+ MULSC(x0, cubicA0[subpos >> 6] << 2) + \
+ MULSC(x1, cubicA1[subpos >> 6] << 2) + \
+ MULSC(x2, cubicA1[1 + (subpos >> 6 ^ 1023)] << 2) + \
+ MULSC(x3, cubicA0[1 + (subpos >> 6 ^ 1023)] << 2))
+#define CUBICVOL(x, vol) MULSC(x, vol)
+#include "resample.inc"
+
+/* Undefine the simplified macros. */
+#undef dumb_resample_get_current_sample
+#undef dumb_resample
+#undef process_pickup
+
+
+/* Now define the proper ones that use SUFFIX. */
+#define dumb_reset_resampler PASTE(dumb_reset_resampler, SUFFIX)
+#define dumb_start_resampler PASTE(dumb_start_resampler, SUFFIX)
+#define process_pickup PASTE(PASTE(process_pickup, SUFFIX), SUFFIX2)
+#define dumb_resample PASTE(PASTE(PASTE(dumb_resample, SUFFIX), SUFFIX2), SUFFIX3)
+#define dumb_resample_get_current_sample PASTE(PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX), SUFFIX2), SUFFIX3)
+#define dumb_end_resampler PASTE(dumb_end_resampler, SUFFIX)
+
+/* Create resamplers for 16-bit source samples. */
+#define SUFFIX _16
+#define SRCTYPE short
+#define SRCBITS 16
+#define ALIAS(x, vol) (x * vol >> 8)
+#define LINEAR(x0, x1) ((x0 << 8) + MULSC16(x1 - x0, subpos))
+/*
+#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
+ a = (3 * (x1 - x2) + (x3 - x0)) << 7; \
+ b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) << 7; \
+ c = (x2 - x0) << 7; \
+}
+#define CUBIC(d) MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + (d << 8), vol)
+*/
+#define CUBIC(x0, x1, x2, x3) ( \
+ x0 * cubicA0[subpos >> 6] + \
+ x1 * cubicA1[subpos >> 6] + \
+ x2 * cubicA1[1 + (subpos >> 6 ^ 1023)] + \
+ x3 * cubicA0[1 + (subpos >> 6 ^ 1023)])
+#define CUBICVOL(x, vol) (int)((LONG_LONG)(x) * (vol << 10) >> 32)
+#include "resample.inc"
+
+/* Create resamplers for 8-bit source samples. */
+#define SUFFIX _8
+#define SRCTYPE signed char
+#define SRCBITS 8
+#define ALIAS(x, vol) (x * vol)
+#define LINEAR(x0, x1) ((x0 << 16) + (x1 - x0) * subpos)
+/*
+#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
+ a = 3 * (x1 - x2) + (x3 - x0); \
+ b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) << 15; \
+ c = (x2 - x0) << 15; \
+}
+#define CUBIC(d) MULSC(MULSC(MULSC((a * subpos >> 1) + b, subpos) + c, subpos) + (d << 16), vol)
+*/
+#define CUBIC(x0, x1, x2, x3) (( \
+ x0 * cubicA0[subpos >> 6] + \
+ x1 * cubicA1[subpos >> 6] + \
+ x2 * cubicA1[1 + (subpos >> 6 ^ 1023)] + \
+ x3 * cubicA0[1 + (subpos >> 6 ^ 1023)]) << 6)
+#define CUBICVOL(x, vol) (int)((LONG_LONG)(x) * (vol << 12) >> 32)
+#include "resample.inc"
+
+
+#undef dumb_reset_resampler
+#undef dumb_start_resampler
+#undef process_pickup
+#undef dumb_resample
+#undef dumb_resample_get_current_sample
+#undef dumb_end_resampler
+
+
+
+void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, int src_channels, long pos, long start, long end, int quality)
+{
+ if (n == 8)
+ dumb_reset_resampler_8(resampler, src, src_channels, pos, start, end, quality);
+ else if (n == 16)
+ dumb_reset_resampler_16(resampler, src, src_channels, pos, start, end, quality);
+ else
+ dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality);
+}
+
+
+
+DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels, long pos, long start, long end, int quality)
+{
+ if (n == 8)
+ return dumb_start_resampler_8(src, src_channels, pos, start, end, quality);
+ else if (n == 16)
+ return dumb_start_resampler_16(src, src_channels, pos, start, end, quality);
+ else
+ return dumb_start_resampler(src, src_channels, pos, start, end, quality);
+}
+
+
+
+long dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta)
+{
+ if (n == 8)
+ return dumb_resample_8_1_1(resampler, dst, dst_size, volume, delta);
+ else if (n == 16)
+ return dumb_resample_16_1_1(resampler, dst, dst_size, volume, delta);
+ else
+ return dumb_resample_1_1(resampler, dst, dst_size, volume, delta);
+}
+
+
+
+long dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
+{
+ if (n == 8)
+ return dumb_resample_8_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
+ else if (n == 16)
+ return dumb_resample_16_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
+ else
+ return dumb_resample_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
+}
+
+
+
+long dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
+{
+ if (n == 8)
+ return dumb_resample_8_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
+ else if (n == 16)
+ return dumb_resample_16_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
+ else
+ return dumb_resample_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
+}
+
+
+
+long dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
+{
+ if (n == 8)
+ return dumb_resample_8_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
+ else if (n == 16)
+ return dumb_resample_16_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
+ else
+ return dumb_resample_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
+}
+
+
+
+void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst)
+{
+ if (n == 8)
+ dumb_resample_get_current_sample_8_1_1(resampler, volume, dst);
+ else if (n == 16)
+ dumb_resample_get_current_sample_16_1_1(resampler, volume, dst);
+ else
+ dumb_resample_get_current_sample_1_1(resampler, volume, dst);
+}
+
+
+
+void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
+{
+ if (n == 8)
+ dumb_resample_get_current_sample_8_1_2(resampler, volume_left, volume_right, dst);
+ else if (n == 16)
+ dumb_resample_get_current_sample_16_1_2(resampler, volume_left, volume_right, dst);
+ else
+ dumb_resample_get_current_sample_1_2(resampler, volume_left, volume_right, dst);
+}
+
+
+
+void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
+{
+ if (n == 8)
+ dumb_resample_get_current_sample_8_2_1(resampler, volume_left, volume_right, dst);
+ else if (n == 16)
+ dumb_resample_get_current_sample_16_2_1(resampler, volume_left, volume_right, dst);
+ else
+ dumb_resample_get_current_sample_2_1(resampler, volume_left, volume_right, dst);
+}
+
+
+
+void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
+{
+ if (n == 8)
+ dumb_resample_get_current_sample_8_2_2(resampler, volume_left, volume_right, dst);
+ else if (n == 16)
+ dumb_resample_get_current_sample_16_2_2(resampler, volume_left, volume_right, dst);
+ else
+ dumb_resample_get_current_sample_2_2(resampler, volume_left, volume_right, dst);
+}
+
+
+
+void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler)
+{
+ if (n == 8)
+ dumb_end_resampler_8(resampler);
+ else if (n == 16)
+ dumb_end_resampler_16(resampler);
+ else
+ dumb_end_resampler(resampler);
+}
diff --git a/plugins/dumb/dumb-kode54/src/helpers/riff.c b/plugins/dumb/dumb-kode54/src/helpers/riff.c
index 62a7eccc..7a7ef065 100644
--- a/plugins/dumb/dumb-kode54/src/helpers/riff.c
+++ b/plugins/dumb/dumb-kode54/src/helpers/riff.c
@@ -1,88 +1,88 @@
-#include "internal/riff.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-struct riff * riff_parse( unsigned char * ptr, unsigned size, unsigned proper )
-{
- unsigned stream_size;
- struct riff * stream;
-
- if ( size < 8 ) return 0;
-
- if ( ptr[0] != 'R' || ptr[1] != 'I' || ptr[2] != 'F' || ptr[3] != 'F' ) return 0;
-
- stream_size = ptr[4] | ( ptr[5] << 8 ) | ( ptr[6] << 16 ) | ( ptr[7] << 24 );
- if ( stream_size + 8 > size ) return 0;
- if ( stream_size < 4 ) return 0;
-
- stream = malloc( sizeof( struct riff ) );
- if ( ! stream ) return 0;
-
- stream->type = ( ptr[8] << 24 ) | ( ptr[9] << 16 ) | ( ptr[10] << 8 ) | ptr[11];
- stream->chunk_count = 0;
- stream->chunks = 0;
-
- ptr += 12;
- stream_size -= 4;
-
- while ( stream_size )
- {
- struct riff_chunk * chunk;
- if ( stream_size < 8 ) break;
- stream->chunks = realloc( stream->chunks, ( stream->chunk_count + 1 ) * sizeof( struct riff_chunk ) );
- if ( ! stream->chunks ) break;
- chunk = stream->chunks + stream->chunk_count;
- chunk->type = ( ptr[0] << 24 ) | ( ptr[1] << 16 ) | ( ptr[2] << 8 ) | ptr[3];
- chunk->size = ptr[4] | ( ptr[5] << 8 ) | ( ptr[6] << 16 ) | ( ptr[7] << 24 );
- ptr += 8;
- stream_size -= 8;
- if ( stream_size < chunk->size ) break;
- if ( chunk->type == 'RIFF' )
- {
- chunk->data = riff_parse( ptr - 8, chunk->size + 8, proper );
- if ( ! chunk->data ) break;
- }
- else
- {
- chunk->data = malloc( chunk->size );
- if ( ! chunk->data ) break;
- memcpy( chunk->data, ptr, chunk->size );
- }
- ptr += chunk->size;
- stream_size -= chunk->size;
- if ( proper && ( chunk->size & 1 ) )
- {
- ++ ptr;
- -- stream_size;
- }
- ++stream->chunk_count;
- }
-
- if ( stream_size )
- {
- riff_free( stream );
- stream = 0;
- }
-
- return stream;
-}
-
-void riff_free( struct riff * stream )
-{
- if ( stream )
- {
- if ( stream->chunks )
- {
- unsigned i;
- for ( i = 0; i < stream->chunk_count; ++i )
- {
- struct riff_chunk * chunk = stream->chunks + i;
- if ( chunk->type == 'RIFF' ) riff_free( ( struct riff * ) chunk->data );
- else free( chunk->data );
- }
- free( stream->chunks );
- }
- free( stream );
- }
-}
+#include "internal/riff.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+struct riff * riff_parse( unsigned char * ptr, unsigned size, unsigned proper )
+{
+ unsigned stream_size;
+ struct riff * stream;
+
+ if ( size < 8 ) return 0;
+
+ if ( ptr[0] != 'R' || ptr[1] != 'I' || ptr[2] != 'F' || ptr[3] != 'F' ) return 0;
+
+ stream_size = ptr[4] | ( ptr[5] << 8 ) | ( ptr[6] << 16 ) | ( ptr[7] << 24 );
+ if ( stream_size + 8 > size ) return 0;
+ if ( stream_size < 4 ) return 0;
+
+ stream = malloc( sizeof( struct riff ) );
+ if ( ! stream ) return 0;
+
+ stream->type = ( ptr[8] << 24 ) | ( ptr[9] << 16 ) | ( ptr[10] << 8 ) | ptr[11];
+ stream->chunk_count = 0;
+ stream->chunks = 0;
+
+ ptr += 12;
+ stream_size -= 4;
+
+ while ( stream_size )
+ {
+ struct riff_chunk * chunk;
+ if ( stream_size < 8 ) break;
+ stream->chunks = realloc( stream->chunks, ( stream->chunk_count + 1 ) * sizeof( struct riff_chunk ) );
+ if ( ! stream->chunks ) break;
+ chunk = stream->chunks + stream->chunk_count;
+ chunk->type = ( ptr[0] << 24 ) | ( ptr[1] << 16 ) | ( ptr[2] << 8 ) | ptr[3];
+ chunk->size = ptr[4] | ( ptr[5] << 8 ) | ( ptr[6] << 16 ) | ( ptr[7] << 24 );
+ ptr += 8;
+ stream_size -= 8;
+ if ( stream_size < chunk->size ) break;
+ if ( chunk->type == 'RIFF' )
+ {
+ chunk->data = riff_parse( ptr - 8, chunk->size + 8, proper );
+ if ( ! chunk->data ) break;
+ }
+ else
+ {
+ chunk->data = malloc( chunk->size );
+ if ( ! chunk->data ) break;
+ memcpy( chunk->data, ptr, chunk->size );
+ }
+ ptr += chunk->size;
+ stream_size -= chunk->size;
+ if ( proper && ( chunk->size & 1 ) )
+ {
+ ++ ptr;
+ -- stream_size;
+ }
+ ++stream->chunk_count;
+ }
+
+ if ( stream_size )
+ {
+ riff_free( stream );
+ stream = 0;
+ }
+
+ return stream;
+}
+
+void riff_free( struct riff * stream )
+{
+ if ( stream )
+ {
+ if ( stream->chunks )
+ {
+ unsigned i;
+ for ( i = 0; i < stream->chunk_count; ++i )
+ {
+ struct riff_chunk * chunk = stream->chunks + i;
+ if ( chunk->type == 'RIFF' ) riff_free( ( struct riff * ) chunk->data );
+ else free( chunk->data );
+ }
+ free( stream->chunks );
+ }
+ free( stream );
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/helpers/sampbuf.c b/plugins/dumb/dumb-kode54/src/helpers/sampbuf.c
index 488db449..6a80f1fa 100644
--- a/plugins/dumb/dumb-kode54/src/helpers/sampbuf.c
+++ b/plugins/dumb/dumb-kode54/src/helpers/sampbuf.c
@@ -1,64 +1,64 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * sampbuf.c - Helper for allocating sample / / \ \
- * buffers. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include "dumb.h"
-
-
-
-/* DEPRECATED */
-sample_t **create_sample_buffer(int n_channels, long length)
-{
- int i;
- sample_t **samples = malloc(n_channels * sizeof(*samples));
- if (!samples) return NULL;
- samples[0] = malloc(n_channels * length * sizeof(*samples[0]));
- if (!samples[0]) {
- free(samples);
- return NULL;
- }
- for (i = 1; i < n_channels; i++) samples[i] = samples[i-1] + length;
- return samples;
-}
-
-
-
-sample_t **allocate_sample_buffer(int n_channels, long length)
-{
- int i;
- sample_t **samples = malloc(((n_channels + 1) >> 1) * sizeof(*samples));
- if (!samples) return NULL;
- samples[0] = malloc(n_channels * length * sizeof(*samples[0]));
- if (!samples[0]) {
- free(samples);
- return NULL;
- }
- for (i = 1; i < (n_channels + 1) >> 1; i++) samples[i] = samples[i-1] + length*2;
- return samples;
-}
-
-
-
-void destroy_sample_buffer(sample_t **samples)
-{
- if (samples) {
- free(samples[0]);
- free(samples);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * sampbuf.c - Helper for allocating sample / / \ \
+ * buffers. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include "dumb.h"
+
+
+
+/* DEPRECATED */
+sample_t **create_sample_buffer(int n_channels, long length)
+{
+ int i;
+ sample_t **samples = malloc(n_channels * sizeof(*samples));
+ if (!samples) return NULL;
+ samples[0] = malloc(n_channels * length * sizeof(*samples[0]));
+ if (!samples[0]) {
+ free(samples);
+ return NULL;
+ }
+ for (i = 1; i < n_channels; i++) samples[i] = samples[i-1] + length;
+ return samples;
+}
+
+
+
+sample_t **allocate_sample_buffer(int n_channels, long length)
+{
+ int i;
+ sample_t **samples = malloc(((n_channels + 1) >> 1) * sizeof(*samples));
+ if (!samples) return NULL;
+ samples[0] = malloc(n_channels * length * sizeof(*samples[0]));
+ if (!samples[0]) {
+ free(samples);
+ return NULL;
+ }
+ for (i = 1; i < (n_channels + 1) >> 1; i++) samples[i] = samples[i-1] + length*2;
+ return samples;
+}
+
+
+
+void destroy_sample_buffer(sample_t **samples)
+{
+ if (samples) {
+ free(samples[0]);
+ free(samples);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/helpers/silence.c b/plugins/dumb/dumb-kode54/src/helpers/silence.c
index 794ae831..4d5fdcf4 100644
--- a/plugins/dumb/dumb-kode54/src/helpers/silence.c
+++ b/plugins/dumb/dumb-kode54/src/helpers/silence.c
@@ -1,29 +1,29 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * silence.c - Silencing helper. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <string.h>
-#include "dumb.h"
-
-
-
-void dumb_silence(sample_t *samples, long length)
-{
- memset(samples, 0, length * sizeof(*samples));
-}
-
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * silence.c - Silencing helper. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <string.h>
+#include "dumb.h"
+
+
+
+void dumb_silence(sample_t *samples, long length)
+{
+ memset(samples, 0, length * sizeof(*samples));
+}
+
diff --git a/plugins/dumb/dumb-kode54/src/helpers/stdfile.c b/plugins/dumb/dumb-kode54/src/helpers/stdfile.c
index aa398f50..2f02539a 100644
--- a/plugins/dumb/dumb-kode54/src/helpers/stdfile.c
+++ b/plugins/dumb/dumb-kode54/src/helpers/stdfile.c
@@ -1,93 +1,93 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * stdfile.c - stdio file input module. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdio.h>
-
-#include "dumb.h"
-
-
-
-static void *dumb_stdfile_open(const char *filename)
-{
- return fopen(filename, "rb");
-}
-
-
-
-static int dumb_stdfile_skip(void *f, long n)
-{
- return fseek(f, n, SEEK_CUR);
-}
-
-
-
-static int dumb_stdfile_getc(void *f)
-{
- return fgetc(f);
-}
-
-
-
-static long dumb_stdfile_getnc(char *ptr, long n, void *f)
-{
- return fread(ptr, 1, n, f);
-}
-
-
-
-static void dumb_stdfile_close(void *f)
-{
- fclose(f);
-}
-
-
-
-static DUMBFILE_SYSTEM stdfile_dfs = {
- &dumb_stdfile_open,
- &dumb_stdfile_skip,
- &dumb_stdfile_getc,
- &dumb_stdfile_getnc,
- &dumb_stdfile_close
-};
-
-
-
-void dumb_register_stdfiles(void)
-{
- register_dumbfile_system(&stdfile_dfs);
-}
-
-
-
-static DUMBFILE_SYSTEM stdfile_dfs_leave_open = {
- NULL,
- &dumb_stdfile_skip,
- &dumb_stdfile_getc,
- &dumb_stdfile_getnc,
- NULL
-};
-
-
-
-DUMBFILE *dumbfile_open_stdfile(FILE *p)
-{
- DUMBFILE *d = dumbfile_open_ex(p, &stdfile_dfs_leave_open);
-
- return d;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * stdfile.c - stdio file input module. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdio.h>
+
+#include "dumb.h"
+
+
+
+static void *dumb_stdfile_open(const char *filename)
+{
+ return fopen(filename, "rb");
+}
+
+
+
+static int dumb_stdfile_skip(void *f, long n)
+{
+ return fseek(f, n, SEEK_CUR);
+}
+
+
+
+static int dumb_stdfile_getc(void *f)
+{
+ return fgetc(f);
+}
+
+
+
+static long dumb_stdfile_getnc(char *ptr, long n, void *f)
+{
+ return fread(ptr, 1, n, f);
+}
+
+
+
+static void dumb_stdfile_close(void *f)
+{
+ fclose(f);
+}
+
+
+
+static DUMBFILE_SYSTEM stdfile_dfs = {
+ &dumb_stdfile_open,
+ &dumb_stdfile_skip,
+ &dumb_stdfile_getc,
+ &dumb_stdfile_getnc,
+ &dumb_stdfile_close
+};
+
+
+
+void dumb_register_stdfiles(void)
+{
+ register_dumbfile_system(&stdfile_dfs);
+}
+
+
+
+static DUMBFILE_SYSTEM stdfile_dfs_leave_open = {
+ NULL,
+ &dumb_stdfile_skip,
+ &dumb_stdfile_getc,
+ &dumb_stdfile_getnc,
+ NULL
+};
+
+
+
+DUMBFILE *dumbfile_open_stdfile(FILE *p)
+{
+ DUMBFILE *d = dumbfile_open_ex(p, &stdfile_dfs_leave_open);
+
+ return d;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/itload.c b/plugins/dumb/dumb-kode54/src/it/itload.c
index 30004233..a26f5e10 100644
--- a/plugins/dumb/dumb-kode54/src/it/itload.c
+++ b/plugins/dumb/dumb-kode54/src/it/itload.c
@@ -1,43 +1,42 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * itload.c - Code to read an Impulse Tracker / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By entheh. Don't worry Bob, you're credited | \ / /
- * in itread.c! | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_it_quick(): loads an IT file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must pass
- * the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_it_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_it_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
-
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * itload.c - Code to read an Impulse Tracker / / \ \
+ * file, opening and closing it for | < / \_
+ * you. | \/ /\ /
+ * \_ / > /
+ * By entheh. Don't worry Bob, you're credited | \ / /
+ * in itread.c! | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_it_quick(): loads an IT file into a DUH struct, returning a
+ * pointer to the DUH struct. When you have finished with it, you must pass
+ * the pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_it_quick(const char *filename)
+{
+ DUH *duh;
+ DUMBFILE *f = dumbfile_open(filename);
+
+ if (!f)
+ return NULL;
+
+ duh = dumb_read_it_quick(f);
+
+ dumbfile_close(f);
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/itload2.c b/plugins/dumb/dumb-kode54/src/it/itload2.c
index 15cff1d0..2dd65a71 100644
--- a/plugins/dumb/dumb-kode54/src/it/itload2.c
+++ b/plugins/dumb/dumb-kode54/src/it/itload2.c
@@ -1,29 +1,29 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * itload2.c - Function to read an Impulse Tracker / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * Split off from itload.c by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_load_it(const char *filename)
-{
- DUH *duh = dumb_load_it_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * itload2.c - Function to read an Impulse Tracker / / \ \
+ * file, opening and closing it for | < / \_
+ * you, and do an initial run-through. | \/ /\ /
+ * \_ / > /
+ * Split off from itload.c by entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_load_it(const char *filename)
+{
+ DUH *duh = dumb_load_it_quick(filename);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/itmisc.c b/plugins/dumb/dumb-kode54/src/it/itmisc.c
index 22e18b78..0eee1717 100644
--- a/plugins/dumb/dumb-kode54/src/it/itmisc.c
+++ b/plugins/dumb/dumb-kode54/src/it/itmisc.c
@@ -1,247 +1,249 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * itmisc.c - Miscellaneous functions relating / / \ \
- * to module files. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh)
-{
- return duh_get_raw_sigdata(duh, 0, SIGTYPE_IT);
-}
-
-
-
-const unsigned char *dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->song_message : NULL;
-}
-
-
-
-int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->n_orders : 0;
-}
-
-
-
-int dumb_it_sd_get_n_samples(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->n_samples : 0;
-}
-
-
-
-int dumb_it_sd_get_n_instruments(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->n_instruments : 0;
-}
-
-
-
-const unsigned char *dumb_it_sd_get_sample_name(DUMB_IT_SIGDATA *sd, int i)
-{
- ASSERT(sd && sd->sample && i >= 0 && i < sd->n_samples);
- return sd->sample[i].name;
-}
-
-
-
-const unsigned char *dumb_it_sd_get_sample_filename(DUMB_IT_SIGDATA *sd, int i)
-{
- ASSERT(sd && sd->sample && i >= 0 && i < sd->n_samples);
- return sd->sample[i].filename;
-}
-
-
-
-const unsigned char *dumb_it_sd_get_instrument_name(DUMB_IT_SIGDATA *sd, int i)
-{
- ASSERT(sd && sd->instrument && i >= 0 && i < sd->n_instruments);
- return sd->instrument[i].name;
-}
-
-
-
-const unsigned char *dumb_it_sd_get_instrument_filename(DUMB_IT_SIGDATA *sd, int i)
-{
- ASSERT(sd && sd->instrument && i >= 0 && i < sd->n_instruments);
- return sd->instrument[i].filename;
-}
-
-
-
-int dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->global_volume : 0;
-}
-
-
-
-void dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv)
-{
- if (sd) sd->global_volume = gv;
-}
-
-
-
-int dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->mixing_volume : 0;
-}
-
-
-
-void dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv)
-{
- if (sd) sd->mixing_volume = mv;
-}
-
-
-
-int dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->speed : 0;
-}
-
-
-
-void dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed)
-{
- if (sd) sd->speed = speed;
-}
-
-
-
-int dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->tempo : 0;
-}
-
-
-
-void dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo)
-{
- if (sd) sd->tempo = tempo;
-}
-
-
-
-int dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel)
-{
- ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS);
- return sd ? sd->channel_volume[channel] : 0;
-}
-
-void dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel, int volume)
-{
- ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS);
- if (sd) sd->channel_volume[channel] = volume;
-}
-
-
-
-int dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr)
-{
- return sr ? sr->order : -1;
-}
-
-
-
-int dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr)
-{
- return sr ? sr->row : -1;
-}
-
-
-
-int dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr)
-{
- return sr ? sr->globalvolume : 0;
-}
-
-
-
-void dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv)
-{
- if (sr) sr->globalvolume = gv;
-}
-
-
-
-int dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr)
-{
- return sr ? sr->tempo : 0;
-}
-
-
-
-void dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo)
-{
- if (sr) sr->tempo = tempo;
-}
-
-
-
-int dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr)
-{
- return sr ? sr->speed : 0;
-}
-
-
-
-void dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed)
-{
- if (sr) sr->speed = speed;
-}
-
-
-
-int dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel)
-{
- return sr ? sr->channel[channel].channelvolume : 0;
-}
-
-
-
-void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, int volume)
-{
- if (sr) sr->channel[channel].channelvolume = volume;
-}
-
-
-
-void dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel, int muted)
-{
- if (sr) {
- if (muted)
- sr->channel[channel].flags |= IT_CHANNEL_MUTED;
- else
- sr->channel[channel].flags &= ~IT_CHANNEL_MUTED;
- }
-}
-
-
-
-int dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel)
-{
- return sr ? (sr->channel[channel].flags & IT_CHANNEL_MUTED) != 0 : 0;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * itmisc.c - Miscellaneous functions relating / / \ \
+ * to module files. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh)
+{
+ return duh_get_raw_sigdata(duh, 0, SIGTYPE_IT);
+}
+
+
+
+const unsigned char *dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd)
+{
+ return sd ? sd->song_message : NULL;
+}
+
+
+
+int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd)
+{
+ return sd ? sd->n_orders : 0;
+}
+
+
+
+int dumb_it_sd_get_n_samples(DUMB_IT_SIGDATA *sd)
+{
+ return sd ? sd->n_samples : 0;
+}
+
+
+
+int dumb_it_sd_get_n_instruments(DUMB_IT_SIGDATA *sd)
+{
+ return sd ? sd->n_instruments : 0;
+}
+
+
+
+const unsigned char *dumb_it_sd_get_sample_name(DUMB_IT_SIGDATA *sd, int i)
+{
+ ASSERT(sd && sd->sample && i >= 0 && i < sd->n_samples);
+ return sd->sample[i].name;
+}
+
+
+
+const unsigned char *dumb_it_sd_get_sample_filename(DUMB_IT_SIGDATA *sd, int i)
+{
+ ASSERT(sd && sd->sample && i >= 0 && i < sd->n_samples);
+ return sd->sample[i].filename;
+}
+
+
+
+const unsigned char *dumb_it_sd_get_instrument_name(DUMB_IT_SIGDATA *sd, int i)
+{
+ ASSERT(sd && sd->instrument && i >= 0 && i < sd->n_instruments);
+ return sd->instrument[i].name;
+}
+
+
+
+const unsigned char *dumb_it_sd_get_instrument_filename(DUMB_IT_SIGDATA *sd, int i)
+{
+ ASSERT(sd && sd->instrument && i >= 0 && i < sd->n_instruments);
+ return sd->instrument[i].filename;
+}
+
+
+
+int dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd)
+{
+ return sd ? sd->global_volume : 0;
+}
+
+
+
+void dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv)
+{
+ if (sd) sd->global_volume = gv;
+}
+
+
+
+int dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd)
+{
+ return sd ? sd->mixing_volume : 0;
+}
+
+
+
+void dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv)
+{
+ if (sd) sd->mixing_volume = mv;
+}
+
+
+
+int dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd)
+{
+ return sd ? sd->speed : 0;
+}
+
+
+
+void dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed)
+{
+ if (sd) sd->speed = speed;
+}
+
+
+
+int dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd)
+{
+ return sd ? sd->tempo : 0;
+}
+
+
+
+void dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo)
+{
+ if (sd) sd->tempo = tempo;
+}
+
+
+
+int dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel)
+{
+ ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS);
+ return sd ? sd->channel_volume[channel] : 0;
+}
+
+void dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel, int volume)
+{
+ ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS);
+ if (sd) sd->channel_volume[channel] = volume;
+}
+
+
+
+int dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr)
+{
+ return sr ? sr->order : -1;
+}
+
+
+
+int dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr)
+{
+ return sr ? sr->row : -1;
+}
+
+
+
+int dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr)
+{
+ return sr ? sr->globalvolume : 0;
+}
+
+
+
+void dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv)
+{
+ if (sr) sr->globalvolume = gv;
+}
+
+
+
+int dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr)
+{
+ return sr ? sr->tempo : 0;
+}
+
+
+
+void dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo)
+{
+ if (sr) sr->tempo = tempo;
+}
+
+
+
+int dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr)
+{
+ return sr ? sr->speed : 0;
+}
+
+
+
+void dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed)
+{
+ if (sr) sr->speed = speed;
+}
+
+
+
+int dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel)
+{
+ return sr ? sr->channel[channel].channelvolume : 0;
+}
+
+
+
+void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, int volume)
+{
+ if (sr) sr->channel[channel].channelvolume = volume;
+}
+
+
+
+void dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel, int muted)
+{
+ if (sr) {
+ if (muted)
+ sr->channel[channel].flags |= IT_CHANNEL_MUTED;
+ else
+ sr->channel[channel].flags &= ~IT_CHANNEL_MUTED;
+ }
+}
+
+
+
+int dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel)
+{
+ return sr ? (sr->channel[channel].flags & IT_CHANNEL_MUTED) != 0 : 0;
+}
+
+
diff --git a/plugins/dumb/dumb-kode54/src/it/itorder.c b/plugins/dumb/dumb-kode54/src/it/itorder.c
index c3fe51cb..6959f054 100644
--- a/plugins/dumb/dumb-kode54/src/it/itorder.c
+++ b/plugins/dumb/dumb-kode54/src/it/itorder.c
@@ -1,63 +1,63 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * itorder.c - Code to fix invalid patterns in / / \ \
- * the pattern table. | < / \_
- * | \/ /\ /
- * By Julien Cugniere. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* This function ensures that any pattern mentioned in the order table but
- * not present in the pattern table is treated as an empty 64 rows pattern.
- * This is done by adding such a dummy pattern at the end of the pattern
- * table, and redirect invalid orders to it.
- * Patterns 254 and 255 are left untouched, unless the signal is an XM.
- */
-int _dumb_it_fix_invalid_orders(DUMB_IT_SIGDATA *sigdata)
-{
- int i;
- int found_some = 0;
-
- int first_invalid = sigdata->n_patterns;
- int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253;
-
- for (i = 0; i < sigdata->n_orders; i++) {
- if (sigdata->order[i] >= first_invalid && sigdata->order[i] <= last_invalid) {
- sigdata->order[i] = sigdata->n_patterns;
- found_some = 1;
- }
- }
-
- if (found_some) {
- IT_PATTERN *new_pattern = realloc(sigdata->pattern, sizeof(*sigdata->pattern) * (sigdata->n_patterns + 1));
- if (!new_pattern)
- return -1;
-
- new_pattern[sigdata->n_patterns].n_rows = 64;
- new_pattern[sigdata->n_patterns].n_entries = 0;
- new_pattern[sigdata->n_patterns].entry = NULL;
- sigdata->pattern = new_pattern;
- sigdata->n_patterns++;
- }
-
- return 0;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * itorder.c - Code to fix invalid patterns in / / \ \
+ * the pattern table. | < / \_
+ * | \/ /\ /
+ * By Julien Cugniere. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* This function ensures that any pattern mentioned in the order table but
+ * not present in the pattern table is treated as an empty 64 rows pattern.
+ * This is done by adding such a dummy pattern at the end of the pattern
+ * table, and redirect invalid orders to it.
+ * Patterns 254 and 255 are left untouched, unless the signal is an XM.
+ */
+int _dumb_it_fix_invalid_orders(DUMB_IT_SIGDATA *sigdata)
+{
+ int i;
+ int found_some = 0;
+
+ int first_invalid = sigdata->n_patterns;
+ int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253;
+
+ for (i = 0; i < sigdata->n_orders; i++) {
+ if (sigdata->order[i] >= first_invalid && sigdata->order[i] <= last_invalid) {
+ sigdata->order[i] = sigdata->n_patterns;
+ found_some = 1;
+ }
+ }
+
+ if (found_some) {
+ IT_PATTERN *new_pattern = realloc(sigdata->pattern, sizeof(*sigdata->pattern) * (sigdata->n_patterns + 1));
+ if (!new_pattern)
+ return -1;
+
+ new_pattern[sigdata->n_patterns].n_rows = 64;
+ new_pattern[sigdata->n_patterns].n_entries = 0;
+ new_pattern[sigdata->n_patterns].entry = NULL;
+ sigdata->pattern = new_pattern;
+ sigdata->n_patterns++;
+ }
+
+ return 0;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/itread.c b/plugins/dumb/dumb-kode54/src/it/itread.c
index 8f5e7ef6..7170a57f 100644
--- a/plugins/dumb/dumb-kode54/src/it/itread.c
+++ b/plugins/dumb/dumb-kode54/src/it/itread.c
@@ -1,1332 +1,1343 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * itread.c - Code to read an Impulse Tracker / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * Based on the loader from an IT player by Bob. \_ / > /
- * Adapted for DUMB by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>//might not be necessary later; required for memset
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-#define INVESTIGATE_OLD_INSTRUMENTS
-
-
-
-static int it_seek(DUMBFILE *f, long offset)
-{
- long pos = dumbfile_pos(f);
-
- if (pos > offset)
- return -1;
-
- if (pos < offset)
- if (dumbfile_skip(f, offset - pos))
- return -1;
-
- return 0;
-}
-
-
-
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned long dword;
-
-typedef struct readblock_crap readblock_crap;
-
-struct readblock_crap {
- unsigned char *sourcebuf;
- unsigned char *sourcepos;
- unsigned char *sourceend;
- int rembits;
-};
-
-
-static int readblock(DUMBFILE *f, readblock_crap * crap)
-{
- long size;
- int c;
-
- size = dumbfile_igetw(f);
- if (size < 0)
- return size;
-
- crap->sourcebuf = malloc(size);
- if (!crap->sourcebuf)
- return -1;
-
- c = dumbfile_getnc((char *)crap->sourcebuf, size, f);
- if (c < size) {
- free(crap->sourcebuf);
- crap->sourcebuf = NULL;
- return -1;
- }
-
- crap->sourcepos = crap->sourcebuf;
- crap->sourceend = crap->sourcebuf + size;
- crap->rembits = 8;
- return 0;
-}
-
-
-
-static void freeblock(readblock_crap * crap)
-{
- free(crap->sourcebuf);
- crap->sourcebuf = NULL;
-}
-
-
-
-static int readbits(int bitwidth, readblock_crap * crap)
-{
- int val = 0;
- int b = 0;
-
- if (crap->sourcepos >= crap->sourceend) return val;
-
- while (bitwidth > crap->rembits) {
- val |= *crap->sourcepos++ << b;
- if (crap->sourcepos >= crap->sourceend) return val;
- b += crap->rembits;
- bitwidth -= crap->rembits;
- crap->rembits = 8;
- }
-
- val |= (*crap->sourcepos & ((1 << bitwidth) - 1)) << b;
- *crap->sourcepos >>= bitwidth;
- crap->rembits -= bitwidth;
-
- return val;
-}
-
-
-
-/** WARNING - do we even need to pass `right`? */
-/** WARNING - why bother memsetting at all? The whole array is written... */
-// if we do memset, dumb_silence() would be neater...
-static int decompress8(DUMBFILE *f, signed char *data, int len, int it215)
-{
- int blocklen, blockpos;
- byte bitwidth;
- word val;
- char d1, d2;
- readblock_crap crap;
-
- memset(&crap, 0, sizeof(crap));
-
- memset(data, 0, len * sizeof(*data));
-
- while (len > 0) {
- //Read a block of compressed data:
- if (readblock(f, &crap))
- return -1;
- //Set up a few variables
- blocklen = (len < 0x8000) ? len : 0x8000; //Max block length is 0x8000 bytes
- blockpos = 0;
- bitwidth = 9;
- d1 = d2 = 0;
- //Start the decompression:
- while (blockpos < blocklen) {
- //Read a value:
- val = (word)readbits(bitwidth, &crap);
- //Check for bit width change:
-
- if (bitwidth < 7) { //Method 1:
- if (val == (1 << (bitwidth - 1))) {
- val = (word)readbits(3, &crap) + 1;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth < 9) { //Method 2
- byte border = (0xFF >> (9 - bitwidth)) - 4;
-
- if (val > border && val <= (border + 8)) {
- val -= border;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth == 9) { //Method 3
- if (val & 0x100) {
- bitwidth = (val + 1) & 0xFF;
- continue;
- }
- }
- else { //Illegal width, abort ?
- freeblock(&crap);
- return -1;
- }
-
- //Expand the value to signed byte:
- {
- char v; //The sample value:
- if (bitwidth < 8) {
- byte shift = 8 - bitwidth;
- v = (val << shift);
- v >>= shift;
- }
- else
- v = (char)val;
-
- //And integrate the sample value
- //(It always has to end with integration doesn't it ? ;-)
- d1 += v;
- d2 += d1;
- }
-
- //Store !
- /* Version 2.15 was an unofficial version with hacked compression
- * code. Yay, better compression :D
- */
- *data++ = it215 ? d2 : d1;
- len--;
- blockpos++;
- }
- freeblock(&crap);
- }
- return 0;
-}
-
-
-
-static int decompress16(DUMBFILE *f, short *data, int len, int it215)
-{
- int blocklen, blockpos;
- byte bitwidth;
- long val;
- short d1, d2;
- readblock_crap crap;
-
- memset(&crap, 0, sizeof(crap));
-
- memset(data, 0, len * sizeof(*data));
-
- while (len > 0) {
- //Read a block of compressed data:
- if (readblock(f, &crap))
- return -1;
- //Set up a few variables
- blocklen = (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes
- blockpos = 0;
- bitwidth = 17;
- d1 = d2 = 0;
- //Start the decompression:
- while (blockpos < blocklen) {
- val = readbits(bitwidth, &crap);
- //Check for bit width change:
-
- if (bitwidth < 7) { //Method 1:
- if (val == (1 << (bitwidth - 1))) {
- val = readbits(4, &crap) + 1;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth < 17) { //Method 2
- word border = (0xFFFF >> (17 - bitwidth)) - 8;
-
- if (val > border && val <= (border + 16)) {
- val -= border;
- bitwidth = val < bitwidth ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth == 17) { //Method 3
- if (val & 0x10000) {
- bitwidth = (val + 1) & 0xFF;
- continue;
- }
- }
- else { //Illegal width, abort ?
- freeblock(&crap);
- return -1;
- }
-
- //Expand the value to signed byte:
- {
- short v; //The sample value:
- if (bitwidth < 16) {
- byte shift = 16 - bitwidth;
- v = (short)(val << shift);
- v >>= shift;
- }
- else
- v = (short)val;
-
- //And integrate the sample value
- //(It always has to end with integration doesn't it ? ;-)
- d1 += v;
- d2 += d1;
- }
-
- //Store !
- /* Version 2.15 was an unofficial version with hacked compression
- * code. Yay, better compression :D
- */
- *data++ = it215 ? d2 : d1;
- len--;
- blockpos++;
- }
- freeblock(&crap);
- }
- return 0;
-}
-
-
-
-static int it_read_envelope(IT_ENVELOPE *envelope, DUMBFILE *f)
-{
- int n;
-
- envelope->flags = dumbfile_getc(f);
- envelope->n_nodes = dumbfile_getc(f);
- envelope->loop_start = dumbfile_getc(f);
- envelope->loop_end = dumbfile_getc(f);
- envelope->sus_loop_start = dumbfile_getc(f);
- envelope->sus_loop_end = dumbfile_getc(f);
- for (n = 0; n < envelope->n_nodes; n++) {
- envelope->node_y[n] = dumbfile_getc(f);
- envelope->node_t[n] = dumbfile_igetw(f);
- }
- dumbfile_skip(f, 75 - envelope->n_nodes * 3 + 1);
-
- if (envelope->n_nodes <= 0)
- envelope->flags &= ~IT_ENVELOPE_ON;
- else {
- if (envelope->loop_end >= envelope->n_nodes || envelope->loop_start > envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON;
- if (envelope->sus_loop_end >= envelope->n_nodes || envelope->sus_loop_start > envelope->sus_loop_end) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP;
- }
-
- return dumbfile_error(f);
-}
-
-
-
-static int it_read_old_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f)
-{
- int n;
-
- /*if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE)
- return -1;*/
- // XXX
- dumbfile_skip(f, 4);
-
- dumbfile_getnc(instrument->filename, 13, f);
- instrument->filename[13] = 0;
-
- instrument->volume_envelope.flags = dumbfile_getc(f);
- instrument->volume_envelope.loop_start = dumbfile_getc(f);
- instrument->volume_envelope.loop_end = dumbfile_getc(f);
- instrument->volume_envelope.sus_loop_start = dumbfile_getc(f);
- instrument->volume_envelope.sus_loop_end = dumbfile_getc(f);
-
- /* Skip two unused bytes. */
- dumbfile_skip(f, 2);
-
- /* In the old instrument format, fadeout ranges from 0 to 64, and is
- * subtracted at intervals from a value starting at 512. In the new
- * format, all these values are doubled. Therefore we double when loading
- * from the old instrument format - that way we don't have to think about
- * it later.
- */
- instrument->fadeout = dumbfile_igetw(f) << 1;
- instrument->new_note_action = dumbfile_getc(f);
- instrument->dup_check_type = dumbfile_getc(f);
- instrument->dup_check_action = DCA_NOTE_CUT; // This might be wrong!
- /** WARNING - what is the duplicate check action for old-style instruments? */
-
- /* Skip Tracker Version and Number of Samples. These are only used in
- * separate instrument files. Also skip unused byte.
- */
- dumbfile_skip(f, 4);
-
- dumbfile_getnc(instrument->name, 26, f);
- instrument->name[26] = 0;
-
- /* Skip unused bytes following the Instrument Name. */
- dumbfile_skip(f, 6);
-
- instrument->pp_separation = 0;
- instrument->pp_centre = 60;
- instrument->global_volume = 128;
- /** WARNING - should global_volume be 64 or something? */
- instrument->default_pan = 32;
- /** WARNING - should default_pan be 128, meaning don`t use? */
- instrument->random_volume = 0;
- instrument->random_pan = 0;
-
- for (n = 0; n < 120; n++) {
- instrument->map_note[n] = dumbfile_getc(f);
- instrument->map_sample[n] = dumbfile_getc(f);
- }
-
- /* Skip "Volume envelope (200 bytes)". */
- // - need to know better what this is for though.
- dumbfile_skip(f, 200);
-
-#ifdef INVESTIGATE_OLD_INSTRUMENTS
- fprintf(stderr, "Inst %02d Env:", n);
-#endif
-
- for (n = 0; n < 25; n++)
- {
- instrument->volume_envelope.node_t[n] = dumbfile_getc(f);
- instrument->volume_envelope.node_y[n] = dumbfile_getc(f);
-
-#ifdef INVESTIGATE_OLD_INSTRUMENTS
- fprintf(stderr, " %d,%d",
- instrument->volume_envelope.node_t[n],
- instrument->volume_envelope.node_y[n]);
-#endif
-
- // This loop is unfinished, as we can probably escape from it before
- // the end if we want to. Hence the otherwise useless dumbfile_skip()
- // call below.
- }
- dumbfile_skip(f, 50 - (n << 1));
- instrument->volume_envelope.n_nodes = n;
-
-#ifdef INVESTIGATE_OLD_INSTRUMENTS
- fprintf(stderr, "\n");
-#endif
-
- if (dumbfile_error(f))
- return -1;
-
- {
- IT_ENVELOPE *envelope = &instrument->volume_envelope;
- if (envelope->n_nodes <= 0)
- envelope->flags &= ~IT_ENVELOPE_ON;
- else {
- if (envelope->loop_end >= envelope->n_nodes || envelope->loop_start > envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON;
- if (envelope->sus_loop_end >= envelope->n_nodes || envelope->sus_loop_start > envelope->sus_loop_end) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP;
- }
- }
-
- instrument->filter_cutoff = 127;
- instrument->filter_resonance = 0;
-
- instrument->pan_envelope.flags = 0;
- instrument->pitch_envelope.flags = 0;
-
- return 0;
-}
-
-
-
-static int it_read_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f, int maxlen)
-{
- int n, len;
-
- /*if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE)
- return -1;*/
- // XXX
-
- if (maxlen) len = dumbfile_pos(f);
-
- dumbfile_skip(f, 4);
-
- dumbfile_getnc(instrument->filename, 13, f);
- instrument->filename[13] = 0;
-
- instrument->new_note_action = dumbfile_getc(f);
- instrument->dup_check_type = dumbfile_getc(f);
- instrument->dup_check_action = dumbfile_getc(f);
- instrument->fadeout = dumbfile_igetw(f);
- instrument->pp_separation = dumbfile_getc(f);
- instrument->pp_centre = dumbfile_getc(f);
- instrument->global_volume = dumbfile_getc(f);
- instrument->default_pan = dumbfile_getc(f);
- instrument->random_volume = dumbfile_getc(f);
- instrument->random_pan = dumbfile_getc(f);
-
- /* Skip Tracker Version and Number of Samples. These are only used in
- * separate instrument files. Also skip unused byte.
- */
- dumbfile_skip(f, 4);
-
- dumbfile_getnc(instrument->name, 26, f);
- instrument->name[26] = 0;
-
- instrument->filter_cutoff = dumbfile_getc(f);
- instrument->filter_resonance = dumbfile_getc(f);
-
- /* Skip MIDI Channel, Program and Bank. */
- //dumbfile_skip(f, 4);
- /*instrument->output = dumbfile_getc(f);
- if ( instrument->output > 16 ) {
- instrument->output -= 128;
- } else {
- instrument->output = 0;
- }
- dumbfile_skip(f, 3);*/
- dumbfile_skip(f, 4);
-
- for (n = 0; n < 120; n++) {
- instrument->map_note[n] = dumbfile_getc(f);
- instrument->map_sample[n] = dumbfile_getc(f);
- }
-
- if (dumbfile_error(f))
- return -1;
-
- if (it_read_envelope(&instrument->volume_envelope, f)) return -1;
- if (it_read_envelope(&instrument->pan_envelope, f)) return -1;
- if (it_read_envelope(&instrument->pitch_envelope, f)) return -1;
-
- if (maxlen) {
- len = dumbfile_pos(f) - len;
- if ( maxlen - len < 124 ) return 0;
- }
-
- if ( dumbfile_mgetl(f) == IT_MPTX_SIGNATURE ) {
- for ( n = 0; n < 120; n++ ) {
- instrument->map_sample[ n ] += dumbfile_getc( f ) << 8;
- }
-
- if (dumbfile_error(f))
- return -1;
- }
-
- /*if ( dumbfile_mgetl(f) == IT_INSM_SIGNATURE ) {
- long end = dumbfile_igetl(f);
- end += dumbfile_pos(f);
- while ( dumbfile_pos(f) < end ) {
- int chunkid = dumbfile_igetl(f);
- switch ( chunkid ) {
- case DUMB_ID('P','L','U','G'):
- instrument->output = dumbfile_getc(f);
- break;
- default:
- chunkid = chunkid / 0x100 + dumbfile_getc(f) * 0x1000000;
- break;
- }
- }
-
- if (dumbfile_error(f))
- return -1;
- }*/
-
- return 0;
-}
-
-
-
-static int it_read_sample_header(IT_SAMPLE *sample, unsigned char *convert, long *offset, DUMBFILE *f)
-{
- /* XXX
- if (dumbfile_mgetl(f) != IT_SAMPLE_SIGNATURE)
- return -1;*/
- int hax = 0;
- long s = dumbfile_mgetl(f);
- if (s != IT_SAMPLE_SIGNATURE) {
- if ( s == ( IT_SAMPLE_SIGNATURE >> 16 ) ) {
- s <<= 16;
- s |= dumbfile_mgetw(f);
- if ( s != IT_SAMPLE_SIGNATURE )
- return -1;
- hax = 1;
- }
- }
-
- dumbfile_getnc(sample->filename, 13, f);
- sample->filename[13] = 0;
-
- sample->global_volume = dumbfile_getc(f);
- sample->flags = dumbfile_getc(f);
- sample->default_volume = dumbfile_getc(f);
-
- dumbfile_getnc(sample->name, 26, f);
- sample->name[26] = 0;
-
- *convert = dumbfile_getc(f);
- sample->default_pan = dumbfile_getc(f);
- sample->length = dumbfile_igetl(f);
- sample->loop_start = dumbfile_igetl(f);
- sample->loop_end = dumbfile_igetl(f);
- sample->C5_speed = dumbfile_igetl(f);
- sample->sus_loop_start = dumbfile_igetl(f);
- sample->sus_loop_end = dumbfile_igetl(f);
-
-#ifdef STEREO_SAMPLES_COUNT_AS_TWO
- if (sample->flags & IT_SAMPLE_STEREO) {
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- sample->C5_speed >>= 1;
- sample->sus_loop_start >>= 1;
- sample->sus_loop_end >>= 1;
- }
-#endif
-
- if (sample->flags & IT_SAMPLE_EXISTS) {
- if (sample->length <= 0)
- sample->flags &= ~IT_SAMPLE_EXISTS;
- else {
- if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
- sample->flags &= ~IT_SAMPLE_LOOP;
- else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
- sample->flags &= ~IT_SAMPLE_LOOP;
-
- if ((unsigned int)sample->sus_loop_end > (unsigned int)sample->length)
- sample->flags &= ~IT_SAMPLE_SUS_LOOP;
- else if ((unsigned int)sample->sus_loop_start >= (unsigned int)sample->sus_loop_end)
- sample->flags &= ~IT_SAMPLE_SUS_LOOP;
-
- /* We may be able to truncate the sample to save memory. */
- if (sample->flags & IT_SAMPLE_LOOP &&
- *convert != 0xFF) { /* not truncating compressed samples, for now... */
- if ((sample->flags & IT_SAMPLE_SUS_LOOP) && sample->sus_loop_end >= sample->loop_end)
- sample->length = sample->sus_loop_end;
- else
- sample->length = sample->loop_end;
- }
- }
- }
-
- *offset = dumbfile_igetl(f);
-
- sample->vibrato_speed = dumbfile_getc(f);
- sample->vibrato_depth = dumbfile_getc(f);
- if ( ! hax ) {
- sample->vibrato_rate = dumbfile_getc(f);
- sample->vibrato_waveform = dumbfile_getc(f);
- } else {
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = 0;
- }
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-long _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f)
-{
- long n, len, delta;
- signed char * ptr, * end;
- signed char compression_table[16];
- if (dumbfile_getnc(compression_table, 16, f) != 16)
- return -1;
- ptr = (signed char *) sample->data;
- delta = 0;
-
- end = ptr + sample->length;
- len = (sample->length + 1) / 2;
- for (n = 0; n < len; n++) {
- int b = dumbfile_getc(f);
- if (b < 0) return -1;
- delta += compression_table[b & 0x0F];
- *ptr++ = delta;
- if (ptr >= end) break;
- delta += compression_table[b >> 4];
- *ptr++ = delta;
- }
-
- return 0;
-}
-
-
-static long it_read_sample_data(int cmwt, IT_SAMPLE *sample, unsigned char convert, DUMBFILE *f)
-{
- long n;
-
- long datasize = sample->length;
- if (sample->flags & IT_SAMPLE_STEREO) datasize <<= 1;
-
- sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
- if (!sample->data)
- return -1;
-
- if (!(sample->flags & IT_SAMPLE_16BIT) && (convert == 0xFF)) {
- if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
- return -1;
- } else if (sample->flags & 8) {
- /* If the sample is packed, then we must unpack it. */
-
- /** WARNING - unresolved business here... test with ModPlug? */
-
- if (sample->flags & IT_SAMPLE_STEREO)
- //exit(37); // TODO: if this ever happens, maybe sample->length should be doubled below?
- return -1;
-
-/*
-//#ifndef STEREO_SAMPLES_COUNT_AS_TWO
- ASSERT(!(sample->flags & IT_SAMPLE_STEREO));
-//#endif
-*/
- if (sample->flags & IT_SAMPLE_16BIT)
- decompress16(f, sample->data, datasize, ((cmwt >= 0x215) && (convert & 4)));
- else
- decompress8(f, sample->data, datasize, ((cmwt >= 0x215) && (convert & 4)));
- } else if (sample->flags & IT_SAMPLE_16BIT) {
- if (convert & 2)
- for (n = 0; n < datasize; n++)
- ((short *)sample->data)[n] = dumbfile_mgetw(f);
- else
- for (n = 0; n < datasize; n++)
- ((short *)sample->data)[n] = dumbfile_igetw(f);
- } else
- for (n = 0; n < datasize; n++)
- ((signed char *)sample->data)[n] = dumbfile_getc(f);
-
- if (dumbfile_error(f))
- return -1;
-
- if (!(convert & 1)) {
- /* Convert to signed. */
- if (sample->flags & IT_SAMPLE_16BIT)
- for (n = 0; n < datasize; n++)
- ((short *)sample->data)[n] ^= 0x8000;
- else
- for (n = 0; n < datasize; n++)
- ((signed char *)sample->data)[n] ^= 0x80;
- }
-
- /* NOT SUPPORTED:
- *
- * convert & 4 - Samples stored as delta values
- * convert & 16 - Samples stored as TX-Wave 12-bit values
- * convert & 32 - Left/Right/All Stereo prompt
- */
-
- return 0;
-}
-
-
-
-//#define DETECT_DUPLICATE_CHANNELS
-#ifdef DETECT_DUPLICATE_CHANNELS
-#include <stdio.h>
-#endif
-static int it_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer)
-{
- unsigned char cmask[DUMB_IT_N_CHANNELS];
- unsigned char cnote[DUMB_IT_N_CHANNELS];
- unsigned char cinstrument[DUMB_IT_N_CHANNELS];
- unsigned char cvolpan[DUMB_IT_N_CHANNELS];
- unsigned char ceffect[DUMB_IT_N_CHANNELS];
- unsigned char ceffectvalue[DUMB_IT_N_CHANNELS];
-#ifdef DETECT_DUPLICATE_CHANNELS
- IT_ENTRY *dupentry[DUMB_IT_N_CHANNELS];
-#endif
-
- int n_entries = 0;
- int buflen;
- int bufpos = 0;
-
- IT_ENTRY *entry;
-
- unsigned char channel;
- unsigned char mask;
-
- memset(cmask, 0, sizeof(cmask));
- memset(cnote, 0, sizeof(cnote));
- memset(cinstrument, 0, sizeof(cinstrument));
- memset(cvolpan, 0, sizeof(cvolpan));
- memset(ceffect, 0, sizeof(ceffect));
- memset(ceffectvalue, 0, sizeof(ceffectvalue));
-#ifdef DETECT_DUPLICATE_CHANNELS
- {
- int i;
- for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dupentry[i] = NULL;
- }
-#endif
-
- buflen = dumbfile_igetw(f);
- pattern->n_rows = dumbfile_igetw(f);
-
- /* Skip four unused bytes. */
- dumbfile_skip(f, 4);
-
- if (dumbfile_error(f))
- return -1;
-
- /* Read in the pattern data. */
- dumbfile_getnc(buffer, buflen, f);
-
- if (dumbfile_error(f))
- return -1;
-
- /* Scan the pattern data, and work out how many entries we need room for. */
- while (bufpos < buflen) {
- unsigned char b = buffer[bufpos++];
-
- if (b == 0) {
- /* End of row */
- n_entries++;
- continue;
- }
-
- channel = (b - 1) & 63;
-
- if (b & 128)
- cmask[channel] = mask = buffer[bufpos++];
- else
- mask = cmask[channel];
-
- {
- static const unsigned char used[16] = {0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5};
- n_entries += (mask != 0);
- bufpos += used[mask & 15];
- }
- }
-
- pattern->n_entries = n_entries;
-
- pattern->entry = malloc(n_entries * sizeof(*pattern->entry));
-
- if (!pattern->entry)
- return -1;
-
- bufpos = 0;
- memset(cmask, 0, sizeof(cmask));
-
- entry = pattern->entry;
-
- while (bufpos < buflen) {
- unsigned char b = buffer[bufpos++];
-
- if (b == 0) {
- /* End of row */
- IT_SET_END_ROW(entry);
- entry++;
-#ifdef DETECT_DUPLICATE_CHANNELS
- {
- int i;
- for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dupentry[i] = NULL;
- }
-#endif
- continue;
- }
-
- channel = (b - 1) & 63;
-
- if (b & 128)
- cmask[channel] = mask = buffer[bufpos++];
- else
- mask = cmask[channel];
-
- if (mask) {
- entry->mask = (mask & 15) | (mask >> 4);
- entry->channel = channel;
-
- if (mask & IT_ENTRY_NOTE)
- cnote[channel] = entry->note = buffer[bufpos++];
- else if (mask & (IT_ENTRY_NOTE << 4))
- entry->note = cnote[channel];
-
- if (mask & IT_ENTRY_INSTRUMENT)
- cinstrument[channel] = entry->instrument = buffer[bufpos++];
- else if (mask & (IT_ENTRY_INSTRUMENT << 4))
- entry->instrument = cinstrument[channel];
-
- if (mask & IT_ENTRY_VOLPAN)
- cvolpan[channel] = entry->volpan = buffer[bufpos++];
- else if (mask & (IT_ENTRY_VOLPAN << 4))
- entry->volpan = cvolpan[channel];
-
- if (mask & IT_ENTRY_EFFECT) {
- ceffect[channel] = entry->effect = buffer[bufpos++];
- ceffectvalue[channel] = entry->effectvalue = buffer[bufpos++];
- } else {
- entry->effect = ceffect[channel];
- entry->effectvalue = ceffectvalue[channel];
- }
-
-#ifdef DETECT_DUPLICATE_CHANNELS
- if (dupentry[channel]) {
- FILE *f = fopen("dupentry.txt", "a");
- if (!f) abort();
- fprintf(f, "Two events on channel %d:", channel);
- fprintf(f, " Event #1:");
- if (dupentry[channel]->mask & IT_ENTRY_NOTE ) fprintf(f, " %03d", dupentry[channel]->note ); else fprintf(f, " ...");
- if (dupentry[channel]->mask & IT_ENTRY_INSTRUMENT) fprintf(f, " %03d", dupentry[channel]->instrument); else fprintf(f, " ...");
- if (dupentry[channel]->mask & IT_ENTRY_VOLPAN ) fprintf(f, " %03d", dupentry[channel]->volpan ); else fprintf(f, " ...");
- if (dupentry[channel]->mask & IT_ENTRY_EFFECT) fprintf(f, " %c%02X\n", 'A' - 1 + dupentry[channel]->effect, dupentry[channel]->effectvalue); else fprintf(f, " ...\n");
- fprintf(f, " Event #2:");
- if (entry->mask & IT_ENTRY_NOTE ) fprintf(f, " %03d", entry->note ); else fprintf(f, " ...");
- if (entry->mask & IT_ENTRY_INSTRUMENT) fprintf(f, " %03d", entry->instrument); else fprintf(f, " ...");
- if (entry->mask & IT_ENTRY_VOLPAN ) fprintf(f, " %03d", entry->volpan ); else fprintf(f, " ...");
- if (entry->mask & IT_ENTRY_EFFECT) fprintf(f, " %c%02X\n", 'A' - 1 + entry->effect, entry->effectvalue); else fprintf(f, " ...\n");
- fclose(f);
- }
- dupentry[channel] = entry;
-#endif
-
- entry++;
- }
- }
-
- ASSERT(entry == pattern->entry + n_entries);
-
- return 0;
-}
-
-
-
-/* Currently we assume the sample data are stored after the sample headers in
- * module files. This assumption may be unjustified; let me know if you have
- * trouble.
- */
-
-#define IT_COMPONENT_SONG_MESSAGE 1
-#define IT_COMPONENT_INSTRUMENT 2
-#define IT_COMPONENT_PATTERN 3
-#define IT_COMPONENT_SAMPLE 4
-
-typedef struct IT_COMPONENT
-{
- unsigned char type;
- unsigned short n;
- long offset;
- short sampfirst; /* component[sampfirst] = first sample data after this */
- short sampnext; /* sampnext is used to create linked lists of sample data */
-}
-IT_COMPONENT;
-
-
-
-static int it_component_compare(const void *e1, const void *e2)
-{
- return ((const IT_COMPONENT *)e1)->offset -
- ((const IT_COMPONENT *)e2)->offset;
-}
-
-
-
-static sigdata_t *it_load_sigdata(DUMBFILE *f)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- int cwt, cmwt;
- int special;
- int message_length, message_offset;
-
- IT_COMPONENT *component;
- int n_components = 0;
-
- unsigned char sample_convert[4096];
-
- int n;
-
- unsigned char *buffer;
-
- if (dumbfile_mgetl(f) != IT_SIGNATURE)
- return NULL;
-
- sigdata = malloc(sizeof(*sigdata));
-
- if (!sigdata)
- return NULL;
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- dumbfile_getnc(sigdata->name, 26, f);
- sigdata->name[26] = 0;
-
- /* Skip pattern row highlight info. */
- dumbfile_skip(f, 2);
-
- sigdata->n_orders = dumbfile_igetw(f);
- sigdata->n_instruments = dumbfile_igetw(f);
- sigdata->n_samples = dumbfile_igetw(f);
- sigdata->n_patterns = dumbfile_igetw(f);
-
- cwt = dumbfile_igetw(f);
- cmwt = dumbfile_igetw(f);
-
- sigdata->flags = dumbfile_igetw(f);
- special = dumbfile_igetw(f);
-
- sigdata->global_volume = dumbfile_getc(f);
- sigdata->mixing_volume = dumbfile_getc(f);
- sigdata->speed = dumbfile_getc(f);
- if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
- sigdata->tempo = dumbfile_getc(f);
- sigdata->pan_separation = dumbfile_getc(f); /** WARNING: use this */
-
- /* Skip Pitch Wheel Depth */
- dumbfile_skip(f, 1);
-
- message_length = dumbfile_igetw(f);
- message_offset = dumbfile_igetl(f);
-
- /* Skip Reserved. */
- dumbfile_skip(f, 4);
-
- dumbfile_getnc(sigdata->channel_pan, DUMB_IT_N_CHANNELS, f);
- dumbfile_getnc(sigdata->channel_volume, DUMB_IT_N_CHANNELS, f);
-
- // XXX sample count
- if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_instruments > 256 || sigdata->n_samples > 4000 || sigdata->n_patterns > 256) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->order = malloc(sigdata->n_orders);
- if (!sigdata->order) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (sigdata->n_instruments) {
- sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
- if (!sigdata->instrument) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
-
- if (sigdata->n_samples) {
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
- }
-
- if (sigdata->n_patterns) {
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
- }
-
- dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
- sigdata->restart_position = 0;
-
- component = malloc(769 * sizeof(*component));
- if (!component) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (special & 1) {
- component[n_components].type = IT_COMPONENT_SONG_MESSAGE;
- component[n_components].offset = message_offset;
- component[n_components].sampfirst = -1;
- n_components++;
- }
-
- for (n = 0; n < sigdata->n_instruments; n++) {
- component[n_components].type = IT_COMPONENT_INSTRUMENT;
- component[n_components].n = n;
- component[n_components].offset = dumbfile_igetl(f);
- component[n_components].sampfirst = -1;
- n_components++;
- }
-
- for (n = 0; n < sigdata->n_samples; n++) {
- component[n_components].type = IT_COMPONENT_SAMPLE;
- component[n_components].n = n;
- component[n_components].offset = dumbfile_igetl(f);
- component[n_components].sampfirst = -1;
- n_components++;
- }
-
- for (n = 0; n < sigdata->n_patterns; n++) {
- long offset = dumbfile_igetl(f);
- if (offset) {
- component[n_components].type = IT_COMPONENT_PATTERN;
- component[n_components].n = n;
- component[n_components].offset = offset;
- component[n_components].sampfirst = -1;
- n_components++;
- } else {
- /* Empty 64-row pattern */
- sigdata->pattern[n].n_rows = 64;
- sigdata->pattern[n].n_entries = 0;
- }
- }
-
- if (dumbfile_error(f)) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- /*
- if (!(sigdata->flags & 128) != !(special & 8)) {
- fprintf(stderr, "Flags Bit 7 (\"Request embedded MIDI configuration\"): %s\n", sigdata->flags & 128 ? "=SET=" : "clear");
- fprintf(stderr, "Special Bit 3 (\"MIDI configuration embedded\") : %s\n", special & 8 ? "=SET=" : "clear");
- fprintf(stderr, "entheh would like to investigate this IT file.\n");
- fprintf(stderr, "Please contact him! entheh@users.sf.net\n");
- }
- */
-
- if (special & 8) {
- /* MIDI configuration is embedded. */
- unsigned char mididata[32];
- int i;
- sigdata->midi = malloc(sizeof(*sigdata->midi));
- if (!sigdata->midi) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- // Should we be happy with this outcome in some situations?
- }
- // What are we skipping?
- i = dumbfile_igetw(f);
- if (dumbfile_error(f) || dumbfile_skip(f, 8*i)) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- /* Read embedded MIDI configuration */
- // What are the first 9 commands for?
- if (dumbfile_skip(f, 32*9)) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (i = 0; i < 16; i++) {
- unsigned char len = 0;
- int j, leftdigit = -1;
- if (dumbfile_getnc(mididata, 32, f) < 32) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- sigdata->midi->SFmacroz[i] = 0;
- for (j = 0; j < 32; j++) {
- if (leftdigit >= 0) {
- if (mididata[j] == 0) {
- sigdata->midi->SFmacro[i][len++] = leftdigit;
- break;
- } else if (mididata[j] == ' ')
- sigdata->midi->SFmacro[i][len++] = leftdigit;
- else if (mididata[j] >= '0' && mididata[j] <= '9')
- sigdata->midi->SFmacro[i][len++] = (leftdigit << 4) | (mididata[j] - '0');
- else if (mididata[j] >= 'A' && mididata[j] <= 'F')
- sigdata->midi->SFmacro[i][len++] = (leftdigit << 4) | (mididata[j] - 'A' + 0xA);
- leftdigit = -1;
- } else if (mididata[j] == 0)
- break;
- else if (mididata[j] == 'z')
- sigdata->midi->SFmacroz[i] |= 1 << len++;
- else if (mididata[j] >= '0' && mididata[j] <= '9')
- leftdigit = mididata[j] - '0';
- else if (mididata[j] >= 'A' && mididata[j] <= 'F')
- leftdigit = mididata[j] - 'A' + 0xA;
- }
- sigdata->midi->SFmacrolen[i] = len;
- }
- for (i = 0; i < 128; i++) {
- unsigned char len = 0;
- int j, leftdigit = -1;
- dumbfile_getnc(mididata, 32, f);
- for (j = 0; j < 32; j++) {
- if (leftdigit >= 0) {
- if (mididata[j] == 0) {
- sigdata->midi->Zmacro[i][len++] = leftdigit;
- break;
- } else if (mididata[j] == ' ')
- sigdata->midi->Zmacro[i][len++] = leftdigit;
- else if (mididata[j] >= '0' && mididata[j] <= '9')
- sigdata->midi->Zmacro[i][len++] = (leftdigit << 4) | (mididata[j] - '0');
- else if (mididata[j] >= 'A' && mididata[j] <= 'F')
- sigdata->midi->Zmacro[i][len++] = (leftdigit << 4) | (mididata[j] - 'A' + 0xA);
- leftdigit = -1;
- } else if (mididata[j] == 0)
- break;
- else if (mididata[j] >= '0' && mididata[j] <= '9')
- leftdigit = mididata[j] - '0';
- else if (mididata[j] >= 'A' && mididata[j] <= 'F')
- leftdigit = mididata[j] - 'A' + 0xA;
- }
- sigdata->midi->Zmacrolen[i] = len;
- }
- }
-
- sigdata->flags &= IT_REAL_FLAGS;
-
- qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare);
-
- buffer = malloc(65536);
- if (!buffer) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (n = 0; n < n_components; n++) {
- long offset;
- int m;
-
- /* XXX */
- if ( component[n].offset == 0 ) {
- switch (component[n].type) {
- case IT_COMPONENT_INSTRUMENT:
- memset( &sigdata->instrument[component[n].n], 0, sizeof(IT_INSTRUMENT) );
- break;
- case IT_COMPONENT_SAMPLE:
- memset( &sigdata->sample[component[n].n], 0, sizeof(IT_SAMPLE) );
- break;
- case IT_COMPONENT_PATTERN:
- {
- IT_PATTERN * p = &sigdata->pattern[component[n].n];
- p->entry = 0;
- p->n_rows = 64;
- p->n_entries = 0;
- }
- break;
- }
- continue;
- }
-
- if (it_seek(f, component[n].offset)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- switch (component[n].type) {
-
- case IT_COMPONENT_SONG_MESSAGE:
- if ( n < n_components ) {
- message_length = min( message_length, component[n+1].offset - component[n].offset );
- }
- sigdata->song_message = malloc(message_length + 1);
- if (sigdata->song_message) {
- if (dumbfile_getnc(sigdata->song_message, message_length, f) < message_length) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- sigdata->song_message[message_length] = 0;
- }
- break;
-
- case IT_COMPONENT_INSTRUMENT:
- if (cmwt < 0x200)
- m = it_read_old_instrument(&sigdata->instrument[component[n].n], f);
- else
- m = it_read_instrument(&sigdata->instrument[component[n].n], f, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0);
-
- if (m) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- break;
-
- case IT_COMPONENT_PATTERN:
- if (it_read_pattern(&sigdata->pattern[component[n].n], f, buffer)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- break;
-
- case IT_COMPONENT_SAMPLE:
- if (it_read_sample_header(&sigdata->sample[component[n].n], &sample_convert[component[n].n], &offset, f)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (sigdata->sample[component[n].n].flags & IT_SAMPLE_EXISTS) {
- short *sample;
-
- for (m = n + 1; m < n_components; m++)
- if (component[m].offset > offset)
- break;
- m--;
-
- sample = &component[m].sampfirst;
-
- while (*sample >= 0 && component[*sample].offset <= offset)
- sample = &component[*sample].sampnext;
-
- component[n].sampnext = *sample;
- *sample = n;
-
- component[n].offset = offset;
- }
- }
-
- m = component[n].sampfirst;
-
- while (m >= 0) {
- if (it_seek(f, component[m].offset)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (it_read_sample_data(cmwt, &sigdata->sample[component[m].n], sample_convert[component[m].n], f)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- m = component[m].sampnext;
- }
- }
-
- free(buffer);
- free(component);
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-
-
-DUH *dumb_read_it_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_load_sigdata(f);
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[1][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- return make_duh(-1, 1, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * itread.c - Code to read an Impulse Tracker / / \ \
+ * module from an open file. | < / \_
+ * | \/ /\ /
+ * Based on the loader from an IT player by Bob. \_ / > /
+ * Adapted for DUMB by entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <string.h>//might not be necessary later; required for memset
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+#define INVESTIGATE_OLD_INSTRUMENTS
+
+
+
+static int it_seek(DUMBFILE *f, long offset)
+{
+ long pos = dumbfile_pos(f);
+
+ if (pos > offset)
+ return -1;
+
+ if (pos < offset)
+ if (dumbfile_skip(f, offset - pos))
+ return -1;
+
+ return 0;
+}
+
+
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned long dword;
+
+typedef struct readblock_crap readblock_crap;
+
+struct readblock_crap {
+ unsigned char *sourcebuf;
+ unsigned char *sourcepos;
+ unsigned char *sourceend;
+ int rembits;
+};
+
+
+static int readblock(DUMBFILE *f, readblock_crap * crap)
+{
+ long size;
+ int c;
+
+ size = dumbfile_igetw(f);
+ if (size < 0)
+ return size;
+
+ crap->sourcebuf = malloc(size);
+ if (!crap->sourcebuf)
+ return -1;
+
+ c = dumbfile_getnc((char *)crap->sourcebuf, size, f);
+ if (c < size) {
+ free(crap->sourcebuf);
+ crap->sourcebuf = NULL;
+ return -1;
+ }
+
+ crap->sourcepos = crap->sourcebuf;
+ crap->sourceend = crap->sourcebuf + size;
+ crap->rembits = 8;
+ return 0;
+}
+
+
+
+static void freeblock(readblock_crap * crap)
+{
+ free(crap->sourcebuf);
+ crap->sourcebuf = NULL;
+}
+
+
+
+static int readbits(int bitwidth, readblock_crap * crap)
+{
+ int val = 0;
+ int b = 0;
+
+ if (crap->sourcepos >= crap->sourceend) return val;
+
+ while (bitwidth > crap->rembits) {
+ val |= *crap->sourcepos++ << b;
+ if (crap->sourcepos >= crap->sourceend) return val;
+ b += crap->rembits;
+ bitwidth -= crap->rembits;
+ crap->rembits = 8;
+ }
+
+ val |= (*crap->sourcepos & ((1 << bitwidth) - 1)) << b;
+ *crap->sourcepos >>= bitwidth;
+ crap->rembits -= bitwidth;
+
+ return val;
+}
+
+
+
+/** WARNING - do we even need to pass `right`? */
+/** WARNING - why bother memsetting at all? The whole array is written... */
+// if we do memset, dumb_silence() would be neater...
+static int decompress8(DUMBFILE *f, signed char *data, int len, int cmwt)
+{
+ int blocklen, blockpos;
+ byte bitwidth;
+ word val;
+ char d1, d2;
+ readblock_crap crap;
+
+ memset(&crap, 0, sizeof(crap));
+
+ memset(data, 0, len * sizeof(*data));
+
+ while (len > 0) {
+ //Read a block of compressed data:
+ if (readblock(f, &crap))
+ return -1;
+ //Set up a few variables
+ blocklen = (len < 0x8000) ? len : 0x8000; //Max block length is 0x8000 bytes
+ blockpos = 0;
+ bitwidth = 9;
+ d1 = d2 = 0;
+ //Start the decompression:
+ while (blockpos < blocklen) {
+ //Read a value:
+ val = (word)readbits(bitwidth, &crap);
+ //Check for bit width change:
+
+ if (bitwidth < 7) { //Method 1:
+ if (val == (1 << (bitwidth - 1))) {
+ val = (word)readbits(3, &crap) + 1;
+ bitwidth = (val < bitwidth) ? val : val + 1;
+ continue;
+ }
+ }
+ else if (bitwidth < 9) { //Method 2
+ byte border = (0xFF >> (9 - bitwidth)) - 4;
+
+ if (val > border && val <= (border + 8)) {
+ val -= border;
+ bitwidth = (val < bitwidth) ? val : val + 1;
+ continue;
+ }
+ }
+ else if (bitwidth == 9) { //Method 3
+ if (val & 0x100) {
+ bitwidth = (val + 1) & 0xFF;
+ continue;
+ }
+ }
+ else { //Illegal width, abort ?
+ freeblock(&crap);
+ return -1;
+ }
+
+ //Expand the value to signed byte:
+ {
+ char v; //The sample value:
+ if (bitwidth < 8) {
+ byte shift = 8 - bitwidth;
+ v = (val << shift);
+ v >>= shift;
+ }
+ else
+ v = (char)val;
+
+ //And integrate the sample value
+ //(It always has to end with integration doesn't it ? ;-)
+ d1 += v;
+ d2 += d1;
+ }
+
+ //Store !
+ /* Version 2.15 was an unofficial version with hacked compression
+ * code. Yay, better compression :D
+ */
+ *data++ = cmwt == 0x215 ? d2 : d1;
+ len--;
+ blockpos++;
+ }
+ freeblock(&crap);
+ }
+ return 0;
+}
+
+
+
+static int decompress16(DUMBFILE *f, short *data, int len, int cmwt)
+{
+ int blocklen, blockpos;
+ byte bitwidth;
+ long val;
+ short d1, d2;
+ readblock_crap crap;
+
+ memset(&crap, 0, sizeof(crap));
+
+ memset(data, 0, len * sizeof(*data));
+
+ while (len > 0) {
+ //Read a block of compressed data:
+ if (readblock(f, &crap))
+ return -1;
+ //Set up a few variables
+ blocklen = (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes
+ blockpos = 0;
+ bitwidth = 17;
+ d1 = d2 = 0;
+ //Start the decompression:
+ while (blockpos < blocklen) {
+ val = readbits(bitwidth, &crap);
+ //Check for bit width change:
+
+ if (bitwidth < 7) { //Method 1:
+ if (val == (1 << (bitwidth - 1))) {
+ val = readbits(4, &crap) + 1;
+ bitwidth = (val < bitwidth) ? val : val + 1;
+ continue;
+ }
+ }
+ else if (bitwidth < 17) { //Method 2
+ word border = (0xFFFF >> (17 - bitwidth)) - 8;
+
+ if (val > border && val <= (border + 16)) {
+ val -= border;
+ bitwidth = val < bitwidth ? val : val + 1;
+ continue;
+ }
+ }
+ else if (bitwidth == 17) { //Method 3
+ if (val & 0x10000) {
+ bitwidth = (val + 1) & 0xFF;
+ continue;
+ }
+ }
+ else { //Illegal width, abort ?
+ freeblock(&crap);
+ return -1;
+ }
+
+ //Expand the value to signed byte:
+ {
+ short v; //The sample value:
+ if (bitwidth < 16) {
+ byte shift = 16 - bitwidth;
+ v = (short)(val << shift);
+ v >>= shift;
+ }
+ else
+ v = (short)val;
+
+ //And integrate the sample value
+ //(It always has to end with integration doesn't it ? ;-)
+ d1 += v;
+ d2 += d1;
+ }
+
+ //Store !
+ /* Version 2.15 was an unofficial version with hacked compression
+ * code. Yay, better compression :D
+ */
+ *data++ = cmwt == 0x215 ? d2 : d1;
+ len--;
+ blockpos++;
+ }
+ freeblock(&crap);
+ }
+ return 0;
+}
+
+
+
+static int it_read_envelope(IT_ENVELOPE *envelope, DUMBFILE *f)
+{
+ int n;
+
+ envelope->flags = dumbfile_getc(f);
+ envelope->n_nodes = dumbfile_getc(f);
+ envelope->loop_start = dumbfile_getc(f);
+ envelope->loop_end = dumbfile_getc(f);
+ envelope->sus_loop_start = dumbfile_getc(f);
+ envelope->sus_loop_end = dumbfile_getc(f);
+ for (n = 0; n < envelope->n_nodes; n++) {
+ envelope->node_y[n] = dumbfile_getc(f);
+ envelope->node_t[n] = dumbfile_igetw(f);
+ }
+ dumbfile_skip(f, 75 - envelope->n_nodes * 3 + 1);
+
+ if (envelope->n_nodes <= 0)
+ envelope->flags &= ~IT_ENVELOPE_ON;
+ else {
+ if (envelope->loop_end >= envelope->n_nodes || envelope->loop_start > envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON;
+ if (envelope->sus_loop_end >= envelope->n_nodes || envelope->sus_loop_start > envelope->sus_loop_end) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP;
+ }
+
+ if (envelope->n_nodes <= 0)
+ envelope->flags &= ~IT_ENVELOPE_ON;
+ else {
+ if (envelope->loop_end >= envelope->n_nodes || envelope->loop_start > envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON;
+ if (envelope->sus_loop_end >= envelope->n_nodes || envelope->sus_loop_start > envelope->sus_loop_end) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP;
+ }
+
+ return dumbfile_error(f);
+}
+
+
+
+static int it_read_old_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f)
+{
+ int n;
+
+ /*if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE)
+ return -1;*/
+ // XXX
+ dumbfile_skip(f, 4);
+
+ dumbfile_getnc(instrument->filename, 13, f);
+ instrument->filename[13] = 0;
+
+ instrument->volume_envelope.flags = dumbfile_getc(f);
+ instrument->volume_envelope.loop_start = dumbfile_getc(f);
+ instrument->volume_envelope.loop_end = dumbfile_getc(f);
+ instrument->volume_envelope.sus_loop_start = dumbfile_getc(f);
+ instrument->volume_envelope.sus_loop_end = dumbfile_getc(f);
+
+ /* Skip two unused bytes. */
+ dumbfile_skip(f, 2);
+
+ /* In the old instrument format, fadeout ranges from 0 to 64, and is
+ * subtracted at intervals from a value starting at 512. In the new
+ * format, all these values are doubled. Therefore we double when loading
+ * from the old instrument format - that way we don't have to think about
+ * it later.
+ */
+ instrument->fadeout = dumbfile_igetw(f) << 1;
+ instrument->new_note_action = dumbfile_getc(f);
+ instrument->dup_check_type = dumbfile_getc(f);
+ instrument->dup_check_action = DCA_NOTE_CUT; // This might be wrong!
+ /** WARNING - what is the duplicate check action for old-style instruments? */
+
+ /* Skip Tracker Version and Number of Samples. These are only used in
+ * separate instrument files. Also skip unused byte.
+ */
+ dumbfile_skip(f, 4);
+
+ dumbfile_getnc(instrument->name, 26, f);
+ instrument->name[26] = 0;
+
+ /* Skip unused bytes following the Instrument Name. */
+ dumbfile_skip(f, 6);
+
+ instrument->pp_separation = 0;
+ instrument->pp_centre = 60;
+ instrument->global_volume = 128;
+ /** WARNING - should global_volume be 64 or something? */
+ instrument->default_pan = 32;
+ /** WARNING - should default_pan be 128, meaning don`t use? */
+ instrument->random_volume = 0;
+ instrument->random_pan = 0;
+
+ for (n = 0; n < 120; n++) {
+ instrument->map_note[n] = dumbfile_getc(f);
+ instrument->map_sample[n] = dumbfile_getc(f);
+ }
+
+ /* Skip "Volume envelope (200 bytes)". */
+ // - need to know better what this is for though.
+ dumbfile_skip(f, 200);
+
+#ifdef INVESTIGATE_OLD_INSTRUMENTS
+ fprintf(stderr, "Inst %02d Env:", n);
+#endif
+
+ for (n = 0; n < 25; n++)
+ {
+ instrument->volume_envelope.node_t[n] = dumbfile_getc(f);
+ instrument->volume_envelope.node_y[n] = dumbfile_getc(f);
+
+#ifdef INVESTIGATE_OLD_INSTRUMENTS
+ fprintf(stderr, " %d,%d",
+ instrument->volume_envelope.node_t[n],
+ instrument->volume_envelope.node_y[n]);
+#endif
+
+ // This loop is unfinished, as we can probably escape from it before
+ // the end if we want to. Hence the otherwise useless dumbfile_skip()
+ // call below.
+ }
+ dumbfile_skip(f, 50 - (n << 1));
+ instrument->volume_envelope.n_nodes = n;
+
+#ifdef INVESTIGATE_OLD_INSTRUMENTS
+ fprintf(stderr, "\n");
+#endif
+
+ if (dumbfile_error(f))
+ return -1;
+
+ {
+ IT_ENVELOPE *envelope = &instrument->volume_envelope;
+ if (envelope->n_nodes <= 0)
+ envelope->flags &= ~IT_ENVELOPE_ON;
+ else {
+ if (envelope->loop_end >= envelope->n_nodes || envelope->loop_start > envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON;
+ if (envelope->sus_loop_end >= envelope->n_nodes || envelope->sus_loop_start > envelope->sus_loop_end) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP;
+ }
+ }
+
+ {
+ IT_ENVELOPE *envelope = &instrument->volume_envelope;
+ if (envelope->n_nodes <= 0)
+ envelope->flags &= ~IT_ENVELOPE_ON;
+ else {
+ if (envelope->loop_end >= envelope->n_nodes || envelope->loop_start > envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON;
+ if (envelope->sus_loop_end >= envelope->n_nodes || envelope->sus_loop_start > envelope->sus_loop_end) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP;
+ }
+ }
+
+ instrument->filter_cutoff = 127;
+ instrument->filter_resonance = 0;
+
+ instrument->pan_envelope.flags = 0;
+ instrument->pitch_envelope.flags = 0;
+
+ return 0;
+}
+
+
+
+static int it_read_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f, int maxlen)
+{
+ int n, len;
+
+ /*if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE)
+ return -1;*/
+ // XXX
+
+ if (maxlen) len = dumbfile_pos(f);
+
+ dumbfile_skip(f, 4);
+
+ dumbfile_getnc(instrument->filename, 13, f);
+ instrument->filename[13] = 0;
+
+ instrument->new_note_action = dumbfile_getc(f);
+ instrument->dup_check_type = dumbfile_getc(f);
+ instrument->dup_check_action = dumbfile_getc(f);
+ instrument->fadeout = dumbfile_igetw(f);
+ instrument->pp_separation = dumbfile_getc(f);
+ instrument->pp_centre = dumbfile_getc(f);
+ instrument->global_volume = dumbfile_getc(f);
+ instrument->default_pan = dumbfile_getc(f);
+ instrument->random_volume = dumbfile_getc(f);
+ instrument->random_pan = dumbfile_getc(f);
+
+ /* Skip Tracker Version and Number of Samples. These are only used in
+ * separate instrument files. Also skip unused byte.
+ */
+ dumbfile_skip(f, 4);
+
+ dumbfile_getnc(instrument->name, 26, f);
+ instrument->name[26] = 0;
+
+ instrument->filter_cutoff = dumbfile_getc(f);
+ instrument->filter_resonance = dumbfile_getc(f);
+
+ /* Skip MIDI Channel, Program and Bank. */
+ //dumbfile_skip(f, 4);
+ /*instrument->output = dumbfile_getc(f);
+ if ( instrument->output > 16 ) {
+ instrument->output -= 128;
+ } else {
+ instrument->output = 0;
+ }
+ dumbfile_skip(f, 3);*/
+ dumbfile_skip(f, 4);
+
+ for (n = 0; n < 120; n++) {
+ instrument->map_note[n] = dumbfile_getc(f);
+ instrument->map_sample[n] = dumbfile_getc(f);
+ }
+
+ if (dumbfile_error(f))
+ return -1;
+
+ if (it_read_envelope(&instrument->volume_envelope, f)) return -1;
+ if (it_read_envelope(&instrument->pan_envelope, f)) return -1;
+ if (it_read_envelope(&instrument->pitch_envelope, f)) return -1;
+
+ if (maxlen) {
+ len = dumbfile_pos(f) - len;
+ if ( maxlen - len < 124 ) return 0;
+ }
+
+ if ( dumbfile_mgetl(f) == IT_MPTX_SIGNATURE ) {
+ for ( n = 0; n < 120; n++ ) {
+ instrument->map_sample[ n ] += dumbfile_getc( f ) << 8;
+ }
+
+ if (dumbfile_error(f))
+ return -1;
+ }
+
+ /*if ( dumbfile_mgetl(f) == IT_INSM_SIGNATURE ) {
+ long end = dumbfile_igetl(f);
+ end += dumbfile_pos(f);
+ while ( dumbfile_pos(f) < end ) {
+ int chunkid = dumbfile_igetl(f);
+ switch ( chunkid ) {
+ case DUMB_ID('P','L','U','G'):
+ instrument->output = dumbfile_getc(f);
+ break;
+ default:
+ chunkid = chunkid / 0x100 + dumbfile_getc(f) * 0x1000000;
+ break;
+ }
+ }
+
+ if (dumbfile_error(f))
+ return -1;
+ }*/
+
+ return 0;
+}
+
+
+
+static int it_read_sample_header(IT_SAMPLE *sample, unsigned char *convert, long *offset, DUMBFILE *f)
+{
+ /* XXX
+ if (dumbfile_mgetl(f) != IT_SAMPLE_SIGNATURE)
+ return -1;*/
+ int hax = 0;
+ long s = dumbfile_mgetl(f);
+ if (s != IT_SAMPLE_SIGNATURE) {
+ if ( s == ( IT_SAMPLE_SIGNATURE >> 16 ) ) {
+ s <<= 16;
+ s |= dumbfile_mgetw(f);
+ if ( s != IT_SAMPLE_SIGNATURE )
+ return -1;
+ hax = 1;
+ }
+ }
+
+ dumbfile_getnc(sample->filename, 13, f);
+ sample->filename[13] = 0;
+
+ sample->global_volume = dumbfile_getc(f);
+ sample->flags = dumbfile_getc(f);
+ sample->default_volume = dumbfile_getc(f);
+
+ dumbfile_getnc(sample->name, 26, f);
+ sample->name[26] = 0;
+
+ *convert = dumbfile_getc(f);
+ sample->default_pan = dumbfile_getc(f);
+ sample->length = dumbfile_igetl(f);
+ sample->loop_start = dumbfile_igetl(f);
+ sample->loop_end = dumbfile_igetl(f);
+ sample->C5_speed = dumbfile_igetl(f);
+ sample->sus_loop_start = dumbfile_igetl(f);
+ sample->sus_loop_end = dumbfile_igetl(f);
+
+#ifdef STEREO_SAMPLES_COUNT_AS_TWO
+ if (sample->flags & IT_SAMPLE_STEREO) {
+ sample->length >>= 1;
+ sample->loop_start >>= 1;
+ sample->loop_end >>= 1;
+ sample->C5_speed >>= 1;
+ sample->sus_loop_start >>= 1;
+ sample->sus_loop_end >>= 1;
+ }
+#endif
+
+ if (sample->flags & IT_SAMPLE_EXISTS) {
+ if (sample->length <= 0)
+ sample->flags &= ~IT_SAMPLE_EXISTS;
+ else {
+ if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
+ sample->flags &= ~IT_SAMPLE_LOOP;
+ else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
+ sample->flags &= ~IT_SAMPLE_LOOP;
+
+ if ((unsigned int)sample->sus_loop_end > (unsigned int)sample->length)
+ sample->flags &= ~IT_SAMPLE_SUS_LOOP;
+ else if ((unsigned int)sample->sus_loop_start >= (unsigned int)sample->sus_loop_end)
+ sample->flags &= ~IT_SAMPLE_SUS_LOOP;
+
+ /* We may be able to truncate the sample to save memory. */
+ if (sample->flags & IT_SAMPLE_LOOP &&
+ *convert != 0xFF) { /* not truncating compressed samples, for now... */
+ if ((sample->flags & IT_SAMPLE_SUS_LOOP) && sample->sus_loop_end >= sample->loop_end)
+ sample->length = sample->sus_loop_end;
+ else
+ sample->length = sample->loop_end;
+ }
+ }
+ }
+
+ *offset = dumbfile_igetl(f);
+
+ sample->vibrato_speed = dumbfile_getc(f);
+ sample->vibrato_depth = dumbfile_getc(f);
+ if ( ! hax ) {
+ sample->vibrato_rate = dumbfile_getc(f);
+ sample->vibrato_waveform = dumbfile_getc(f);
+ } else {
+ sample->vibrato_rate = 0;
+ sample->vibrato_waveform = 0;
+ }
+ sample->finetune = 0;
+ sample->max_resampling_quality = -1;
+
+ return dumbfile_error(f);
+}
+
+long _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f)
+{
+ long n, len, delta;
+ signed char * ptr, * end;
+ signed char compression_table[16];
+ if (dumbfile_getnc(compression_table, 16, f) != 16)
+ return -1;
+ ptr = (signed char *) sample->data;
+ delta = 0;
+
+ end = ptr + sample->length;
+ len = (sample->length + 1) / 2;
+ for (n = 0; n < len; n++) {
+ int b = dumbfile_getc(f);
+ if (b < 0) return -1;
+ delta += compression_table[b & 0x0F];
+ *ptr++ = delta;
+ if (ptr >= end) break;
+ delta += compression_table[b >> 4];
+ *ptr++ = delta;
+ }
+
+ return 0;
+}
+
+
+static long it_read_sample_data(int cmwt, IT_SAMPLE *sample, unsigned char convert, DUMBFILE *f)
+{
+ long n;
+
+ long datasize = sample->length;
+ if (sample->flags & IT_SAMPLE_STEREO) datasize <<= 1;
+
+ sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
+ if (!sample->data)
+ return -1;
+
+ if (!(sample->flags & IT_SAMPLE_16BIT) && (convert == 0xFF)) {
+ if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
+ return -1;
+ } else if (sample->flags & 8) {
+ /* If the sample is packed, then we must unpack it. */
+
+ /** WARNING - unresolved business here... test with ModPlug? */
+
+ if (sample->flags & IT_SAMPLE_STEREO)
+ return -1;
+
+/*
+//#ifndef STEREO_SAMPLES_COUNT_AS_TWO
+ ASSERT(!(sample->flags & IT_SAMPLE_STEREO));
+//#endif
+*/
+ if (sample->flags & IT_SAMPLE_16BIT)
+ decompress16(f, sample->data, datasize, ((cmwt >= 0x215) && (convert & 4)));
+ else
+ decompress8(f, sample->data, datasize, ((cmwt >= 0x215) && (convert & 4)));
+ } else if (sample->flags & IT_SAMPLE_16BIT) {
+ if (convert & 2)
+ for (n = 0; n < datasize; n++)
+ ((short *)sample->data)[n] = dumbfile_mgetw(f);
+ else
+ for (n = 0; n < datasize; n++)
+ ((short *)sample->data)[n] = dumbfile_igetw(f);
+ } else
+ for (n = 0; n < datasize; n++)
+ ((signed char *)sample->data)[n] = dumbfile_getc(f);
+
+ if (dumbfile_error(f))
+ return -1;
+
+ if (!(convert & 1)) {
+ /* Convert to signed. */
+ if (sample->flags & IT_SAMPLE_16BIT)
+ for (n = 0; n < datasize; n++)
+ ((short *)sample->data)[n] ^= 0x8000;
+ else
+ for (n = 0; n < datasize; n++)
+ ((signed char *)sample->data)[n] ^= 0x80;
+ }
+
+ /* NOT SUPPORTED:
+ *
+ * convert & 4 - Samples stored as delta values
+ * convert & 16 - Samples stored as TX-Wave 12-bit values
+ * convert & 32 - Left/Right/All Stereo prompt
+ */
+
+ return 0;
+}
+
+
+
+//#define DETECT_DUPLICATE_CHANNELS
+#ifdef DETECT_DUPLICATE_CHANNELS
+#include <stdio.h>
+#endif
+static int it_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer)
+{
+ unsigned char cmask[DUMB_IT_N_CHANNELS];
+ unsigned char cnote[DUMB_IT_N_CHANNELS];
+ unsigned char cinstrument[DUMB_IT_N_CHANNELS];
+ unsigned char cvolpan[DUMB_IT_N_CHANNELS];
+ unsigned char ceffect[DUMB_IT_N_CHANNELS];
+ unsigned char ceffectvalue[DUMB_IT_N_CHANNELS];
+#ifdef DETECT_DUPLICATE_CHANNELS
+ IT_ENTRY *dupentry[DUMB_IT_N_CHANNELS];
+#endif
+
+ int n_entries = 0;
+ int buflen;
+ int bufpos = 0;
+
+ IT_ENTRY *entry;
+
+ unsigned char channel;
+ unsigned char mask;
+
+ memset(cmask, 0, sizeof(cmask));
+ memset(cnote, 0, sizeof(cnote));
+ memset(cinstrument, 0, sizeof(cinstrument));
+ memset(cvolpan, 0, sizeof(cvolpan));
+ memset(ceffect, 0, sizeof(ceffect));
+ memset(ceffectvalue, 0, sizeof(ceffectvalue));
+#ifdef DETECT_DUPLICATE_CHANNELS
+ {
+ int i;
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dupentry[i] = NULL;
+ }
+#endif
+
+ buflen = dumbfile_igetw(f);
+ pattern->n_rows = dumbfile_igetw(f);
+
+ /* Skip four unused bytes. */
+ dumbfile_skip(f, 4);
+
+ if (dumbfile_error(f))
+ return -1;
+
+ /* Read in the pattern data. */
+ dumbfile_getnc(buffer, buflen, f);
+
+ if (dumbfile_error(f))
+ return -1;
+
+ /* Scan the pattern data, and work out how many entries we need room for. */
+ while (bufpos < buflen) {
+ unsigned char b = buffer[bufpos++];
+
+ if (b == 0) {
+ /* End of row */
+ n_entries++;
+ continue;
+ }
+
+ channel = (b - 1) & 63;
+
+ if (b & 128)
+ cmask[channel] = mask = buffer[bufpos++];
+ else
+ mask = cmask[channel];
+
+ {
+ static const unsigned char used[16] = {0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5};
+ n_entries += (mask != 0);
+ bufpos += used[mask & 15];
+ }
+ }
+
+ pattern->n_entries = n_entries;
+
+ pattern->entry = malloc(n_entries * sizeof(*pattern->entry));
+
+ if (!pattern->entry)
+ return -1;
+
+ bufpos = 0;
+ memset(cmask, 0, sizeof(cmask));
+
+ entry = pattern->entry;
+
+ while (bufpos < buflen) {
+ unsigned char b = buffer[bufpos++];
+
+ if (b == 0) {
+ /* End of row */
+ IT_SET_END_ROW(entry);
+ entry++;
+#ifdef DETECT_DUPLICATE_CHANNELS
+ {
+ int i;
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dupentry[i] = NULL;
+ }
+#endif
+ continue;
+ }
+
+ channel = (b - 1) & 63;
+
+ if (b & 128)
+ cmask[channel] = mask = buffer[bufpos++];
+ else
+ mask = cmask[channel];
+
+ if (mask) {
+ entry->mask = (mask & 15) | (mask >> 4);
+ entry->channel = channel;
+
+ if (mask & IT_ENTRY_NOTE)
+ cnote[channel] = entry->note = buffer[bufpos++];
+ else if (mask & (IT_ENTRY_NOTE << 4))
+ entry->note = cnote[channel];
+
+ if (mask & IT_ENTRY_INSTRUMENT)
+ cinstrument[channel] = entry->instrument = buffer[bufpos++];
+ else if (mask & (IT_ENTRY_INSTRUMENT << 4))
+ entry->instrument = cinstrument[channel];
+
+ if (mask & IT_ENTRY_VOLPAN)
+ cvolpan[channel] = entry->volpan = buffer[bufpos++];
+ else if (mask & (IT_ENTRY_VOLPAN << 4))
+ entry->volpan = cvolpan[channel];
+
+ if (mask & IT_ENTRY_EFFECT) {
+ ceffect[channel] = entry->effect = buffer[bufpos++];
+ ceffectvalue[channel] = entry->effectvalue = buffer[bufpos++];
+ } else {
+ entry->effect = ceffect[channel];
+ entry->effectvalue = ceffectvalue[channel];
+ }
+
+#ifdef DETECT_DUPLICATE_CHANNELS
+ if (dupentry[channel]) {
+ FILE *f = fopen("dupentry.txt", "a");
+ if (!f) abort();
+ fprintf(f, "Two events on channel %d:", channel);
+ fprintf(f, " Event #1:");
+ if (dupentry[channel]->mask & IT_ENTRY_NOTE ) fprintf(f, " %03d", dupentry[channel]->note ); else fprintf(f, " ...");
+ if (dupentry[channel]->mask & IT_ENTRY_INSTRUMENT) fprintf(f, " %03d", dupentry[channel]->instrument); else fprintf(f, " ...");
+ if (dupentry[channel]->mask & IT_ENTRY_VOLPAN ) fprintf(f, " %03d", dupentry[channel]->volpan ); else fprintf(f, " ...");
+ if (dupentry[channel]->mask & IT_ENTRY_EFFECT) fprintf(f, " %c%02X\n", 'A' - 1 + dupentry[channel]->effect, dupentry[channel]->effectvalue); else fprintf(f, " ...\n");
+ fprintf(f, " Event #2:");
+ if (entry->mask & IT_ENTRY_NOTE ) fprintf(f, " %03d", entry->note ); else fprintf(f, " ...");
+ if (entry->mask & IT_ENTRY_INSTRUMENT) fprintf(f, " %03d", entry->instrument); else fprintf(f, " ...");
+ if (entry->mask & IT_ENTRY_VOLPAN ) fprintf(f, " %03d", entry->volpan ); else fprintf(f, " ...");
+ if (entry->mask & IT_ENTRY_EFFECT) fprintf(f, " %c%02X\n", 'A' - 1 + entry->effect, entry->effectvalue); else fprintf(f, " ...\n");
+ fclose(f);
+ }
+ dupentry[channel] = entry;
+#endif
+
+ entry++;
+ }
+ }
+
+ ASSERT(entry == pattern->entry + n_entries);
+
+ return 0;
+}
+
+
+
+/* Currently we assume the sample data are stored after the sample headers in
+ * module files. This assumption may be unjustified; let me know if you have
+ * trouble.
+ */
+
+#define IT_COMPONENT_SONG_MESSAGE 1
+#define IT_COMPONENT_INSTRUMENT 2
+#define IT_COMPONENT_PATTERN 3
+#define IT_COMPONENT_SAMPLE 4
+
+typedef struct IT_COMPONENT
+{
+ unsigned char type;
+ unsigned short n;
+ long offset;
+ short sampfirst; /* component[sampfirst] = first sample data after this */
+ short sampnext; /* sampnext is used to create linked lists of sample data */
+}
+IT_COMPONENT;
+
+
+
+static int it_component_compare(const void *e1, const void *e2)
+{
+ return ((const IT_COMPONENT *)e1)->offset -
+ ((const IT_COMPONENT *)e2)->offset;
+}
+
+
+
+static sigdata_t *it_load_sigdata(DUMBFILE *f)
+{
+ DUMB_IT_SIGDATA *sigdata;
+
+ int cwt, cmwt;
+ int special;
+ int message_length, message_offset;
+
+ IT_COMPONENT *component;
+ int n_components = 0;
+
+ unsigned char sample_convert[4096];
+
+ int n;
+
+ unsigned char *buffer;
+
+ if (dumbfile_mgetl(f) != IT_SIGNATURE)
+ return NULL;
+
+ sigdata = malloc(sizeof(*sigdata));
+
+ if (!sigdata)
+ return NULL;
+
+ sigdata->song_message = NULL;
+ sigdata->order = NULL;
+ sigdata->instrument = NULL;
+ sigdata->sample = NULL;
+ sigdata->pattern = NULL;
+ sigdata->midi = NULL;
+ sigdata->checkpoint = NULL;
+
+ dumbfile_getnc(sigdata->name, 26, f);
+ sigdata->name[26] = 0;
+
+ /* Skip pattern row highlight info. */
+ dumbfile_skip(f, 2);
+
+ sigdata->n_orders = dumbfile_igetw(f);
+ sigdata->n_instruments = dumbfile_igetw(f);
+ sigdata->n_samples = dumbfile_igetw(f);
+ sigdata->n_patterns = dumbfile_igetw(f);
+
+ cwt = dumbfile_igetw(f);
+ cmwt = dumbfile_igetw(f);
+
+ sigdata->flags = dumbfile_igetw(f);
+ special = dumbfile_igetw(f);
+
+ sigdata->global_volume = dumbfile_getc(f);
+ sigdata->mixing_volume = dumbfile_getc(f);
+ sigdata->speed = dumbfile_getc(f);
+ if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
+ sigdata->tempo = dumbfile_getc(f);
+ sigdata->pan_separation = dumbfile_getc(f); /** WARNING: use this */
+
+ /* Skip Pitch Wheel Depth */
+ dumbfile_skip(f, 1);
+
+ message_length = dumbfile_igetw(f);
+ message_offset = dumbfile_igetl(f);
+
+ /* Skip Reserved. */
+ dumbfile_skip(f, 4);
+
+ dumbfile_getnc(sigdata->channel_pan, DUMB_IT_N_CHANNELS, f);
+ dumbfile_getnc(sigdata->channel_volume, DUMB_IT_N_CHANNELS, f);
+
+ // XXX sample count
+ if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_instruments > 256 || sigdata->n_samples > 4000 || sigdata->n_patterns > 256) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ sigdata->order = malloc(sigdata->n_orders);
+ if (!sigdata->order) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ if (sigdata->n_instruments) {
+ sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
+ if (!sigdata->instrument) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ }
+
+ if (sigdata->n_samples) {
+ sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
+ if (!sigdata->sample) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (n = 0; n < sigdata->n_samples; n++)
+ sigdata->sample[n].data = NULL;
+ }
+
+ if (sigdata->n_patterns) {
+ sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
+ if (!sigdata->pattern) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (n = 0; n < sigdata->n_patterns; n++)
+ sigdata->pattern[n].entry = NULL;
+ }
+
+ dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
+ sigdata->restart_position = 0;
+
+ component = malloc(769 * sizeof(*component));
+ if (!component) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ if (special & 1) {
+ component[n_components].type = IT_COMPONENT_SONG_MESSAGE;
+ component[n_components].offset = message_offset;
+ component[n_components].sampfirst = -1;
+ n_components++;
+ }
+
+ for (n = 0; n < sigdata->n_instruments; n++) {
+ component[n_components].type = IT_COMPONENT_INSTRUMENT;
+ component[n_components].n = n;
+ component[n_components].offset = dumbfile_igetl(f);
+ component[n_components].sampfirst = -1;
+ n_components++;
+ }
+
+ for (n = 0; n < sigdata->n_samples; n++) {
+ component[n_components].type = IT_COMPONENT_SAMPLE;
+ component[n_components].n = n;
+ component[n_components].offset = dumbfile_igetl(f);
+ component[n_components].sampfirst = -1;
+ n_components++;
+ }
+
+ for (n = 0; n < sigdata->n_patterns; n++) {
+ long offset = dumbfile_igetl(f);
+ if (offset) {
+ component[n_components].type = IT_COMPONENT_PATTERN;
+ component[n_components].n = n;
+ component[n_components].offset = offset;
+ component[n_components].sampfirst = -1;
+ n_components++;
+ } else {
+ /* Empty 64-row pattern */
+ sigdata->pattern[n].n_rows = 64;
+ sigdata->pattern[n].n_entries = 0;
+ }
+ }
+
+ if (dumbfile_error(f)) {
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ /*
+ if (!(sigdata->flags & 128) != !(special & 8)) {
+ fprintf(stderr, "Flags Bit 7 (\"Request embedded MIDI configuration\"): %s\n", sigdata->flags & 128 ? "=SET=" : "clear");
+ fprintf(stderr, "Special Bit 3 (\"MIDI configuration embedded\") : %s\n", special & 8 ? "=SET=" : "clear");
+ fprintf(stderr, "entheh would like to investigate this IT file.\n");
+ fprintf(stderr, "Please contact him! entheh@users.sf.net\n");
+ }
+ */
+
+ if (special & 8) {
+ /* MIDI configuration is embedded. */
+ unsigned char mididata[32];
+ int i;
+ sigdata->midi = malloc(sizeof(*sigdata->midi));
+ if (!sigdata->midi) {
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ // Should we be happy with this outcome in some situations?
+ }
+ // What are we skipping?
+ i = dumbfile_igetw(f);
+ if (dumbfile_error(f) || dumbfile_skip(f, 8*i)) {
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ /* Read embedded MIDI configuration */
+ // What are the first 9 commands for?
+ if (dumbfile_skip(f, 32*9)) {
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (i = 0; i < 16; i++) {
+ unsigned char len = 0;
+ int j, leftdigit = -1;
+ if (dumbfile_getnc(mididata, 32, f) < 32) {
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ sigdata->midi->SFmacroz[i] = 0;
+ for (j = 0; j < 32; j++) {
+ if (leftdigit >= 0) {
+ if (mididata[j] == 0) {
+ sigdata->midi->SFmacro[i][len++] = leftdigit;
+ break;
+ } else if (mididata[j] == ' ')
+ sigdata->midi->SFmacro[i][len++] = leftdigit;
+ else if (mididata[j] >= '0' && mididata[j] <= '9')
+ sigdata->midi->SFmacro[i][len++] = (leftdigit << 4) | (mididata[j] - '0');
+ else if (mididata[j] >= 'A' && mididata[j] <= 'F')
+ sigdata->midi->SFmacro[i][len++] = (leftdigit << 4) | (mididata[j] - 'A' + 0xA);
+ leftdigit = -1;
+ } else if (mididata[j] == 0)
+ break;
+ else if (mididata[j] == 'z')
+ sigdata->midi->SFmacroz[i] |= 1 << len++;
+ else if (mididata[j] >= '0' && mididata[j] <= '9')
+ leftdigit = mididata[j] - '0';
+ else if (mididata[j] >= 'A' && mididata[j] <= 'F')
+ leftdigit = mididata[j] - 'A' + 0xA;
+ }
+ sigdata->midi->SFmacrolen[i] = len;
+ }
+ for (i = 0; i < 128; i++) {
+ unsigned char len = 0;
+ int j, leftdigit = -1;
+ dumbfile_getnc(mididata, 32, f);
+ for (j = 0; j < 32; j++) {
+ if (leftdigit >= 0) {
+ if (mididata[j] == 0) {
+ sigdata->midi->Zmacro[i][len++] = leftdigit;
+ break;
+ } else if (mididata[j] == ' ')
+ sigdata->midi->Zmacro[i][len++] = leftdigit;
+ else if (mididata[j] >= '0' && mididata[j] <= '9')
+ sigdata->midi->Zmacro[i][len++] = (leftdigit << 4) | (mididata[j] - '0');
+ else if (mididata[j] >= 'A' && mididata[j] <= 'F')
+ sigdata->midi->Zmacro[i][len++] = (leftdigit << 4) | (mididata[j] - 'A' + 0xA);
+ leftdigit = -1;
+ } else if (mididata[j] == 0)
+ break;
+ else if (mididata[j] >= '0' && mididata[j] <= '9')
+ leftdigit = mididata[j] - '0';
+ else if (mididata[j] >= 'A' && mididata[j] <= 'F')
+ leftdigit = mididata[j] - 'A' + 0xA;
+ }
+ sigdata->midi->Zmacrolen[i] = len;
+ }
+ }
+
+ sigdata->flags &= IT_REAL_FLAGS;
+
+ qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare);
+
+ buffer = malloc(65536);
+ if (!buffer) {
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ for (n = 0; n < n_components; n++) {
+ long offset;
+ int m;
+
+ /* XXX */
+ if ( component[n].offset == 0 ) {
+ switch (component[n].type) {
+ case IT_COMPONENT_INSTRUMENT:
+ memset( &sigdata->instrument[component[n].n], 0, sizeof(IT_INSTRUMENT) );
+ break;
+ case IT_COMPONENT_SAMPLE:
+ memset( &sigdata->sample[component[n].n], 0, sizeof(IT_SAMPLE) );
+ break;
+ case IT_COMPONENT_PATTERN:
+ {
+ IT_PATTERN * p = &sigdata->pattern[component[n].n];
+ p->entry = 0;
+ p->n_rows = 64;
+ p->n_entries = 0;
+ }
+ break;
+ }
+ continue;
+ }
+
+ if (it_seek(f, component[n].offset)) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ switch (component[n].type) {
+
+ case IT_COMPONENT_SONG_MESSAGE:
+ sigdata->song_message = malloc(message_length + 1);
+ if (sigdata->song_message) {
+ if (dumbfile_getnc(sigdata->song_message, message_length, f) < message_length) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ sigdata->song_message[message_length] = 0;
+ }
+ break;
+
+ case IT_COMPONENT_INSTRUMENT:
+ if (cmwt < 0x200)
+ m = it_read_old_instrument(&sigdata->instrument[component[n].n], f);
+ else
+ m = it_read_instrument(&sigdata->instrument[component[n].n], f, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0);
+
+ if (m) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ break;
+
+ case IT_COMPONENT_PATTERN:
+ if (it_read_pattern(&sigdata->pattern[component[n].n], f, buffer)) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ break;
+
+ case IT_COMPONENT_SAMPLE:
+ if (it_read_sample_header(&sigdata->sample[component[n].n], &sample_convert[component[n].n], &offset, f)) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ if (sigdata->sample[component[n].n].flags & IT_SAMPLE_EXISTS) {
+ short *sample;
+
+ for (m = n + 1; m < n_components; m++)
+ if (component[m].offset > offset)
+ break;
+ m--;
+
+ sample = &component[m].sampfirst;
+
+ while (*sample >= 0 && component[*sample].offset <= offset)
+ sample = &component[*sample].sampnext;
+
+ component[n].sampnext = *sample;
+ *sample = n;
+
+ component[n].offset = offset;
+ }
+ }
+
+ m = component[n].sampfirst;
+
+ while (m >= 0) {
+ if (it_seek(f, component[m].offset)) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ if (it_read_sample_data(cmwt, &sigdata->sample[component[m].n], sample_convert[component[m].n], f)) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ m = component[m].sampnext;
+ }
+ }
+
+ free(buffer);
+ free(component);
+
+ _dumb_it_fix_invalid_orders(sigdata);
+
+ return sigdata;
+}
+
+DUH *dumb_read_it_quick(DUMBFILE *f)
+{
+ sigdata_t *sigdata;
+
+ DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
+
+ sigdata = it_load_sigdata(f);
+
+ if (!sigdata)
+ return NULL;
+
+ {
+ const char *tag[1][2];
+ tag[0][0] = "TITLE";
+ tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+ return make_duh(-1, 1, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/itread2.c b/plugins/dumb/dumb-kode54/src/it/itread2.c
index 202b8bb9..e152737e 100644
--- a/plugins/dumb/dumb-kode54/src/it/itread2.c
+++ b/plugins/dumb/dumb-kode54/src/it/itread2.c
@@ -1,29 +1,29 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * itread2.c - Function to read an Impulse Tracker / / \ \
- * module from an open file and do an | < / \_
- * initial run-through. | \/ /\ /
- * \_ / > /
- * Split off from itread.c by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_read_it(DUMBFILE *f)
-{
- DUH *duh = dumb_read_it_quick(f);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * itread2.c - Function to read an Impulse Tracker / / \ \
+ * module from an open file and do an | < / \_
+ * initial run-through. | \/ /\ /
+ * \_ / > /
+ * Split off from itread.c by entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_read_it(DUMBFILE *f)
+{
+ DUH *duh = dumb_read_it_quick(f);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/itrender.c b/plugins/dumb/dumb-kode54/src/it/itrender.c
index 5dd8e4ef..d1ffc559 100644
--- a/plugins/dumb/dumb-kode54/src/it/itrender.c
+++ b/plugins/dumb/dumb-kode54/src/it/itrender.c
@@ -500,7 +500,6 @@ static void it_reset_filter_state(IT_FILTER_STATE *state)
* output starting at dst[pos]. The pos parameter is required for getting
* click removal right.
*/
-
static void it_filter(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, long pos, sample_t *src, long size, int step, int sampfreq, int cutoff, int resonance)
{
sample_t currsample = state->currsample;
@@ -732,7 +731,6 @@ static void reset_tick_counts(DUMB_IT_SIGRENDERER *sigrenderer)
}
-
static void reset_channel_effects(IT_CHANNEL *channel)
{
channel->volslide = 0;
@@ -1058,6 +1056,24 @@ static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer)
}
}
+ if (channel->panslide && !IT_IS_SURROUND(channel->pan)) {
+ if (sigrenderer->sigdata->flags & IT_WAS_AN_XM) {
+ if (channel->panslide == -128)
+ channel->truepan = 32;
+ else
+ channel->truepan = MID(32, channel->truepan + channel->panslide*64, 32+255*64);
+ } else {
+ channel->pan += channel->panslide;
+ if (channel->pan > 64) {
+ if (channel->panslide >= 0)
+ channel->pan = 64;
+ else
+ channel->pan = 0;
+ }
+ channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
+ }
+ }
+
if (channel->channelvolslide) {
channel->channelvolume += channel->channelvolslide;
if (channel->channelvolume > 64) {
@@ -1685,6 +1701,12 @@ static void get_default_volpan(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel)
return;
}
+ if (sigdata->flags & IT_WAS_AN_XM) {
+ if (!(sigdata->flags & IT_WAS_A_MOD))
+ channel->truepan = 32 + sigdata->sample[channel->sample-1].default_pan*64;
+ return;
+ }
+
{
int pan = sigdata->sample[channel->sample-1].default_pan;
if (pan >= 128 && pan <= 192) {
@@ -5540,3 +5562,4 @@ int dumb_it_scan_for_playable_orders(DUMB_IT_SIGDATA *sigdata, dumb_scan_callbac
return 0;
}
+
diff --git a/plugins/dumb/dumb-kode54/src/it/itunload.c b/plugins/dumb/dumb-kode54/src/it/itunload.c
index 136fd5c5..efed192a 100644
--- a/plugins/dumb/dumb-kode54/src/it/itunload.c
+++ b/plugins/dumb/dumb-kode54/src/it/itunload.c
@@ -1,72 +1,72 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * itunload.c - Code to free an Impulse Tracker / / \ \
- * module from memory. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-void _dumb_it_unload_sigdata(sigdata_t *vsigdata)
-{
- if (vsigdata) {
- DUMB_IT_SIGDATA *sigdata = vsigdata;
- int n;
-
- if (sigdata->song_message)
- free(sigdata->song_message);
-
- if (sigdata->order)
- free(sigdata->order);
-
- if (sigdata->instrument)
- free(sigdata->instrument);
-
- if (sigdata->sample) {
- for (n = 0; n < sigdata->n_samples; n++)
- if (sigdata->sample[n].data)
- free(sigdata->sample[n].data);
-
- free(sigdata->sample);
- }
-
- if (sigdata->pattern) {
- for (n = 0; n < sigdata->n_patterns; n++)
- if (sigdata->pattern[n].entry)
- free(sigdata->pattern[n].entry);
- free(sigdata->pattern);
- }
-
- if (sigdata->midi)
- free(sigdata->midi);
-
- {
- IT_CHECKPOINT *checkpoint = sigdata->checkpoint;
- while (checkpoint) {
- IT_CHECKPOINT *next = checkpoint->next;
- _dumb_it_end_sigrenderer(checkpoint->sigrenderer);
- free(checkpoint);
- checkpoint = next;
- }
- }
-
- free(vsigdata);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * itunload.c - Code to free an Impulse Tracker / / \ \
+ * module from memory. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+void _dumb_it_unload_sigdata(sigdata_t *vsigdata)
+{
+ if (vsigdata) {
+ DUMB_IT_SIGDATA *sigdata = vsigdata;
+ int n;
+
+ if (sigdata->song_message)
+ free(sigdata->song_message);
+
+ if (sigdata->order)
+ free(sigdata->order);
+
+ if (sigdata->instrument)
+ free(sigdata->instrument);
+
+ if (sigdata->sample) {
+ for (n = 0; n < sigdata->n_samples; n++)
+ if (sigdata->sample[n].data)
+ free(sigdata->sample[n].data);
+
+ free(sigdata->sample);
+ }
+
+ if (sigdata->pattern) {
+ for (n = 0; n < sigdata->n_patterns; n++)
+ if (sigdata->pattern[n].entry)
+ free(sigdata->pattern[n].entry);
+ free(sigdata->pattern);
+ }
+
+ if (sigdata->midi)
+ free(sigdata->midi);
+
+ {
+ IT_CHECKPOINT *checkpoint = sigdata->checkpoint;
+ while (checkpoint) {
+ IT_CHECKPOINT *next = checkpoint->next;
+ _dumb_it_end_sigrenderer(checkpoint->sigrenderer);
+ free(checkpoint);
+ checkpoint = next;
+ }
+ }
+
+ free(vsigdata);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/load669.c b/plugins/dumb/dumb-kode54/src/it/load669.c
index e5a3fc3f..5fbe92c8 100644
--- a/plugins/dumb/dumb-kode54/src/it/load669.c
+++ b/plugins/dumb/dumb-kode54/src/it/load669.c
@@ -1,42 +1,42 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadmod.c - Code to read a 669 Composer module / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By Chris Moeller | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_669_quick(): loads a 669 file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_669_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_669_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadmod.c - Code to read a 669 Composer module / / \ \
+ * file, opening and closing it for | < / \_
+ * you. | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_669_quick(): loads a 669 file into a DUH struct, returning a
+ * pointer to the DUH struct. When you have finished with it, you must
+ * pass the pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_669_quick(const char *filename)
+{
+ DUH *duh;
+ DUMBFILE *f = dumbfile_open(filename);
+
+ if (!f)
+ return NULL;
+
+ duh = dumb_read_669_quick(f);
+
+ dumbfile_close(f);
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/load6692.c b/plugins/dumb/dumb-kode54/src/it/load6692.c
index 2358838f..20a18012 100644
--- a/plugins/dumb/dumb-kode54/src/it/load6692.c
+++ b/plugins/dumb/dumb-kode54/src/it/load6692.c
@@ -1,34 +1,34 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadmod2.c - Code to read a 669 Composer module / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * By Chris Moeller | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_669(): loads a 669 file into a DUH struct, returning a pointer
- * to the DUH struct. When you have finished with it, you must pass the
- * pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_669(const char *filename)
-{
- DUH *duh = dumb_load_669_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadmod2.c - Code to read a 669 Composer module / / \ \
+ * file, opening and closing it for | < / \_
+ * you, and do an initial run-through. | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_669(): loads a 669 file into a DUH struct, returning a pointer
+ * to the DUH struct. When you have finished with it, you must pass the
+ * pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_669(const char *filename)
+{
+ DUH *duh = dumb_load_669_quick(filename);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadasy.c b/plugins/dumb/dumb-kode54/src/it/loadasy.c
index 86c6ad8c..1bd481af 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadasy.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadasy.c
@@ -1,42 +1,42 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadasy.c - Code to read an ASYLUM Music Format / / \ \
- * module file, opening and closing it | < / \_
- * for you. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_asy_quick(): loads a AMF file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_asy_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_asy_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadasy.c - Code to read an ASYLUM Music Format / / \ \
+ * module file, opening and closing it | < / \_
+ * for you. | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_asy_quick(): loads a AMF file into a DUH struct, returning a
+ * pointer to the DUH struct. When you have finished with it, you must
+ * pass the pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_asy_quick(const char *filename)
+{
+ DUH *duh;
+ DUMBFILE *f = dumbfile_open(filename);
+
+ if (!f)
+ return NULL;
+
+ duh = dumb_read_asy_quick(f);
+
+ dumbfile_close(f);
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadasy2.c b/plugins/dumb/dumb-kode54/src/it/loadasy2.c
index 7b253320..845b26cb 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadasy2.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadasy2.c
@@ -1,34 +1,34 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadasy2.c - Code to read an ASYLUM Music Format / / \ \
- * module file, opening and closing it | < / \_
- * for you, and do an initial run- | \/ /\ /
- * through. \_ / > /
- * | \ / /
- * By Chris Moeller. | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_asy(): loads a AMF file into a DUH struct, returning a pointer
- * to the DUH struct. When you have finished with it, you must pass the
- * pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_asy(const char *filename)
-{
- DUH *duh = dumb_load_asy_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadasy2.c - Code to read an ASYLUM Music Format / / \ \
+ * module file, opening and closing it | < / \_
+ * for you, and do an initial run- | \/ /\ /
+ * through. \_ / > /
+ * | \ / /
+ * By Chris Moeller. | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_asy(): loads a AMF file into a DUH struct, returning a pointer
+ * to the DUH struct. When you have finished with it, you must pass the
+ * pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_asy(const char *filename)
+{
+ DUH *duh = dumb_load_asy_quick(filename);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadmod.c b/plugins/dumb/dumb-kode54/src/it/loadmod.c
index 1c76302d..0b7dc618 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadmod.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadmod.c
@@ -1,42 +1,42 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadmod.c - Code to read a good old-fashioned / / \ \
- * Amiga module file, opening and | < / \_
- * closing it for you. | \/ /\ /
- * \_ / > /
- * By entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_mod_quick(): loads a MOD file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_mod_quick(const char *filename, int restrict)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_mod_quick(f, restrict);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadmod.c - Code to read a good old-fashioned / / \ \
+ * Amiga module file, opening and | < / \_
+ * closing it for you. | \/ /\ /
+ * \_ / > /
+ * By entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_mod_quick(): loads a MOD file into a DUH struct, returning a
+ * pointer to the DUH struct. When you have finished with it, you must
+ * pass the pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_mod_quick(const char *filename, int restrict)
+{
+ DUH *duh;
+ DUMBFILE *f = dumbfile_open(filename);
+
+ if (!f)
+ return NULL;
+
+ duh = dumb_read_mod_quick(f, restrict);
+
+ dumbfile_close(f);
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadmod2.c b/plugins/dumb/dumb-kode54/src/it/loadmod2.c
index f5ca5310..7847d19f 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadmod2.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadmod2.c
@@ -1,29 +1,29 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadmod2.c - Function to read a good old- / / \ \
- * fashioned Amiga module file, | < / \_
- * opening and closing it for you, | \/ /\ /
- * and do an initial run-through. \_ / > /
- * | \ / /
- * Split off from loadmod.c by entheh. | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_load_mod(const char *filename, int restrict)
-{
- DUH *duh = dumb_load_mod_quick(filename, restrict);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadmod2.c - Function to read a good old- / / \ \
+ * fashioned Amiga module file, | < / \_
+ * opening and closing it for you, | \/ /\ /
+ * and do an initial run-through. \_ / > /
+ * | \ / /
+ * Split off from loadmod.c by entheh. | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_load_mod(const char *filename, int restrict)
+{
+ DUH *duh = dumb_load_mod_quick(filename, restrict);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadmtm.c b/plugins/dumb/dumb-kode54/src/it/loadmtm.c
index 3c974880..1cfe4643 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadmtm.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadmtm.c
@@ -1,42 +1,42 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadmtm.c - Code to read a MultiTracker Module / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By Chris Moeller | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_mtm_quick(): loads a MTM file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_mtm_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_mtm_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadmtm.c - Code to read a MultiTracker Module / / \ \
+ * file, opening and closing it for | < / \_
+ * you. | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_mtm_quick(): loads a MTM file into a DUH struct, returning a
+ * pointer to the DUH struct. When you have finished with it, you must
+ * pass the pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_mtm_quick(const char *filename)
+{
+ DUH *duh;
+ DUMBFILE *f = dumbfile_open(filename);
+
+ if (!f)
+ return NULL;
+
+ duh = dumb_read_mtm_quick(f);
+
+ dumbfile_close(f);
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadmtm2.c b/plugins/dumb/dumb-kode54/src/it/loadmtm2.c
index 9fc23890..11c0c567 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadmtm2.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadmtm2.c
@@ -1,34 +1,34 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadmtm2.c - Code to read a MultiTracker Module / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * By Chris Moeller | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_mtm(): loads a MTM file into a DUH struct, returning a pointer
- * to the DUH struct. When you have finished with it, you must pass the
- * pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_mtm(const char *filename)
-{
- DUH *duh = dumb_load_mtm_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadmtm2.c - Code to read a MultiTracker Module / / \ \
+ * file, opening and closing it for | < / \_
+ * you, and do an initial run-through. | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_mtm(): loads a MTM file into a DUH struct, returning a pointer
+ * to the DUH struct. When you have finished with it, you must pass the
+ * pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_mtm(const char *filename)
+{
+ DUH *duh = dumb_load_mtm_quick(filename);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadoldpsm.c b/plugins/dumb/dumb-kode54/src/it/loadoldpsm.c
index 547294b3..568d1af6 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadoldpsm.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadoldpsm.c
@@ -1,43 +1,43 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadoldpsm.c - Code to read a ProTracker Studio / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_old_psm_quick(): loads an old PSM file into a DUH struct,
- * returning a pointer to the DUH struct. When you have finished with it,
- * you must pass the pointer to unload_duh() so that the memory can be
- * freed.
- */
-DUH *dumb_load_old_psm_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_old_psm_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadoldpsm.c - Code to read a ProTracker Studio / / \ \
+ * file, opening and closing it for | < / \_
+ * you. | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_old_psm_quick(): loads an old PSM file into a DUH struct,
+ * returning a pointer to the DUH struct. When you have finished with it,
+ * you must pass the pointer to unload_duh() so that the memory can be
+ * freed.
+ */
+DUH *dumb_load_old_psm_quick(const char *filename)
+{
+ DUH *duh;
+ DUMBFILE *f = dumbfile_open(filename);
+
+ if (!f)
+ return NULL;
+
+ duh = dumb_read_old_psm_quick(f);
+
+ dumbfile_close(f);
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadoldpsm2.c b/plugins/dumb/dumb-kode54/src/it/loadoldpsm2.c
index ff2e427c..f9aaaed6 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadoldpsm2.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadoldpsm2.c
@@ -1,34 +1,34 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadoldpsm2.c - Code to read a ProTracker Studio / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run- | \/ /\ /
- * through. \_ / > /
- * | \ / /
- * By Chris Moeller. | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_old_psm(): loads an old PSM file into a DUH struct, returning
- * a pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_old_psm(const char *filename)
-{
- DUH *duh = dumb_load_old_psm_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadoldpsm2.c - Code to read a ProTracker Studio / / \ \
+ * file, opening and closing it for | < / \_
+ * you, and do an initial run- | \/ /\ /
+ * through. \_ / > /
+ * | \ / /
+ * By Chris Moeller. | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_old_psm(): loads an old PSM file into a DUH struct, returning
+ * a pointer to the DUH struct. When you have finished with it, you must
+ * pass the pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_old_psm(const char *filename)
+{
+ DUH *duh = dumb_load_old_psm_quick(filename);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadpsm.c b/plugins/dumb/dumb-kode54/src/it/loadpsm.c
index a6851d5b..9f2e81ef 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadpsm.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadpsm.c
@@ -1,42 +1,42 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadpsm.c - Code to read a ProTracker Studio / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_psm_quick(): loads a PSM file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_psm_quick(const char *filename, int subsong)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_psm_quick(f, subsong);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadpsm.c - Code to read a ProTracker Studio / / \ \
+ * file, opening and closing it for | < / \_
+ * you. | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_psm_quick(): loads a PSM file into a DUH struct, returning a
+ * pointer to the DUH struct. When you have finished with it, you must
+ * pass the pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_psm_quick(const char *filename, int subsong)
+{
+ DUH *duh;
+ DUMBFILE *f = dumbfile_open(filename);
+
+ if (!f)
+ return NULL;
+
+ duh = dumb_read_psm_quick(f, subsong);
+
+ dumbfile_close(f);
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadpsm2.c b/plugins/dumb/dumb-kode54/src/it/loadpsm2.c
index 7a12257a..d6fa4359 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadpsm2.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadpsm2.c
@@ -1,34 +1,34 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadpsm2.c - Code to read a ProTracker Studio / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_psm(): loads a PSM file into a DUH struct, returning a pointer
- * to the DUH struct. When you have finished with it, you must pass the
- * pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_psm(const char *filename, int subsong)
-{
- DUH *duh = dumb_load_psm_quick(filename, subsong);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadpsm2.c - Code to read a ProTracker Studio / / \ \
+ * file, opening and closing it for | < / \_
+ * you, and do an initial run-through. | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_psm(): loads a PSM file into a DUH struct, returning a pointer
+ * to the DUH struct. When you have finished with it, you must pass the
+ * pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_psm(const char *filename, int subsong)
+{
+ DUH *duh = dumb_load_psm_quick(filename, subsong);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadptm.c b/plugins/dumb/dumb-kode54/src/it/loadptm.c
index ddcaaec9..2a3e0fc1 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadptm.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadptm.c
@@ -1,42 +1,42 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadptm.c - Code to read a Poly Tracker v2.03 / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_ptm_quick(): loads a PTM file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_ptm_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_ptm_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadptm.c - Code to read a Poly Tracker v2.03 / / \ \
+ * file, opening and closing it for | < / \_
+ * you. | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_ptm_quick(): loads a PTM file into a DUH struct, returning a
+ * pointer to the DUH struct. When you have finished with it, you must
+ * pass the pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_ptm_quick(const char *filename)
+{
+ DUH *duh;
+ DUMBFILE *f = dumbfile_open(filename);
+
+ if (!f)
+ return NULL;
+
+ duh = dumb_read_ptm_quick(f);
+
+ dumbfile_close(f);
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadptm2.c b/plugins/dumb/dumb-kode54/src/it/loadptm2.c
index ea8982f2..4befb3b6 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadptm2.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadptm2.c
@@ -1,34 +1,34 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadptm2.c - Code to read a Poly Tracker v2.03 / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_ptm(): loads a PTM file into a DUH struct, returning a pointer
- * to the DUH struct. When you have finished with it, you must pass the
- * pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_ptm(const char *filename)
-{
- DUH *duh = dumb_load_ptm_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadptm2.c - Code to read a Poly Tracker v2.03 / / \ \
+ * file, opening and closing it for | < / \_
+ * you, and do an initial run-through. | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_ptm(): loads a PTM file into a DUH struct, returning a pointer
+ * to the DUH struct. When you have finished with it, you must pass the
+ * pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_ptm(const char *filename)
+{
+ DUH *duh = dumb_load_ptm_quick(filename);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadriff.c b/plugins/dumb/dumb-kode54/src/it/loadriff.c
index 07994b0f..edaf43a6 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadriff.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadriff.c
@@ -1,42 +1,42 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadriff.c - Code to read a RIFF module file / / \ \
- * opening and closing it for you. | < / \_
- * | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_riff_quick(): loads a RIFF file into a DUH struct, returning
- * a pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH * dumb_load_riff_quick( const char *filename )
-{
- DUH * duh;
- DUMBFILE * f = dumbfile_open( filename );
-
- if ( ! f )
- return NULL;
-
- duh = dumb_read_riff_quick( f );
-
- dumbfile_close( f );
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadriff.c - Code to read a RIFF module file / / \ \
+ * opening and closing it for you. | < / \_
+ * | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_riff_quick(): loads a RIFF file into a DUH struct, returning
+ * a pointer to the DUH struct. When you have finished with it, you must
+ * pass the pointer to unload_duh() so that the memory can be freed.
+ */
+DUH * dumb_load_riff_quick( const char *filename )
+{
+ DUH * duh;
+ DUMBFILE * f = dumbfile_open( filename );
+
+ if ( ! f )
+ return NULL;
+
+ duh = dumb_read_riff_quick( f );
+
+ dumbfile_close( f );
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadriff2.c b/plugins/dumb/dumb-kode54/src/it/loadriff2.c
index 11c5d497..5745041e 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadriff2.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadriff2.c
@@ -1,29 +1,29 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadriff2.c - Code to read a RIFF module file / / \ \
- * opening and closing it for you, | < / \_
- * and do an initial run-through. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_load_riff(const char *filename)
-{
- DUH *duh = dumb_load_riff_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadriff2.c - Code to read a RIFF module file / / \ \
+ * opening and closing it for you, | < / \_
+ * and do an initial run-through. | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_load_riff(const char *filename)
+{
+ DUH *duh = dumb_load_riff_quick(filename);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loads3m.c b/plugins/dumb/dumb-kode54/src/it/loads3m.c
index 41af114e..777151c6 100644
--- a/plugins/dumb/dumb-kode54/src/it/loads3m.c
+++ b/plugins/dumb/dumb-kode54/src/it/loads3m.c
@@ -1,42 +1,42 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loads3m.c - Code to read a ScreamTracker 3 / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_s3m_quick(): loads an S3M file into a DUH struct, returning
- * a pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_s3m_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_s3m_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loads3m.c - Code to read a ScreamTracker 3 / / \ \
+ * file, opening and closing it for | < / \_
+ * you. | \/ /\ /
+ * \_ / > /
+ * By entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_s3m_quick(): loads an S3M file into a DUH struct, returning
+ * a pointer to the DUH struct. When you have finished with it, you must
+ * pass the pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_s3m_quick(const char *filename)
+{
+ DUH *duh;
+ DUMBFILE *f = dumbfile_open(filename);
+
+ if (!f)
+ return NULL;
+
+ duh = dumb_read_s3m_quick(f);
+
+ dumbfile_close(f);
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loads3m2.c b/plugins/dumb/dumb-kode54/src/it/loads3m2.c
index de81e09a..8b55e83d 100644
--- a/plugins/dumb/dumb-kode54/src/it/loads3m2.c
+++ b/plugins/dumb/dumb-kode54/src/it/loads3m2.c
@@ -1,29 +1,29 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loads3m2.c - Function to read a ScreamTracker 3 / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * Split off from loads3m.c by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_load_s3m(const char *filename)
-{
- DUH *duh = dumb_load_s3m_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loads3m2.c - Function to read a ScreamTracker 3 / / \ \
+ * file, opening and closing it for | < / \_
+ * you, and do an initial run-through. | \/ /\ /
+ * \_ / > /
+ * Split off from loads3m.c by entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_load_s3m(const char *filename)
+{
+ DUH *duh = dumb_load_s3m_quick(filename);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadstm.c b/plugins/dumb/dumb-kode54/src/it/loadstm.c
index 84785208..94e713c3 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadstm.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadstm.c
@@ -1,42 +1,42 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadstm.c - Code to read a ScreamTracker 2 / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_stm_quick(): loads an STM file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_stm_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_stm_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadstm.c - Code to read a ScreamTracker 2 / / \ \
+ * file, opening and closing it for | < / \_
+ * you. | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_stm_quick(): loads an STM file into a DUH struct, returning a
+ * pointer to the DUH struct. When you have finished with it, you must
+ * pass the pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_stm_quick(const char *filename)
+{
+ DUH *duh;
+ DUMBFILE *f = dumbfile_open(filename);
+
+ if (!f)
+ return NULL;
+
+ duh = dumb_read_stm_quick(f);
+
+ dumbfile_close(f);
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadstm2.c b/plugins/dumb/dumb-kode54/src/it/loadstm2.c
index 4655b52d..ca0f134d 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadstm2.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadstm2.c
@@ -1,29 +1,29 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadstm2.c - Function to read a ScreamTracker 2 / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_load_stm(const char *filename)
-{
- DUH *duh = dumb_load_stm_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadstm2.c - Function to read a ScreamTracker 2 / / \ \
+ * file, opening and closing it for | < / \_
+ * you, and do an initial run-through. | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_load_stm(const char *filename)
+{
+ DUH *duh = dumb_load_stm_quick(filename);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadxm.c b/plugins/dumb/dumb-kode54/src/it/loadxm.c
index a0eba616..2c8067cb 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadxm.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadxm.c
@@ -1,42 +1,42 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadxm.c - Code to read a Fast Tracker II / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_xm_quick(): loads an XM file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_xm_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_xm_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadxm.c - Code to read a Fast Tracker II / / \ \
+ * file, opening and closing it for | < / \_
+ * you. | \/ /\ /
+ * \_ / > /
+ * By entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_xm_quick(): loads an XM file into a DUH struct, returning a
+ * pointer to the DUH struct. When you have finished with it, you must
+ * pass the pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_load_xm_quick(const char *filename)
+{
+ DUH *duh;
+ DUMBFILE *f = dumbfile_open(filename);
+
+ if (!f)
+ return NULL;
+
+ duh = dumb_read_xm_quick(f);
+
+ dumbfile_close(f);
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/loadxm2.c b/plugins/dumb/dumb-kode54/src/it/loadxm2.c
index 242a586d..a596542a 100644
--- a/plugins/dumb/dumb-kode54/src/it/loadxm2.c
+++ b/plugins/dumb/dumb-kode54/src/it/loadxm2.c
@@ -1,29 +1,29 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadxm2.c - Function to read a Fast Tracker II / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * Split off from loadxm.c by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_load_xm(const char *filename)
-{
- DUH *duh = dumb_load_xm_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * loadxm2.c - Function to read a Fast Tracker II / / \ \
+ * file, opening and closing it for | < / \_
+ * you, and do an initial run-through. | \/ /\ /
+ * \_ / > /
+ * Split off from loadxm.c by entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_load_xm(const char *filename)
+{
+ DUH *duh = dumb_load_xm_quick(filename);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/ptmeffect.c b/plugins/dumb/dumb-kode54/src/it/ptmeffect.c
index b05a5d74..cbc2e90c 100644
--- a/plugins/dumb/dumb-kode54/src/it/ptmeffect.c
+++ b/plugins/dumb/dumb-kode54/src/it/ptmeffect.c
@@ -1,125 +1,125 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * ptmeffect.c - Code for converting PTM / / \ \
- * effects to IT effects. | < / \_
- * | \/ /\ /
- * By Chris Moeller. Based on xmeffect.c \_ / > /
- * by Julien Cugniere. | \ / /
- * | ' /
- * \__/
- */
-
-
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-void _dumb_it_ptm_convert_effect(int effect, int value, IT_ENTRY *entry)
-{
- if (effect >= PTM_N_EFFECTS)
- return;
-
- /* Linearisation of the effect number... */
- if (effect == PTM_E) {
- effect = PTM_EBASE + HIGH(value);
- value = LOW(value);
- }
-
- /* convert effect */
- entry->mask |= IT_ENTRY_EFFECT;
- switch (effect) {
-
- case PTM_APPREGIO: effect = IT_ARPEGGIO; break;
- case PTM_PORTAMENTO_UP: effect = IT_PORTAMENTO_UP; break;
- case PTM_PORTAMENTO_DOWN: effect = IT_PORTAMENTO_DOWN; break;
- case PTM_TONE_PORTAMENTO: effect = IT_TONE_PORTAMENTO; break;
- case PTM_VIBRATO: effect = IT_VIBRATO; break;
- case PTM_VOLSLIDE_TONEPORTA: effect = IT_VOLSLIDE_TONEPORTA; break;
- case PTM_VOLSLIDE_VIBRATO: effect = IT_VOLSLIDE_VIBRATO; break;
- case PTM_TREMOLO: effect = IT_TREMOLO; break;
- case PTM_SAMPLE_OFFSET: effect = IT_SET_SAMPLE_OFFSET; break;
- case PTM_VOLUME_SLIDE: effect = IT_VOLUME_SLIDE; break;
- case PTM_POSITION_JUMP: effect = IT_JUMP_TO_ORDER; break;
- case PTM_SET_CHANNEL_VOLUME: effect = IT_SET_CHANNEL_VOLUME; break;
- case PTM_PATTERN_BREAK: effect = IT_BREAK_TO_ROW; break;
- case PTM_SET_GLOBAL_VOLUME: effect = IT_SET_GLOBAL_VOLUME; break;
- case PTM_RETRIGGER: effect = IT_RETRIGGER_NOTE; break;
- case PTM_FINE_VIBRATO: effect = IT_FINE_VIBRATO; break;
-
- /* TODO properly */
- case PTM_NOTE_SLIDE_UP: effect = IT_PTM_NOTE_SLIDE_UP; break;
- case PTM_NOTE_SLIDE_DOWN: effect = IT_PTM_NOTE_SLIDE_DOWN; break;
- case PTM_NOTE_SLIDE_UP_RETRIG: effect = IT_PTM_NOTE_SLIDE_UP_RETRIG; break;
- case PTM_NOTE_SLIDE_DOWN_RETRIG: effect = IT_PTM_NOTE_SLIDE_DOWN_RETRIG; break;
-
- case PTM_SET_TEMPO_BPM:
- effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
- break;
-
- case PTM_EBASE+PTM_E_SET_FINETUNE: effect = SBASE+IT_S_FINETUNE; break; /** TODO */
- case PTM_EBASE+PTM_E_SET_LOOP: effect = SBASE+IT_S_PATTERN_LOOP; break;
- case PTM_EBASE+PTM_E_NOTE_CUT: effect = SBASE+IT_S_DELAYED_NOTE_CUT; break;
- case PTM_EBASE+PTM_E_NOTE_DELAY: effect = SBASE+IT_S_NOTE_DELAY; break;
- case PTM_EBASE+PTM_E_PATTERN_DELAY: effect = SBASE+IT_S_PATTERN_DELAY; break;
- case PTM_EBASE+PTM_E_SET_PANNING: effect = SBASE+IT_S_SET_PAN; break;
-
- case PTM_EBASE+PTM_E_FINE_VOLSLIDE_UP:
- effect = IT_VOLUME_SLIDE;
- value = EFFECT_VALUE(value, 0xF);
- break;
-
- case PTM_EBASE + PTM_E_FINE_VOLSLIDE_DOWN:
- effect = IT_VOLUME_SLIDE;
- value = EFFECT_VALUE(0xF, value);
- break;
-
- case PTM_EBASE + PTM_E_FINE_PORTA_UP:
- effect = IT_PORTAMENTO_UP;
- value = EFFECT_VALUE(0xF, value);
- break;
-
- case PTM_EBASE + PTM_E_FINE_PORTA_DOWN:
- effect = IT_PORTAMENTO_DOWN;
- value = EFFECT_VALUE(0xF, value);
- break;
-
- case PTM_EBASE + PTM_E_RETRIG_NOTE:
- effect = IT_XM_RETRIGGER_NOTE;
- value = EFFECT_VALUE(0, value);
- break;
-
- case PTM_EBASE + PTM_E_SET_VIBRATO_CONTROL:
- effect = SBASE+IT_S_SET_VIBRATO_WAVEFORM;
- value &= ~4; /** TODO: value&4 -> don't retrig wave */
- break;
-
- case PTM_EBASE + PTM_E_SET_TREMOLO_CONTROL:
- effect = SBASE+IT_S_SET_TREMOLO_WAVEFORM;
- value &= ~4; /** TODO: value&4 -> don't retrig wave */
- break;
-
- default:
- /* user effect (often used in demos for synchronisation) */
- entry->mask &= ~IT_ENTRY_EFFECT;
- }
-
- /* Inverse linearisation... */
- if (effect >= SBASE && effect < SBASE+16) {
- value = EFFECT_VALUE(effect-SBASE, value);
- effect = IT_S;
- }
-
- entry->effect = effect;
- entry->effectvalue = value;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * ptmeffect.c - Code for converting PTM / / \ \
+ * effects to IT effects. | < / \_
+ * | \/ /\ /
+ * By Chris Moeller. Based on xmeffect.c \_ / > /
+ * by Julien Cugniere. | \ / /
+ * | ' /
+ * \__/
+ */
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+
+void _dumb_it_ptm_convert_effect(int effect, int value, IT_ENTRY *entry)
+{
+ if (effect >= PTM_N_EFFECTS)
+ return;
+
+ /* Linearisation of the effect number... */
+ if (effect == PTM_E) {
+ effect = PTM_EBASE + HIGH(value);
+ value = LOW(value);
+ }
+
+ /* convert effect */
+ entry->mask |= IT_ENTRY_EFFECT;
+ switch (effect) {
+
+ case PTM_APPREGIO: effect = IT_ARPEGGIO; break;
+ case PTM_PORTAMENTO_UP: effect = IT_PORTAMENTO_UP; break;
+ case PTM_PORTAMENTO_DOWN: effect = IT_PORTAMENTO_DOWN; break;
+ case PTM_TONE_PORTAMENTO: effect = IT_TONE_PORTAMENTO; break;
+ case PTM_VIBRATO: effect = IT_VIBRATO; break;
+ case PTM_VOLSLIDE_TONEPORTA: effect = IT_VOLSLIDE_TONEPORTA; break;
+ case PTM_VOLSLIDE_VIBRATO: effect = IT_VOLSLIDE_VIBRATO; break;
+ case PTM_TREMOLO: effect = IT_TREMOLO; break;
+ case PTM_SAMPLE_OFFSET: effect = IT_SET_SAMPLE_OFFSET; break;
+ case PTM_VOLUME_SLIDE: effect = IT_VOLUME_SLIDE; break;
+ case PTM_POSITION_JUMP: effect = IT_JUMP_TO_ORDER; break;
+ case PTM_SET_CHANNEL_VOLUME: effect = IT_SET_CHANNEL_VOLUME; break;
+ case PTM_PATTERN_BREAK: effect = IT_BREAK_TO_ROW; break;
+ case PTM_SET_GLOBAL_VOLUME: effect = IT_SET_GLOBAL_VOLUME; break;
+ case PTM_RETRIGGER: effect = IT_RETRIGGER_NOTE; break;
+ case PTM_FINE_VIBRATO: effect = IT_FINE_VIBRATO; break;
+
+ /* TODO properly */
+ case PTM_NOTE_SLIDE_UP: effect = IT_PTM_NOTE_SLIDE_UP; break;
+ case PTM_NOTE_SLIDE_DOWN: effect = IT_PTM_NOTE_SLIDE_DOWN; break;
+ case PTM_NOTE_SLIDE_UP_RETRIG: effect = IT_PTM_NOTE_SLIDE_UP_RETRIG; break;
+ case PTM_NOTE_SLIDE_DOWN_RETRIG: effect = IT_PTM_NOTE_SLIDE_DOWN_RETRIG; break;
+
+ case PTM_SET_TEMPO_BPM:
+ effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
+ break;
+
+ case PTM_EBASE+PTM_E_SET_FINETUNE: effect = SBASE+IT_S_FINETUNE; break; /** TODO */
+ case PTM_EBASE+PTM_E_SET_LOOP: effect = SBASE+IT_S_PATTERN_LOOP; break;
+ case PTM_EBASE+PTM_E_NOTE_CUT: effect = SBASE+IT_S_DELAYED_NOTE_CUT; break;
+ case PTM_EBASE+PTM_E_NOTE_DELAY: effect = SBASE+IT_S_NOTE_DELAY; break;
+ case PTM_EBASE+PTM_E_PATTERN_DELAY: effect = SBASE+IT_S_PATTERN_DELAY; break;
+ case PTM_EBASE+PTM_E_SET_PANNING: effect = SBASE+IT_S_SET_PAN; break;
+
+ case PTM_EBASE+PTM_E_FINE_VOLSLIDE_UP:
+ effect = IT_VOLUME_SLIDE;
+ value = EFFECT_VALUE(value, 0xF);
+ break;
+
+ case PTM_EBASE + PTM_E_FINE_VOLSLIDE_DOWN:
+ effect = IT_VOLUME_SLIDE;
+ value = EFFECT_VALUE(0xF, value);
+ break;
+
+ case PTM_EBASE + PTM_E_FINE_PORTA_UP:
+ effect = IT_PORTAMENTO_UP;
+ value = EFFECT_VALUE(0xF, value);
+ break;
+
+ case PTM_EBASE + PTM_E_FINE_PORTA_DOWN:
+ effect = IT_PORTAMENTO_DOWN;
+ value = EFFECT_VALUE(0xF, value);
+ break;
+
+ case PTM_EBASE + PTM_E_RETRIG_NOTE:
+ effect = IT_XM_RETRIGGER_NOTE;
+ value = EFFECT_VALUE(0, value);
+ break;
+
+ case PTM_EBASE + PTM_E_SET_VIBRATO_CONTROL:
+ effect = SBASE+IT_S_SET_VIBRATO_WAVEFORM;
+ value &= ~4; /** TODO: value&4 -> don't retrig wave */
+ break;
+
+ case PTM_EBASE + PTM_E_SET_TREMOLO_CONTROL:
+ effect = SBASE+IT_S_SET_TREMOLO_WAVEFORM;
+ value &= ~4; /** TODO: value&4 -> don't retrig wave */
+ break;
+
+ default:
+ /* user effect (often used in demos for synchronisation) */
+ entry->mask &= ~IT_ENTRY_EFFECT;
+ }
+
+ /* Inverse linearisation... */
+ if (effect >= SBASE && effect < SBASE+16) {
+ value = EFFECT_VALUE(effect-SBASE, value);
+ effect = IT_S;
+ }
+
+ entry->effect = effect;
+ entry->effectvalue = value;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/read669.c b/plugins/dumb/dumb-kode54/src/it/read669.c
index 4cb88d30..f52d397f 100644
--- a/plugins/dumb/dumb-kode54/src/it/read669.c
+++ b/plugins/dumb/dumb-kode54/src/it/read669.c
@@ -1,447 +1,447 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * read669.c - Code to read a 669 Composer module / / \ \
- * from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-static int it_669_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int tempo, int breakpoint, unsigned char *buffer, int * used_channels)
-{
- int pos;
- int channel;
- int row;
- IT_ENTRY *entry;
-
- pattern->n_rows = 64;
-
- if (dumbfile_getnc(buffer, 64 * 3 * 8, f) < 64 * 3 * 8)
- return -1;
-
- /* compute number of entries */
- pattern->n_entries = 64 + 1; /* Account for the row end markers, speed command */
- if (breakpoint < 63) pattern->n_entries++; /* and break to row 0 */
-
- pos = 0;
- for (row = 0; row < 64; row++) {
- for (channel = 0; channel < 8; channel++) {
- if (buffer[pos+0] != 0xFF || buffer[pos+2] != 0xFF)
- pattern->n_entries++;
- pos += 3;
- }
- }
-
- pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
- if (!pattern->entry)
- return -1;
-
- if (breakpoint == 63) breakpoint++;
-
- entry = pattern->entry;
-
- entry->channel = 8;
- entry->mask = IT_ENTRY_EFFECT;
- entry->effect = IT_SET_SPEED;
- entry->effectvalue = tempo;
- entry++;
-
- pos = 0;
- for (row = 0; row < 64; row++) {
-
- if (row == breakpoint) {
- entry->channel = 8;
- entry->mask = IT_ENTRY_EFFECT;
- entry->effect = IT_BREAK_TO_ROW;
- entry->effectvalue = 0;
- entry++;
- }
-
- for (channel = 0; channel < 8; channel++) {
- if (buffer[pos+0] != 0xFF || buffer[pos+2] != 0xFF) {
- entry->channel = channel;
- entry->mask = 0;
-
- if (buffer[pos+0] < 0xFE) {
- entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT;
- entry->note = (buffer[pos+0] >> 2) + 36;
- entry->instrument = (((buffer[pos+0] << 4) | (buffer[pos+1] >> 4)) & 0x3F) + 1;
- }
- if (buffer[pos+0] <= 0xFE) {
- entry->mask |= IT_ENTRY_VOLPAN;
- entry->volpan = ((buffer[pos+1] & 15) << 6) / 15;
- if (*used_channels < channel + 1) *used_channels = channel + 1;
- }
- if (buffer[pos+2] != 0xFF) {
- entry->mask |= IT_ENTRY_EFFECT;
- entry->effectvalue = buffer[pos+2] & 15;
- switch (buffer[pos+2] >> 4) {
- case 0:
- entry->effect = IT_PORTAMENTO_UP;
- break;
- case 1:
- entry->effect = IT_PORTAMENTO_DOWN;
- break;
- case 2:
- entry->effect = IT_TONE_PORTAMENTO;
- break;
- case 3:
- entry->effect = IT_S;
- entry->effectvalue += IT_S_FINETUNE * 16 + 8;
- break;
- case 4:
- entry->effect = IT_VIBRATO;
- // XXX speed unknown
- entry->effectvalue |= 0x10;
- break;
- case 5:
- if (entry->effectvalue) {
- entry->effect = IT_SET_SPEED;
- } else {
- entry->mask &= ~IT_ENTRY_EFFECT;
- }
- break;
-#if 0
- /* dunno about this, really... */
- case 6:
- if (entry->effectvalue == 0) {
- entry->effect = IT_PANNING_SLIDE;
- entry->effectvalue = 0xFE;
- } else if (entry->effectvalue == 1) {
- entry->effect = IT_PANNING_SLIDE;
- entry->effectvalue = 0xEF;
- } else {
- entry->mask &= ~IT_ENTRY_EFFECT;
- }
- break;
-#endif
- default:
- entry->mask &= ~IT_ENTRY_EFFECT;
- break;
- }
- if (*used_channels < channel + 1) *used_channels = channel + 1;
- }
-
- entry++;
- }
- pos += 3;
- }
- IT_SET_END_ROW(entry);
- entry++;
- }
-
- return 0;
-}
-
-
-
-static int it_669_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
-{
- dumbfile_getnc(sample->name, 13, f);
- sample->name[13] = 0;
-
- sample->filename[0] = 0;
-
- sample->length = dumbfile_igetl(f);
- sample->loop_start = dumbfile_igetl(f);
- sample->loop_end = dumbfile_igetl(f);
-
- if (dumbfile_error(f))
- return -1;
-
- if (sample->length <= 0) {
- sample->flags = 0;
- return 0;
- }
-
- sample->flags = IT_SAMPLE_EXISTS;
-
- sample->global_volume = 64;
- sample->default_volume = 64;
-
- sample->default_pan = 0;
- sample->C5_speed = 8363;
- // the above line might be wrong
-
- if ((sample->loop_end > sample->length) && !(sample->loop_start))
- sample->loop_end = 0;
-
- if (sample->loop_end > sample->length)
- sample->loop_end = sample->length;
-
- if (sample->loop_end - sample->loop_start > 2)
- sample->flags |= IT_SAMPLE_LOOP;
-
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = 0; // do we have to set _all_ these?
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- return 0;
-}
-
-
-
-static int it_669_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f)
-{
- long i;
- long truncated_size;
-
- /* let's get rid of the sample data coming after the end of the loop */
- if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
- truncated_size = sample->length - sample->loop_end;
- sample->length = sample->loop_end;
- } else {
- truncated_size = 0;
- }
-
- sample->data = malloc(sample->length);
-
- if (!sample->data)
- return -1;
-
- if (sample->length)
- {
- i = dumbfile_getnc(sample->data, sample->length, f);
-
- if (i < sample->length) {
- //return -1;
- // ficking truncated files
- if (i <= 0) {
- sample->flags = 0;
- return 0;
- }
- sample->length = i;
- if (sample->loop_end > i) sample->loop_end = i;
- } else {
- /* skip truncated data */
- dumbfile_skip(f, truncated_size);
- // Should we be truncating it?
- if (dumbfile_error(f))
- return -1;
- }
-
- for (i = 0; i < sample->length; i++)
- ((signed char *)sample->data)[i] ^= 0x80;
- }
-
- return 0;
-}
-
-
-static DUMB_IT_SIGDATA *it_669_load_sigdata(DUMBFILE *f, int * ext)
-{
- DUMB_IT_SIGDATA *sigdata;
- int n_channels;
- int i;
- unsigned char tempolist[128];
- unsigned char breaklist[128];
-
- i = dumbfile_igetw(f);
- if (i != 0x6669 && i != 0x4E4A) return NULL;
-
- *ext = (i == 0x4E4A);
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) {
- return NULL;
- }
-
- if (dumbfile_getnc(sigdata->name, 36, f) < 36) {
- free(sigdata);
- return NULL;
- }
- sigdata->name[36] = 0;
-
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
- sigdata->sample = NULL;
-
- sigdata->n_instruments = 0;
-
- sigdata->song_message = malloc(72 + 2 + 1);
- if (!sigdata->song_message) {
- free(sigdata);
- return NULL;
- }
- if (dumbfile_getnc(sigdata->song_message, 36, f) < 36) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- sigdata->song_message[36] = 13;
- sigdata->song_message[36 + 1] = 10;
- if (dumbfile_getnc(sigdata->song_message + 38, 36, f) < 36) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- sigdata->song_message[38 + 36] = 0;
-
- sigdata->n_samples = dumbfile_getc(f);
- sigdata->n_patterns = dumbfile_getc(f);
- sigdata->restart_position = dumbfile_getc(f);
-
- if ((sigdata->n_samples) > 64 || (sigdata->n_patterns > 128)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->order = malloc(128); /* We may need to scan the extra ones! */
- if (!sigdata->order) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- if (dumbfile_getnc(sigdata->order, 128, f) < 128) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (i = 0; i < 128; i++) {
- if (sigdata->order[i] == 255) break;
- if (sigdata->order[i] >= sigdata->n_patterns) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
- if (!i) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- sigdata->n_orders = i;
-
- if (dumbfile_getnc(tempolist, 128, f) < 128) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (dumbfile_getnc(breaklist, 128, f) < 128) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (i = 0; i < sigdata->n_samples; i++)
- sigdata->sample[i].data = NULL;
-
- for (i = 0; i < sigdata->n_samples; i++) {
- if (it_669_read_sample_header(&sigdata->sample[i], f)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
-
- /* May as well try to save a tiny bit of memory. */
- if (sigdata->n_orders < 128) {
- unsigned char *order = realloc(sigdata->order, sigdata->n_orders);
- if (order) sigdata->order = order;
- }
-
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++)
- sigdata->pattern[i].entry = NULL;
-
- n_channels = 0;
-
- /* Read in the patterns */
- {
- unsigned char *buffer = malloc(64 * 3 * 8); /* 64 rows * 3 bytes * 8 channels */
- if (!buffer) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++) {
- if (it_669_read_pattern(&sigdata->pattern[i], f, tempolist[i], breaklist[i], buffer, &n_channels) != 0) {
- free(buffer);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
- free(buffer);
- }
-
- sigdata->n_pchannels = n_channels;
-
- /* And finally, the sample data */
- for (i = 0; i < sigdata->n_samples; i++) {
- if (it_669_read_sample_data(&sigdata->sample[i], f)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
-
- /* Now let's initialise the remaining variables, and we're done! */
- sigdata->flags = IT_OLD_EFFECTS | IT_LINEAR_SLIDES | IT_STEREO | IT_WAS_A_669;
-
- sigdata->global_volume = 128;
- sigdata->mixing_volume = 48;
- sigdata->speed = 4;
- sigdata->tempo = 78;
- sigdata->pan_separation = 128;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (i = 0; i < DUMB_IT_N_CHANNELS; i += 2) {
- sigdata->channel_pan[i+0] = 48;
- sigdata->channel_pan[i+1] = 16;
- }
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-
-
-DUH *dumb_read_669_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
- int ext;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_669_load_sigdata(f, &ext);
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = ext ? "669 Extended" : "669";
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * read669.c - Code to read a 669 Composer module / / \ \
+ * from an open file. | < / \_
+ * | \/ /\ /
+ * By Chris Moeller. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+static int it_669_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int tempo, int breakpoint, unsigned char *buffer, int * used_channels)
+{
+ int pos;
+ int channel;
+ int row;
+ IT_ENTRY *entry;
+
+ pattern->n_rows = 64;
+
+ if (dumbfile_getnc(buffer, 64 * 3 * 8, f) < 64 * 3 * 8)
+ return -1;
+
+ /* compute number of entries */
+ pattern->n_entries = 64 + 1; /* Account for the row end markers, speed command */
+ if (breakpoint < 63) pattern->n_entries++; /* and break to row 0 */
+
+ pos = 0;
+ for (row = 0; row < 64; row++) {
+ for (channel = 0; channel < 8; channel++) {
+ if (buffer[pos+0] != 0xFF || buffer[pos+2] != 0xFF)
+ pattern->n_entries++;
+ pos += 3;
+ }
+ }
+
+ pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
+ if (!pattern->entry)
+ return -1;
+
+ if (breakpoint == 63) breakpoint++;
+
+ entry = pattern->entry;
+
+ entry->channel = 8;
+ entry->mask = IT_ENTRY_EFFECT;
+ entry->effect = IT_SET_SPEED;
+ entry->effectvalue = tempo;
+ entry++;
+
+ pos = 0;
+ for (row = 0; row < 64; row++) {
+
+ if (row == breakpoint) {
+ entry->channel = 8;
+ entry->mask = IT_ENTRY_EFFECT;
+ entry->effect = IT_BREAK_TO_ROW;
+ entry->effectvalue = 0;
+ entry++;
+ }
+
+ for (channel = 0; channel < 8; channel++) {
+ if (buffer[pos+0] != 0xFF || buffer[pos+2] != 0xFF) {
+ entry->channel = channel;
+ entry->mask = 0;
+
+ if (buffer[pos+0] < 0xFE) {
+ entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT;
+ entry->note = (buffer[pos+0] >> 2) + 36;
+ entry->instrument = (((buffer[pos+0] << 4) | (buffer[pos+1] >> 4)) & 0x3F) + 1;
+ }
+ if (buffer[pos+0] <= 0xFE) {
+ entry->mask |= IT_ENTRY_VOLPAN;
+ entry->volpan = ((buffer[pos+1] & 15) << 6) / 15;
+ if (*used_channels < channel + 1) *used_channels = channel + 1;
+ }
+ if (buffer[pos+2] != 0xFF) {
+ entry->mask |= IT_ENTRY_EFFECT;
+ entry->effectvalue = buffer[pos+2] & 15;
+ switch (buffer[pos+2] >> 4) {
+ case 0:
+ entry->effect = IT_PORTAMENTO_UP;
+ break;
+ case 1:
+ entry->effect = IT_PORTAMENTO_DOWN;
+ break;
+ case 2:
+ entry->effect = IT_TONE_PORTAMENTO;
+ break;
+ case 3:
+ entry->effect = IT_S;
+ entry->effectvalue += IT_S_FINETUNE * 16 + 8;
+ break;
+ case 4:
+ entry->effect = IT_VIBRATO;
+ // XXX speed unknown
+ entry->effectvalue |= 0x10;
+ break;
+ case 5:
+ if (entry->effectvalue) {
+ entry->effect = IT_SET_SPEED;
+ } else {
+ entry->mask &= ~IT_ENTRY_EFFECT;
+ }
+ break;
+#if 0
+ /* dunno about this, really... */
+ case 6:
+ if (entry->effectvalue == 0) {
+ entry->effect = IT_PANNING_SLIDE;
+ entry->effectvalue = 0xFE;
+ } else if (entry->effectvalue == 1) {
+ entry->effect = IT_PANNING_SLIDE;
+ entry->effectvalue = 0xEF;
+ } else {
+ entry->mask &= ~IT_ENTRY_EFFECT;
+ }
+ break;
+#endif
+ default:
+ entry->mask &= ~IT_ENTRY_EFFECT;
+ break;
+ }
+ if (*used_channels < channel + 1) *used_channels = channel + 1;
+ }
+
+ entry++;
+ }
+ pos += 3;
+ }
+ IT_SET_END_ROW(entry);
+ entry++;
+ }
+
+ return 0;
+}
+
+
+
+static int it_669_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
+{
+ dumbfile_getnc(sample->name, 13, f);
+ sample->name[13] = 0;
+
+ sample->filename[0] = 0;
+
+ sample->length = dumbfile_igetl(f);
+ sample->loop_start = dumbfile_igetl(f);
+ sample->loop_end = dumbfile_igetl(f);
+
+ if (dumbfile_error(f))
+ return -1;
+
+ if (sample->length <= 0) {
+ sample->flags = 0;
+ return 0;
+ }
+
+ sample->flags = IT_SAMPLE_EXISTS;
+
+ sample->global_volume = 64;
+ sample->default_volume = 64;
+
+ sample->default_pan = 0;
+ sample->C5_speed = 8363;
+ // the above line might be wrong
+
+ if ((sample->loop_end > sample->length) && !(sample->loop_start))
+ sample->loop_end = 0;
+
+ if (sample->loop_end > sample->length)
+ sample->loop_end = sample->length;
+
+ if (sample->loop_end - sample->loop_start > 2)
+ sample->flags |= IT_SAMPLE_LOOP;
+
+ sample->vibrato_speed = 0;
+ sample->vibrato_depth = 0;
+ sample->vibrato_rate = 0;
+ sample->vibrato_waveform = 0; // do we have to set _all_ these?
+ sample->finetune = 0;
+ sample->max_resampling_quality = -1;
+
+ return 0;
+}
+
+
+
+static int it_669_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f)
+{
+ long i;
+ long truncated_size;
+
+ /* let's get rid of the sample data coming after the end of the loop */
+ if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
+ truncated_size = sample->length - sample->loop_end;
+ sample->length = sample->loop_end;
+ } else {
+ truncated_size = 0;
+ }
+
+ sample->data = malloc(sample->length);
+
+ if (!sample->data)
+ return -1;
+
+ if (sample->length)
+ {
+ i = dumbfile_getnc(sample->data, sample->length, f);
+
+ if (i < sample->length) {
+ //return -1;
+ // ficking truncated files
+ if (i <= 0) {
+ sample->flags = 0;
+ return 0;
+ }
+ sample->length = i;
+ if (sample->loop_end > i) sample->loop_end = i;
+ } else {
+ /* skip truncated data */
+ dumbfile_skip(f, truncated_size);
+ // Should we be truncating it?
+ if (dumbfile_error(f))
+ return -1;
+ }
+
+ for (i = 0; i < sample->length; i++)
+ ((signed char *)sample->data)[i] ^= 0x80;
+ }
+
+ return 0;
+}
+
+
+static DUMB_IT_SIGDATA *it_669_load_sigdata(DUMBFILE *f, int * ext)
+{
+ DUMB_IT_SIGDATA *sigdata;
+ int n_channels;
+ int i;
+ unsigned char tempolist[128];
+ unsigned char breaklist[128];
+
+ i = dumbfile_igetw(f);
+ if (i != 0x6669 && i != 0x4E4A) return NULL;
+
+ *ext = (i == 0x4E4A);
+
+ sigdata = malloc(sizeof(*sigdata));
+ if (!sigdata) {
+ return NULL;
+ }
+
+ if (dumbfile_getnc(sigdata->name, 36, f) < 36) {
+ free(sigdata);
+ return NULL;
+ }
+ sigdata->name[36] = 0;
+
+ sigdata->order = NULL;
+ sigdata->instrument = NULL;
+ sigdata->pattern = NULL;
+ sigdata->midi = NULL;
+ sigdata->checkpoint = NULL;
+ sigdata->sample = NULL;
+
+ sigdata->n_instruments = 0;
+
+ sigdata->song_message = malloc(72 + 2 + 1);
+ if (!sigdata->song_message) {
+ free(sigdata);
+ return NULL;
+ }
+ if (dumbfile_getnc(sigdata->song_message, 36, f) < 36) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ sigdata->song_message[36] = 13;
+ sigdata->song_message[36 + 1] = 10;
+ if (dumbfile_getnc(sigdata->song_message + 38, 36, f) < 36) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ sigdata->song_message[38 + 36] = 0;
+
+ sigdata->n_samples = dumbfile_getc(f);
+ sigdata->n_patterns = dumbfile_getc(f);
+ sigdata->restart_position = dumbfile_getc(f);
+
+ if ((sigdata->n_samples) > 64 || (sigdata->n_patterns > 128)) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ sigdata->order = malloc(128); /* We may need to scan the extra ones! */
+ if (!sigdata->order) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ if (dumbfile_getnc(sigdata->order, 128, f) < 128) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ for (i = 0; i < 128; i++) {
+ if (sigdata->order[i] == 255) break;
+ if (sigdata->order[i] >= sigdata->n_patterns) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ }
+ if (!i) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ sigdata->n_orders = i;
+
+ if (dumbfile_getnc(tempolist, 128, f) < 128) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ if (dumbfile_getnc(breaklist, 128, f) < 128) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
+ if (!sigdata->sample) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ for (i = 0; i < sigdata->n_samples; i++)
+ sigdata->sample[i].data = NULL;
+
+ for (i = 0; i < sigdata->n_samples; i++) {
+ if (it_669_read_sample_header(&sigdata->sample[i], f)) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ }
+
+ /* May as well try to save a tiny bit of memory. */
+ if (sigdata->n_orders < 128) {
+ unsigned char *order = realloc(sigdata->order, sigdata->n_orders);
+ if (order) sigdata->order = order;
+ }
+
+ sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
+ if (!sigdata->pattern) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (i = 0; i < sigdata->n_patterns; i++)
+ sigdata->pattern[i].entry = NULL;
+
+ n_channels = 0;
+
+ /* Read in the patterns */
+ {
+ unsigned char *buffer = malloc(64 * 3 * 8); /* 64 rows * 3 bytes * 8 channels */
+ if (!buffer) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (i = 0; i < sigdata->n_patterns; i++) {
+ if (it_669_read_pattern(&sigdata->pattern[i], f, tempolist[i], breaklist[i], buffer, &n_channels) != 0) {
+ free(buffer);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ }
+ free(buffer);
+ }
+
+ sigdata->n_pchannels = n_channels;
+
+ /* And finally, the sample data */
+ for (i = 0; i < sigdata->n_samples; i++) {
+ if (it_669_read_sample_data(&sigdata->sample[i], f)) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ }
+
+ /* Now let's initialise the remaining variables, and we're done! */
+ sigdata->flags = IT_OLD_EFFECTS | IT_LINEAR_SLIDES | IT_STEREO | IT_WAS_A_669;
+
+ sigdata->global_volume = 128;
+ sigdata->mixing_volume = 48;
+ sigdata->speed = 4;
+ sigdata->tempo = 78;
+ sigdata->pan_separation = 128;
+
+ memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
+
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i += 2) {
+ sigdata->channel_pan[i+0] = 48;
+ sigdata->channel_pan[i+1] = 16;
+ }
+
+ _dumb_it_fix_invalid_orders(sigdata);
+
+ return sigdata;
+}
+
+
+
+DUH *dumb_read_669_quick(DUMBFILE *f)
+{
+ sigdata_t *sigdata;
+ int ext;
+
+ DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
+
+ sigdata = it_669_load_sigdata(f, &ext);
+
+ if (!sigdata)
+ return NULL;
+
+ {
+ const char *tag[2][2];
+ tag[0][0] = "TITLE";
+ tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+ tag[1][0] = "FORMAT";
+ tag[1][1] = ext ? "669 Extended" : "669";
+ return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/readam.c b/plugins/dumb/dumb-kode54/src/it/readam.c
index 14ad3c07..b51a80d6 100644
--- a/plugins/dumb/dumb-kode54/src/it/readam.c
+++ b/plugins/dumb/dumb-kode54/src/it/readam.c
@@ -1,752 +1,752 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readam.c - Code to read a RIFF AM module / / \ \
- * from a parsed RIFF structure. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-#include "internal/riff.h"
-
-static int it_riff_am_process_sample( IT_SAMPLE * sample, const unsigned char * data, int len, int ver )
-{
- int header_length;
- int default_pan;
- int default_volume;
- int flags;
- int length;
- int length_bytes;
- int loop_start;
- int loop_end;
- int sample_rate;
-
- if ( ver == 0 )
- {
- if ( len < 0x38 )
- return -1;
-
- header_length = 0x38;
-
- memcpy( sample->name, data, 28 );
- sample->name[ 28 ] = 0;
-
- default_pan = data[ 0x1C ];
- default_volume = data[ 0x1D ];
- flags = data[ 0x1E ] | ( data[ 0x1F ] << 8 );
- length = data[ 0x20 ] | ( data[ 0x21 ] << 8 ) | ( data[ 0x22 ] << 16 ) | ( data[ 0x23 ] << 24 );
- loop_start = data[ 0x24 ] | ( data[ 0x25 ] << 8 ) | ( data[ 0x26 ] << 16 ) | ( data[ 0x27 ] << 24 );
- loop_end = data[ 0x28 ] | ( data[ 0x29 ] << 8 ) | ( data[ 0x2A ] << 16 ) | ( data[ 0x2B ] << 24 );
- sample_rate = data[ 0x2C ] | ( data[ 0x2D ] << 8 ) | ( data[ 0x2E ] << 16 ) | ( data[ 0x2F ] << 24 );
- }
- else
- {
- if (len < 4) return -1;
-
- header_length = data[ 0 ] | ( data[ 1 ] << 8 ) | ( data[ 2 ] << 16 ) | ( data[ 3 ] << 24 );
- if ( header_length < 0x40 )
- return -1;
- if ( header_length + 4 > len )
- return -1;
-
- data += 4;
- len -= 4;
-
- memcpy( sample->name, data, 32 );
- sample->name[ 32 ] = 0;
-
- default_pan = data[ 0x20 ] | ( data[ 0x21 ] << 8 );
- default_volume = data[ 0x22 ] | ( data[ 0x23 ] << 8 );
- flags = data[ 0x24 ] | ( data[ 0x25 ] << 8 ); /* | ( data[ 0x26 ] << 16 ) | ( data[ 0x27 ] << 24 );*/
- length = data[ 0x28 ] | ( data[ 0x29 ] << 8 ) | ( data[ 0x2A ] << 16 ) | ( data[ 0x2B ] << 24 );
- loop_start = data[ 0x2C ] | ( data[ 0x2D ] << 8 ) | ( data[ 0x2E ] << 16 ) | ( data[ 0x2F ] << 24 );
- loop_end = data[ 0x30 ] | ( data[ 0x31 ] << 8 ) | ( data[ 0x32 ] << 16 ) | ( data[ 0x33 ] << 24 );
- sample_rate = data[ 0x34 ] | ( data[ 0x35 ] << 8 ) | ( data[ 0x36 ] << 16 ) | ( data[ 0x37 ] << 24 );
-
- if ( default_pan > 0x7FFF || default_volume > 0x7FFF )
- return -1;
-
- default_pan = default_pan * 64 / 32767;
- default_volume = default_volume * 64 / 32767;
- }
-
- /*if ( data[ 0x38 ] || data[ 0x39 ] || data[ 0x3A ] || data[ 0x3B ] )
- return -1;*/
-
- if ( ! length ) {
- sample->flags &= ~IT_SAMPLE_EXISTS;
- return 0;
- }
-
- if ( flags & ~( 0x8000 | 0x80 | 0x20 | 0x10 | 0x08 | 0x04 ) )
- return -1;
-
- length_bytes = length << ( ( flags & 0x04 ) >> 2 );
-
- if ( length_bytes + header_length > len )
- return -1;
-
- sample->flags = 0;
-
- if ( flags & 0x80 ) sample->flags |= IT_SAMPLE_EXISTS;
- if ( flags & 0x04 ) sample->flags |= IT_SAMPLE_16BIT;
-
- sample->length = length;
- sample->loop_start = loop_start;
- sample->loop_end = loop_end;
- sample->C5_speed = sample_rate;
- sample->default_volume = default_volume;
- sample->default_pan = default_pan | ( ( flags & 0x20 ) << 2 );
- sample->filename[0] = 0;
- sample->global_volume = 64;
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = IT_VIBRATO_SINE;
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- if ( flags & 0x08 )
- {
- if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) &&
- ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end))
- {
- sample->length = sample->loop_end;
- sample->flags |= IT_SAMPLE_LOOP;
- if ( flags & 0x10 ) sample->flags |= IT_SAMPLE_PINGPONG_LOOP;
- }
- }
-
- length_bytes = sample->length << ( ( flags & 0x04 ) >> 2 );
-
- sample->data = malloc( length_bytes );
- if ( ! sample->data )
- return -1;
-
- memcpy( sample->data, data + header_length, length_bytes );
-
- return 0;
-}
-
-static int it_riff_am_process_pattern( IT_PATTERN * pattern, const unsigned char * data, int len, int ver )
-{
- int nrows, row, pos;
- unsigned flags;
- IT_ENTRY * entry;
-
- nrows = data[0] + 1;
-
- pattern->n_rows = nrows;
-
- data += 1;
- len -= 1;
-
- pattern->n_entries = 0;
-
- row = 0;
- pos = 0;
-
- while ( (row < nrows) && (pos < len) ) {
- if ( ! data[ pos ] ) {
- ++ row;
- ++ pos;
- continue;
- }
-
- flags = data[ pos++ ] & 0xE0;
-
- if (flags) {
- ++ pattern->n_entries;
- if (flags & 0x80) pos += 2;
- if (flags & 0x40) pos += 2;
- if (flags & 0x20) pos ++;
- }
- }
-
- if ( ! pattern->n_entries ) return 0;
-
- pattern->n_entries += nrows;
-
- pattern->entry = malloc( pattern->n_entries * sizeof( * pattern->entry ) );
- if ( ! pattern->entry ) return -1;
-
- entry = pattern->entry;
-
- row = 0;
- pos = 0;
-
- while ( ( row < nrows ) && ( pos < len ) )
- {
- if ( ! data[ pos ] )
- {
- IT_SET_END_ROW( entry );
- ++ entry;
- ++ row;
- ++ pos;
- continue;
- }
-
- flags = data[ pos++ ];
- entry->channel = flags & 0x1F;
- entry->mask = 0;
-
- if (flags & 0xE0)
- {
- if ( flags & 0x80 )
- {
- _dumb_it_xm_convert_effect( data[ pos + 1 ], data[ pos ], entry, 0 );
- pos += 2;
- }
-
- if ( flags & 0x40 )
- {
- if ( data[ pos ] )
- {
- entry->mask |= IT_ENTRY_INSTRUMENT;
- entry->instrument = data[ pos ];
- }
- if ( data[ pos + 1 ] )
- {
- entry->mask |= IT_ENTRY_NOTE;
- entry->note = data[ pos + 1 ] - 1;
- }
- pos += 2;
- }
-
- if ( flags & 0x20 )
- {
- entry->mask |= IT_ENTRY_VOLPAN;
- if ( ver == 0 ) entry->volpan = data[ pos ];
- else entry->volpan = data[ pos ] * 64 / 127;
- ++ pos;
- }
-
- if (entry->mask) entry++;
- }
- }
-
- while ( row < nrows )
- {
- IT_SET_END_ROW( entry );
- ++ entry;
- ++ row;
- }
-
- pattern->n_entries = entry - pattern->entry;
- if ( ! pattern->n_entries ) return -1;
-
- return 0;
-}
-
-static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( struct riff * stream )
-{
- DUMB_IT_SIGDATA *sigdata;
-
- int n, o, found;
-
- unsigned char * ptr;
-
- if ( ! stream ) goto error;
-
- if ( stream->type != DUMB_ID( 'A', 'M', 'F', 'F' ) ) goto error;
-
- sigdata = malloc( sizeof( *sigdata ) );
- if ( ! sigdata ) goto error;
-
- sigdata->n_patterns = 0;
- sigdata->n_samples = 0;
- sigdata->name[0] = 0;
-
- found = 0;
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch( c->type )
- {
- case DUMB_ID( 'M', 'A', 'I', 'N' ):
- /* initialization data */
- if ( ( found & 1 ) || ( c->size < 0x48 ) ) goto error_sd;
- found |= 1;
- break;
-
- case DUMB_ID( 'O', 'R', 'D', 'R' ):
- if ( ( found & 2 ) || ( c->size < 1 ) ) goto error_sd;
- found |= 2;
- break;
-
- case DUMB_ID( 'P', 'A', 'T', 'T' ):
- ptr = ( unsigned char * ) c->data;
- if ( ptr[ 0 ] >= sigdata->n_patterns ) sigdata->n_patterns = ptr[ 0 ] + 1;
- o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
- if ( o + 5 > c->size ) goto error_sd;
- break;
-
- case DUMB_ID( 'I', 'N', 'S', 'T' ):
- {
- if ( c->size < 0xE1 ) goto error;
- ptr = ( unsigned char * ) c->data;
- if ( ptr[ 1 ] >= sigdata->n_samples ) sigdata->n_samples = ptr[ 1 ] + 1;
- if ( c->size >= 0x121 && ( ptr[ 0xE1 ] == 'S' && ptr[ 0xE2 ] == 'A' &&
- ptr[ 0xE3 ] == 'M' && ptr[ 0xE4 ] == 'P' ) )
- {
- unsigned size = ptr[ 0xE5 ] | ( ptr[ 0xE6 ] << 8 ) | ( ptr[ 0xE7 ] << 16 ) | ( ptr[ 0xE8 ] << 24 );
- if ( size + 0xE1 + 8 > c->size ) goto error;
- }
- }
- break;
- }
- }
-
- if ( found != 3 || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd;
-
- if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd;
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->mixing_volume = 48;
- sigdata->pan_separation = 128;
-
- sigdata->n_instruments = 0;
- sigdata->n_orders = 0;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
- sigdata->channel_pan[n ] = 16;
- sigdata->channel_pan[n+1] = 48;
- sigdata->channel_pan[n+2] = 48;
- sigdata->channel_pan[n+3] = 16;
- }
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch ( c->type )
- {
- case DUMB_ID( 'M', 'A', 'I', 'N' ):
- ptr = ( unsigned char * ) c->data;
- memcpy( sigdata->name, c->data, 64 );
- sigdata->name[ 64 ] = 0;
- sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
- if ( ! ( ptr[ 0x40 ] & 1 ) ) sigdata->flags |= IT_LINEAR_SLIDES;
- if ( ( ptr[ 0x40 ] & ~3 ) || ! ( ptr[ 0x40 ] & 2 ) ) goto error_usd; // unknown flags
- sigdata->n_pchannels = ptr[ 0x41 ];
- sigdata->speed = ptr[ 0x42 ];
- sigdata->tempo = ptr[ 0x43 ];
-
- sigdata->global_volume = ptr[ 0x48 ];
-
- if ( c->size < 0x48 + sigdata->n_pchannels ) goto error_usd;
-
- for ( o = 0; o < sigdata->n_pchannels; ++o )
- {
- sigdata->channel_pan[ o ] = ptr[ 0x49 + o ];
- if ( ptr[ 0x49 + o ] >= 128 )
- {
- sigdata->channel_volume[ o ] = 0;
- }
- }
- break;
- }
- }
-
- sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
- if ( ! sigdata->pattern ) goto error_usd;
- for ( n = 0; n < sigdata->n_patterns; ++n )
- sigdata->pattern[ n ].entry = NULL;
-
- sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
- if ( ! sigdata->sample ) goto error_usd;
- for ( n = 0; n < sigdata->n_samples; ++n )
- {
- IT_SAMPLE * sample = sigdata->sample + n;
- sample->data = NULL;
- sample->flags = 0;
- sample->name[ 0 ] = 0;
- }
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch ( c->type )
- {
- case DUMB_ID( 'O', 'R', 'D', 'R' ):
- ptr = ( unsigned char * ) c->data;
- sigdata->n_orders = ptr[ 0 ] + 1;
- if ( sigdata->n_orders + 1 > c->size ) goto error_usd;
- sigdata->order = malloc( sigdata->n_orders );
- if ( ! sigdata->order ) goto error_usd;
- memcpy( sigdata->order, ptr + 1, sigdata->n_orders );
- break;
-
- case DUMB_ID( 'P', 'A', 'T', 'T' ):
- ptr = ( unsigned char * ) c->data;
- o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
- if ( it_riff_am_process_pattern( sigdata->pattern + ptr[ 0 ], ptr + 5, o, 0 ) ) goto error_usd;
- break;
-
- case DUMB_ID( 'I', 'N', 'S', 'T' ):
- {
- IT_SAMPLE * sample;
- ptr = ( unsigned char * ) c->data;
- sample = sigdata->sample + ptr[ 1 ];
- if ( c->size >= 0x121 && ( ptr[ 0xE1 ] == 'S' && ptr[ 0xE2 ] == 'A' &&
- ptr[ 0xE3 ] == 'M' && ptr[ 0xE4 ] == 'P' ) )
- {
- unsigned size = ptr[ 0xE5 ] | ( ptr[ 0xE6 ] << 8 ) | ( ptr[ 0xE7 ] << 16 ) | ( ptr[ 0xE8 ] << 24 );
- if ( it_riff_am_process_sample( sample, ptr + 0xE1 + 8, size, 0 ) ) goto error_usd;
- }
- else
- {
- memcpy( sample->name, ptr + 2, 28 );
- sample->name[ 28 ] = 0;
- }
- }
- break;
- }
- }
-
- _dumb_it_fix_invalid_orders( sigdata );
-
- return sigdata;
-
-error_usd:
- _dumb_it_unload_sigdata( sigdata );
- goto error;
-error_sd:
- free( sigdata );
-error:
- return NULL;
-}
-
-static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream )
-{
- DUMB_IT_SIGDATA *sigdata;
-
- int n, o, p, found;
-
- unsigned char * ptr;
-
- if ( ! stream ) goto error;
-
- if ( stream->type != DUMB_ID( 'A', 'M', ' ', ' ' ) ) goto error;
-
- sigdata = malloc(sizeof(*sigdata));
- if ( ! sigdata ) goto error;
-
- sigdata->n_patterns = 0;
- sigdata->n_samples = 0;
- sigdata->name[0] = 0;
-
- found = 0;
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch( c->type )
- {
- case DUMB_ID( 'I' ,'N' ,'I' ,'T' ):
- /* initialization data */
- if ( ( found & 1 ) || ( c->size < 0x48 ) ) goto error_sd;
- found |= 1;
- break;
-
- case DUMB_ID( 'O', 'R', 'D', 'R' ):
- if ( ( found & 2 ) || ( c->size < 1 ) ) goto error_sd;
- found |= 2;
- break;
-
- case DUMB_ID( 'P', 'A', 'T', 'T' ):
- ptr = ( unsigned char * ) c->data;
- if ( ptr[ 0 ] >= sigdata->n_patterns ) sigdata->n_patterns = ptr[ 0 ] + 1;
- o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
- if ( o + 5 > c->size ) goto error_sd;
- break;
-
- case DUMB_ID( 'R', 'I', 'F', 'F' ):
- {
- struct riff * str = ( struct riff * ) c->data;
- switch ( str->type )
- {
- case DUMB_ID( 'A', 'I', ' ', ' ' ):
- for ( o = 0; o < str->chunk_count; ++o )
- {
- struct riff_chunk * chk = str->chunks + o;
- switch( chk->type )
- {
- case DUMB_ID( 'I', 'N', 'S', 'T' ):
- {
- struct riff * temp;
- unsigned size;
- unsigned sample_found;
- ptr = ( unsigned char * ) chk->data;
- size = ptr[ 0 ] | ( ptr[ 1 ] << 8 ) | ( ptr[ 2 ] << 16 ) | ( ptr[ 3 ] << 24 );
- if ( size < 0x142 ) goto error;
- sample_found = 0;
- if ( ptr[ 5 ] >= sigdata->n_samples ) sigdata->n_samples = ptr[ 5 ] + 1;
- temp = riff_parse( ptr + 4 + size, chk->size - size - 4, 1 );
- if ( temp )
- {
- if ( temp->type == DUMB_ID( 'A', 'S', ' ', ' ' ) )
- {
- for ( p = 0; p < temp->chunk_count; ++p )
- {
- if ( temp->chunks[ p ].type == DUMB_ID( 'S', 'A', 'M', 'P' ) )
- {
- if ( sample_found )
- {
- riff_free( temp );
- goto error;
- }
- sample_found = 1;
- }
- }
- }
- riff_free( temp );
- }
- }
- }
- }
- }
- }
- break;
- }
- }
-
- if ( found != 3 || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd;
-
- if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd;
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->mixing_volume = 48;
- sigdata->pan_separation = 128;
-
- sigdata->n_instruments = 0;
- sigdata->n_orders = 0;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
- sigdata->channel_pan[n ] = 16;
- sigdata->channel_pan[n+1] = 48;
- sigdata->channel_pan[n+2] = 48;
- sigdata->channel_pan[n+3] = 16;
- }
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch ( c->type )
- {
- case DUMB_ID( 'I', 'N', 'I', 'T' ):
- ptr = ( unsigned char * ) c->data;
- memcpy( sigdata->name, c->data, 64 );
- sigdata->name[ 64 ] = 0;
- sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
- if ( ! ( ptr[ 0x40 ] & 1 ) ) sigdata->flags |= IT_LINEAR_SLIDES;
- if ( ( ptr[ 0x40 ] & ~3 ) || ! ( ptr[ 0x40 ] & 2 ) ) goto error_usd; // unknown flags
- sigdata->n_pchannels = ptr[ 0x41 ];
- sigdata->speed = ptr[ 0x42 ];
- sigdata->tempo = ptr[ 0x43 ];
-
- sigdata->global_volume = ptr[ 0x48 ];
-
- if ( c->size < 0x48 + sigdata->n_pchannels ) goto error_usd;
-
- for ( o = 0; o < sigdata->n_pchannels; ++o )
- {
- if ( ptr[ 0x49 + o ] <= 128 )
- {
- sigdata->channel_pan[ o ] = ptr[ 0x49 + o ] / 2;
- }
- else
- {
- sigdata->channel_volume[ o ] = 0;
- }
- }
- break;
- }
- }
-
- sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
- if ( ! sigdata->pattern ) goto error_usd;
- for ( n = 0; n < sigdata->n_patterns; ++n )
- sigdata->pattern[ n ].entry = NULL;
-
- sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
- if ( ! sigdata->sample ) goto error_usd;
- for ( n = 0; n < sigdata->n_samples; ++n )
- {
- IT_SAMPLE * sample = sigdata->sample + n;
- sample->data = NULL;
- sample->flags = 0;
- sample->name[ 0 ] = 0;
- }
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch ( c->type )
- {
- case DUMB_ID( 'O', 'R', 'D', 'R' ):
- ptr = ( unsigned char * ) c->data;
- sigdata->n_orders = ptr[ 0 ] + 1;
- if ( sigdata->n_orders + 1 > c->size ) goto error_usd;
- sigdata->order = malloc( sigdata->n_orders );
- if ( ! sigdata->order ) goto error_usd;
- memcpy( sigdata->order, ptr + 1, sigdata->n_orders );
- break;
-
- case DUMB_ID( 'P', 'A', 'T', 'T' ):
- ptr = ( unsigned char * ) c->data;
- o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
- if ( it_riff_am_process_pattern( sigdata->pattern + ptr[ 0 ], ptr + 5, o, 1 ) ) goto error_usd;
- break;
-
- case DUMB_ID( 'R', 'I', 'F', 'F' ):
- {
- struct riff * str = ( struct riff * ) c->data;
- switch ( str->type )
- {
- case DUMB_ID('A', 'I', ' ', ' '):
- for ( o = 0; o < str->chunk_count; ++o )
- {
- struct riff_chunk * chk = str->chunks + o;
- switch( chk->type )
- {
- case DUMB_ID( 'I', 'N', 'S', 'T' ):
- {
- struct riff * temp;
- unsigned size;
- unsigned sample_found;
- IT_SAMPLE * sample;
- ptr = ( unsigned char * ) chk->data;
- size = ptr[ 0 ] | ( ptr[ 1 ] << 8 ) | ( ptr[ 2 ] << 16 ) | ( ptr[ 3 ] << 24 );
- temp = riff_parse( ptr + 4 + size, chk->size - size - 4, 1 );
- sample_found = 0;
- sample = sigdata->sample + ptr[ 5 ];
- if ( temp )
- {
- if ( temp->type == DUMB_ID( 'A', 'S', ' ', ' ' ) )
- {
- for ( p = 0; p < temp->chunk_count; ++p )
- {
- struct riff_chunk * c = temp->chunks + p;
- if ( c->type == DUMB_ID( 'S', 'A', 'M', 'P' ) )
- {
- if ( sample_found )
- {
- riff_free( temp );
- goto error_usd;
- }
- if ( it_riff_am_process_sample( sigdata->sample + ptr[ 5 ], ( unsigned char * ) c->data, c->size, 1 ) )
- {
- riff_free( temp );
- goto error_usd;
- }
- sample_found = 1;
- }
- }
- }
- riff_free( temp );
- }
- if ( ! sample_found )
- {
- memcpy( sample->name, ptr + 6, 32 );
- sample->name[ 32 ] = 0;
- }
- }
- }
- }
- }
- }
- break;
- }
- }
-
- _dumb_it_fix_invalid_orders( sigdata );
-
- return sigdata;
-
-error_usd:
- _dumb_it_unload_sigdata( sigdata );
- goto error;
-error_sd:
- free( sigdata );
-error:
- return NULL;
-}
-
-DUH *dumb_read_riff_amff( struct riff * stream )
-{
- sigdata_t *sigdata;
- long length;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_riff_amff_load_sigdata( stream );
-
- if (!sigdata)
- return NULL;
-
- length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "RIFF AMFF";
- return make_duh( length, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
- }
-}
-
-DUH *dumb_read_riff_am( struct riff * stream )
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_riff_am_load_sigdata( stream );
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "RIFF AM";
- return make_duh( -1, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readam.c - Code to read a RIFF AM module / / \ \
+ * from a parsed RIFF structure. | < / \_
+ * | \/ /\ /
+ * By Chris Moeller. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+#include "internal/riff.h"
+
+static int it_riff_am_process_sample( IT_SAMPLE * sample, const unsigned char * data, int len, int ver )
+{
+ int header_length;
+ int default_pan;
+ int default_volume;
+ int flags;
+ int length;
+ int length_bytes;
+ int loop_start;
+ int loop_end;
+ int sample_rate;
+
+ if ( ver == 0 )
+ {
+ if ( len < 0x38 )
+ return -1;
+
+ header_length = 0x38;
+
+ memcpy( sample->name, data, 28 );
+ sample->name[ 28 ] = 0;
+
+ default_pan = data[ 0x1C ];
+ default_volume = data[ 0x1D ];
+ flags = data[ 0x1E ] | ( data[ 0x1F ] << 8 );
+ length = data[ 0x20 ] | ( data[ 0x21 ] << 8 ) | ( data[ 0x22 ] << 16 ) | ( data[ 0x23 ] << 24 );
+ loop_start = data[ 0x24 ] | ( data[ 0x25 ] << 8 ) | ( data[ 0x26 ] << 16 ) | ( data[ 0x27 ] << 24 );
+ loop_end = data[ 0x28 ] | ( data[ 0x29 ] << 8 ) | ( data[ 0x2A ] << 16 ) | ( data[ 0x2B ] << 24 );
+ sample_rate = data[ 0x2C ] | ( data[ 0x2D ] << 8 ) | ( data[ 0x2E ] << 16 ) | ( data[ 0x2F ] << 24 );
+ }
+ else
+ {
+ if (len < 4) return -1;
+
+ header_length = data[ 0 ] | ( data[ 1 ] << 8 ) | ( data[ 2 ] << 16 ) | ( data[ 3 ] << 24 );
+ if ( header_length < 0x40 )
+ return -1;
+ if ( header_length + 4 > len )
+ return -1;
+
+ data += 4;
+ len -= 4;
+
+ memcpy( sample->name, data, 32 );
+ sample->name[ 32 ] = 0;
+
+ default_pan = data[ 0x20 ] | ( data[ 0x21 ] << 8 );
+ default_volume = data[ 0x22 ] | ( data[ 0x23 ] << 8 );
+ flags = data[ 0x24 ] | ( data[ 0x25 ] << 8 ); /* | ( data[ 0x26 ] << 16 ) | ( data[ 0x27 ] << 24 );*/
+ length = data[ 0x28 ] | ( data[ 0x29 ] << 8 ) | ( data[ 0x2A ] << 16 ) | ( data[ 0x2B ] << 24 );
+ loop_start = data[ 0x2C ] | ( data[ 0x2D ] << 8 ) | ( data[ 0x2E ] << 16 ) | ( data[ 0x2F ] << 24 );
+ loop_end = data[ 0x30 ] | ( data[ 0x31 ] << 8 ) | ( data[ 0x32 ] << 16 ) | ( data[ 0x33 ] << 24 );
+ sample_rate = data[ 0x34 ] | ( data[ 0x35 ] << 8 ) | ( data[ 0x36 ] << 16 ) | ( data[ 0x37 ] << 24 );
+
+ if ( default_pan > 0x7FFF || default_volume > 0x7FFF )
+ return -1;
+
+ default_pan = default_pan * 64 / 32767;
+ default_volume = default_volume * 64 / 32767;
+ }
+
+ /*if ( data[ 0x38 ] || data[ 0x39 ] || data[ 0x3A ] || data[ 0x3B ] )
+ return -1;*/
+
+ if ( ! length ) {
+ sample->flags &= ~IT_SAMPLE_EXISTS;
+ return 0;
+ }
+
+ if ( flags & ~( 0x8000 | 0x80 | 0x20 | 0x10 | 0x08 | 0x04 ) )
+ return -1;
+
+ length_bytes = length << ( ( flags & 0x04 ) >> 2 );
+
+ if ( length_bytes + header_length > len )
+ return -1;
+
+ sample->flags = 0;
+
+ if ( flags & 0x80 ) sample->flags |= IT_SAMPLE_EXISTS;
+ if ( flags & 0x04 ) sample->flags |= IT_SAMPLE_16BIT;
+
+ sample->length = length;
+ sample->loop_start = loop_start;
+ sample->loop_end = loop_end;
+ sample->C5_speed = sample_rate;
+ sample->default_volume = default_volume;
+ sample->default_pan = default_pan | ( ( flags & 0x20 ) << 2 );
+ sample->filename[0] = 0;
+ sample->global_volume = 64;
+ sample->vibrato_speed = 0;
+ sample->vibrato_depth = 0;
+ sample->vibrato_rate = 0;
+ sample->vibrato_waveform = IT_VIBRATO_SINE;
+ sample->finetune = 0;
+ sample->max_resampling_quality = -1;
+
+ if ( flags & 0x08 )
+ {
+ if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) &&
+ ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end))
+ {
+ sample->length = sample->loop_end;
+ sample->flags |= IT_SAMPLE_LOOP;
+ if ( flags & 0x10 ) sample->flags |= IT_SAMPLE_PINGPONG_LOOP;
+ }
+ }
+
+ length_bytes = sample->length << ( ( flags & 0x04 ) >> 2 );
+
+ sample->data = malloc( length_bytes );
+ if ( ! sample->data )
+ return -1;
+
+ memcpy( sample->data, data + header_length, length_bytes );
+
+ return 0;
+}
+
+static int it_riff_am_process_pattern( IT_PATTERN * pattern, const unsigned char * data, int len, int ver )
+{
+ int nrows, row, pos;
+ unsigned flags;
+ IT_ENTRY * entry;
+
+ nrows = data[0] + 1;
+
+ pattern->n_rows = nrows;
+
+ data += 1;
+ len -= 1;
+
+ pattern->n_entries = 0;
+
+ row = 0;
+ pos = 0;
+
+ while ( (row < nrows) && (pos < len) ) {
+ if ( ! data[ pos ] ) {
+ ++ row;
+ ++ pos;
+ continue;
+ }
+
+ flags = data[ pos++ ] & 0xE0;
+
+ if (flags) {
+ ++ pattern->n_entries;
+ if (flags & 0x80) pos += 2;
+ if (flags & 0x40) pos += 2;
+ if (flags & 0x20) pos ++;
+ }
+ }
+
+ if ( ! pattern->n_entries ) return 0;
+
+ pattern->n_entries += nrows;
+
+ pattern->entry = malloc( pattern->n_entries * sizeof( * pattern->entry ) );
+ if ( ! pattern->entry ) return -1;
+
+ entry = pattern->entry;
+
+ row = 0;
+ pos = 0;
+
+ while ( ( row < nrows ) && ( pos < len ) )
+ {
+ if ( ! data[ pos ] )
+ {
+ IT_SET_END_ROW( entry );
+ ++ entry;
+ ++ row;
+ ++ pos;
+ continue;
+ }
+
+ flags = data[ pos++ ];
+ entry->channel = flags & 0x1F;
+ entry->mask = 0;
+
+ if (flags & 0xE0)
+ {
+ if ( flags & 0x80 )
+ {
+ _dumb_it_xm_convert_effect( data[ pos + 1 ], data[ pos ], entry, 0 );
+ pos += 2;
+ }
+
+ if ( flags & 0x40 )
+ {
+ if ( data[ pos ] )
+ {
+ entry->mask |= IT_ENTRY_INSTRUMENT;
+ entry->instrument = data[ pos ];
+ }
+ if ( data[ pos + 1 ] )
+ {
+ entry->mask |= IT_ENTRY_NOTE;
+ entry->note = data[ pos + 1 ] - 1;
+ }
+ pos += 2;
+ }
+
+ if ( flags & 0x20 )
+ {
+ entry->mask |= IT_ENTRY_VOLPAN;
+ if ( ver == 0 ) entry->volpan = data[ pos ];
+ else entry->volpan = data[ pos ] * 64 / 127;
+ ++ pos;
+ }
+
+ if (entry->mask) entry++;
+ }
+ }
+
+ while ( row < nrows )
+ {
+ IT_SET_END_ROW( entry );
+ ++ entry;
+ ++ row;
+ }
+
+ pattern->n_entries = entry - pattern->entry;
+ if ( ! pattern->n_entries ) return -1;
+
+ return 0;
+}
+
+static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( struct riff * stream )
+{
+ DUMB_IT_SIGDATA *sigdata;
+
+ int n, o, found;
+
+ unsigned char * ptr;
+
+ if ( ! stream ) goto error;
+
+ if ( stream->type != DUMB_ID( 'A', 'M', 'F', 'F' ) ) goto error;
+
+ sigdata = malloc( sizeof( *sigdata ) );
+ if ( ! sigdata ) goto error;
+
+ sigdata->n_patterns = 0;
+ sigdata->n_samples = 0;
+ sigdata->name[0] = 0;
+
+ found = 0;
+
+ for ( n = 0; n < stream->chunk_count; ++n )
+ {
+ struct riff_chunk * c = stream->chunks + n;
+ switch( c->type )
+ {
+ case DUMB_ID( 'M', 'A', 'I', 'N' ):
+ /* initialization data */
+ if ( ( found & 1 ) || ( c->size < 0x48 ) ) goto error_sd;
+ found |= 1;
+ break;
+
+ case DUMB_ID( 'O', 'R', 'D', 'R' ):
+ if ( ( found & 2 ) || ( c->size < 1 ) ) goto error_sd;
+ found |= 2;
+ break;
+
+ case DUMB_ID( 'P', 'A', 'T', 'T' ):
+ ptr = ( unsigned char * ) c->data;
+ if ( ptr[ 0 ] >= sigdata->n_patterns ) sigdata->n_patterns = ptr[ 0 ] + 1;
+ o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
+ if ( o + 5 > c->size ) goto error_sd;
+ break;
+
+ case DUMB_ID( 'I', 'N', 'S', 'T' ):
+ {
+ if ( c->size < 0xE1 ) goto error;
+ ptr = ( unsigned char * ) c->data;
+ if ( ptr[ 1 ] >= sigdata->n_samples ) sigdata->n_samples = ptr[ 1 ] + 1;
+ if ( c->size >= 0x121 && ( ptr[ 0xE1 ] == 'S' && ptr[ 0xE2 ] == 'A' &&
+ ptr[ 0xE3 ] == 'M' && ptr[ 0xE4 ] == 'P' ) )
+ {
+ unsigned size = ptr[ 0xE5 ] | ( ptr[ 0xE6 ] << 8 ) | ( ptr[ 0xE7 ] << 16 ) | ( ptr[ 0xE8 ] << 24 );
+ if ( size + 0xE1 + 8 > c->size ) goto error;
+ }
+ }
+ break;
+ }
+ }
+
+ if ( found != 3 || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd;
+
+ if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd;
+
+ sigdata->song_message = NULL;
+ sigdata->order = NULL;
+ sigdata->instrument = NULL;
+ sigdata->sample = NULL;
+ sigdata->pattern = NULL;
+ sigdata->midi = NULL;
+ sigdata->checkpoint = NULL;
+
+ sigdata->mixing_volume = 48;
+ sigdata->pan_separation = 128;
+
+ sigdata->n_instruments = 0;
+ sigdata->n_orders = 0;
+
+ memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
+
+ for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
+ sigdata->channel_pan[n ] = 16;
+ sigdata->channel_pan[n+1] = 48;
+ sigdata->channel_pan[n+2] = 48;
+ sigdata->channel_pan[n+3] = 16;
+ }
+
+ for ( n = 0; n < stream->chunk_count; ++n )
+ {
+ struct riff_chunk * c = stream->chunks + n;
+ switch ( c->type )
+ {
+ case DUMB_ID( 'M', 'A', 'I', 'N' ):
+ ptr = ( unsigned char * ) c->data;
+ memcpy( sigdata->name, c->data, 64 );
+ sigdata->name[ 64 ] = 0;
+ sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
+ if ( ! ( ptr[ 0x40 ] & 1 ) ) sigdata->flags |= IT_LINEAR_SLIDES;
+ if ( ( ptr[ 0x40 ] & ~3 ) || ! ( ptr[ 0x40 ] & 2 ) ) goto error_usd; // unknown flags
+ sigdata->n_pchannels = ptr[ 0x41 ];
+ sigdata->speed = ptr[ 0x42 ];
+ sigdata->tempo = ptr[ 0x43 ];
+
+ sigdata->global_volume = ptr[ 0x48 ];
+
+ if ( c->size < 0x48 + sigdata->n_pchannels ) goto error_usd;
+
+ for ( o = 0; o < sigdata->n_pchannels; ++o )
+ {
+ sigdata->channel_pan[ o ] = ptr[ 0x49 + o ];
+ if ( ptr[ 0x49 + o ] >= 128 )
+ {
+ sigdata->channel_volume[ o ] = 0;
+ }
+ }
+ break;
+ }
+ }
+
+ sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
+ if ( ! sigdata->pattern ) goto error_usd;
+ for ( n = 0; n < sigdata->n_patterns; ++n )
+ sigdata->pattern[ n ].entry = NULL;
+
+ sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
+ if ( ! sigdata->sample ) goto error_usd;
+ for ( n = 0; n < sigdata->n_samples; ++n )
+ {
+ IT_SAMPLE * sample = sigdata->sample + n;
+ sample->data = NULL;
+ sample->flags = 0;
+ sample->name[ 0 ] = 0;
+ }
+
+ for ( n = 0; n < stream->chunk_count; ++n )
+ {
+ struct riff_chunk * c = stream->chunks + n;
+ switch ( c->type )
+ {
+ case DUMB_ID( 'O', 'R', 'D', 'R' ):
+ ptr = ( unsigned char * ) c->data;
+ sigdata->n_orders = ptr[ 0 ] + 1;
+ if ( sigdata->n_orders + 1 > c->size ) goto error_usd;
+ sigdata->order = malloc( sigdata->n_orders );
+ if ( ! sigdata->order ) goto error_usd;
+ memcpy( sigdata->order, ptr + 1, sigdata->n_orders );
+ break;
+
+ case DUMB_ID( 'P', 'A', 'T', 'T' ):
+ ptr = ( unsigned char * ) c->data;
+ o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
+ if ( it_riff_am_process_pattern( sigdata->pattern + ptr[ 0 ], ptr + 5, o, 0 ) ) goto error_usd;
+ break;
+
+ case DUMB_ID( 'I', 'N', 'S', 'T' ):
+ {
+ IT_SAMPLE * sample;
+ ptr = ( unsigned char * ) c->data;
+ sample = sigdata->sample + ptr[ 1 ];
+ if ( c->size >= 0x121 && ( ptr[ 0xE1 ] == 'S' && ptr[ 0xE2 ] == 'A' &&
+ ptr[ 0xE3 ] == 'M' && ptr[ 0xE4 ] == 'P' ) )
+ {
+ unsigned size = ptr[ 0xE5 ] | ( ptr[ 0xE6 ] << 8 ) | ( ptr[ 0xE7 ] << 16 ) | ( ptr[ 0xE8 ] << 24 );
+ if ( it_riff_am_process_sample( sample, ptr + 0xE1 + 8, size, 0 ) ) goto error_usd;
+ }
+ else
+ {
+ memcpy( sample->name, ptr + 2, 28 );
+ sample->name[ 28 ] = 0;
+ }
+ }
+ break;
+ }
+ }
+
+ _dumb_it_fix_invalid_orders( sigdata );
+
+ return sigdata;
+
+error_usd:
+ _dumb_it_unload_sigdata( sigdata );
+ goto error;
+error_sd:
+ free( sigdata );
+error:
+ return NULL;
+}
+
+static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream )
+{
+ DUMB_IT_SIGDATA *sigdata;
+
+ int n, o, p, found;
+
+ unsigned char * ptr;
+
+ if ( ! stream ) goto error;
+
+ if ( stream->type != DUMB_ID( 'A', 'M', ' ', ' ' ) ) goto error;
+
+ sigdata = malloc(sizeof(*sigdata));
+ if ( ! sigdata ) goto error;
+
+ sigdata->n_patterns = 0;
+ sigdata->n_samples = 0;
+ sigdata->name[0] = 0;
+
+ found = 0;
+
+ for ( n = 0; n < stream->chunk_count; ++n )
+ {
+ struct riff_chunk * c = stream->chunks + n;
+ switch( c->type )
+ {
+ case DUMB_ID( 'I' ,'N' ,'I' ,'T' ):
+ /* initialization data */
+ if ( ( found & 1 ) || ( c->size < 0x48 ) ) goto error_sd;
+ found |= 1;
+ break;
+
+ case DUMB_ID( 'O', 'R', 'D', 'R' ):
+ if ( ( found & 2 ) || ( c->size < 1 ) ) goto error_sd;
+ found |= 2;
+ break;
+
+ case DUMB_ID( 'P', 'A', 'T', 'T' ):
+ ptr = ( unsigned char * ) c->data;
+ if ( ptr[ 0 ] >= sigdata->n_patterns ) sigdata->n_patterns = ptr[ 0 ] + 1;
+ o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
+ if ( o + 5 > c->size ) goto error_sd;
+ break;
+
+ case DUMB_ID( 'R', 'I', 'F', 'F' ):
+ {
+ struct riff * str = ( struct riff * ) c->data;
+ switch ( str->type )
+ {
+ case DUMB_ID( 'A', 'I', ' ', ' ' ):
+ for ( o = 0; o < str->chunk_count; ++o )
+ {
+ struct riff_chunk * chk = str->chunks + o;
+ switch( chk->type )
+ {
+ case DUMB_ID( 'I', 'N', 'S', 'T' ):
+ {
+ struct riff * temp;
+ unsigned size;
+ unsigned sample_found;
+ ptr = ( unsigned char * ) chk->data;
+ size = ptr[ 0 ] | ( ptr[ 1 ] << 8 ) | ( ptr[ 2 ] << 16 ) | ( ptr[ 3 ] << 24 );
+ if ( size < 0x142 ) goto error;
+ sample_found = 0;
+ if ( ptr[ 5 ] >= sigdata->n_samples ) sigdata->n_samples = ptr[ 5 ] + 1;
+ temp = riff_parse( ptr + 4 + size, chk->size - size - 4, 1 );
+ if ( temp )
+ {
+ if ( temp->type == DUMB_ID( 'A', 'S', ' ', ' ' ) )
+ {
+ for ( p = 0; p < temp->chunk_count; ++p )
+ {
+ if ( temp->chunks[ p ].type == DUMB_ID( 'S', 'A', 'M', 'P' ) )
+ {
+ if ( sample_found )
+ {
+ riff_free( temp );
+ goto error;
+ }
+ sample_found = 1;
+ }
+ }
+ }
+ riff_free( temp );
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if ( found != 3 || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd;
+
+ if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd;
+
+ sigdata->song_message = NULL;
+ sigdata->order = NULL;
+ sigdata->instrument = NULL;
+ sigdata->sample = NULL;
+ sigdata->pattern = NULL;
+ sigdata->midi = NULL;
+ sigdata->checkpoint = NULL;
+
+ sigdata->mixing_volume = 48;
+ sigdata->pan_separation = 128;
+
+ sigdata->n_instruments = 0;
+ sigdata->n_orders = 0;
+
+ memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
+
+ for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
+ sigdata->channel_pan[n ] = 16;
+ sigdata->channel_pan[n+1] = 48;
+ sigdata->channel_pan[n+2] = 48;
+ sigdata->channel_pan[n+3] = 16;
+ }
+
+ for ( n = 0; n < stream->chunk_count; ++n )
+ {
+ struct riff_chunk * c = stream->chunks + n;
+ switch ( c->type )
+ {
+ case DUMB_ID( 'I', 'N', 'I', 'T' ):
+ ptr = ( unsigned char * ) c->data;
+ memcpy( sigdata->name, c->data, 64 );
+ sigdata->name[ 64 ] = 0;
+ sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
+ if ( ! ( ptr[ 0x40 ] & 1 ) ) sigdata->flags |= IT_LINEAR_SLIDES;
+ if ( ( ptr[ 0x40 ] & ~3 ) || ! ( ptr[ 0x40 ] & 2 ) ) goto error_usd; // unknown flags
+ sigdata->n_pchannels = ptr[ 0x41 ];
+ sigdata->speed = ptr[ 0x42 ];
+ sigdata->tempo = ptr[ 0x43 ];
+
+ sigdata->global_volume = ptr[ 0x48 ];
+
+ if ( c->size < 0x48 + sigdata->n_pchannels ) goto error_usd;
+
+ for ( o = 0; o < sigdata->n_pchannels; ++o )
+ {
+ if ( ptr[ 0x49 + o ] <= 128 )
+ {
+ sigdata->channel_pan[ o ] = ptr[ 0x49 + o ] / 2;
+ }
+ else
+ {
+ sigdata->channel_volume[ o ] = 0;
+ }
+ }
+ break;
+ }
+ }
+
+ sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
+ if ( ! sigdata->pattern ) goto error_usd;
+ for ( n = 0; n < sigdata->n_patterns; ++n )
+ sigdata->pattern[ n ].entry = NULL;
+
+ sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
+ if ( ! sigdata->sample ) goto error_usd;
+ for ( n = 0; n < sigdata->n_samples; ++n )
+ {
+ IT_SAMPLE * sample = sigdata->sample + n;
+ sample->data = NULL;
+ sample->flags = 0;
+ sample->name[ 0 ] = 0;
+ }
+
+ for ( n = 0; n < stream->chunk_count; ++n )
+ {
+ struct riff_chunk * c = stream->chunks + n;
+ switch ( c->type )
+ {
+ case DUMB_ID( 'O', 'R', 'D', 'R' ):
+ ptr = ( unsigned char * ) c->data;
+ sigdata->n_orders = ptr[ 0 ] + 1;
+ if ( sigdata->n_orders + 1 > c->size ) goto error_usd;
+ sigdata->order = malloc( sigdata->n_orders );
+ if ( ! sigdata->order ) goto error_usd;
+ memcpy( sigdata->order, ptr + 1, sigdata->n_orders );
+ break;
+
+ case DUMB_ID( 'P', 'A', 'T', 'T' ):
+ ptr = ( unsigned char * ) c->data;
+ o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
+ if ( it_riff_am_process_pattern( sigdata->pattern + ptr[ 0 ], ptr + 5, o, 1 ) ) goto error_usd;
+ break;
+
+ case DUMB_ID( 'R', 'I', 'F', 'F' ):
+ {
+ struct riff * str = ( struct riff * ) c->data;
+ switch ( str->type )
+ {
+ case DUMB_ID('A', 'I', ' ', ' '):
+ for ( o = 0; o < str->chunk_count; ++o )
+ {
+ struct riff_chunk * chk = str->chunks + o;
+ switch( chk->type )
+ {
+ case DUMB_ID( 'I', 'N', 'S', 'T' ):
+ {
+ struct riff * temp;
+ unsigned size;
+ unsigned sample_found;
+ IT_SAMPLE * sample;
+ ptr = ( unsigned char * ) chk->data;
+ size = ptr[ 0 ] | ( ptr[ 1 ] << 8 ) | ( ptr[ 2 ] << 16 ) | ( ptr[ 3 ] << 24 );
+ temp = riff_parse( ptr + 4 + size, chk->size - size - 4, 1 );
+ sample_found = 0;
+ sample = sigdata->sample + ptr[ 5 ];
+ if ( temp )
+ {
+ if ( temp->type == DUMB_ID( 'A', 'S', ' ', ' ' ) )
+ {
+ for ( p = 0; p < temp->chunk_count; ++p )
+ {
+ struct riff_chunk * c = temp->chunks + p;
+ if ( c->type == DUMB_ID( 'S', 'A', 'M', 'P' ) )
+ {
+ if ( sample_found )
+ {
+ riff_free( temp );
+ goto error_usd;
+ }
+ if ( it_riff_am_process_sample( sigdata->sample + ptr[ 5 ], ( unsigned char * ) c->data, c->size, 1 ) )
+ {
+ riff_free( temp );
+ goto error_usd;
+ }
+ sample_found = 1;
+ }
+ }
+ }
+ riff_free( temp );
+ }
+ if ( ! sample_found )
+ {
+ memcpy( sample->name, ptr + 6, 32 );
+ sample->name[ 32 ] = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ _dumb_it_fix_invalid_orders( sigdata );
+
+ return sigdata;
+
+error_usd:
+ _dumb_it_unload_sigdata( sigdata );
+ goto error;
+error_sd:
+ free( sigdata );
+error:
+ return NULL;
+}
+
+DUH *dumb_read_riff_amff( struct riff * stream )
+{
+ sigdata_t *sigdata;
+ long length;
+
+ DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
+
+ sigdata = it_riff_amff_load_sigdata( stream );
+
+ if (!sigdata)
+ return NULL;
+
+ length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
+
+ {
+ const char *tag[2][2];
+ tag[0][0] = "TITLE";
+ tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+ tag[1][0] = "FORMAT";
+ tag[1][1] = "RIFF AMFF";
+ return make_duh( length, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
+ }
+}
+
+DUH *dumb_read_riff_am( struct riff * stream )
+{
+ sigdata_t *sigdata;
+
+ DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
+
+ sigdata = it_riff_am_load_sigdata( stream );
+
+ if (!sigdata)
+ return NULL;
+
+ {
+ const char *tag[2][2];
+ tag[0][0] = "TITLE";
+ tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+ tag[1][0] = "FORMAT";
+ tag[1][1] = "RIFF AM";
+ return make_duh( -1, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/readasy.c b/plugins/dumb/dumb-kode54/src/it/readasy.c
index 4c1c09f8..2969eb6f 100644
--- a/plugins/dumb/dumb-kode54/src/it/readasy.c
+++ b/plugins/dumb/dumb-kode54/src/it/readasy.c
@@ -1,331 +1,331 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readasy.c - Code to read an ASYLUM Music Format / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-static int it_asy_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer )
-{
- int pos;
- int channel;
- int row;
- IT_ENTRY *entry;
-
- pattern->n_rows = 64;
-
- if ( dumbfile_getnc( buffer, 64 * 8 * 4, f ) != 64 * 8 * 4 )
- return -1;
-
- /* compute number of entries */
- pattern->n_entries = 64; /* Account for the row end markers */
- pos = 0;
- for ( row = 0; row < 64; ++row ) {
- for ( channel = 0; channel < 8; ++channel ) {
- if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] )
- ++pattern->n_entries;
- pos += 4;
- }
- }
-
- pattern->entry = malloc( pattern->n_entries * sizeof( *pattern->entry ) );
- if ( !pattern->entry )
- return -1;
-
- entry = pattern->entry;
- pos = 0;
- for ( row = 0; row < 64; ++row ) {
- for ( channel = 0; channel < 8; ++channel ) {
- if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) {
- entry->channel = channel;
- entry->mask = 0;
-
- if ( buffer[ pos + 0 ] && buffer[ pos + 0 ] < 96 ) {
- entry->note = buffer[ pos + 0 ];
- entry->mask |= IT_ENTRY_NOTE;
- }
-
- if ( buffer[ pos + 1 ] && buffer[ pos + 1 ] <= 64 ) {
- entry->instrument = buffer[ pos + 1 ];
- entry->mask |= IT_ENTRY_INSTRUMENT;
- }
-
- _dumb_it_xm_convert_effect( buffer[ pos + 2 ] & 0x0F, buffer[ pos + 3 ], entry, 1 );
-
- if ( entry->mask ) ++entry;
- }
- pos += 4;
- }
- IT_SET_END_ROW( entry );
- ++entry;
- }
-
- pattern->n_entries = entry - pattern->entry;
-
- return 0;
-}
-
-
-
-static int it_asy_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f )
-{
- int finetune;
-
-/**
- 21 22 Chars Sample 1 name. If the name is not a full
- 22 chars in length, it will be null
- terminated.
-
-If
-the sample name begins with a '#' character (ASCII $23 (35)) then this is
-assumed not to be an instrument name, and is probably a message.
-*/
- dumbfile_getnc( sample->name, 22, f );
- sample->name[22] = 0;
-
- sample->filename[0] = 0;
-
-/** Each finetune step changes the note 1/8th of a semitone. */
- finetune = ( signed char ) ( dumbfile_getc( f ) << 4 ) >> 4; /* signed nibble */
- sample->default_volume = dumbfile_getc( f ); // Should we be setting global_volume to this instead?
- sample->global_volume = 64;
- if ( sample->default_volume > 64 ) sample->default_volume = 64;
- dumbfile_skip( f, 1 ); /* XXX unknown */
- sample->length = dumbfile_igetl( f );
- sample->loop_start = dumbfile_igetl( f );
- sample->loop_end = sample->loop_start + dumbfile_igetl( f );
-
- if ( sample->length <= 0 ) {
- sample->flags = 0;
- return 0;
- }
-
- sample->flags = IT_SAMPLE_EXISTS;
-
- sample->default_pan = 0;
- sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 );//( long )( 16726.0 * pow( DUMB_PITCH_BASE, finetune * 32 ) );
- sample->finetune = finetune * 32;
- // the above line might be wrong
-
- if ( ( sample->loop_end - sample->loop_start > 2 ) && ( sample->loop_end <= sample->length ) )
- sample->flags |= IT_SAMPLE_LOOP;
-
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = 0; // do we have to set _all_ these?
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-
-
-static int it_asy_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f )
-{
- long truncated_size;
-
- /* let's get rid of the sample data coming after the end of the loop */
- if ( ( sample->flags & IT_SAMPLE_LOOP ) && sample->loop_end < sample->length ) {
- truncated_size = sample->length - sample->loop_end;
- sample->length = sample->loop_end;
- } else {
- truncated_size = 0;
- }
-
- sample->data = malloc( sample->length );
-
- if ( !sample->data )
- return -1;
-
- if ( sample->length )
- dumbfile_getnc( sample->data, sample->length, f );
-
- dumbfile_skip( f, truncated_size );
-
- return dumbfile_error( f );
-}
-
-
-
-static DUMB_IT_SIGDATA *it_asy_load_sigdata(DUMBFILE *f)
-{
- DUMB_IT_SIGDATA *sigdata;
- int i;
-
- static const char sig_part[] = "ASYLUM Music Format";
- static const char sig_rest[] = " V1.0"; /* whee, string space optimization with format type below */
-
- char signature [32];
-
- if ( dumbfile_getnc( signature, 32, f ) != 32 ||
- memcmp( signature, sig_part, 19 ) ||
- memcmp( signature + 19, sig_rest, 5 ) ) {
- return NULL;
- }
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) {
- return NULL;
- }
-
- sigdata->speed = dumbfile_getc( f ); /* XXX seems to fit the files I have */
- sigdata->tempo = dumbfile_getc( f ); /* ditto */
- sigdata->n_samples = dumbfile_getc( f ); /* ditto */
- sigdata->n_patterns = dumbfile_getc( f );
- sigdata->n_orders = dumbfile_getc( f );
- sigdata->restart_position = dumbfile_getc( f );
-
- if ( dumbfile_error( f ) || !sigdata->n_samples || sigdata->n_samples > 64 || !sigdata->n_patterns ||
- !sigdata->n_orders ) {
- free( sigdata );
- return NULL;
- }
-
- if ( sigdata->restart_position > sigdata->n_orders ) /* XXX */
- sigdata->restart_position = 0;
-
- sigdata->order = malloc( sigdata->n_orders );
- if ( !sigdata->order ) {
- free( sigdata );
- return NULL;
- }
-
- if ( dumbfile_getnc( sigdata->order, sigdata->n_orders, f ) != sigdata->n_orders ||
- dumbfile_skip( f, 256 - sigdata->n_orders ) ) {
- free( sigdata->order );
- free( sigdata );
- return NULL;
- }
-
- sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
- if ( !sigdata->sample ) {
- free( sigdata->order );
- free( sigdata );
- return NULL;
- }
-
- sigdata->song_message = NULL;
- sigdata->instrument = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_instruments = 0;
-
- for ( i = 0; i < sigdata->n_samples; ++i )
- sigdata->sample[i].data = NULL;
-
- for ( i = 0; i < sigdata->n_samples; ++i ) {
- if ( it_asy_read_sample_header( &sigdata->sample[i], f ) ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- }
-
- if ( dumbfile_skip( f, 37 * ( 64 - sigdata->n_samples ) ) ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
-
- sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
- if ( !sigdata->pattern ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; ++i)
- sigdata->pattern[i].entry = NULL;
-
- /* Read in the patterns */
- {
- unsigned char *buffer = malloc( 64 * 8 * 4 ); /* 64 rows * 8 channels * 4 bytes */
- if ( !buffer ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- for ( i = 0; i < sigdata->n_patterns; ++i ) {
- if ( it_asy_read_pattern( &sigdata->pattern[i], f, buffer ) != 0 ) {
- free( buffer );
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- }
- free( buffer );
- }
-
- /* And finally, the sample data */
- for ( i = 0; i < sigdata->n_samples; ++i ) {
- if ( it_asy_read_sample_data( &sigdata->sample[i], f ) ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- }
-
- /* Now let's initialise the remaining variables, and we're done! */
- sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO;
-
- sigdata->global_volume = 128;
- sigdata->mixing_volume = 48;
- sigdata->pan_separation = 128;
-
- sigdata->n_pchannels = 8;
-
- sigdata->name[0] = 0;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
- sigdata->channel_pan[i+0] = 16;
- sigdata->channel_pan[i+1] = 48;
- sigdata->channel_pan[i+2] = 48;
- sigdata->channel_pan[i+3] = 16;
- }
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-
-
-DUH *dumb_read_asy_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_asy_load_sigdata(f);
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "ASYLUM Music Format";
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readasy.c - Code to read an ASYLUM Music Format / / \ \
+ * module from an open file. | < / \_
+ * | \/ /\ /
+ * By Chris Moeller. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+static int it_asy_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer )
+{
+ int pos;
+ int channel;
+ int row;
+ IT_ENTRY *entry;
+
+ pattern->n_rows = 64;
+
+ if ( dumbfile_getnc( buffer, 64 * 8 * 4, f ) != 64 * 8 * 4 )
+ return -1;
+
+ /* compute number of entries */
+ pattern->n_entries = 64; /* Account for the row end markers */
+ pos = 0;
+ for ( row = 0; row < 64; ++row ) {
+ for ( channel = 0; channel < 8; ++channel ) {
+ if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] )
+ ++pattern->n_entries;
+ pos += 4;
+ }
+ }
+
+ pattern->entry = malloc( pattern->n_entries * sizeof( *pattern->entry ) );
+ if ( !pattern->entry )
+ return -1;
+
+ entry = pattern->entry;
+ pos = 0;
+ for ( row = 0; row < 64; ++row ) {
+ for ( channel = 0; channel < 8; ++channel ) {
+ if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) {
+ entry->channel = channel;
+ entry->mask = 0;
+
+ if ( buffer[ pos + 0 ] && buffer[ pos + 0 ] < 96 ) {
+ entry->note = buffer[ pos + 0 ];
+ entry->mask |= IT_ENTRY_NOTE;
+ }
+
+ if ( buffer[ pos + 1 ] && buffer[ pos + 1 ] <= 64 ) {
+ entry->instrument = buffer[ pos + 1 ];
+ entry->mask |= IT_ENTRY_INSTRUMENT;
+ }
+
+ _dumb_it_xm_convert_effect( buffer[ pos + 2 ] & 0x0F, buffer[ pos + 3 ], entry, 1 );
+
+ if ( entry->mask ) ++entry;
+ }
+ pos += 4;
+ }
+ IT_SET_END_ROW( entry );
+ ++entry;
+ }
+
+ pattern->n_entries = entry - pattern->entry;
+
+ return 0;
+}
+
+
+
+static int it_asy_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f )
+{
+ int finetune;
+
+/**
+ 21 22 Chars Sample 1 name. If the name is not a full
+ 22 chars in length, it will be null
+ terminated.
+
+If
+the sample name begins with a '#' character (ASCII $23 (35)) then this is
+assumed not to be an instrument name, and is probably a message.
+*/
+ dumbfile_getnc( sample->name, 22, f );
+ sample->name[22] = 0;
+
+ sample->filename[0] = 0;
+
+/** Each finetune step changes the note 1/8th of a semitone. */
+ finetune = ( signed char ) ( dumbfile_getc( f ) << 4 ) >> 4; /* signed nibble */
+ sample->default_volume = dumbfile_getc( f ); // Should we be setting global_volume to this instead?
+ sample->global_volume = 64;
+ if ( sample->default_volume > 64 ) sample->default_volume = 64;
+ dumbfile_skip( f, 1 ); /* XXX unknown */
+ sample->length = dumbfile_igetl( f );
+ sample->loop_start = dumbfile_igetl( f );
+ sample->loop_end = sample->loop_start + dumbfile_igetl( f );
+
+ if ( sample->length <= 0 ) {
+ sample->flags = 0;
+ return 0;
+ }
+
+ sample->flags = IT_SAMPLE_EXISTS;
+
+ sample->default_pan = 0;
+ sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 );//( long )( 16726.0 * pow( DUMB_PITCH_BASE, finetune * 32 ) );
+ sample->finetune = finetune * 32;
+ // the above line might be wrong
+
+ if ( ( sample->loop_end - sample->loop_start > 2 ) && ( sample->loop_end <= sample->length ) )
+ sample->flags |= IT_SAMPLE_LOOP;
+
+ sample->vibrato_speed = 0;
+ sample->vibrato_depth = 0;
+ sample->vibrato_rate = 0;
+ sample->vibrato_waveform = 0; // do we have to set _all_ these?
+ sample->max_resampling_quality = -1;
+
+ return dumbfile_error(f);
+}
+
+
+
+static int it_asy_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f )
+{
+ long truncated_size;
+
+ /* let's get rid of the sample data coming after the end of the loop */
+ if ( ( sample->flags & IT_SAMPLE_LOOP ) && sample->loop_end < sample->length ) {
+ truncated_size = sample->length - sample->loop_end;
+ sample->length = sample->loop_end;
+ } else {
+ truncated_size = 0;
+ }
+
+ sample->data = malloc( sample->length );
+
+ if ( !sample->data )
+ return -1;
+
+ if ( sample->length )
+ dumbfile_getnc( sample->data, sample->length, f );
+
+ dumbfile_skip( f, truncated_size );
+
+ return dumbfile_error( f );
+}
+
+
+
+static DUMB_IT_SIGDATA *it_asy_load_sigdata(DUMBFILE *f)
+{
+ DUMB_IT_SIGDATA *sigdata;
+ int i;
+
+ static const char sig_part[] = "ASYLUM Music Format";
+ static const char sig_rest[] = " V1.0"; /* whee, string space optimization with format type below */
+
+ char signature [32];
+
+ if ( dumbfile_getnc( signature, 32, f ) != 32 ||
+ memcmp( signature, sig_part, 19 ) ||
+ memcmp( signature + 19, sig_rest, 5 ) ) {
+ return NULL;
+ }
+
+ sigdata = malloc(sizeof(*sigdata));
+ if (!sigdata) {
+ return NULL;
+ }
+
+ sigdata->speed = dumbfile_getc( f ); /* XXX seems to fit the files I have */
+ sigdata->tempo = dumbfile_getc( f ); /* ditto */
+ sigdata->n_samples = dumbfile_getc( f ); /* ditto */
+ sigdata->n_patterns = dumbfile_getc( f );
+ sigdata->n_orders = dumbfile_getc( f );
+ sigdata->restart_position = dumbfile_getc( f );
+
+ if ( dumbfile_error( f ) || !sigdata->n_samples || sigdata->n_samples > 64 || !sigdata->n_patterns ||
+ !sigdata->n_orders ) {
+ free( sigdata );
+ return NULL;
+ }
+
+ if ( sigdata->restart_position > sigdata->n_orders ) /* XXX */
+ sigdata->restart_position = 0;
+
+ sigdata->order = malloc( sigdata->n_orders );
+ if ( !sigdata->order ) {
+ free( sigdata );
+ return NULL;
+ }
+
+ if ( dumbfile_getnc( sigdata->order, sigdata->n_orders, f ) != sigdata->n_orders ||
+ dumbfile_skip( f, 256 - sigdata->n_orders ) ) {
+ free( sigdata->order );
+ free( sigdata );
+ return NULL;
+ }
+
+ sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
+ if ( !sigdata->sample ) {
+ free( sigdata->order );
+ free( sigdata );
+ return NULL;
+ }
+
+ sigdata->song_message = NULL;
+ sigdata->instrument = NULL;
+ sigdata->pattern = NULL;
+ sigdata->midi = NULL;
+ sigdata->checkpoint = NULL;
+
+ sigdata->n_instruments = 0;
+
+ for ( i = 0; i < sigdata->n_samples; ++i )
+ sigdata->sample[i].data = NULL;
+
+ for ( i = 0; i < sigdata->n_samples; ++i ) {
+ if ( it_asy_read_sample_header( &sigdata->sample[i], f ) ) {
+ _dumb_it_unload_sigdata( sigdata );
+ return NULL;
+ }
+ }
+
+ if ( dumbfile_skip( f, 37 * ( 64 - sigdata->n_samples ) ) ) {
+ _dumb_it_unload_sigdata( sigdata );
+ return NULL;
+ }
+
+ sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
+ if ( !sigdata->pattern ) {
+ _dumb_it_unload_sigdata( sigdata );
+ return NULL;
+ }
+ for (i = 0; i < sigdata->n_patterns; ++i)
+ sigdata->pattern[i].entry = NULL;
+
+ /* Read in the patterns */
+ {
+ unsigned char *buffer = malloc( 64 * 8 * 4 ); /* 64 rows * 8 channels * 4 bytes */
+ if ( !buffer ) {
+ _dumb_it_unload_sigdata( sigdata );
+ return NULL;
+ }
+ for ( i = 0; i < sigdata->n_patterns; ++i ) {
+ if ( it_asy_read_pattern( &sigdata->pattern[i], f, buffer ) != 0 ) {
+ free( buffer );
+ _dumb_it_unload_sigdata( sigdata );
+ return NULL;
+ }
+ }
+ free( buffer );
+ }
+
+ /* And finally, the sample data */
+ for ( i = 0; i < sigdata->n_samples; ++i ) {
+ if ( it_asy_read_sample_data( &sigdata->sample[i], f ) ) {
+ _dumb_it_unload_sigdata( sigdata );
+ return NULL;
+ }
+ }
+
+ /* Now let's initialise the remaining variables, and we're done! */
+ sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO;
+
+ sigdata->global_volume = 128;
+ sigdata->mixing_volume = 48;
+ sigdata->pan_separation = 128;
+
+ sigdata->n_pchannels = 8;
+
+ sigdata->name[0] = 0;
+
+ memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
+
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
+ sigdata->channel_pan[i+0] = 16;
+ sigdata->channel_pan[i+1] = 48;
+ sigdata->channel_pan[i+2] = 48;
+ sigdata->channel_pan[i+3] = 16;
+ }
+
+ _dumb_it_fix_invalid_orders(sigdata);
+
+ return sigdata;
+}
+
+
+
+DUH *dumb_read_asy_quick(DUMBFILE *f)
+{
+ sigdata_t *sigdata;
+
+ DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
+
+ sigdata = it_asy_load_sigdata(f);
+
+ if (!sigdata)
+ return NULL;
+
+ {
+ const char *tag[2][2];
+ tag[0][0] = "TITLE";
+ tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+ tag[1][0] = "FORMAT";
+ tag[1][1] = "ASYLUM Music Format";
+ return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/readdsmf.c b/plugins/dumb/dumb-kode54/src/it/readdsmf.c
index 2a4f23e6..4fa04f0e 100644
--- a/plugins/dumb/dumb-kode54/src/it/readdsmf.c
+++ b/plugins/dumb/dumb-kode54/src/it/readdsmf.c
@@ -1,373 +1,373 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readam.c - Code to read a RIFF DSMF module / / \ \
- * from a parsed RIFF structure. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-#include "internal/riff.h"
-
-static int it_riff_dsmf_process_sample( IT_SAMPLE * sample, const unsigned char * data, int len )
-{
- int flags;
-
- memcpy( sample->filename, data, 13 );
- sample->filename[ 14 ] = 0;
-
- flags = data[ 13 ] | ( data[ 14 ] << 8 );
- sample->default_volume = data[ 15 ];
- sample->length = data[ 16 ] | ( data[ 17 ] << 8 ) | ( data[ 18 ] << 16 ) | ( data[ 19 ] << 24 );
- sample->loop_start = data[ 20 ] | ( data[ 21 ] << 8 ) | ( data[ 22 ] << 16 ) | ( data[ 23 ] << 24 );
- sample->loop_end = data[ 24 ] | ( data[ 25 ] << 8 ) | ( data[ 26 ] << 16 ) | ( data[ 27 ] << 24 );
- sample->C5_speed = ( data[ 32 ] | ( data[ 33 ] << 8 ) ) * 2;
- memcpy( sample->name, data + 36, 28 );
- sample->name[ 28 ] = 0;
-
- /*if ( data[ 0x38 ] || data[ 0x39 ] || data[ 0x3A ] || data[ 0x3B ] )
- return -1;*/
-
- if ( ! sample->length ) {
- sample->flags &= ~IT_SAMPLE_EXISTS;
- return 0;
- }
-
- /*if ( flags & ~( 2 | 1 ) )
- return -1;*/
-
- if ( sample->length + 64 > len )
- return -1;
-
- sample->flags = IT_SAMPLE_EXISTS;
-
- sample->default_pan = 0;
- sample->global_volume = 64;
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = IT_VIBRATO_SINE;
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- if ( flags & 1 )
- {
- if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) &&
- ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end))
- {
- sample->length = sample->loop_end;
- sample->flags |= IT_SAMPLE_LOOP;
- if ( flags & 0x10 ) sample->flags |= IT_SAMPLE_PINGPONG_LOOP;
- }
- }
-
- sample->data = malloc( sample->length );
- if ( ! sample->data )
- return -1;
-
- memcpy( sample->data, data + 64, sample->length );
-
- if ( ! ( flags & 2 ) )
- {
- for ( flags = 0; flags < sample->length; ++flags )
- ( ( signed char * ) sample->data ) [ flags ] ^= 0x80;
- }
-
- return 0;
-}
-
-static int it_riff_dsmf_process_pattern( IT_PATTERN * pattern, const unsigned char * data, int len )
-{
- int length, row, pos;
- unsigned flags;
- IT_ENTRY * entry;
-
- length = data[ 0 ] | ( data[ 1 ] << 8 );
- if ( length > len ) return -1;
-
- data += 2;
- len = length - 2;
-
- pattern->n_rows = 64;
- pattern->n_entries = 64;
-
- row = 0;
- pos = 0;
-
- while ( (row < 64) && (pos < len) ) {
- if ( ! data[ pos ] ) {
- ++ row;
- ++ pos;
- continue;
- }
-
- flags = data[ pos++ ] & 0xF0;
-
- if (flags) {
- ++ pattern->n_entries;
- if (flags & 0x80) pos ++;
- if (flags & 0x40) pos ++;
- if (flags & 0x20) pos ++;
- if (flags & 0x10) pos += 2;
- }
- }
-
- if ( pattern->n_entries == 64 ) return 0;
-
- pattern->entry = malloc( pattern->n_entries * sizeof( * pattern->entry ) );
- if ( ! pattern->entry ) return -1;
-
- entry = pattern->entry;
-
- row = 0;
- pos = 0;
-
- while ( ( row < 64 ) && ( pos < len ) )
- {
- if ( ! data[ pos ] )
- {
- IT_SET_END_ROW( entry );
- ++ entry;
- ++ row;
- ++ pos;
- continue;
- }
-
- flags = data[ pos++ ];
- entry->channel = flags & 0x0F;
- entry->mask = 0;
-
- if ( flags & 0xF0 )
- {
- if ( flags & 0x80 )
- {
- if ( data[ pos ] )
- {
- entry->mask |= IT_ENTRY_NOTE;
- entry->note = data[ pos ] - 1;
- }
- ++ pos;
- }
-
- if ( flags & 0x40 )
- {
- if ( data[ pos ] )
- {
- entry->mask |= IT_ENTRY_INSTRUMENT;
- entry->instrument = data[ pos ];
- }
- ++ pos;
- }
-
- if ( flags & 0x20 )
- {
- entry->mask |= IT_ENTRY_VOLPAN;
- entry->volpan = data[ pos ];
- ++ pos;
- }
-
- if ( flags & 0x10 )
- {
- _dumb_it_xm_convert_effect( data[ pos ], data[ pos + 1 ], entry, 0 );
- pos += 2;
- }
-
- if (entry->mask) entry++;
- }
- }
-
- while ( row < 64 )
- {
- IT_SET_END_ROW( entry );
- ++ entry;
- ++ row;
- }
-
- pattern->n_entries = entry - pattern->entry;
- if ( ! pattern->n_entries ) return -1;
-
- return 0;
-}
-
-static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( struct riff * stream )
-{
- DUMB_IT_SIGDATA *sigdata;
-
- int n, o, found;
-
- unsigned char * ptr;
-
- if ( ! stream ) goto error;
-
- if ( stream->type != DUMB_ID( 'D', 'S', 'M', 'F' ) ) goto error;
-
- sigdata = malloc(sizeof(*sigdata));
- if ( ! sigdata ) goto error;
-
- sigdata->n_patterns = 0;
- sigdata->n_samples = 0;
- sigdata->name[0] = 0;
-
- found = 0;
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch( c->type )
- {
- case DUMB_ID( 'S' ,'O' ,'N' ,'G' ):
- /* initialization data */
- if ( ( found ) || ( c->size < 192 ) ) goto error_sd;
- found = 1;
- break;
-
- case DUMB_ID( 'P', 'A', 'T', 'T' ):
- ++ sigdata->n_patterns;
- break;
-
- case DUMB_ID( 'I', 'N', 'S', 'T' ):
- ++ sigdata->n_samples;
- break;
- }
- }
-
- if ( !found || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd;
-
- if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd;
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->mixing_volume = 48;
- sigdata->pan_separation = 128;
-
- sigdata->n_instruments = 0;
- sigdata->n_orders = 0;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
- sigdata->channel_pan[n ] = 16;
- sigdata->channel_pan[n+1] = 48;
- sigdata->channel_pan[n+2] = 48;
- sigdata->channel_pan[n+3] = 16;
- }
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch ( c->type )
- {
- case DUMB_ID( 'S', 'O', 'N', 'G' ):
- ptr = ( unsigned char * ) c->data;
- memcpy( sigdata->name, c->data, 28 );
- sigdata->name[ 28 ] = 0;
- sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
- sigdata->n_orders = ptr[ 36 ] | ( ptr[ 37 ] << 8 );
- //sigdata->n_samples = ptr[ 38 ] | ( ptr[ 39 ] << 8 ); // whatever
- //sigdata->n_patterns = ptr[ 40 ] | ( ptr[ 41 ] << 8 );
- sigdata->n_pchannels = ptr[ 42 ] | ( ptr[ 43 ] << 8 );
- sigdata->global_volume = ptr[ 44 ];
- sigdata->mixing_volume = ptr[ 45 ];
- sigdata->speed = ptr[ 46 ];
- sigdata->tempo = ptr[ 47 ];
-
- for ( o = 0; o < 16; ++o )
- {
- sigdata->channel_pan[ o ] = ptr[ 48 + o ] / 2;
- }
-
- sigdata->order = malloc( 128 );
- if ( ! sigdata->order ) goto error_usd;
- memcpy( sigdata->order, ptr + 64, 128 );
-
- break;
- }
- }
-
- sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
- if ( ! sigdata->pattern ) goto error_usd;
- for ( n = 0; n < sigdata->n_patterns; ++n )
- sigdata->pattern[ n ].entry = NULL;
-
- sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
- if ( ! sigdata->sample ) goto error_usd;
- for ( n = 0; n < sigdata->n_samples; ++n )
- {
- IT_SAMPLE * sample = sigdata->sample + n;
- sample->data = NULL;
- }
-
- sigdata->n_samples = 0;
- sigdata->n_patterns = 0;
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch ( c->type )
- {
- case DUMB_ID( 'P', 'A', 'T', 'T' ):
- if ( it_riff_dsmf_process_pattern( sigdata->pattern + sigdata->n_patterns, ( unsigned char * ) c->data, c->size ) ) goto error_usd;
- ++ sigdata->n_patterns;
- break;
-
- case DUMB_ID( 'I', 'N', 'S', 'T' ):
- if ( it_riff_dsmf_process_sample( sigdata->sample + sigdata->n_samples, ( unsigned char * ) c->data, c->size ) ) goto error_usd;
- ++ sigdata->n_samples;
- break;
- }
- }
-
- _dumb_it_fix_invalid_orders( sigdata );
-
- return sigdata;
-
-error_usd:
- _dumb_it_unload_sigdata( sigdata );
- goto error;
-error_sd:
- free( sigdata );
-error:
- return NULL;
-}
-
-DUH *dumb_read_riff_dsmf( struct riff * stream )
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_riff_dsmf_load_sigdata( stream );
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "RIFF DSMF";
- return make_duh( -1, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readam.c - Code to read a RIFF DSMF module / / \ \
+ * from a parsed RIFF structure. | < / \_
+ * | \/ /\ /
+ * By Chris Moeller. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+#include "internal/riff.h"
+
+static int it_riff_dsmf_process_sample( IT_SAMPLE * sample, const unsigned char * data, int len )
+{
+ int flags;
+
+ memcpy( sample->filename, data, 13 );
+ sample->filename[ 14 ] = 0;
+
+ flags = data[ 13 ] | ( data[ 14 ] << 8 );
+ sample->default_volume = data[ 15 ];
+ sample->length = data[ 16 ] | ( data[ 17 ] << 8 ) | ( data[ 18 ] << 16 ) | ( data[ 19 ] << 24 );
+ sample->loop_start = data[ 20 ] | ( data[ 21 ] << 8 ) | ( data[ 22 ] << 16 ) | ( data[ 23 ] << 24 );
+ sample->loop_end = data[ 24 ] | ( data[ 25 ] << 8 ) | ( data[ 26 ] << 16 ) | ( data[ 27 ] << 24 );
+ sample->C5_speed = ( data[ 32 ] | ( data[ 33 ] << 8 ) ) * 2;
+ memcpy( sample->name, data + 36, 28 );
+ sample->name[ 28 ] = 0;
+
+ /*if ( data[ 0x38 ] || data[ 0x39 ] || data[ 0x3A ] || data[ 0x3B ] )
+ return -1;*/
+
+ if ( ! sample->length ) {
+ sample->flags &= ~IT_SAMPLE_EXISTS;
+ return 0;
+ }
+
+ /*if ( flags & ~( 2 | 1 ) )
+ return -1;*/
+
+ if ( sample->length + 64 > len )
+ return -1;
+
+ sample->flags = IT_SAMPLE_EXISTS;
+
+ sample->default_pan = 0;
+ sample->global_volume = 64;
+ sample->vibrato_speed = 0;
+ sample->vibrato_depth = 0;
+ sample->vibrato_rate = 0;
+ sample->vibrato_waveform = IT_VIBRATO_SINE;
+ sample->finetune = 0;
+ sample->max_resampling_quality = -1;
+
+ if ( flags & 1 )
+ {
+ if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) &&
+ ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end))
+ {
+ sample->length = sample->loop_end;
+ sample->flags |= IT_SAMPLE_LOOP;
+ if ( flags & 0x10 ) sample->flags |= IT_SAMPLE_PINGPONG_LOOP;
+ }
+ }
+
+ sample->data = malloc( sample->length );
+ if ( ! sample->data )
+ return -1;
+
+ memcpy( sample->data, data + 64, sample->length );
+
+ if ( ! ( flags & 2 ) )
+ {
+ for ( flags = 0; flags < sample->length; ++flags )
+ ( ( signed char * ) sample->data ) [ flags ] ^= 0x80;
+ }
+
+ return 0;
+}
+
+static int it_riff_dsmf_process_pattern( IT_PATTERN * pattern, const unsigned char * data, int len )
+{
+ int length, row, pos;
+ unsigned flags;
+ IT_ENTRY * entry;
+
+ length = data[ 0 ] | ( data[ 1 ] << 8 );
+ if ( length > len ) return -1;
+
+ data += 2;
+ len = length - 2;
+
+ pattern->n_rows = 64;
+ pattern->n_entries = 64;
+
+ row = 0;
+ pos = 0;
+
+ while ( (row < 64) && (pos < len) ) {
+ if ( ! data[ pos ] ) {
+ ++ row;
+ ++ pos;
+ continue;
+ }
+
+ flags = data[ pos++ ] & 0xF0;
+
+ if (flags) {
+ ++ pattern->n_entries;
+ if (flags & 0x80) pos ++;
+ if (flags & 0x40) pos ++;
+ if (flags & 0x20) pos ++;
+ if (flags & 0x10) pos += 2;
+ }
+ }
+
+ if ( pattern->n_entries == 64 ) return 0;
+
+ pattern->entry = malloc( pattern->n_entries * sizeof( * pattern->entry ) );
+ if ( ! pattern->entry ) return -1;
+
+ entry = pattern->entry;
+
+ row = 0;
+ pos = 0;
+
+ while ( ( row < 64 ) && ( pos < len ) )
+ {
+ if ( ! data[ pos ] )
+ {
+ IT_SET_END_ROW( entry );
+ ++ entry;
+ ++ row;
+ ++ pos;
+ continue;
+ }
+
+ flags = data[ pos++ ];
+ entry->channel = flags & 0x0F;
+ entry->mask = 0;
+
+ if ( flags & 0xF0 )
+ {
+ if ( flags & 0x80 )
+ {
+ if ( data[ pos ] )
+ {
+ entry->mask |= IT_ENTRY_NOTE;
+ entry->note = data[ pos ] - 1;
+ }
+ ++ pos;
+ }
+
+ if ( flags & 0x40 )
+ {
+ if ( data[ pos ] )
+ {
+ entry->mask |= IT_ENTRY_INSTRUMENT;
+ entry->instrument = data[ pos ];
+ }
+ ++ pos;
+ }
+
+ if ( flags & 0x20 )
+ {
+ entry->mask |= IT_ENTRY_VOLPAN;
+ entry->volpan = data[ pos ];
+ ++ pos;
+ }
+
+ if ( flags & 0x10 )
+ {
+ _dumb_it_xm_convert_effect( data[ pos ], data[ pos + 1 ], entry, 0 );
+ pos += 2;
+ }
+
+ if (entry->mask) entry++;
+ }
+ }
+
+ while ( row < 64 )
+ {
+ IT_SET_END_ROW( entry );
+ ++ entry;
+ ++ row;
+ }
+
+ pattern->n_entries = entry - pattern->entry;
+ if ( ! pattern->n_entries ) return -1;
+
+ return 0;
+}
+
+static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( struct riff * stream )
+{
+ DUMB_IT_SIGDATA *sigdata;
+
+ int n, o, found;
+
+ unsigned char * ptr;
+
+ if ( ! stream ) goto error;
+
+ if ( stream->type != DUMB_ID( 'D', 'S', 'M', 'F' ) ) goto error;
+
+ sigdata = malloc(sizeof(*sigdata));
+ if ( ! sigdata ) goto error;
+
+ sigdata->n_patterns = 0;
+ sigdata->n_samples = 0;
+ sigdata->name[0] = 0;
+
+ found = 0;
+
+ for ( n = 0; n < stream->chunk_count; ++n )
+ {
+ struct riff_chunk * c = stream->chunks + n;
+ switch( c->type )
+ {
+ case DUMB_ID( 'S' ,'O' ,'N' ,'G' ):
+ /* initialization data */
+ if ( ( found ) || ( c->size < 192 ) ) goto error_sd;
+ found = 1;
+ break;
+
+ case DUMB_ID( 'P', 'A', 'T', 'T' ):
+ ++ sigdata->n_patterns;
+ break;
+
+ case DUMB_ID( 'I', 'N', 'S', 'T' ):
+ ++ sigdata->n_samples;
+ break;
+ }
+ }
+
+ if ( !found || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd;
+
+ if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd;
+
+ sigdata->song_message = NULL;
+ sigdata->order = NULL;
+ sigdata->instrument = NULL;
+ sigdata->sample = NULL;
+ sigdata->pattern = NULL;
+ sigdata->midi = NULL;
+ sigdata->checkpoint = NULL;
+
+ sigdata->mixing_volume = 48;
+ sigdata->pan_separation = 128;
+
+ sigdata->n_instruments = 0;
+ sigdata->n_orders = 0;
+
+ memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
+
+ for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
+ sigdata->channel_pan[n ] = 16;
+ sigdata->channel_pan[n+1] = 48;
+ sigdata->channel_pan[n+2] = 48;
+ sigdata->channel_pan[n+3] = 16;
+ }
+
+ for ( n = 0; n < stream->chunk_count; ++n )
+ {
+ struct riff_chunk * c = stream->chunks + n;
+ switch ( c->type )
+ {
+ case DUMB_ID( 'S', 'O', 'N', 'G' ):
+ ptr = ( unsigned char * ) c->data;
+ memcpy( sigdata->name, c->data, 28 );
+ sigdata->name[ 28 ] = 0;
+ sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
+ sigdata->n_orders = ptr[ 36 ] | ( ptr[ 37 ] << 8 );
+ //sigdata->n_samples = ptr[ 38 ] | ( ptr[ 39 ] << 8 ); // whatever
+ //sigdata->n_patterns = ptr[ 40 ] | ( ptr[ 41 ] << 8 );
+ sigdata->n_pchannels = ptr[ 42 ] | ( ptr[ 43 ] << 8 );
+ sigdata->global_volume = ptr[ 44 ];
+ sigdata->mixing_volume = ptr[ 45 ];
+ sigdata->speed = ptr[ 46 ];
+ sigdata->tempo = ptr[ 47 ];
+
+ for ( o = 0; o < 16; ++o )
+ {
+ sigdata->channel_pan[ o ] = ptr[ 48 + o ] / 2;
+ }
+
+ sigdata->order = malloc( 128 );
+ if ( ! sigdata->order ) goto error_usd;
+ memcpy( sigdata->order, ptr + 64, 128 );
+
+ break;
+ }
+ }
+
+ sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
+ if ( ! sigdata->pattern ) goto error_usd;
+ for ( n = 0; n < sigdata->n_patterns; ++n )
+ sigdata->pattern[ n ].entry = NULL;
+
+ sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
+ if ( ! sigdata->sample ) goto error_usd;
+ for ( n = 0; n < sigdata->n_samples; ++n )
+ {
+ IT_SAMPLE * sample = sigdata->sample + n;
+ sample->data = NULL;
+ }
+
+ sigdata->n_samples = 0;
+ sigdata->n_patterns = 0;
+
+ for ( n = 0; n < stream->chunk_count; ++n )
+ {
+ struct riff_chunk * c = stream->chunks + n;
+ switch ( c->type )
+ {
+ case DUMB_ID( 'P', 'A', 'T', 'T' ):
+ if ( it_riff_dsmf_process_pattern( sigdata->pattern + sigdata->n_patterns, ( unsigned char * ) c->data, c->size ) ) goto error_usd;
+ ++ sigdata->n_patterns;
+ break;
+
+ case DUMB_ID( 'I', 'N', 'S', 'T' ):
+ if ( it_riff_dsmf_process_sample( sigdata->sample + sigdata->n_samples, ( unsigned char * ) c->data, c->size ) ) goto error_usd;
+ ++ sigdata->n_samples;
+ break;
+ }
+ }
+
+ _dumb_it_fix_invalid_orders( sigdata );
+
+ return sigdata;
+
+error_usd:
+ _dumb_it_unload_sigdata( sigdata );
+ goto error;
+error_sd:
+ free( sigdata );
+error:
+ return NULL;
+}
+
+DUH *dumb_read_riff_dsmf( struct riff * stream )
+{
+ sigdata_t *sigdata;
+
+ DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
+
+ sigdata = it_riff_dsmf_load_sigdata( stream );
+
+ if (!sigdata)
+ return NULL;
+
+ {
+ const char *tag[2][2];
+ tag[0][0] = "TITLE";
+ tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+ tag[1][0] = "FORMAT";
+ tag[1][1] = "RIFF DSMF";
+ return make_duh( -1, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/readmod.c b/plugins/dumb/dumb-kode54/src/it/readmod.c
index b6b35cbe..a934af40 100644
--- a/plugins/dumb/dumb-kode54/src/it/readmod.c
+++ b/plugins/dumb/dumb-kode54/src/it/readmod.c
@@ -1,780 +1,782 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readmod.c - Code to read a good old-fashioned / / \ \
- * Amiga module from an open file. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-static int it_mod_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer)
-{
- int pos;
- int channel;
- int row;
- IT_ENTRY *entry;
-
- pattern->n_rows = 64;
-
- if (n_channels == 0) {
- /* Read the first four channels, leaving gaps for the rest. */
- for (pos = 0; pos < 64*8*4; pos += 8*4)
- dumbfile_getnc(buffer + pos, 4*4, f);
- /* Read the other channels into the gaps we left. */
- for (pos = 4*4; pos < 64*8*4; pos += 8*4)
- dumbfile_getnc(buffer + pos, 4*4, f);
-
- n_channels = 8;
- } else
- dumbfile_getnc(buffer, 64 * n_channels * 4, f);
-
- if (dumbfile_error(f))
- return -1;
-
- /* compute number of entries */
- pattern->n_entries = 64; /* Account for the row end markers */
- pos = 0;
- for (row = 0; row < 64; row++) {
- for (channel = 0; channel < n_channels; channel++) {
- if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3])
- pattern->n_entries++;
- pos += 4;
- }
- }
-
- pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
- if (!pattern->entry)
- return -1;
-
- entry = pattern->entry;
- pos = 0;
- for (row = 0; row < 64; row++) {
- for (channel = 0; channel < n_channels; channel++) {
- if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3]) {
- unsigned char sample = (buffer[pos+0] & 0xF0) | (buffer[pos+2] >> 4);
- int period = ((int)(buffer[pos+0] & 0x0F) << 8) | buffer[pos+1];
-
- entry->channel = channel;
- entry->mask = 0;
-
- if (period) {
- int note;
- entry->mask |= IT_ENTRY_NOTE;
-
- /* frequency = (AMIGA_DIVISOR / 8) / (period * 2)
- * C-1: period = 214 -> frequency = 16726
- * so, set C5_speed to 16726
- * and period = 214 should translate to C5 aka 60
- * halve the period, go up an octive
- *
- * period = 214 / pow(DUMB_SEMITONE_BASE, note - 60)
- * pow(DUMB_SEMITONE_BASE, note - 60) = 214 / period
- * note - 60 = log(214/period) / log(DUMB_SEMITONE_BASE)
- */
- note = (int)floor(log(214.0/period) / log(DUMB_SEMITONE_BASE) + 60.5);
- entry->note = MID(0, note, 119);
- // or should we preserve the period?
- //entry->note = buffer[pos+0] & 0x0F; /* High nibble */
- //entry->volpan = buffer[pos+1]; /* Low byte */
- // and what about finetune?
- }
-
- if (sample) {
- entry->mask |= IT_ENTRY_INSTRUMENT;
- entry->instrument = sample;
- }
-
- _dumb_it_xm_convert_effect(buffer[pos+2] & 0x0F, buffer[pos+3], entry, 1);
-
- entry++;
- }
- pos += 4;
- }
- IT_SET_END_ROW(entry);
- entry++;
- }
-
- return 0;
-}
-
-
-
-static int it_mod_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
-{
- int finetune, loop_start, loop_length;
-
-/**
- 21 22 Chars Sample 1 name. If the name is not a full
- 22 chars in length, it will be null
- terminated.
-
-If
-the sample name begins with a '#' character (ASCII $23 (35)) then this is
-assumed not to be an instrument name, and is probably a message.
-*/
- dumbfile_getnc(sample->name, 22, f);
- sample->name[22] = 0;
-
- sample->filename[0] = 0;
-
- sample->length = dumbfile_mgetw(f) << 1;
- finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */
-/** Each finetune step changes the note 1/8th of a semitone. */
- sample->global_volume = 64;
- sample->default_volume = dumbfile_getc(f); // Should we be setting global_volume to this instead?
- loop_start = dumbfile_mgetw(f) << 1;
- loop_length = dumbfile_mgetw(f) << 1;
- if ( loop_length > 2 && loop_start + loop_length > sample->length && loop_start / 2 + loop_length <= sample->length )
- loop_start /= 2;
- sample->loop_start = loop_start;
- sample->loop_end = loop_start + loop_length;
-/**
-Once this sample has been played completely from beginning
-to end, if the repeat length (next field) is greater than two bytes it
-will loop back to this position in the sample and continue playing. Once
-it has played for the repeat length, it continues to loop back to the
-repeat start offset. This means the sample continues playing until it is
-told to stop.
-*/
-
- if (sample->length <= 0) {
- sample->flags = 0;
- return 0;
- }
-
- sample->flags = IT_SAMPLE_EXISTS;
-
- sample->default_pan = 0;
- sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 ); //(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
- sample->finetune = finetune * 32;
- // the above line might be wrong
-
- if (sample->loop_end > sample->length)
- sample->loop_end = sample->length;
-
- if (sample->loop_end - sample->loop_start > 2)
- sample->flags |= IT_SAMPLE_LOOP;
-
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = 0; // do we have to set _all_ these?
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-
-
-static int it_mod_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f, unsigned long fft)
-{
- long i;
- long truncated_size;
-
- /* let's get rid of the sample data coming after the end of the loop */
- if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
- truncated_size = sample->length - sample->loop_end;
- sample->length = sample->loop_end;
- } else {
- truncated_size = 0;
- }
-
- if (sample->length) {
- sample->data = malloc(sample->length);
-
- if (!sample->data)
- return -1;
-
- /* Sample data are stored in "8-bit two's compliment format" (sic). */
- /*
- for (i = 0; i < sample->length; i++)
- ((signed char *)sample->left)[i] = dumbfile_getc(f);
- */
- /* F U Olivier Lapicque */
- if (sample->length >= 5)
- {
- i = dumbfile_getnc(sample->data, 5, f);
- if (i == 5)
- {
- if (!memcmp(sample->data, "ADPCM", 5))
- {
- if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
- return -1;
-
- return 0;
- }
- else
- {
- i += dumbfile_getnc(((char *)sample->data) + 5, sample->length - 5, f);
- }
- }
- }
- else
- {
- i = dumbfile_getnc(sample->data, sample->length, f);
- }
- if (i < sample->length)
- {
- if (i <= 0)
- {
- sample->flags = 0;
- return 0;
- }
- sample->length = i;
- if (sample->loop_end > i) sample->loop_end = i;
- // holy crap!
- if (sample->loop_start > i) sample->flags &= ~IT_SAMPLE_LOOP;
- }
- else
- {
- /* skip truncated data */
- int feh = dumbfile_error(f);
-
- if (truncated_size) dumbfile_skip(f, truncated_size);
- // Should we be truncating it?
-
- if (feh)
- return -1;
- }
-
- if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) {
- int delta = 0;
- for (i = 0; i < sample->length; i++) {
- delta += ((signed char *)sample->data)[i];
- ((signed char *)sample->data)[i] = delta;
- }
- }
- }
-
- return 0;
-}
-
-
-
-typedef struct BUFFERED_MOD BUFFERED_MOD;
-
-struct BUFFERED_MOD
-{
- unsigned char *buffered;
- long ptr, len;
- DUMBFILE *remaining;
-};
-
-
-
-static int buffer_mod_skip(void *f, long n)
-{
- BUFFERED_MOD *bm = f;
- if (bm->buffered) {
- bm->ptr += n;
- if (bm->ptr >= bm->len) {
- free(bm->buffered);
- bm->buffered = NULL;
- return dumbfile_skip(bm->remaining, bm->ptr - bm->len);
- }
- return 0;
- }
- return dumbfile_skip(bm->remaining, n);
-}
-
-
-
-static int buffer_mod_getc(void *f)
-{
- BUFFERED_MOD *bm = f;
- if (bm->buffered) {
- int rv = bm->buffered[bm->ptr++];
- if (bm->ptr >= bm->len) {
- free(bm->buffered);
- bm->buffered = NULL;
- }
- return rv;
- }
- return dumbfile_getc(bm->remaining);
-}
-
-
-
-static long buffer_mod_getnc(char *ptr, long n, void *f)
-{
- BUFFERED_MOD *bm = f;
- if (bm->buffered) {
- int left = bm->len - bm->ptr;
- if (n >= left) {
- memcpy(ptr, bm->buffered + bm->ptr, left);
- free(bm->buffered);
- bm->buffered = NULL;
- if (n - left) {
- int rv = dumbfile_getnc(ptr + left, n - left, bm->remaining);
- return left + MAX(rv, 0);
- } else {
- return left;
- }
- }
- memcpy(ptr, bm->buffered + bm->ptr, n);
- bm->ptr += n;
- return n;
- }
- return dumbfile_getnc(ptr, n, bm->remaining);
-}
-
-
-
-static void buffer_mod_close(void *f)
-{
- BUFFERED_MOD *bm = f;
- if (bm->buffered) free(bm->buffered);
- /* Do NOT close bm->remaining */
- free(f);
-}
-
-
-
-DUMBFILE_SYSTEM buffer_mod_dfs = {
- NULL,
- &buffer_mod_skip,
- &buffer_mod_getc,
- &buffer_mod_getnc,
- &buffer_mod_close
-};
-
-
-
-#define MOD_FFT_OFFSET (20 + 31*(22+2+1+1+2+2) + 1 + 1 + 128)
-
-static DUMBFILE *dumbfile_buffer_mod(DUMBFILE *f, unsigned long *fft)
-{
- BUFFERED_MOD *bm = malloc(sizeof(*bm));
- if (!bm) return NULL;
-
- bm->buffered = malloc(MOD_FFT_OFFSET + 4);
- if (!bm->buffered) {
- free(bm);
- return NULL;
- }
-
- bm->len = dumbfile_getnc(bm->buffered, MOD_FFT_OFFSET + 4, f);
-
- if (bm->len > 0) {
- if (bm->len >= MOD_FFT_OFFSET + 4)
- *fft = (unsigned long)bm->buffered[MOD_FFT_OFFSET ] << 24
- | (unsigned long)bm->buffered[MOD_FFT_OFFSET+1] << 16
- | (unsigned long)bm->buffered[MOD_FFT_OFFSET+2] << 8
- | (unsigned long)bm->buffered[MOD_FFT_OFFSET+3];
- else
- *fft = 0;
- bm->ptr = 0;
- } else {
- free(bm->buffered);
- bm->buffered = NULL;
- }
-
- bm->remaining = f;
-
- return dumbfile_open_ex(bm, &buffer_mod_dfs);
-}
-
-static DUMBFILE *dumbfile_buffer_mod_2(DUMBFILE *f, long *remain)
-{
- long read;
- BUFFERED_MOD *bm = malloc(sizeof(*bm));
- if (!bm) return NULL;
-
- bm->buffered = malloc(32768);
- if (!bm->buffered) {
- free(bm);
- return NULL;
- }
-
- bm->len = 0;
- *remain = 0;
-
- read = dumbfile_getnc(bm->buffered, 32768, f);
-
- if (read >= 0) {
- bm->len += read;
- *remain += read;
-
- while (read >= 32768) {
- bm->buffered = realloc(bm->buffered, *remain + 32768);
- if (!bm->buffered) {
- free(bm);
- return 0;
- }
- read = dumbfile_getnc(bm->buffered + *remain, 32768, f);
- if (read >= 0) {
- bm->len += read;
- *remain += read;
- }
- }
- }
-
- if (*remain) {
- bm->ptr = 0;
- } else {
- free(bm->buffered);
- bm->buffered = NULL;
- }
-
- bm->remaining = f;
-
- return dumbfile_open_ex(bm, &buffer_mod_dfs);
-}
-
-
-static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
-{
- DUMB_IT_SIGDATA *sigdata;
- int n_channels;
- int i;
- unsigned long fft = 0;
- DUMBFILE *rem;
-
- f = dumbfile_buffer_mod(f, &fft);
- if (!f)
- return NULL;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) {
- dumbfile_close(f);
- return NULL;
- }
-
- /**
- 1 20 Chars Title of the song. If the title is not a
- full 20 chars in length, it will be null-
- terminated.
- */
- if (dumbfile_getnc(sigdata->name, 20, f) < 20) {
- free(sigdata);
- dumbfile_close(f);
- return NULL;
- }
- sigdata->name[20] = 0;
-
- sigdata->n_samples = 31;
-
- switch (fft) {
- case DUMB_ID('M','.','K','.'):
- case DUMB_ID('M','!','K','!'):
- case DUMB_ID('M','&','K','!'):
- case DUMB_ID('N','.','T','.'):
- case DUMB_ID('N','S','M','S'):
- case DUMB_ID('F','L','T','4'):
- case DUMB_ID('M',0,0,0):
- case DUMB_ID('8',0,0,0):
- n_channels = 4;
- break;
- case DUMB_ID('F','L','T','8'):
- n_channels = 0;
- /* 0 indicates a special case; two four-channel patterns must be
- * combined into one eight-channel pattern. Pattern indexes must
- * be halved. Why oh why do they obfuscate so?
- */
- /*for (i = 0; i < 128; i++)
- sigdata->order[i] >>= 1;*/
- break;
- case DUMB_ID('C','D','8','1'):
- case DUMB_ID('O','C','T','A'):
- case DUMB_ID('O','K','T','A'):
- n_channels = 8;
- break;
- case DUMB_ID('1','6','C','N'):
- n_channels = 16;
- break;
- case DUMB_ID('3','2','C','N'):
- n_channels = 32;
- break;
- default:
- /* If we get an illegal tag, assume 4 channels 15 samples. */
- if ((fft & 0x0000FFFFL) == DUMB_ID(0,0,'C','H')) {
- if (fft >= '1' << 24 && fft < '4' << 24) {
- n_channels = ((fft & 0x00FF0000L) >> 16) - '0';
- if ((unsigned int)n_channels >= 10) {
- /* Rightmost character wasn't a digit. */
- n_channels = 4;
- sigdata->n_samples = 15;
- } else {
- n_channels += (((fft & 0xFF000000L) >> 24) - '0') * 10;
- /* MODs should really only go up to 32 channels, but we're lenient. */
- if ((unsigned int)(n_channels - 1) >= DUMB_IT_N_CHANNELS - 1) {
- /* No channels or too many? Can't be right... */
- n_channels = 4;
- sigdata->n_samples = 15;
- }
- }
- } else {
- n_channels = 4;
- sigdata->n_samples = 15;
- }
- } else if ((fft & 0x00FFFFFFL) == DUMB_ID(0,'C','H','N')) {
- n_channels = (fft >> 24) - '0';
- if ((unsigned int)(n_channels - 1) >= 9) {
- /* Character was '0' or it wasn't a digit */
- n_channels = 4;
- sigdata->n_samples = 15;
- }
- } else if ((fft & 0xFFFFFF00L) == DUMB_ID('T','D','Z',0)) {
- n_channels = (fft & 0x000000FFL) - '0';
- if ((unsigned int)(n_channels - 1) >= 9) {
- /* We've been very lenient, given that it should have
- * been 1, 2 or 3, but this MOD has been very naughty and
- * must be punished.
- */
- n_channels = 4;
- sigdata->n_samples = 15;
- }
- } else {
- n_channels = 4;
- sigdata->n_samples = 15;
- }
- }
-
- // moo
- if ( restrict && sigdata->n_samples == 15 )
- {
- free(sigdata);
- dumbfile_close(f);
- return NULL;
- }
-
- sigdata->n_pchannels = n_channels ? n_channels : 8; /* special case for 0, see above */
-
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) {
- free(sigdata);
- dumbfile_close(f);
- return NULL;
- }
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_instruments = 0;
-
- for (i = 0; i < sigdata->n_samples; i++)
- sigdata->sample[i].data = NULL;
-
- for (i = 0; i < sigdata->n_samples; i++) {
- if (it_mod_read_sample_header(&sigdata->sample[i], f)) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- return NULL;
- }
- }
-
- sigdata->n_orders = dumbfile_getc(f);
- sigdata->restart_position = dumbfile_getc(f);
- // what if this is >= 127? what about with Fast Tracker II?
-
-/* if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right?
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- return NULL;
- }*/
-
- //if (sigdata->restart_position >= sigdata->n_orders)
- //sigdata->restart_position = 0;
-
- sigdata->order = malloc(128); /* We may need to scan the extra ones! */
- if (!sigdata->order) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- return NULL;
- }
- if (dumbfile_getnc(sigdata->order, 128, f) < 128) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- return NULL;
- }
-
- if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right?
- sigdata->n_orders = 128;
- //while (sigdata->n_orders > 1 && !sigdata->order[sigdata->n_orders - 1]) sigdata->n_orders--;
- }
-
- if ( ! n_channels )
- for (i = 0; i < 128; i++)
- sigdata->order[i] >>= 1;
-
- /* "The old NST format contains only 15 samples (instead of 31). Further
- * it doesn't contain a file format tag (id). So Pattern data offset is
- * at 20+15*30+1+1+128."
- * - Then I shall assume the File Format Tag never exists if there are
- * only 15 samples. I hope this isn't a faulty assumption...
- */
- if (sigdata->n_samples == 31)
- dumbfile_skip(f, 4);
-
- /* Work out how many patterns there are. */
- sigdata->n_patterns = -1;
- for (i = 0; i < 128; i++)
- if (sigdata->n_patterns < sigdata->order[i])
- sigdata->n_patterns = sigdata->order[i];
- sigdata->n_patterns++;
-
- /* May as well try to save a tiny bit of memory. */
- if (sigdata->n_orders < 128) {
- unsigned char *order = realloc(sigdata->order, sigdata->n_orders);
- if (order) sigdata->order = order;
- }
-
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++)
- sigdata->pattern[i].entry = NULL;
-
- /* Read in the patterns */
- {
- unsigned char *buffer = malloc(256 * n_channels); /* 64 rows * 4 bytes */
- if (!buffer) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++) {
- if (it_mod_read_pattern(&sigdata->pattern[i], f, n_channels, buffer) != 0) {
- free(buffer);
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- return NULL;
- }
- }
- free(buffer);
- }
-
- rem = NULL;
-
- /* uggly */
- if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) {
- long skip;
- long remain;
- rem = f;
- f = dumbfile_buffer_mod_2(rem, &remain);
- if (!f) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(rem);
- return NULL;
- }
- for (skip = 0, i = 0; i < sigdata->n_samples; i++) {
- if (sigdata->sample[i].flags & IT_SAMPLE_EXISTS) {
- skip += sigdata->sample[i].length;
- }
- }
- if (remain - skip) {
- if (dumbfile_skip(f, remain - skip)) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- dumbfile_close(rem);
- return NULL;
- }
- }
- }
-
- /* And finally, the sample data */
- for (i = 0; i < sigdata->n_samples; i++) {
- if (it_mod_read_sample_data(&sigdata->sample[i], f, fft)) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- if (rem) dumbfile_close(rem);
- return NULL;
- }
- }
-
- /* w00t! */
- /*if ( n_channels == 4 &&
- ( sigdata->n_samples == 15 ||
- ( ( fft & 240 ) != DUMB_ID( 0, 0, 'C', 0 ) &&
- ( fft & 240 ) != DUMB_ID( 0, 0, 'H', 0 ) &&
- ( fft & 240 ) != 0 ) ) ) {
- for ( i = 0; i < sigdata->n_samples; ++i ) {
- IT_SAMPLE * sample = &sigdata->sample [i];
- if ( sample && ( sample->flags & IT_SAMPLE_EXISTS ) ) {
- int n, o;
- o = sample->length;
- if ( o > 4 ) o = 4;
- for ( n = 0; n < o; ++n )
- ( ( char * ) sample->data ) [n] = 0;
- }
- }
- }*/
-
- dumbfile_close(f); /* Destroy the BUFFERED_MOD DUMBFILE we were using. */
- /* The DUMBFILE originally passed to our function is intact. */
- if (rem) dumbfile_close(rem);
-
- /* Now let's initialise the remaining variables, and we're done! */
- sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO;
-
- sigdata->global_volume = 128;
- sigdata->mixing_volume = 48;
- /* We want 50 ticks per second; 50/6 row advances per second;
- * 50*10=500 row advances per minute; 500/4=125 beats per minute.
- */
- sigdata->speed = 6;
- sigdata->tempo = 125;
- sigdata->pan_separation = 128;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
- sigdata->channel_pan[i+0] = 16;
- sigdata->channel_pan[i+1] = 48;
- sigdata->channel_pan[i+2] = 48;
- sigdata->channel_pan[i+3] = 16;
- }
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-
-
-DUH *dumb_read_mod_quick(DUMBFILE *f, int restrict)
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_mod_load_sigdata(f, restrict);
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "MOD";
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readmod.c - Code to read a good old-fashioned / / \ \
+ * Amiga module from an open file. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+static int it_mod_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer)
+{
+ int pos;
+ int channel;
+ int row;
+ IT_ENTRY *entry;
+
+ pattern->n_rows = 64;
+
+ if (n_channels == 0) {
+ /* Read the first four channels, leaving gaps for the rest. */
+ for (pos = 0; pos < 64*8*4; pos += 8*4)
+ dumbfile_getnc(buffer + pos, 4*4, f);
+ /* Read the other channels into the gaps we left. */
+ for (pos = 4*4; pos < 64*8*4; pos += 8*4)
+ dumbfile_getnc(buffer + pos, 4*4, f);
+
+ n_channels = 8;
+ } else
+ dumbfile_getnc(buffer, 64 * n_channels * 4, f);
+
+ if (dumbfile_error(f))
+ return -1;
+
+ /* compute number of entries */
+ pattern->n_entries = 64; /* Account for the row end markers */
+ pos = 0;
+ for (row = 0; row < 64; row++) {
+ for (channel = 0; channel < n_channels; channel++) {
+ if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3])
+ pattern->n_entries++;
+ pos += 4;
+ }
+ }
+
+ pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
+ if (!pattern->entry)
+ return -1;
+
+ entry = pattern->entry;
+ pos = 0;
+ for (row = 0; row < 64; row++) {
+ for (channel = 0; channel < n_channels; channel++) {
+ if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3]) {
+ unsigned char sample = (buffer[pos+0] & 0xF0) | (buffer[pos+2] >> 4);
+ int period = ((int)(buffer[pos+0] & 0x0F) << 8) | buffer[pos+1];
+
+ entry->channel = channel;
+ entry->mask = 0;
+
+ if (period) {
+ int note;
+ entry->mask |= IT_ENTRY_NOTE;
+
+ /* frequency = (AMIGA_DIVISOR / 8) / (period * 2)
+ * C-1: period = 214 -> frequency = 16726
+ * so, set C5_speed to 16726
+ * and period = 214 should translate to C5 aka 60
+ * halve the period, go up an octive
+ *
+ * period = 214 / pow(DUMB_SEMITONE_BASE, note - 60)
+ * pow(DUMB_SEMITONE_BASE, note - 60) = 214 / period
+ * note - 60 = log(214/period) / log(DUMB_SEMITONE_BASE)
+ */
+ note = (int)floor(log(214.0/period) / log(DUMB_SEMITONE_BASE) + 60.5);
+ entry->note = MID(0, note, 119);
+ // or should we preserve the period?
+ //entry->note = buffer[pos+0] & 0x0F; /* High nibble */
+ //entry->volpan = buffer[pos+1]; /* Low byte */
+ // and what about finetune?
+ }
+
+ if (sample) {
+ entry->mask |= IT_ENTRY_INSTRUMENT;
+ entry->instrument = sample;
+ }
+
+ _dumb_it_xm_convert_effect(buffer[pos+2] & 0x0F, buffer[pos+3], entry, 1);
+
+ entry++;
+ }
+ pos += 4;
+ }
+ IT_SET_END_ROW(entry);
+ entry++;
+ }
+
+ return 0;
+}
+
+
+
+static int it_mod_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
+{
+ int finetune, loop_start, loop_length;
+
+/**
+ 21 22 Chars Sample 1 name. If the name is not a full
+ 22 chars in length, it will be null
+ terminated.
+
+If
+the sample name begins with a '#' character (ASCII $23 (35)) then this is
+assumed not to be an instrument name, and is probably a message.
+*/
+ dumbfile_getnc(sample->name, 22, f);
+ sample->name[22] = 0;
+
+ sample->filename[0] = 0;
+
+ sample->length = dumbfile_mgetw(f) << 1;
+ finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */
+/** Each finetune step changes the note 1/8th of a semitone. */
+ sample->global_volume = 64;
+ sample->default_volume = dumbfile_getc(f); // Should we be setting global_volume to this instead?
+ loop_start = dumbfile_mgetw(f) << 1;
+ loop_length = dumbfile_mgetw(f) << 1;
+ if ( loop_length > 2 && loop_start + loop_length > sample->length && loop_start / 2 + loop_length <= sample->length )
+ loop_start /= 2;
+ sample->loop_start = loop_start;
+ sample->loop_end = loop_start + loop_length;
+/**
+Once this sample has been played completely from beginning
+to end, if the repeat length (next field) is greater than two bytes it
+will loop back to this position in the sample and continue playing. Once
+it has played for the repeat length, it continues to loop back to the
+repeat start offset. This means the sample continues playing until it is
+told to stop.
+*/
+
+ if (sample->length <= 0) {
+ sample->flags = 0;
+ return 0;
+ }
+
+ sample->flags = IT_SAMPLE_EXISTS;
+
+ sample->default_pan = 0;
+ sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 ); //(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
+ sample->finetune = finetune * 32;
+ // the above line might be wrong
+
+ if (sample->loop_end > sample->length)
+ sample->loop_end = sample->length;
+
+ if (sample->loop_end - sample->loop_start > 2)
+ sample->flags |= IT_SAMPLE_LOOP;
+
+ sample->vibrato_speed = 0;
+ sample->vibrato_depth = 0;
+ sample->vibrato_rate = 0;
+ sample->vibrato_waveform = 0; // do we have to set _all_ these?
+ sample->max_resampling_quality = -1;
+
+ return dumbfile_error(f);
+}
+
+
+
+static int it_mod_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f, unsigned long fft)
+{
+ long i;
+ long truncated_size;
+
+ /* let's get rid of the sample data coming after the end of the loop */
+ if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
+ truncated_size = sample->length - sample->loop_end;
+ sample->length = sample->loop_end;
+ } else {
+ truncated_size = 0;
+ }
+ if (sample->length) {
+ sample->data = malloc(sample->length);
+ if (!sample->data)
+ return -1;
+
+ /* Sample data are stored in "8-bit two's compliment format" (sic). */
+ /*
+ for (i = 0; i < sample->length; i++)
+ ((signed char *)sample->left)[i] = dumbfile_getc(f);
+ */
+ /* F U Olivier Lapicque */
+ if (sample->length >= 5)
+ {
+ i = dumbfile_getnc(sample->data, 5, f);
+ if (i == 5)
+ {
+ if (!memcmp(sample->data, "ADPCM", 5))
+ {
+ if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
+ return -1;
+
+ return 0;
+ }
+ else
+ {
+ i += dumbfile_getnc(((char *)sample->data) + 5, sample->length - 5, f);
+ }
+ }
+ }
+ else
+ {
+ i = dumbfile_getnc(sample->data, sample->length, f);
+ }
+ if (i < sample->length)
+ {
+ if (i <= 0)
+ {
+ sample->flags = 0;
+ return 0;
+ }
+ sample->length = i;
+ if (sample->loop_end > i) sample->loop_end = i;
+ // holy crap!
+ if (sample->loop_start > i) sample->flags &= ~IT_SAMPLE_LOOP;
+ }
+ else
+ {
+ /* skip truncated data */
+ int feh = dumbfile_error(f);
+
+ if (truncated_size) dumbfile_skip(f, truncated_size);
+ // Should we be truncating it?
+
+ if (feh)
+ return -1;
+ }
+
+ if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) {
+ int delta = 0;
+ for (i = 0; i < sample->length; i++) {
+ delta += ((signed char *)sample->data)[i];
+ ((signed char *)sample->data)[i] = delta;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+typedef struct BUFFERED_MOD BUFFERED_MOD;
+
+struct BUFFERED_MOD
+{
+ unsigned char *buffered;
+ long ptr, len;
+ DUMBFILE *remaining;
+};
+
+
+
+static int buffer_mod_skip(void *f, long n)
+{
+ BUFFERED_MOD *bm = f;
+ if (bm->buffered) {
+ bm->ptr += n;
+ if (bm->ptr >= bm->len) {
+ free(bm->buffered);
+ bm->buffered = NULL;
+ return dumbfile_skip(bm->remaining, bm->ptr - bm->len);
+ }
+ return 0;
+ }
+ return dumbfile_skip(bm->remaining, n);
+}
+
+
+
+static int buffer_mod_getc(void *f)
+{
+ BUFFERED_MOD *bm = f;
+ if (bm->buffered) {
+ int rv = bm->buffered[bm->ptr++];
+ if (bm->ptr >= bm->len) {
+ free(bm->buffered);
+ bm->buffered = NULL;
+ }
+ return rv;
+ }
+ return dumbfile_getc(bm->remaining);
+}
+
+
+
+static long buffer_mod_getnc(char *ptr, long n, void *f)
+{
+ BUFFERED_MOD *bm = f;
+ if (bm->buffered) {
+ int left = bm->len - bm->ptr;
+ if (n >= left) {
+ memcpy(ptr, bm->buffered + bm->ptr, left);
+ free(bm->buffered);
+ bm->buffered = NULL;
+ if (n - left) {
+ int rv = dumbfile_getnc(ptr + left, n - left, bm->remaining);
+ return left + MAX(rv, 0);
+ } else {
+ return left;
+ }
+ }
+ memcpy(ptr, bm->buffered + bm->ptr, n);
+ bm->ptr += n;
+ return n;
+ }
+ return dumbfile_getnc(ptr, n, bm->remaining);
+}
+
+
+
+static void buffer_mod_close(void *f)
+{
+ BUFFERED_MOD *bm = f;
+ if (bm->buffered) free(bm->buffered);
+ /* Do NOT close bm->remaining */
+ free(f);
+}
+
+
+
+DUMBFILE_SYSTEM buffer_mod_dfs = {
+ NULL,
+ &buffer_mod_skip,
+ &buffer_mod_getc,
+ &buffer_mod_getnc,
+ &buffer_mod_close
+};
+
+
+
+#define MOD_FFT_OFFSET (20 + 31*(22+2+1+1+2+2) + 1 + 1 + 128)
+
+static DUMBFILE *dumbfile_buffer_mod(DUMBFILE *f, unsigned long *fft)
+{
+ BUFFERED_MOD *bm = malloc(sizeof(*bm));
+ if (!bm) return NULL;
+
+ bm->buffered = malloc(MOD_FFT_OFFSET + 4);
+ if (!bm->buffered) {
+ free(bm);
+ return NULL;
+ }
+
+ bm->len = dumbfile_getnc(bm->buffered, MOD_FFT_OFFSET + 4, f);
+
+ if (bm->len > 0) {
+ if (bm->len >= MOD_FFT_OFFSET + 4)
+ *fft = (unsigned long)bm->buffered[MOD_FFT_OFFSET ] << 24
+ | (unsigned long)bm->buffered[MOD_FFT_OFFSET+1] << 16
+ | (unsigned long)bm->buffered[MOD_FFT_OFFSET+2] << 8
+ | (unsigned long)bm->buffered[MOD_FFT_OFFSET+3];
+ else
+ *fft = 0;
+ bm->ptr = 0;
+ } else {
+ free(bm->buffered);
+ bm->buffered = NULL;
+ }
+
+ bm->remaining = f;
+
+ return dumbfile_open_ex(bm, &buffer_mod_dfs);
+}
+
+static DUMBFILE *dumbfile_buffer_mod_2(DUMBFILE *f, long *remain)
+{
+ long read;
+ BUFFERED_MOD *bm = malloc(sizeof(*bm));
+ if (!bm) return NULL;
+
+ bm->buffered = malloc(32768);
+ if (!bm->buffered) {
+ free(bm);
+ return NULL;
+ }
+
+ bm->len = 0;
+ *remain = 0;
+
+ read = dumbfile_getnc(bm->buffered, 32768, f);
+
+ if (read >= 0) {
+ bm->len += read;
+ *remain += read;
+
+ while (read >= 32768) {
+ bm->buffered = realloc(bm->buffered, *remain + 32768);
+ if (!bm->buffered) {
+ free(bm);
+ return 0;
+ }
+ read = dumbfile_getnc(bm->buffered + *remain, 32768, f);
+ if (read >= 0) {
+ bm->len += read;
+ *remain += read;
+ }
+ }
+ }
+
+ if (*remain) {
+ bm->ptr = 0;
+ } else {
+ free(bm->buffered);
+ bm->buffered = NULL;
+ }
+
+ bm->remaining = f;
+
+ return dumbfile_open_ex(bm, &buffer_mod_dfs);
+}
+
+
+static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
+{
+ DUMB_IT_SIGDATA *sigdata;
+ int n_channels;
+ int i;
+ unsigned long fft = 0;
+ DUMBFILE *rem;
+
+ f = dumbfile_buffer_mod(f, &fft);
+ if (!f)
+ return NULL;
+
+ sigdata = malloc(sizeof(*sigdata));
+ if (!sigdata) {
+ dumbfile_close(f);
+ return NULL;
+ }
+
+ sigdata = malloc(sizeof(*sigdata));
+ if (!sigdata) {
+ dumbfile_close(f);
+ return NULL;
+ }
+
+ /**
+ 1 20 Chars Title of the song. If the title is not a
+ full 20 chars in length, it will be null-
+ terminated.
+ */
+ if (dumbfile_getnc(sigdata->name, 20, f) < 20) {
+ free(sigdata);
+ dumbfile_close(f);
+ return NULL;
+ }
+ sigdata->name[20] = 0;
+
+ sigdata->n_samples = 31;
+
+ switch (fft) {
+ case DUMB_ID('M','.','K','.'):
+ case DUMB_ID('M','!','K','!'):
+ case DUMB_ID('M','&','K','!'):
+ case DUMB_ID('N','.','T','.'):
+ case DUMB_ID('N','S','M','S'):
+ case DUMB_ID('F','L','T','4'):
+ case DUMB_ID('M',0,0,0):
+ case DUMB_ID('8',0,0,0):
+ n_channels = 4;
+ break;
+ case DUMB_ID('F','L','T','8'):
+ n_channels = 0;
+ /* 0 indicates a special case; two four-channel patterns must be
+ * combined into one eight-channel pattern. Pattern indexes must
+ * be halved. Why oh why do they obfuscate so?
+ */
+ /*for (i = 0; i < 128; i++)
+ sigdata->order[i] >>= 1;*/
+ break;
+ case DUMB_ID('C','D','8','1'):
+ case DUMB_ID('O','C','T','A'):
+ case DUMB_ID('O','K','T','A'):
+ n_channels = 8;
+ break;
+ case DUMB_ID('1','6','C','N'):
+ n_channels = 16;
+ break;
+ case DUMB_ID('3','2','C','N'):
+ n_channels = 32;
+ break;
+ default:
+ /* If we get an illegal tag, assume 4 channels 15 samples. */
+ if ((fft & 0x0000FFFFL) == DUMB_ID(0,0,'C','H')) {
+ if (fft >= '1' << 24 && fft < '4' << 24) {
+ n_channels = ((fft & 0x00FF0000L) >> 16) - '0';
+ if ((unsigned int)n_channels >= 10) {
+ /* Rightmost character wasn't a digit. */
+ n_channels = 4;
+ sigdata->n_samples = 15;
+ } else {
+ n_channels += (((fft & 0xFF000000L) >> 24) - '0') * 10;
+ /* MODs should really only go up to 32 channels, but we're lenient. */
+ if ((unsigned int)(n_channels - 1) >= DUMB_IT_N_CHANNELS - 1) {
+ /* No channels or too many? Can't be right... */
+ n_channels = 4;
+ sigdata->n_samples = 15;
+ }
+ }
+ } else {
+ n_channels = 4;
+ sigdata->n_samples = 15;
+ }
+ } else if ((fft & 0x00FFFFFFL) == DUMB_ID(0,'C','H','N')) {
+ n_channels = (fft >> 24) - '0';
+ if ((unsigned int)(n_channels - 1) >= 9) {
+ /* Character was '0' or it wasn't a digit */
+ n_channels = 4;
+ sigdata->n_samples = 15;
+ }
+ } else if ((fft & 0xFFFFFF00L) == DUMB_ID('T','D','Z',0)) {
+ n_channels = (fft & 0x000000FFL) - '0';
+ if ((unsigned int)(n_channels - 1) >= 9) {
+ /* We've been very lenient, given that it should have
+ * been 1, 2 or 3, but this MOD has been very naughty and
+ * must be punished.
+ */
+ n_channels = 4;
+ sigdata->n_samples = 15;
+ }
+ } else {
+ n_channels = 4;
+ sigdata->n_samples = 15;
+ }
+ }
+
+ // moo
+ if ( restrict && sigdata->n_samples == 15 )
+ {
+ free(sigdata);
+ dumbfile_close(f);
+ return NULL;
+ }
+
+ sigdata->n_pchannels = n_channels ? n_channels : 8; /* special case for 0, see above */
+
+ sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
+ if (!sigdata->sample) {
+ free(sigdata);
+ dumbfile_close(f);
+ return NULL;
+ }
+
+ sigdata->song_message = NULL;
+ sigdata->order = NULL;
+ sigdata->instrument = NULL;
+ sigdata->pattern = NULL;
+ sigdata->midi = NULL;
+ sigdata->checkpoint = NULL;
+
+ sigdata->n_instruments = 0;
+
+ for (i = 0; i < sigdata->n_samples; i++)
+ sigdata->sample[i].data = NULL;
+
+ for (i = 0; i < sigdata->n_samples; i++) {
+ if (it_mod_read_sample_header(&sigdata->sample[i], f)) {
+ _dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ return NULL;
+ }
+ }
+
+ sigdata->n_orders = dumbfile_getc(f);
+ sigdata->restart_position = dumbfile_getc(f);
+ // what if this is >= 127? what about with Fast Tracker II?
+
+/* if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right?
+ _dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ return NULL;
+ }*/
+
+ //if (sigdata->restart_position >= sigdata->n_orders)
+ //sigdata->restart_position = 0;
+
+ sigdata->order = malloc(128); /* We may need to scan the extra ones! */
+ if (!sigdata->order) {
+ _dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ return NULL;
+ }
+ if (dumbfile_getnc(sigdata->order, 128, f) < 128) {
+ _dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ return NULL;
+ }
+
+ if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right?
+ sigdata->n_orders = 128;
+ //while (sigdata->n_orders > 1 && !sigdata->order[sigdata->n_orders - 1]) sigdata->n_orders--;
+ }
+
+ if ( ! n_channels )
+ for (i = 0; i < 128; i++)
+ sigdata->order[i] >>= 1;
+
+ /* "The old NST format contains only 15 samples (instead of 31). Further
+ * it doesn't contain a file format tag (id). So Pattern data offset is
+ * at 20+15*30+1+1+128."
+ * - Then I shall assume the File Format Tag never exists if there are
+ * only 15 samples. I hope this isn't a faulty assumption...
+ */
+ if (sigdata->n_samples == 31)
+ dumbfile_skip(f, 4);
+
+ /* Work out how many patterns there are. */
+ sigdata->n_patterns = -1;
+ for (i = 0; i < 128; i++)
+ if (sigdata->n_patterns < sigdata->order[i])
+ sigdata->n_patterns = sigdata->order[i];
+ sigdata->n_patterns++;
+
+ /* May as well try to save a tiny bit of memory. */
+ if (sigdata->n_orders < 128) {
+ unsigned char *order = realloc(sigdata->order, sigdata->n_orders);
+ if (order) sigdata->order = order;
+ }
+
+ sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
+ if (!sigdata->pattern) {
+ _dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ return NULL;
+ }
+ for (i = 0; i < sigdata->n_patterns; i++)
+ sigdata->pattern[i].entry = NULL;
+
+ /* Read in the patterns */
+ {
+ unsigned char *buffer = malloc(256 * n_channels); /* 64 rows * 4 bytes */
+ if (!buffer) {
+ _dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ return NULL;
+ }
+ for (i = 0; i < sigdata->n_patterns; i++) {
+ if (it_mod_read_pattern(&sigdata->pattern[i], f, n_channels, buffer) != 0) {
+ free(buffer);
+ _dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ return NULL;
+ }
+ }
+ free(buffer);
+ }
+
+ rem = NULL;
+
+ /* uggly */
+ if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) {
+ long skip;
+ long remain;
+ rem = f;
+ f = dumbfile_buffer_mod_2(rem, &remain);
+ if (!f) {
+ _dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(rem);
+ return NULL;
+ }
+ for (skip = 0, i = 0; i < sigdata->n_samples; i++) {
+ if (sigdata->sample[i].flags & IT_SAMPLE_EXISTS) {
+ skip += sigdata->sample[i].length;
+ }
+ }
+ if (remain - skip) {
+ if (dumbfile_skip(f, remain - skip)) {
+ _dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ dumbfile_close(rem);
+ return NULL;
+ }
+ }
+ }
+
+ /* And finally, the sample data */
+ for (i = 0; i < sigdata->n_samples; i++) {
+ if (it_mod_read_sample_data(&sigdata->sample[i], f, fft)) {
+ _dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ if (rem) dumbfile_close(rem);
+ return NULL;
+ }
+ }
+
+ /* w00t! */
+ /*if ( n_channels == 4 &&
+ ( sigdata->n_samples == 15 ||
+ ( ( fft & 240 ) != DUMB_ID( 0, 0, 'C', 0 ) &&
+ ( fft & 240 ) != DUMB_ID( 0, 0, 'H', 0 ) &&
+ ( fft & 240 ) != 0 ) ) ) {
+ for ( i = 0; i < sigdata->n_samples; ++i ) {
+ IT_SAMPLE * sample = &sigdata->sample [i];
+ if ( sample && ( sample->flags & IT_SAMPLE_EXISTS ) ) {
+ int n, o;
+ o = sample->length;
+ if ( o > 4 ) o = 4;
+ for ( n = 0; n < o; ++n )
+ ( ( char * ) sample->data ) [n] = 0;
+ }
+ }
+ }*/
+
+ dumbfile_close(f); /* Destroy the BUFFERED_MOD DUMBFILE we were using. */
+ /* The DUMBFILE originally passed to our function is intact. */
+ if (rem) dumbfile_close(rem);
+
+ /* Now let's initialise the remaining variables, and we're done! */
+ sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO;
+
+ sigdata->global_volume = 128;
+ sigdata->mixing_volume = 48;
+ /* We want 50 ticks per second; 50/6 row advances per second;
+ * 50*10=500 row advances per minute; 500/4=125 beats per minute.
+ */
+ sigdata->speed = 6;
+ sigdata->tempo = 125;
+ sigdata->pan_separation = 128;
+
+ memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
+
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
+ sigdata->channel_pan[i+0] = 16;
+ sigdata->channel_pan[i+1] = 48;
+ sigdata->channel_pan[i+2] = 48;
+ sigdata->channel_pan[i+3] = 16;
+ }
+
+ _dumb_it_fix_invalid_orders(sigdata);
+
+ return sigdata;
+}
+
+DUH *dumb_read_mod_quick(DUMBFILE *f, int restrict)
+{
+ sigdata_t *sigdata;
+
+ DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
+
+ sigdata = it_mod_load_sigdata(f, restrict);
+
+ if (!sigdata)
+ return NULL;
+
+ {
+ const char *tag[2][2];
+ tag[0][0] = "TITLE";
+ tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+ tag[1][0] = "FORMAT";
+ tag[1][1] = "MOD";
+ return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/readmod2.c b/plugins/dumb/dumb-kode54/src/it/readmod2.c
index a22548a1..102ead12 100644
--- a/plugins/dumb/dumb-kode54/src/it/readmod2.c
+++ b/plugins/dumb/dumb-kode54/src/it/readmod2.c
@@ -1,29 +1,29 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readmod2.c - Function to read a good old- / / \ \
- * fashioned Amiga module from an | < / \_
- * open file and do an initial | \/ /\ /
- * run-through. \_ / > /
- * | \ / /
- * Split off from readmod.c by entheh. | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_read_mod(DUMBFILE *f, int restrict)
-{
- DUH *duh = dumb_read_mod_quick(f, restrict);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readmod2.c - Function to read a good old- / / \ \
+ * fashioned Amiga module from an | < / \_
+ * open file and do an initial | \/ /\ /
+ * run-through. \_ / > /
+ * | \ / /
+ * Split off from readmod.c by entheh. | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_read_mod(DUMBFILE *f, int restrict)
+{
+ DUH *duh = dumb_read_mod_quick(f, restrict);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/readmtm.c b/plugins/dumb/dumb-kode54/src/it/readmtm.c
index 8f0c2e4c..4e8e5dca 100644
--- a/plugins/dumb/dumb-kode54/src/it/readmtm.c
+++ b/plugins/dumb/dumb-kode54/src/it/readmtm.c
@@ -1,412 +1,412 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readmtm.c - Code to read a MultiTracker Module / / \ \
- * from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-size_t strlen_max(const char * ptr, size_t max)
-{
- const char * end, * start;
- if (ptr==0) return 0;
- start = ptr;
- end = ptr + max;
- while(*ptr && ptr < end) ptr++;
- return ptr - start;
-}
-
-static int it_mtm_assemble_pattern(IT_PATTERN *pattern, const unsigned char * track, const unsigned short * sequence, int n_rows)
-{
- int n, o, note, sample;
- const unsigned char * t;
- IT_ENTRY * entry;
-
- pattern->n_rows = n_rows;
- pattern->n_entries = n_rows;
-
- for (n = 0; n < 32; n++) {
- if (sequence[n]) {
- t = &track[192 * (sequence[n] - 1)];
- for (o = 0; o < n_rows; o++) {
- if (t[0] || t[1] || t[2]) pattern->n_entries++;
- t += 3;
- }
- }
- }
-
- entry = malloc(pattern->n_entries * sizeof(*entry));
- if (!entry) return -1;
- pattern->entry = entry;
-
- for (n = 0; n < n_rows; n++) {
- for (o = 0; o < 32; o++) {
- if (sequence[o]) {
- t = &track[192 * (sequence[o] - 1) + (n * 3)];
- if (t[0] || t[1] || t[2]) {
- entry->channel = o;
- entry->mask = 0;
- note = t[0] >> 2;
- sample = ((t[0] << 4) | (t[1] >> 4)) & 0x3F;
-
- if (note) {
- entry->mask |= IT_ENTRY_NOTE;
- entry->note = note + 24;
- }
-
- if (sample) {
- entry->mask |= IT_ENTRY_INSTRUMENT;
- entry->instrument = sample;
- }
-
- _dumb_it_xm_convert_effect(t[1] & 0xF, t[2], entry, 1);
-
- if (entry->mask) entry++;
- }
- }
- }
- IT_SET_END_ROW(entry);
- entry++;
- }
-
- pattern->n_entries = entry - pattern->entry;
-
- return 0;
-}
-
-static int it_mtm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
-{
- int finetune, flags;
-
- dumbfile_getnc(sample->name, 22, f);
- sample->name[22] = 0;
-
- sample->filename[0] = 0;
-
- sample->length = dumbfile_igetl(f);
- sample->loop_start = dumbfile_igetl(f);
- sample->loop_end = dumbfile_igetl(f);
- finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */
- sample->global_volume = 64;
- sample->default_volume = dumbfile_getc(f);
-
- flags = dumbfile_getc(f);
-
- if (sample->length <= 0) {
- sample->flags = 0;
- return 0;
- }
-
- sample->flags = IT_SAMPLE_EXISTS;
-
- if (flags & 1) {
- sample->flags |= IT_SAMPLE_16BIT;
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- }
-
- sample->default_pan = 0;
- sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 );//(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
- sample->finetune = finetune * 32;
- // the above line might be wrong
-
- if (sample->loop_end > sample->length)
- sample->loop_end = sample->length;
-
- if (sample->loop_end - sample->loop_start > 2)
- sample->flags |= IT_SAMPLE_LOOP;
-
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = 0; // do we have to set _all_ these?
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-static int it_mtm_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f)
-{
- long i;
- long truncated_size;
-
- /* let's get rid of the sample data coming after the end of the loop */
- if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
- truncated_size = sample->length - sample->loop_end;
- sample->length = sample->loop_end;
- } else {
- truncated_size = 0;
- }
-
- sample->data = malloc(sample->length);
-
- if (!sample->data)
- return -1;
-
- dumbfile_getnc((char *)sample->data, sample->length, f);
- dumbfile_skip(f, truncated_size);
-
- if (dumbfile_error(f))
- return -1;
-
- for (i = 0; i < sample->length; i++)
- ((signed char *)sample->data)[i] ^= 0x80;
-
- return 0;
-}
-
-static DUMB_IT_SIGDATA *it_mtm_load_sigdata(DUMBFILE *f, int * version)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- int n, o, n_tracks, l_comment, n_rows, n_channels;
-
- unsigned char * track;
-
- unsigned short * sequence;
-
- char * comment;
-
- if (dumbfile_getc(f) != 'M' ||
- dumbfile_getc(f) != 'T' ||
- dumbfile_getc(f) != 'M') goto error;
-
- *version = dumbfile_getc(f);
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) goto error;
-
- dumbfile_getnc(sigdata->name, 20, f);
- sigdata->name[20] = 0;
-
- n_tracks = dumbfile_igetw(f);
- sigdata->n_patterns = dumbfile_getc(f) + 1;
- sigdata->n_orders = dumbfile_getc(f) + 1;
- l_comment = dumbfile_igetw(f);
- sigdata->n_samples = dumbfile_getc(f);
- //if (dumbfile_getc(f)) goto error_sd;
- dumbfile_getc(f);
- n_rows = dumbfile_getc(f);
- n_channels = dumbfile_getc(f);
-
- if (dumbfile_error(f) ||
- (n_tracks <= 0) ||
- (sigdata->n_samples <= 0) ||
- (n_rows <= 0 || n_rows > 64) ||
- (n_channels <= 0 || n_channels > 32)) goto error_sd;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- if (dumbfile_getnc(sigdata->channel_pan, 32, f) < 32) goto error_sd;
-
- for (n = 0; n < 32; n++) {
- if (sigdata->channel_pan[n] <= 15) {
- sigdata->channel_pan[n] -= (sigdata->channel_pan[n] & 8) >> 3;
- sigdata->channel_pan[n] = (sigdata->channel_pan[n] * 32) / 7;
- } else {
- sigdata->channel_volume[n] = 0;
- sigdata->channel_pan[n] = 7;
- }
- }
-
- for (n = 32; n < DUMB_IT_N_CHANNELS; n += 4) {
- sigdata->channel_pan[n ] = 16;
- sigdata->channel_pan[n+1] = 48;
- sigdata->channel_pan[n+2] = 48;
- sigdata->channel_pan[n+3] = 16;
- }
-
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) goto error_sd;
-
- sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
-
- sigdata->global_volume = 128;
- sigdata->mixing_volume = 48;
- sigdata->speed = 6;
- sigdata->tempo = 125;
- sigdata->pan_separation = 128;
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_instruments = 0;
-
- sigdata->restart_position = 0;
- sigdata->n_pchannels = n_channels;
-
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
-
- for (n = 0; n < sigdata->n_samples; n++) {
- if (it_mtm_read_sample_header(&sigdata->sample[n], f)) goto error_usd;
- }
-
- sigdata->order = malloc(sigdata->n_orders);
- if (!sigdata->order) goto error_usd;
-
- if (dumbfile_getnc(sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_usd;
- if (sigdata->n_orders < 128)
- if (dumbfile_skip(f, 128 - sigdata->n_orders)) goto error_usd;
-
- track = malloc(192 * n_tracks);
- if (!track) goto error_usd;
-
- if (dumbfile_getnc(track, 192 * n_tracks, f) < 192 * n_tracks) goto error_ft;
-
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) goto error_ft;
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
-
- sequence = malloc(sigdata->n_patterns * 32 * sizeof(*sequence));
- if (!sequence) goto error_ft;
-
- for (n = 0; n < sigdata->n_patterns; n++) {
- for (o = 0; o < 32; o++) {
- sequence[(n * 32) + o] = dumbfile_igetw(f);
- if (sequence[(n * 32) + o] > n_tracks)
- {
- //goto error_fs;
- // illegal track number, silence instead of rejecting the file
- sequence[(n * 32) + o] = 0;
- }
- }
- }
-
- for (n = 0; n < sigdata->n_patterns; n++) {
- if (it_mtm_assemble_pattern(&sigdata->pattern[n], track, &sequence[n * 32], n_rows)) goto error_fs;
- }
-
- if (l_comment) {
- comment = malloc(l_comment);
- if (!comment) goto error_fs;
- if (dumbfile_getnc(comment, l_comment, f) < l_comment) goto error_fc;
-
- /* Time for annoying "logic", yes. We want each line which has text,
- * and each blank line in between all the valid lines.
- */
-
- /* Find last actual line. */
- for (o = -1, n = 0; n < l_comment; n += 40) {
- if (comment[n]) o = n;
- }
-
- if (o >= 0) {
-
- int l, m;
-
- for (l = 0, n = 0; n <= o; n += 40) {
- l += strlen_max(&comment[n], 40) + 2;
- }
-
- l -= 1;
-
- sigdata->song_message = malloc(l);
- if (!sigdata->song_message) goto error_fc;
-
- for (m = 0, n = 0; n <= o; n += 40) {
- int p = strlen_max(&comment[n], 40);
- if (p) {
- memcpy(sigdata->song_message + m, &comment[n], p);
- m += p;
- }
- if (l - m > 1) {
- sigdata->song_message[m++] = 13;
- sigdata->song_message[m++] = 10;
- }
- }
-
- sigdata->song_message[m] = 0;
- }
-
- free(comment);
- }
-
- for (n = 0; n < sigdata->n_samples; n++) {
- if (it_mtm_read_sample_data(&sigdata->sample[n], f)) goto error_fs;
- }
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- free(sequence);
- free(track);
-
- return sigdata;
-
-error_fc:
- free(comment);
-error_fs:
- free(sequence);
-error_ft:
- free(track);
-error_usd:
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
-
-error_sd:
- free(sigdata);
-error:
- return NULL;
-}
-
-static char hexdigit(int in)
-{
- if (in < 10) return in + '0';
- else return in + 'A' - 10;
-}
-
-DUH *dumb_read_mtm_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
- int ver;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_mtm_load_sigdata(f, &ver);
-
- if (!sigdata)
- return NULL;
-
- {
- char version[16];
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- version[0] = 'M';
- version[1] = 'T';
- version[2] = 'M';
- version[3] = ' ';
- version[4] = 'v';
- version[5] = hexdigit(ver >> 4);
- version[6] = '.';
- version[7] = hexdigit(ver & 15);
- version[8] = 0;
- tag[1][1] = (const char *) &version;
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readmtm.c - Code to read a MultiTracker Module / / \ \
+ * from an open file. | < / \_
+ * | \/ /\ /
+ * By Chris Moeller. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+
+size_t strlen_max(const char * ptr, size_t max)
+{
+ const char * end, * start;
+ if (ptr==0) return 0;
+ start = ptr;
+ end = ptr + max;
+ while(*ptr && ptr < end) ptr++;
+ return ptr - start;
+}
+
+static int it_mtm_assemble_pattern(IT_PATTERN *pattern, const unsigned char * track, const unsigned short * sequence, int n_rows)
+{
+ int n, o, note, sample;
+ const unsigned char * t;
+ IT_ENTRY * entry;
+
+ pattern->n_rows = n_rows;
+ pattern->n_entries = n_rows;
+
+ for (n = 0; n < 32; n++) {
+ if (sequence[n]) {
+ t = &track[192 * (sequence[n] - 1)];
+ for (o = 0; o < n_rows; o++) {
+ if (t[0] || t[1] || t[2]) pattern->n_entries++;
+ t += 3;
+ }
+ }
+ }
+
+ entry = malloc(pattern->n_entries * sizeof(*entry));
+ if (!entry) return -1;
+ pattern->entry = entry;
+
+ for (n = 0; n < n_rows; n++) {
+ for (o = 0; o < 32; o++) {
+ if (sequence[o]) {
+ t = &track[192 * (sequence[o] - 1) + (n * 3)];
+ if (t[0] || t[1] || t[2]) {
+ entry->channel = o;
+ entry->mask = 0;
+ note = t[0] >> 2;
+ sample = ((t[0] << 4) | (t[1] >> 4)) & 0x3F;
+
+ if (note) {
+ entry->mask |= IT_ENTRY_NOTE;
+ entry->note = note + 24;
+ }
+
+ if (sample) {
+ entry->mask |= IT_ENTRY_INSTRUMENT;
+ entry->instrument = sample;
+ }
+
+ _dumb_it_xm_convert_effect(t[1] & 0xF, t[2], entry, 1);
+
+ if (entry->mask) entry++;
+ }
+ }
+ }
+ IT_SET_END_ROW(entry);
+ entry++;
+ }
+
+ pattern->n_entries = entry - pattern->entry;
+
+ return 0;
+}
+
+static int it_mtm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
+{
+ int finetune, flags;
+
+ dumbfile_getnc(sample->name, 22, f);
+ sample->name[22] = 0;
+
+ sample->filename[0] = 0;
+
+ sample->length = dumbfile_igetl(f);
+ sample->loop_start = dumbfile_igetl(f);
+ sample->loop_end = dumbfile_igetl(f);
+ finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */
+ sample->global_volume = 64;
+ sample->default_volume = dumbfile_getc(f);
+
+ flags = dumbfile_getc(f);
+
+ if (sample->length <= 0) {
+ sample->flags = 0;
+ return 0;
+ }
+
+ sample->flags = IT_SAMPLE_EXISTS;
+
+ if (flags & 1) {
+ sample->flags |= IT_SAMPLE_16BIT;
+ sample->length >>= 1;
+ sample->loop_start >>= 1;
+ sample->loop_end >>= 1;
+ }
+
+ sample->default_pan = 0;
+ sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 );//(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
+ sample->finetune = finetune * 32;
+ // the above line might be wrong
+
+ if (sample->loop_end > sample->length)
+ sample->loop_end = sample->length;
+
+ if (sample->loop_end - sample->loop_start > 2)
+ sample->flags |= IT_SAMPLE_LOOP;
+
+ sample->vibrato_speed = 0;
+ sample->vibrato_depth = 0;
+ sample->vibrato_rate = 0;
+ sample->vibrato_waveform = 0; // do we have to set _all_ these?
+ sample->max_resampling_quality = -1;
+
+ return dumbfile_error(f);
+}
+
+static int it_mtm_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f)
+{
+ long i;
+ long truncated_size;
+
+ /* let's get rid of the sample data coming after the end of the loop */
+ if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
+ truncated_size = sample->length - sample->loop_end;
+ sample->length = sample->loop_end;
+ } else {
+ truncated_size = 0;
+ }
+
+ sample->data = malloc(sample->length);
+
+ if (!sample->data)
+ return -1;
+
+ dumbfile_getnc((char *)sample->data, sample->length, f);
+ dumbfile_skip(f, truncated_size);
+
+ if (dumbfile_error(f))
+ return -1;
+
+ for (i = 0; i < sample->length; i++)
+ ((signed char *)sample->data)[i] ^= 0x80;
+
+ return 0;
+}
+
+static DUMB_IT_SIGDATA *it_mtm_load_sigdata(DUMBFILE *f, int * version)
+{
+ DUMB_IT_SIGDATA *sigdata;
+
+ int n, o, n_tracks, l_comment, n_rows, n_channels;
+
+ unsigned char * track;
+
+ unsigned short * sequence;
+
+ char * comment;
+
+ if (dumbfile_getc(f) != 'M' ||
+ dumbfile_getc(f) != 'T' ||
+ dumbfile_getc(f) != 'M') goto error;
+
+ *version = dumbfile_getc(f);
+
+ sigdata = malloc(sizeof(*sigdata));
+ if (!sigdata) goto error;
+
+ dumbfile_getnc(sigdata->name, 20, f);
+ sigdata->name[20] = 0;
+
+ n_tracks = dumbfile_igetw(f);
+ sigdata->n_patterns = dumbfile_getc(f) + 1;
+ sigdata->n_orders = dumbfile_getc(f) + 1;
+ l_comment = dumbfile_igetw(f);
+ sigdata->n_samples = dumbfile_getc(f);
+ //if (dumbfile_getc(f)) goto error_sd;
+ dumbfile_getc(f);
+ n_rows = dumbfile_getc(f);
+ n_channels = dumbfile_getc(f);
+
+ if (dumbfile_error(f) ||
+ (n_tracks <= 0) ||
+ (sigdata->n_samples <= 0) ||
+ (n_rows <= 0 || n_rows > 64) ||
+ (n_channels <= 0 || n_channels > 32)) goto error_sd;
+
+ memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
+
+ if (dumbfile_getnc(sigdata->channel_pan, 32, f) < 32) goto error_sd;
+
+ for (n = 0; n < 32; n++) {
+ if (sigdata->channel_pan[n] <= 15) {
+ sigdata->channel_pan[n] -= (sigdata->channel_pan[n] & 8) >> 3;
+ sigdata->channel_pan[n] = (sigdata->channel_pan[n] * 32) / 7;
+ } else {
+ sigdata->channel_volume[n] = 0;
+ sigdata->channel_pan[n] = 7;
+ }
+ }
+
+ for (n = 32; n < DUMB_IT_N_CHANNELS; n += 4) {
+ sigdata->channel_pan[n ] = 16;
+ sigdata->channel_pan[n+1] = 48;
+ sigdata->channel_pan[n+2] = 48;
+ sigdata->channel_pan[n+3] = 16;
+ }
+
+ sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
+ if (!sigdata->sample) goto error_sd;
+
+ sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
+
+ sigdata->global_volume = 128;
+ sigdata->mixing_volume = 48;
+ sigdata->speed = 6;
+ sigdata->tempo = 125;
+ sigdata->pan_separation = 128;
+
+ sigdata->song_message = NULL;
+ sigdata->order = NULL;
+ sigdata->instrument = NULL;
+ sigdata->pattern = NULL;
+ sigdata->midi = NULL;
+ sigdata->checkpoint = NULL;
+
+ sigdata->n_instruments = 0;
+
+ sigdata->restart_position = 0;
+ sigdata->n_pchannels = n_channels;
+
+ for (n = 0; n < sigdata->n_samples; n++)
+ sigdata->sample[n].data = NULL;
+
+ for (n = 0; n < sigdata->n_samples; n++) {
+ if (it_mtm_read_sample_header(&sigdata->sample[n], f)) goto error_usd;
+ }
+
+ sigdata->order = malloc(sigdata->n_orders);
+ if (!sigdata->order) goto error_usd;
+
+ if (dumbfile_getnc(sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_usd;
+ if (sigdata->n_orders < 128)
+ if (dumbfile_skip(f, 128 - sigdata->n_orders)) goto error_usd;
+
+ track = malloc(192 * n_tracks);
+ if (!track) goto error_usd;
+
+ if (dumbfile_getnc(track, 192 * n_tracks, f) < 192 * n_tracks) goto error_ft;
+
+ sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
+ if (!sigdata->pattern) goto error_ft;
+ for (n = 0; n < sigdata->n_patterns; n++)
+ sigdata->pattern[n].entry = NULL;
+
+ sequence = malloc(sigdata->n_patterns * 32 * sizeof(*sequence));
+ if (!sequence) goto error_ft;
+
+ for (n = 0; n < sigdata->n_patterns; n++) {
+ for (o = 0; o < 32; o++) {
+ sequence[(n * 32) + o] = dumbfile_igetw(f);
+ if (sequence[(n * 32) + o] > n_tracks)
+ {
+ //goto error_fs;
+ // illegal track number, silence instead of rejecting the file
+ sequence[(n * 32) + o] = 0;
+ }
+ }
+ }
+
+ for (n = 0; n < sigdata->n_patterns; n++) {
+ if (it_mtm_assemble_pattern(&sigdata->pattern[n], track, &sequence[n * 32], n_rows)) goto error_fs;
+ }
+
+ if (l_comment) {
+ comment = malloc(l_comment);
+ if (!comment) goto error_fs;
+ if (dumbfile_getnc(comment, l_comment, f) < l_comment) goto error_fc;
+
+ /* Time for annoying "logic", yes. We want each line which has text,
+ * and each blank line in between all the valid lines.
+ */
+
+ /* Find last actual line. */
+ for (o = -1, n = 0; n < l_comment; n += 40) {
+ if (comment[n]) o = n;
+ }
+
+ if (o >= 0) {
+
+ int l, m;
+
+ for (l = 0, n = 0; n <= o; n += 40) {
+ l += strlen_max(&comment[n], 40) + 2;
+ }
+
+ l -= 1;
+
+ sigdata->song_message = malloc(l);
+ if (!sigdata->song_message) goto error_fc;
+
+ for (m = 0, n = 0; n <= o; n += 40) {
+ int p = strlen_max(&comment[n], 40);
+ if (p) {
+ memcpy(sigdata->song_message + m, &comment[n], p);
+ m += p;
+ }
+ if (l - m > 1) {
+ sigdata->song_message[m++] = 13;
+ sigdata->song_message[m++] = 10;
+ }
+ }
+
+ sigdata->song_message[m] = 0;
+ }
+
+ free(comment);
+ }
+
+ for (n = 0; n < sigdata->n_samples; n++) {
+ if (it_mtm_read_sample_data(&sigdata->sample[n], f)) goto error_fs;
+ }
+
+ _dumb_it_fix_invalid_orders(sigdata);
+
+ free(sequence);
+ free(track);
+
+ return sigdata;
+
+error_fc:
+ free(comment);
+error_fs:
+ free(sequence);
+error_ft:
+ free(track);
+error_usd:
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+
+error_sd:
+ free(sigdata);
+error:
+ return NULL;
+}
+
+static char hexdigit(int in)
+{
+ if (in < 10) return in + '0';
+ else return in + 'A' - 10;
+}
+
+DUH *dumb_read_mtm_quick(DUMBFILE *f)
+{
+ sigdata_t *sigdata;
+ int ver;
+
+ DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
+
+ sigdata = it_mtm_load_sigdata(f, &ver);
+
+ if (!sigdata)
+ return NULL;
+
+ {
+ char version[16];
+ const char *tag[2][2];
+ tag[0][0] = "TITLE";
+ tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+ tag[1][0] = "FORMAT";
+ version[0] = 'M';
+ version[1] = 'T';
+ version[2] = 'M';
+ version[3] = ' ';
+ version[4] = 'v';
+ version[5] = hexdigit(ver >> 4);
+ version[6] = '.';
+ version[7] = hexdigit(ver & 15);
+ version[8] = 0;
+ tag[1][1] = (const char *) &version;
+ return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/readoldpsm.c b/plugins/dumb/dumb-kode54/src/it/readoldpsm.c
index e7830f2a..1b60187e 100644
--- a/plugins/dumb/dumb-kode54/src/it/readoldpsm.c
+++ b/plugins/dumb/dumb-kode54/src/it/readoldpsm.c
@@ -1,727 +1,727 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readpsm.c - Code to read an old Protracker / / \ \
- * Studio module from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-static int psm_sample_compare(const void *e1, const void *e2)
-{
- const unsigned char * pa = e1;
- const unsigned char * pb = e2;
- int a = pa[37] | (pa[38] << 8) | (pa[39] << 16) | (pa[40] << 24);
- int b = pb[37] | (pb[38] << 8) | (pb[39] << 16) | (pb[40] << 24);
- return a - b;
-}
-
-static int it_old_psm_read_samples(IT_SAMPLE ** sample, DUMBFILE * f, int * num, const unsigned char * prebuffer, long data_pos, long data_size)
-{
- int n, o, pos, count = *num, true_num, snum, offset, flags, finetune, delta;
-
- unsigned char * buffer, * sbuffer = 0;
- const unsigned char * sdata;
-
- buffer = malloc(count * 64);
- if (!buffer) goto error;
-
- if (dumbfile_getnc(buffer, count * 64, f) < count * 64) goto error_fb;
-
- pos = dumbfile_pos(f);
-
- true_num = 0;
-
- for (n = 0; n < count; n++) {
- snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8);
- if ((snum < 1) || (snum > 255)) goto error_fb;
- if (true_num < snum) true_num = snum;
- }
-
- if (true_num > count) {
- IT_SAMPLE * meh = realloc(*sample, true_num * sizeof(*meh));
- if (!meh) goto error_fb;
- for (n = count; n < true_num; n++) {
- meh[n].data = NULL;
- }
- *sample = meh;
- *num = true_num;
- }
-
- qsort(buffer, count, 64, &psm_sample_compare);
-
- for (n = 0; n < true_num; n++) {
- (*sample)[n].flags = 0;
- }
-
- for (n = 0; n < count; n++) {
- IT_SAMPLE * s;
- snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8);
- s = &((*sample)[snum - 1]);
- memcpy(s->filename, buffer + (n * 64), 13);
- s->filename[13] = 0;
- memcpy(s->name, buffer + (n * 64) + 13, 24);
- s->name[24] = 0;
- offset = buffer[(n * 64) + 37] | (buffer[(n * 64) + 38] << 8) |
- (buffer[(n * 64) + 39] << 16) | (buffer[(n * 64) + 40] << 24);
- flags = buffer[(n * 64) + 47];
- s->length = buffer[(n * 64) + 48] | (buffer[(n * 64) + 49] << 8) |
- (buffer[(n * 64) + 50] << 16) | (buffer[(n * 64) + 51] << 24);
- s->loop_start = buffer[(n * 64) + 52] | (buffer[(n * 64) + 53] << 8) |
- (buffer[(n * 64) + 54] << 16) | (buffer[(n * 64) + 55] << 24);
- s->loop_end = buffer[(n * 64) + 56] | (buffer[(n * 64) + 57] << 8) |
- (buffer[(n * 64) + 58] << 16) | (buffer[(n * 64) + 59] << 24);
-
- if (s->length <= 0) continue;
-
- finetune = buffer[(n * 64) + 60];
- s->default_volume = buffer[(n * 64) + 61];
- s->C5_speed = buffer[(n * 64) + 62] | (buffer[(n * 64) + 63] << 8);
- if (finetune < 16) {
- if (finetune >= 8) finetune -= 16;
- //s->C5_speed = (long)((double)s->C5_speed * pow(DUMB_PITCH_BASE, finetune*32));
- s->finetune = finetune * 32;
- }
- else s->finetune = 0;
-
- s->flags |= IT_SAMPLE_EXISTS;
- if (flags & 0x41) {
- s->flags &= ~IT_SAMPLE_EXISTS;
- continue;
- }
- if (flags & 0x20) s->flags |= IT_SAMPLE_PINGPONG_LOOP;
- if (flags & 4) s->flags |= IT_SAMPLE_16BIT;
-
- if (flags & 0x80) {
- s->flags |= IT_SAMPLE_LOOP;
- if ((unsigned int)s->loop_end > (unsigned int)s->length)
- s->loop_end = s->length;
- else if ((unsigned int)s->loop_start >= (unsigned int)s->loop_end)
- s->flags &= ~IT_SAMPLE_LOOP;
- else
- s->length = s->loop_end;
- }
-
- s->global_volume = 64;
-
- s->vibrato_speed = 0;
- s->vibrato_depth = 0;
- s->vibrato_rate = 0;
- s->vibrato_waveform = IT_VIBRATO_SINE;
- s->max_resampling_quality = -1;
-
- s->data = malloc(s->length * ((flags & 4) ? 2 : 1));
- if (!s->data) goto error_fb;
-
- if ((offset >= data_pos) &&
- ((offset + s->length * ((flags & 4) ? 2 : 1)) <= (data_pos + data_size))) {
- sdata = prebuffer + offset - data_pos;
- } else if (offset >= pos) {
- if (dumbfile_skip(f, offset - pos)) goto error_fb;
- pos = offset;
- offset = s->length * ((flags & 4) ? 2 : 1);
- sbuffer = malloc(offset);
- if (!sbuffer) goto error_fb;
- if (dumbfile_getnc(sbuffer, offset, f) < offset) goto error_fsb;
- sdata = sbuffer;
- } else
- goto error_fb;
-
- if (flags & 0x10) {
- if (flags & 8) {
- if (flags & 4) {
- for (o = 0; o < s->length; o++)
- ((short *)s->data)[o] = (sdata[o * 2] | (sdata[(o * 2) + 1] << 8)) ^ 0x8000;
- } else {
- for (o = 0; o < s->length; o++)
- ((signed char *)s->data)[o] = sdata[o] ^ 0x80;
- }
- } else {
- if (flags & 4) {
- for (o = 0; o < s->length; o++)
- ((short *)s->data)[o] = sdata[o * 2] | (sdata[(o * 2) + 1] << 8);
- } else {
- memcpy(s->data, sdata, s->length);
- }
- }
- } else {
- delta = 0;
- if (flags & 8) {
- /* unsigned delta? mehhh, does anything even use this? */
- if (flags & 4) {
- for (o = 0; o < s->length; o++) {
- delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8));
- ((short *)s->data)[o] = delta ^ 0x8000;
- }
- } else {
- for (o = 0; o < s->length; o++) {
- delta += (signed char)sdata[o];
- ((signed char *)s->data)[o] = delta ^ 0x80;
- }
- }
- } else {
- if (flags & 4) {
- for (o = 0; o < s->length; o++) {
- delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8));
- ((short *)s->data)[o] = delta;
- }
- } else {
- for (o = 0; o < s->length; o++) {
- delta += (signed char)sdata[o];
- ((signed char *)s->data)[o] = delta;
- }
- }
- }
- }
-
- if (sbuffer) {
- free(sbuffer);
- sbuffer = 0;
- }
- }
-
- free(buffer);
-
- return 0;
-
-error_fsb:
- if (sbuffer) free(sbuffer);
-error_fb:
- free(buffer);
-error:
- return -1;
-}
-
-static int it_old_psm_read_patterns(IT_PATTERN * pattern, DUMBFILE * f, int num, int size, int pchans, int sflags)
-{
- int n, offset, psize, rows, chans, row, flags, channel;
-
- unsigned char * buffer, * ptr, * end;
-
- IT_ENTRY * entry;
-
- buffer = malloc(size);
- if (!buffer) goto error;
-
- if (dumbfile_getnc(buffer, size, f) < size) goto error_fb;
-
- offset = 0;
-
- for (n = 0; n < num; n++) {
- IT_PATTERN * p = &pattern[n];
-
- if (offset >= size) goto error_fb;
-
- ptr = buffer + offset;
- psize = ptr[0] | (ptr[1] << 8);
- rows = ptr[2];
- chans = ptr[3];
-
- if (!rows || !chans) {
- p->n_rows = 1;
- p->n_entries = 0;
- continue;
- }
-
- psize = (psize + 15) & ~15;
-
- end = ptr + psize;
- ptr += 4;
-
- p->n_rows = rows;
- p->n_entries = rows;
- row = 0;
-
- while ((row < rows) && (ptr < end)) {
- flags = *ptr++;
- if (!flags) {
- row++;
- continue;
- }
- if (flags & 0xE0) {
- p->n_entries++;
- if (flags & 0x80) ptr += 2;
- if (flags & 0x40) ptr++;
- if (flags & 0x20) {
- ptr++;
- if (*ptr == 40) ptr += 3;
- else ptr++;
- }
- }
- }
-
- entry = malloc(p->n_entries * sizeof(*p->entry));
- if (!entry) goto error_fb;
-
- p->entry = entry;
-
- ptr = buffer + offset + 4;
- row = 0;
-
- while ((row < rows) && (ptr < end)) {
- flags = *ptr++;
- if (!flags) {
- IT_SET_END_ROW(entry);
- entry++;
- row++;
- continue;
- }
- if (flags & 0xE0) {
- entry->mask = 0;
- entry->channel = channel = flags & 0x1F;
- if (channel >= chans)
- {
- //channel = 0;
- goto error_fb;
- }
- if (flags & 0x80) {
- if ((*ptr < 60) && (channel < pchans)) {
- entry->mask |= IT_ENTRY_NOTE;
- entry->note = *ptr + 36;
- }
- ptr++;
- if (*ptr) {
- entry->mask |= IT_ENTRY_INSTRUMENT;
- entry->instrument = *ptr;
- }
- ptr++;
- }
- if (flags & 0x40) {
- if (*ptr <= 64) {
- entry->mask |= IT_ENTRY_VOLPAN;
- entry->volpan = *ptr;
- }
- ptr++;
- }
- if (flags & 0x20) {
- entry->mask |= IT_ENTRY_EFFECT;
-
- switch (*ptr) {
- case 1:
- entry->effect = IT_XM_FINE_VOLSLIDE_UP;
- entry->effectvalue = ptr[1];
- break;
-
- case 2:
- entry->effect = IT_VOLUME_SLIDE;
- entry->effectvalue = (ptr[1] << 4) & 0xF0;
- break;
-
- case 3:
- entry->effect = IT_XM_FINE_VOLSLIDE_DOWN;
- entry->effectvalue = ptr[1];
- break;
-
- case 4:
- entry->effect = IT_VOLUME_SLIDE;
- entry->effectvalue = ptr[1] & 0xF;
- break;
-
- case 10:
- entry->effect = IT_PORTAMENTO_UP;
- entry->effectvalue = EFFECT_VALUE(0xF, ptr[1]);
- break;
-
- case 11:
- entry->effect = IT_PORTAMENTO_UP;
- entry->effectvalue = ptr[1];
- break;
-
- case 12:
- entry->effect = IT_PORTAMENTO_DOWN;
- entry->effectvalue = EFFECT_VALUE(ptr[1], 0xF);
- break;
-
- case 13:
- entry->effect = IT_PORTAMENTO_DOWN;
- entry->effectvalue = ptr[1];
- break;
-
- case 14:
- entry->effect = IT_TONE_PORTAMENTO;
- entry->effectvalue = ptr[1];
- break;
-
- case 15:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_SET_GLISSANDO_CONTROL, ptr[1] & 15);
- break;
-
- case 16:
- entry->effect = IT_VOLSLIDE_TONEPORTA;
- entry->effectvalue = ptr[1] << 4;
- break;
-
- case 17:
- entry->effect = IT_VOLSLIDE_TONEPORTA;
- entry->effectvalue = ptr[1] & 0xF;
- break;
-
- case 20:
- entry->effect = IT_VIBRATO;
- entry->effectvalue = ptr[1];
- break;
-
- case 21:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_SET_VIBRATO_WAVEFORM, ptr[1] & 11);
- break;
-
- case 22:
- entry->effect = IT_VOLSLIDE_VIBRATO;
- entry->effectvalue = ptr[1] << 4;
- break;
-
- case 23:
- entry->effect = IT_VOLSLIDE_VIBRATO;
- entry->effectvalue = ptr[1] & 0xF;
- break;
-
- case 30:
- entry->effect = IT_TREMOLO;
- entry->effectvalue = ptr[1];
- break;
-
- case 31:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_SET_TREMOLO_WAVEFORM, ptr[1] & 11);
- break;
-
- case 40:
- entry->effect = IT_SET_SAMPLE_OFFSET;
- entry->effectvalue = ptr[2];
- ptr += 2;
- break;
-
- case 41:
- entry->effect = IT_XM_RETRIGGER_NOTE;
- entry->effectvalue = ptr[1];
- break;
-
- case 42:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_DELAYED_NOTE_CUT, ptr[1] & 0xF);
- break;
-
- case 43:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_NOTE_DELAY, ptr[1] & 0xF);
- break;
-
- case 50:
- entry->effect = IT_JUMP_TO_ORDER;
- entry->effectvalue = ptr[1];
- break;
-
- case 51:
- entry->effect = IT_BREAK_TO_ROW;
- entry->effectvalue = ptr[1];
- break;
-
- case 52:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_LOOP, ptr[1] & 0xF);
- break;
-
- case 53:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_DELAY, ptr[1] & 0xF);
- break;
-
- case 60:
- entry->effect = IT_SET_SPEED;
- entry->effectvalue = ptr[1];
- break;
-
- case 61:
- entry->effect = IT_SET_SONG_TEMPO;
- entry->effectvalue = ptr[1];
- break;
-
- case 70:
- entry->effect = IT_ARPEGGIO;
- entry->effectvalue = ptr[1];
- break;
-
- case 71:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_FINETUNE, ptr[1] & 0xF);
- break;
-
- case 72:
- /* "balance" ... panning? */
- entry->effect = IT_SET_PANNING;
- entry->effectvalue = ((ptr[1] - ((ptr[1] & 8) >> 3)) << 5) / 7;
- break;
-
- default:
- entry->mask &= ~IT_ENTRY_EFFECT;
- }
-
- ptr += 2;
- }
- if (entry->mask) entry++;
- }
- }
-
- p->n_entries = entry - p->entry;
- offset += psize;
- }
-
- free(buffer);
-
- return 0;
-
-error_fb:
- free(buffer);
-error:
- return -1;
-}
-
-#define PSM_COMPONENT_ORDERS 0
-#define PSM_COMPONENT_PANPOS 1
-#define PSM_COMPONENT_PATTERNS 2
-#define PSM_COMPONENT_SAMPLE_HEADERS 3
-#define PSM_COMPONENT_COMMENTS 4
-
-typedef struct PSM_COMPONENT
-{
- unsigned char type;
- long offset;
-}
-PSM_COMPONENT;
-
-static int psm_component_compare(const void *e1, const void *e2)
-{
- return ((const PSM_COMPONENT *)e1)->offset -
- ((const PSM_COMPONENT *)e2)->offset;
-}
-
-static DUMB_IT_SIGDATA *it_old_psm_load_sigdata(DUMBFILE *f)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- unsigned char * ptr = 0;
-
- PSM_COMPONENT *component;
- int n_components = 0;
-
- int n, flags, version, pver, n_orders, n_channels, total_pattern_size;
-
- if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',254)) goto error;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) goto error;
-
- if (dumbfile_getnc(sigdata->name, 60, f) < 60 ||
- sigdata->name[59] != 0x1A) goto error_sd;
- sigdata->name[59] = 0;
-
- flags = dumbfile_getc(f);
- version = dumbfile_getc(f);
- pver = dumbfile_getc(f);
- sigdata->speed = dumbfile_getc(f);
- sigdata->tempo = dumbfile_getc(f);
- sigdata->mixing_volume = dumbfile_getc(f);
- sigdata->n_orders = dumbfile_igetw(f);
- n_orders = dumbfile_igetw(f);
- sigdata->n_patterns = dumbfile_igetw(f);
- sigdata->n_samples = dumbfile_igetw(f);
- sigdata->n_pchannels = dumbfile_igetw(f);
- n_channels = dumbfile_igetw(f);
-
- if (dumbfile_error(f) ||
- (flags & 1) ||
- (version != 1 && version != 0x10) ||
- (pver) ||
- (sigdata->n_orders <= 0) ||
- (sigdata->n_orders > 255) ||
- (n_orders > 255) ||
- (n_orders < sigdata->n_orders) ||
- (sigdata->n_patterns > 255) ||
- (sigdata->n_samples > 255) ||
- (sigdata->n_pchannels > DUMB_IT_N_CHANNELS) ||
- (sigdata->n_pchannels > n_channels) ||
- (n_channels > DUMB_IT_N_CHANNELS))
- goto error_sd;
-
- sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
-
- sigdata->global_volume = 128;
- sigdata->pan_separation = 128;
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_instruments = 0;
-
- sigdata->restart_position = 0;
-
- sigdata->order = malloc(sigdata->n_orders);
- if (!sigdata->order) goto error_usd;
-
- if (sigdata->n_samples) {
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) goto error_usd;
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
- }
-
- if (sigdata->n_patterns) {
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) goto error_usd;
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
- }
-
- component = malloc(5 * sizeof(*component));
- if (!component) goto error_usd;
-
- for (n = 0; n < 5; n++) {
- component[n_components].offset = dumbfile_igetl(f);
- if (component[n_components].offset) {
- component[n_components].type = n;
- n_components++;
- }
- }
-
- if (!n_components) goto error_fc;
-
- total_pattern_size = dumbfile_igetl(f);
- if (!total_pattern_size) goto error_fc;
-
- qsort(component, n_components, sizeof(PSM_COMPONENT), &psm_component_compare);
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
- sigdata->channel_pan[n ] = 16;
- sigdata->channel_pan[n+1] = 48;
- sigdata->channel_pan[n+2] = 48;
- sigdata->channel_pan[n+3] = 16;
- }
-
- for (n = 0; n < n_components; n++)
- {
- int o;
- long data_pos, data_size;
-
- /* Whee, sample data may be before the sample headers */
-
- data_pos = dumbfile_pos(f);
- if (data_pos > component[n].offset) goto error_fc;
-
- data_size = component[n].offset - data_pos;
-
- if (data_size) {
- ptr = malloc(data_size);
- if (!ptr) goto error_fc;
-
- if (dumbfile_getnc(ptr, data_size, f) < data_size) goto error_fp;
- }
-
- switch (component[n].type) {
-
- case PSM_COMPONENT_ORDERS:
- if (dumbfile_getnc(sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_fp;
- if (n_orders > sigdata->n_orders)
- if (dumbfile_skip(f, n_orders - sigdata->n_orders))
- goto error_fp;
- if (dumbfile_igetw(f)) goto error_fp;
- break;
-
- case PSM_COMPONENT_PANPOS:
- if (dumbfile_getnc(sigdata->channel_pan, sigdata->n_pchannels, f) < sigdata->n_pchannels) goto error_fp;
- for (o = 0; o < sigdata->n_pchannels; o++) {
- sigdata->channel_pan[o] -= (sigdata->channel_pan[o] & 8) >> 3;
- sigdata->channel_pan[o] = ((int)sigdata->channel_pan[o] << 5) / 7;
- }
- break;
-
- case PSM_COMPONENT_PATTERNS:
- if (it_old_psm_read_patterns(sigdata->pattern, f, sigdata->n_patterns, total_pattern_size, sigdata->n_pchannels, flags)) goto error_fp;
- break;
-
- case PSM_COMPONENT_SAMPLE_HEADERS:
- if (it_old_psm_read_samples(&sigdata->sample, f, &sigdata->n_samples, ptr, data_pos, data_size)) goto error_fp;
- break;
-
- case PSM_COMPONENT_COMMENTS:
- if (dumbfile_mgetl(f) == DUMB_ID('T','E','X','T')) {
- o = dumbfile_igetw(f);
- if (o > 0) {
- sigdata->song_message = malloc(o + 1);
- if (dumbfile_getnc(sigdata->song_message, o, f) < o) goto error_fp;
- sigdata->song_message[o] = 0;
- }
- }
- break;
- }
-
- if (ptr) {
- free(ptr);
- ptr = 0;
- }
- }
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- free(component);
-
- return sigdata;
-
-error_fp:
- if (ptr) free(ptr);
-error_fc:
- free(component);
-error_usd:
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
-error_sd:
- free(sigdata);
-error:
- return NULL;
-}
-
-DUH *dumb_read_old_psm_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_old_psm_load_sigdata(f);
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "PSM (old)";
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readpsm.c - Code to read an old Protracker / / \ \
+ * Studio module from an open file. | < / \_
+ * | \/ /\ /
+ * By Chris Moeller. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+
+static int psm_sample_compare(const void *e1, const void *e2)
+{
+ const unsigned char * pa = e1;
+ const unsigned char * pb = e2;
+ int a = pa[37] | (pa[38] << 8) | (pa[39] << 16) | (pa[40] << 24);
+ int b = pb[37] | (pb[38] << 8) | (pb[39] << 16) | (pb[40] << 24);
+ return a - b;
+}
+
+static int it_old_psm_read_samples(IT_SAMPLE ** sample, DUMBFILE * f, int * num, const unsigned char * prebuffer, long data_pos, long data_size)
+{
+ int n, o, pos, count = *num, true_num, snum, offset, flags, finetune, delta;
+
+ unsigned char * buffer, * sbuffer = 0;
+ const unsigned char * sdata;
+
+ buffer = malloc(count * 64);
+ if (!buffer) goto error;
+
+ if (dumbfile_getnc(buffer, count * 64, f) < count * 64) goto error_fb;
+
+ pos = dumbfile_pos(f);
+
+ true_num = 0;
+
+ for (n = 0; n < count; n++) {
+ snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8);
+ if ((snum < 1) || (snum > 255)) goto error_fb;
+ if (true_num < snum) true_num = snum;
+ }
+
+ if (true_num > count) {
+ IT_SAMPLE * meh = realloc(*sample, true_num * sizeof(*meh));
+ if (!meh) goto error_fb;
+ for (n = count; n < true_num; n++) {
+ meh[n].data = NULL;
+ }
+ *sample = meh;
+ *num = true_num;
+ }
+
+ qsort(buffer, count, 64, &psm_sample_compare);
+
+ for (n = 0; n < true_num; n++) {
+ (*sample)[n].flags = 0;
+ }
+
+ for (n = 0; n < count; n++) {
+ IT_SAMPLE * s;
+ snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8);
+ s = &((*sample)[snum - 1]);
+ memcpy(s->filename, buffer + (n * 64), 13);
+ s->filename[13] = 0;
+ memcpy(s->name, buffer + (n * 64) + 13, 24);
+ s->name[24] = 0;
+ offset = buffer[(n * 64) + 37] | (buffer[(n * 64) + 38] << 8) |
+ (buffer[(n * 64) + 39] << 16) | (buffer[(n * 64) + 40] << 24);
+ flags = buffer[(n * 64) + 47];
+ s->length = buffer[(n * 64) + 48] | (buffer[(n * 64) + 49] << 8) |
+ (buffer[(n * 64) + 50] << 16) | (buffer[(n * 64) + 51] << 24);
+ s->loop_start = buffer[(n * 64) + 52] | (buffer[(n * 64) + 53] << 8) |
+ (buffer[(n * 64) + 54] << 16) | (buffer[(n * 64) + 55] << 24);
+ s->loop_end = buffer[(n * 64) + 56] | (buffer[(n * 64) + 57] << 8) |
+ (buffer[(n * 64) + 58] << 16) | (buffer[(n * 64) + 59] << 24);
+
+ if (s->length <= 0) continue;
+
+ finetune = buffer[(n * 64) + 60];
+ s->default_volume = buffer[(n * 64) + 61];
+ s->C5_speed = buffer[(n * 64) + 62] | (buffer[(n * 64) + 63] << 8);
+ if (finetune < 16) {
+ if (finetune >= 8) finetune -= 16;
+ //s->C5_speed = (long)((double)s->C5_speed * pow(DUMB_PITCH_BASE, finetune*32));
+ s->finetune = finetune * 32;
+ }
+ else s->finetune = 0;
+
+ s->flags |= IT_SAMPLE_EXISTS;
+ if (flags & 0x41) {
+ s->flags &= ~IT_SAMPLE_EXISTS;
+ continue;
+ }
+ if (flags & 0x20) s->flags |= IT_SAMPLE_PINGPONG_LOOP;
+ if (flags & 4) s->flags |= IT_SAMPLE_16BIT;
+
+ if (flags & 0x80) {
+ s->flags |= IT_SAMPLE_LOOP;
+ if ((unsigned int)s->loop_end > (unsigned int)s->length)
+ s->loop_end = s->length;
+ else if ((unsigned int)s->loop_start >= (unsigned int)s->loop_end)
+ s->flags &= ~IT_SAMPLE_LOOP;
+ else
+ s->length = s->loop_end;
+ }
+
+ s->global_volume = 64;
+
+ s->vibrato_speed = 0;
+ s->vibrato_depth = 0;
+ s->vibrato_rate = 0;
+ s->vibrato_waveform = IT_VIBRATO_SINE;
+ s->max_resampling_quality = -1;
+
+ s->data = malloc(s->length * ((flags & 4) ? 2 : 1));
+ if (!s->data) goto error_fb;
+
+ if ((offset >= data_pos) &&
+ ((offset + s->length * ((flags & 4) ? 2 : 1)) <= (data_pos + data_size))) {
+ sdata = prebuffer + offset - data_pos;
+ } else if (offset >= pos) {
+ if (dumbfile_skip(f, offset - pos)) goto error_fb;
+ pos = offset;
+ offset = s->length * ((flags & 4) ? 2 : 1);
+ sbuffer = malloc(offset);
+ if (!sbuffer) goto error_fb;
+ if (dumbfile_getnc(sbuffer, offset, f) < offset) goto error_fsb;
+ sdata = sbuffer;
+ } else
+ goto error_fb;
+
+ if (flags & 0x10) {
+ if (flags & 8) {
+ if (flags & 4) {
+ for (o = 0; o < s->length; o++)
+ ((short *)s->data)[o] = (sdata[o * 2] | (sdata[(o * 2) + 1] << 8)) ^ 0x8000;
+ } else {
+ for (o = 0; o < s->length; o++)
+ ((signed char *)s->data)[o] = sdata[o] ^ 0x80;
+ }
+ } else {
+ if (flags & 4) {
+ for (o = 0; o < s->length; o++)
+ ((short *)s->data)[o] = sdata[o * 2] | (sdata[(o * 2) + 1] << 8);
+ } else {
+ memcpy(s->data, sdata, s->length);
+ }
+ }
+ } else {
+ delta = 0;
+ if (flags & 8) {
+ /* unsigned delta? mehhh, does anything even use this? */
+ if (flags & 4) {
+ for (o = 0; o < s->length; o++) {
+ delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8));
+ ((short *)s->data)[o] = delta ^ 0x8000;
+ }
+ } else {
+ for (o = 0; o < s->length; o++) {
+ delta += (signed char)sdata[o];
+ ((signed char *)s->data)[o] = delta ^ 0x80;
+ }
+ }
+ } else {
+ if (flags & 4) {
+ for (o = 0; o < s->length; o++) {
+ delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8));
+ ((short *)s->data)[o] = delta;
+ }
+ } else {
+ for (o = 0; o < s->length; o++) {
+ delta += (signed char)sdata[o];
+ ((signed char *)s->data)[o] = delta;
+ }
+ }
+ }
+ }
+
+ if (sbuffer) {
+ free(sbuffer);
+ sbuffer = 0;
+ }
+ }
+
+ free(buffer);
+
+ return 0;
+
+error_fsb:
+ if (sbuffer) free(sbuffer);
+error_fb:
+ free(buffer);
+error:
+ return -1;
+}
+
+static int it_old_psm_read_patterns(IT_PATTERN * pattern, DUMBFILE * f, int num, int size, int pchans, int sflags)
+{
+ int n, offset, psize, rows, chans, row, flags, channel;
+
+ unsigned char * buffer, * ptr, * end;
+
+ IT_ENTRY * entry;
+
+ buffer = malloc(size);
+ if (!buffer) goto error;
+
+ if (dumbfile_getnc(buffer, size, f) < size) goto error_fb;
+
+ offset = 0;
+
+ for (n = 0; n < num; n++) {
+ IT_PATTERN * p = &pattern[n];
+
+ if (offset >= size) goto error_fb;
+
+ ptr = buffer + offset;
+ psize = ptr[0] | (ptr[1] << 8);
+ rows = ptr[2];
+ chans = ptr[3];
+
+ if (!rows || !chans) {
+ p->n_rows = 1;
+ p->n_entries = 0;
+ continue;
+ }
+
+ psize = (psize + 15) & ~15;
+
+ end = ptr + psize;
+ ptr += 4;
+
+ p->n_rows = rows;
+ p->n_entries = rows;
+ row = 0;
+
+ while ((row < rows) && (ptr < end)) {
+ flags = *ptr++;
+ if (!flags) {
+ row++;
+ continue;
+ }
+ if (flags & 0xE0) {
+ p->n_entries++;
+ if (flags & 0x80) ptr += 2;
+ if (flags & 0x40) ptr++;
+ if (flags & 0x20) {
+ ptr++;
+ if (*ptr == 40) ptr += 3;
+ else ptr++;
+ }
+ }
+ }
+
+ entry = malloc(p->n_entries * sizeof(*p->entry));
+ if (!entry) goto error_fb;
+
+ p->entry = entry;
+
+ ptr = buffer + offset + 4;
+ row = 0;
+
+ while ((row < rows) && (ptr < end)) {
+ flags = *ptr++;
+ if (!flags) {
+ IT_SET_END_ROW(entry);
+ entry++;
+ row++;
+ continue;
+ }
+ if (flags & 0xE0) {
+ entry->mask = 0;
+ entry->channel = channel = flags & 0x1F;
+ if (channel >= chans)
+ {
+ //channel = 0;
+ goto error_fb;
+ }
+ if (flags & 0x80) {
+ if ((*ptr < 60) && (channel < pchans)) {
+ entry->mask |= IT_ENTRY_NOTE;
+ entry->note = *ptr + 36;
+ }
+ ptr++;
+ if (*ptr) {
+ entry->mask |= IT_ENTRY_INSTRUMENT;
+ entry->instrument = *ptr;
+ }
+ ptr++;
+ }
+ if (flags & 0x40) {
+ if (*ptr <= 64) {
+ entry->mask |= IT_ENTRY_VOLPAN;
+ entry->volpan = *ptr;
+ }
+ ptr++;
+ }
+ if (flags & 0x20) {
+ entry->mask |= IT_ENTRY_EFFECT;
+
+ switch (*ptr) {
+ case 1:
+ entry->effect = IT_XM_FINE_VOLSLIDE_UP;
+ entry->effectvalue = ptr[1];
+ break;
+
+ case 2:
+ entry->effect = IT_VOLUME_SLIDE;
+ entry->effectvalue = (ptr[1] << 4) & 0xF0;
+ break;
+
+ case 3:
+ entry->effect = IT_XM_FINE_VOLSLIDE_DOWN;
+ entry->effectvalue = ptr[1];
+ break;
+
+ case 4:
+ entry->effect = IT_VOLUME_SLIDE;
+ entry->effectvalue = ptr[1] & 0xF;
+ break;
+
+ case 10:
+ entry->effect = IT_PORTAMENTO_UP;
+ entry->effectvalue = EFFECT_VALUE(0xF, ptr[1]);
+ break;
+
+ case 11:
+ entry->effect = IT_PORTAMENTO_UP;
+ entry->effectvalue = ptr[1];
+ break;
+
+ case 12:
+ entry->effect = IT_PORTAMENTO_DOWN;
+ entry->effectvalue = EFFECT_VALUE(ptr[1], 0xF);
+ break;
+
+ case 13:
+ entry->effect = IT_PORTAMENTO_DOWN;
+ entry->effectvalue = ptr[1];
+ break;
+
+ case 14:
+ entry->effect = IT_TONE_PORTAMENTO;
+ entry->effectvalue = ptr[1];
+ break;
+
+ case 15:
+ entry->effect = IT_S;
+ entry->effectvalue = EFFECT_VALUE(IT_S_SET_GLISSANDO_CONTROL, ptr[1] & 15);
+ break;
+
+ case 16:
+ entry->effect = IT_VOLSLIDE_TONEPORTA;
+ entry->effectvalue = ptr[1] << 4;
+ break;
+
+ case 17:
+ entry->effect = IT_VOLSLIDE_TONEPORTA;
+ entry->effectvalue = ptr[1] & 0xF;
+ break;
+
+ case 20:
+ entry->effect = IT_VIBRATO;
+ entry->effectvalue = ptr[1];
+ break;
+
+ case 21:
+ entry->effect = IT_S;
+ entry->effectvalue = EFFECT_VALUE(IT_S_SET_VIBRATO_WAVEFORM, ptr[1] & 11);
+ break;
+
+ case 22:
+ entry->effect = IT_VOLSLIDE_VIBRATO;
+ entry->effectvalue = ptr[1] << 4;
+ break;
+
+ case 23:
+ entry->effect = IT_VOLSLIDE_VIBRATO;
+ entry->effectvalue = ptr[1] & 0xF;
+ break;
+
+ case 30:
+ entry->effect = IT_TREMOLO;
+ entry->effectvalue = ptr[1];
+ break;
+
+ case 31:
+ entry->effect = IT_S;
+ entry->effectvalue = EFFECT_VALUE(IT_S_SET_TREMOLO_WAVEFORM, ptr[1] & 11);
+ break;
+
+ case 40:
+ entry->effect = IT_SET_SAMPLE_OFFSET;
+ entry->effectvalue = ptr[2];
+ ptr += 2;
+ break;
+
+ case 41:
+ entry->effect = IT_XM_RETRIGGER_NOTE;
+ entry->effectvalue = ptr[1];
+ break;
+
+ case 42:
+ entry->effect = IT_S;
+ entry->effectvalue = EFFECT_VALUE(IT_S_DELAYED_NOTE_CUT, ptr[1] & 0xF);
+ break;
+
+ case 43:
+ entry->effect = IT_S;
+ entry->effectvalue = EFFECT_VALUE(IT_S_NOTE_DELAY, ptr[1] & 0xF);
+ break;
+
+ case 50:
+ entry->effect = IT_JUMP_TO_ORDER;
+ entry->effectvalue = ptr[1];
+ break;
+
+ case 51:
+ entry->effect = IT_BREAK_TO_ROW;
+ entry->effectvalue = ptr[1];
+ break;
+
+ case 52:
+ entry->effect = IT_S;
+ entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_LOOP, ptr[1] & 0xF);
+ break;
+
+ case 53:
+ entry->effect = IT_S;
+ entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_DELAY, ptr[1] & 0xF);
+ break;
+
+ case 60:
+ entry->effect = IT_SET_SPEED;
+ entry->effectvalue = ptr[1];
+ break;
+
+ case 61:
+ entry->effect = IT_SET_SONG_TEMPO;
+ entry->effectvalue = ptr[1];
+ break;
+
+ case 70:
+ entry->effect = IT_ARPEGGIO;
+ entry->effectvalue = ptr[1];
+ break;
+
+ case 71:
+ entry->effect = IT_S;
+ entry->effectvalue = EFFECT_VALUE(IT_S_FINETUNE, ptr[1] & 0xF);
+ break;
+
+ case 72:
+ /* "balance" ... panning? */
+ entry->effect = IT_SET_PANNING;
+ entry->effectvalue = ((ptr[1] - ((ptr[1] & 8) >> 3)) << 5) / 7;
+ break;
+
+ default:
+ entry->mask &= ~IT_ENTRY_EFFECT;
+ }
+
+ ptr += 2;
+ }
+ if (entry->mask) entry++;
+ }
+ }
+
+ p->n_entries = entry - p->entry;
+ offset += psize;
+ }
+
+ free(buffer);
+
+ return 0;
+
+error_fb:
+ free(buffer);
+error:
+ return -1;
+}
+
+#define PSM_COMPONENT_ORDERS 0
+#define PSM_COMPONENT_PANPOS 1
+#define PSM_COMPONENT_PATTERNS 2
+#define PSM_COMPONENT_SAMPLE_HEADERS 3
+#define PSM_COMPONENT_COMMENTS 4
+
+typedef struct PSM_COMPONENT
+{
+ unsigned char type;
+ long offset;
+}
+PSM_COMPONENT;
+
+static int psm_component_compare(const void *e1, const void *e2)
+{
+ return ((const PSM_COMPONENT *)e1)->offset -
+ ((const PSM_COMPONENT *)e2)->offset;
+}
+
+static DUMB_IT_SIGDATA *it_old_psm_load_sigdata(DUMBFILE *f)
+{
+ DUMB_IT_SIGDATA *sigdata;
+
+ unsigned char * ptr = 0;
+
+ PSM_COMPONENT *component;
+ int n_components = 0;
+
+ int n, flags, version, pver, n_orders, n_channels, total_pattern_size;
+
+ if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',254)) goto error;
+
+ sigdata = malloc(sizeof(*sigdata));
+ if (!sigdata) goto error;
+
+ if (dumbfile_getnc(sigdata->name, 60, f) < 60 ||
+ sigdata->name[59] != 0x1A) goto error_sd;
+ sigdata->name[59] = 0;
+
+ flags = dumbfile_getc(f);
+ version = dumbfile_getc(f);
+ pver = dumbfile_getc(f);
+ sigdata->speed = dumbfile_getc(f);
+ sigdata->tempo = dumbfile_getc(f);
+ sigdata->mixing_volume = dumbfile_getc(f);
+ sigdata->n_orders = dumbfile_igetw(f);
+ n_orders = dumbfile_igetw(f);
+ sigdata->n_patterns = dumbfile_igetw(f);
+ sigdata->n_samples = dumbfile_igetw(f);
+ sigdata->n_pchannels = dumbfile_igetw(f);
+ n_channels = dumbfile_igetw(f);
+
+ if (dumbfile_error(f) ||
+ (flags & 1) ||
+ (version != 1 && version != 0x10) ||
+ (pver) ||
+ (sigdata->n_orders <= 0) ||
+ (sigdata->n_orders > 255) ||
+ (n_orders > 255) ||
+ (n_orders < sigdata->n_orders) ||
+ (sigdata->n_patterns > 255) ||
+ (sigdata->n_samples > 255) ||
+ (sigdata->n_pchannels > DUMB_IT_N_CHANNELS) ||
+ (sigdata->n_pchannels > n_channels) ||
+ (n_channels > DUMB_IT_N_CHANNELS))
+ goto error_sd;
+
+ sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
+
+ sigdata->global_volume = 128;
+ sigdata->pan_separation = 128;
+
+ sigdata->song_message = NULL;
+ sigdata->order = NULL;
+ sigdata->instrument = NULL;
+ sigdata->sample = NULL;
+ sigdata->pattern = NULL;
+ sigdata->midi = NULL;
+ sigdata->checkpoint = NULL;
+
+ sigdata->n_instruments = 0;
+
+ sigdata->restart_position = 0;
+
+ sigdata->order = malloc(sigdata->n_orders);
+ if (!sigdata->order) goto error_usd;
+
+ if (sigdata->n_samples) {
+ sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
+ if (!sigdata->sample) goto error_usd;
+ for (n = 0; n < sigdata->n_samples; n++)
+ sigdata->sample[n].data = NULL;
+ }
+
+ if (sigdata->n_patterns) {
+ sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
+ if (!sigdata->pattern) goto error_usd;
+ for (n = 0; n < sigdata->n_patterns; n++)
+ sigdata->pattern[n].entry = NULL;
+ }
+
+ component = malloc(5 * sizeof(*component));
+ if (!component) goto error_usd;
+
+ for (n = 0; n < 5; n++) {
+ component[n_components].offset = dumbfile_igetl(f);
+ if (component[n_components].offset) {
+ component[n_components].type = n;
+ n_components++;
+ }
+ }
+
+ if (!n_components) goto error_fc;
+
+ total_pattern_size = dumbfile_igetl(f);
+ if (!total_pattern_size) goto error_fc;
+
+ qsort(component, n_components, sizeof(PSM_COMPONENT), &psm_component_compare);
+
+ memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
+
+ for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
+ sigdata->channel_pan[n ] = 16;
+ sigdata->channel_pan[n+1] = 48;
+ sigdata->channel_pan[n+2] = 48;
+ sigdata->channel_pan[n+3] = 16;
+ }
+
+ for (n = 0; n < n_components; n++)
+ {
+ int o;
+ long data_pos, data_size;
+
+ /* Whee, sample data may be before the sample headers */
+
+ data_pos = dumbfile_pos(f);
+ if (data_pos > component[n].offset) goto error_fc;
+
+ data_size = component[n].offset - data_pos;
+
+ if (data_size) {
+ ptr = malloc(data_size);
+ if (!ptr) goto error_fc;
+
+ if (dumbfile_getnc(ptr, data_size, f) < data_size) goto error_fp;
+ }
+
+ switch (component[n].type) {
+
+ case PSM_COMPONENT_ORDERS:
+ if (dumbfile_getnc(sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_fp;
+ if (n_orders > sigdata->n_orders)
+ if (dumbfile_skip(f, n_orders - sigdata->n_orders))
+ goto error_fp;
+ if (dumbfile_igetw(f)) goto error_fp;
+ break;
+
+ case PSM_COMPONENT_PANPOS:
+ if (dumbfile_getnc(sigdata->channel_pan, sigdata->n_pchannels, f) < sigdata->n_pchannels) goto error_fp;
+ for (o = 0; o < sigdata->n_pchannels; o++) {
+ sigdata->channel_pan[o] -= (sigdata->channel_pan[o] & 8) >> 3;
+ sigdata->channel_pan[o] = ((int)sigdata->channel_pan[o] << 5) / 7;
+ }
+ break;
+
+ case PSM_COMPONENT_PATTERNS:
+ if (it_old_psm_read_patterns(sigdata->pattern, f, sigdata->n_patterns, total_pattern_size, sigdata->n_pchannels, flags)) goto error_fp;
+ break;
+
+ case PSM_COMPONENT_SAMPLE_HEADERS:
+ if (it_old_psm_read_samples(&sigdata->sample, f, &sigdata->n_samples, ptr, data_pos, data_size)) goto error_fp;
+ break;
+
+ case PSM_COMPONENT_COMMENTS:
+ if (dumbfile_mgetl(f) == DUMB_ID('T','E','X','T')) {
+ o = dumbfile_igetw(f);
+ if (o > 0) {
+ sigdata->song_message = malloc(o + 1);
+ if (dumbfile_getnc(sigdata->song_message, o, f) < o) goto error_fp;
+ sigdata->song_message[o] = 0;
+ }
+ }
+ break;
+ }
+
+ if (ptr) {
+ free(ptr);
+ ptr = 0;
+ }
+ }
+
+ _dumb_it_fix_invalid_orders(sigdata);
+
+ free(component);
+
+ return sigdata;
+
+error_fp:
+ if (ptr) free(ptr);
+error_fc:
+ free(component);
+error_usd:
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+error_sd:
+ free(sigdata);
+error:
+ return NULL;
+}
+
+DUH *dumb_read_old_psm_quick(DUMBFILE *f)
+{
+ sigdata_t *sigdata;
+
+ DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
+
+ sigdata = it_old_psm_load_sigdata(f);
+
+ if (!sigdata)
+ return NULL;
+
+ {
+ const char *tag[2][2];
+ tag[0][0] = "TITLE";
+ tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+ tag[1][0] = "FORMAT";
+ tag[1][1] = "PSM (old)";
+ return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/readpsm.c b/plugins/dumb/dumb-kode54/src/it/readpsm.c
index 07b33613..ec2bf909 100644
--- a/plugins/dumb/dumb-kode54/src/it/readpsm.c
+++ b/plugins/dumb/dumb-kode54/src/it/readpsm.c
@@ -1,1273 +1,1273 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readpsm.c - Code to read a Protracker Studio / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-#define PSMV_OLD 940730
-#define PSMV_NEW 940902
-
-typedef struct _PSMCHUNK
-{
- int id;
- int len;
- unsigned char * data;
-} PSMCHUNK;
-
-typedef struct _PSMEVENT
-{
- int type;
- unsigned char data[8];
-} PSMEVENT;
-
-#define PSM_EVENT_END 0
-#define PSM_EVENT_PLAY_PATTERN 1
-#define PSM_EVENT_JUMP_TO_LINE 4
-#define PSM_EVENT_SET_SPEED 7
-#define PSM_EVENT_SET_BPM 8
-#define PSM_EVENT_SAMPLE_MAP_TABLE 12
-#define PSM_EVENT_CHANGE_PAN 13
-#define PSM_EVENT_CHANGE_VOL 14
-
-static int it_psm_process_sample(IT_SAMPLE * sample, const unsigned char * data, int len, int id, int version) {
- int flags;
- int insno;
- int length;
- int loopstart;
- int loopend;
- int panpos;
- int defvol;
- int samplerate;
-
- if (len < 0x60) return -1;
-
- flags = data[0];
-
- if (version == PSMV_OLD) {
- memcpy(sample->name, data + 0x0D, 34);
- sample->name[34] = 0;
-
- insno = data[0x34] | (data[0x35] << 8);
- length = data[0x36] | (data[0x37] << 8) | (data[0x38] << 16) | (data[0x39] << 24);
- loopstart = data[0x3A] | (data[0x3B] << 8) | (data[0x3C] << 16) | (data[0x3D] << 24);
- loopend = data[0x3E] | (data[0x3F] << 8) | (data[0x40] << 16) | (data[0x41] << 24);
- panpos = data[0x43];
- defvol = data[0x44];
- samplerate = data[0x49] | (data[0x4A] << 8) | (data[0x4B] << 16) | (data[0x4C] << 24);
- } else if (version == PSMV_NEW) {
- memcpy(sample->name, data + 0x11, 34);
- sample->name[34] = 0;
-
- insno = data[0x38] | (data[0x39] << 8);
- length = data[0x3A] | (data[0x3B] << 8) | (data[0x3C] << 16) | (data[0x3D] << 24);
- loopstart = data[0x3E] | (data[0x3F] << 8) | (data[0x40] << 16) | (data[0x41] << 24);
- loopend = data[0x42] | (data[0x43] << 8) | (data[0x44] << 16) | (data[0x45] << 24);
- panpos = data[0x48];
- defvol = data[0x49];
- samplerate = data[0x4E] | (data[0x4F] << 8) | (data[0x50] << 16) | (data[0x51] << 24);
- }
-
- if (insno != id) return -1;
-
- if (!length) {
- sample->flags &= ~IT_SAMPLE_EXISTS;
- return 0;
- }
-
- if ((length > len - 0x60) || ((flags & 0x7F) != 0)) return -1;
-
- sample->flags = IT_SAMPLE_EXISTS;
- sample->length = length;
- sample->loop_start = loopstart;
- sample->loop_end = loopend;
- sample->C5_speed = samplerate;
- sample->default_volume = defvol >> 1;
- sample->default_pan = 0;
- sample->filename[0] = 0;
- sample->global_volume = 64;
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = IT_VIBRATO_SINE;
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- if (flags & 0x80) {
- if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) &&
- ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end)) {
- sample->length = sample->loop_end;
- sample->flags |= IT_SAMPLE_LOOP;
- }
- }
-
- sample->data = malloc(sample->length);
- if (!sample->data)
- return -1;
-
- flags = 0;
- data += 0x60;
-
- for (insno = 0; insno < sample->length; insno++) {
- flags += (signed char)(*data++);
- ((signed char *)sample->data)[insno] = flags;
- }
-
- return 0;
-}
-
-static int it_psm_process_pattern(IT_PATTERN * pattern, const unsigned char * data, int len, int speed, int bpm, const unsigned char * pan, const int * vol, int version) {
- int length, nrows, row, rowlen, pos;
- unsigned flags, chan;
- IT_ENTRY * entry;
-
- length = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
- if (len > length) len = length;
-
- if (version == PSMV_OLD) {
- if (len < 10) return -1;
- data += 8;
- len -= 8;
- } else if (version == PSMV_NEW) {
- if (len < 14) return -1;
- data += 12;
- len -= 12;
- }
-
- nrows = data[0] | (data[1] << 8);
-
- if (!nrows) return 0;
-
- pattern->n_rows = nrows;
-
- data += 2;
- len -= 2;
-
- pattern->n_entries = 0;
-
- row = 0;
- pos = 2;
- rowlen = data[0] | (data[1] << 8);
-
- while ((row < nrows) && (pos < len)) {
- if (pos >= rowlen) {
- row++;
- rowlen += data[pos] | (data[pos+1] << 8);
- pos += 2;
- continue;
- }
-
- flags = data[pos++];
- chan = data[pos++];
-
- if (chan > 63) return -1;
-
- if (flags & 0xF0) {
- pattern->n_entries++;
- if (flags & 0x80) pos++;
- if (flags & 0x40) pos++;
- if (flags & 0x20) pos++;
- if (flags & 0x10) {
- switch (data[pos]) {
- case 0x29:
- pos++;
- case 0x33:
- pos++;
- default:
- pos += 2;
- }
- }
- }
- }
-
- if (!pattern->n_entries) return 0;
-
- pattern->n_entries += nrows;
- if (speed) pattern->n_entries++;
- if (bpm >= 0x20) pattern->n_entries++;
-
- for (pos = 0; pos < 32; pos++) {
- if (!(pan[pos*2+1] & 0xF9)) pattern->n_entries++;
- if (vol[pos] != -1) pattern->n_entries++;
- }
-
- pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
- if (!pattern->entry) return -1;
-
- entry = pattern->entry;
-
- if (speed) {
- entry->channel = 0;
- entry->mask = IT_ENTRY_EFFECT;
- entry->effect = IT_SET_SPEED;
- entry->effectvalue = speed;
- entry++;
- }
-
- if (bpm >= 0x20) {
- entry->channel = 0;
- entry->mask = IT_ENTRY_EFFECT;
- entry->effect = IT_SET_SONG_TEMPO;
- entry->effectvalue = bpm;
- entry++;
- }
-
- for (pos = 0; pos < 32; pos++) {
- if (!(pan[pos*2+1] & 0xF9)) {
- entry->channel = pos;
- entry->mask = IT_ENTRY_EFFECT;
- switch (pan[pos*2+1]) {
- case 0:
- entry->effect = IT_SET_PANNING;
- entry->effectvalue = pan[pos*2] ^ 128;
- break;
- case 2:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_SET_SURROUND_SOUND,1);
- break;
- case 4:
- entry->effect = IT_SET_PANNING;
- entry->effectvalue = 128;
- break;
- }
- entry++;
- }
- if (vol[pos] != -1) {
- entry->channel = pos;
- entry->mask = IT_ENTRY_EFFECT;
- entry->effect = IT_SET_CHANNEL_VOLUME;
- entry->effectvalue = (vol[pos] + 2) >> 2;
- entry++;
- }
- }
-
- row = 0;
- pos = 2;
- rowlen = data[0] | (data[1] << 8);
-
- while ((row < nrows) && (pos < len)) {
- if (pos >= rowlen) {
- IT_SET_END_ROW(entry);
- entry++;
- row++;
- rowlen += data[pos] | (data[pos+1] << 8);
- pos += 2;
- continue;
- }
-
- flags = data[pos++];
- entry->channel = data[pos++];
- entry->mask = 0;
-
- if (flags & 0xF0) {
- if (flags & 0x80) {
- entry->mask |= IT_ENTRY_NOTE;
- if (version == PSMV_OLD) {
- if ((data[pos] < 0x80)) entry->note = (data[pos]>>4)*12+(data[pos]&0x0f)+12;
- else entry->mask &= ~IT_ENTRY_NOTE;
- } else if (version == PSMV_NEW) {
- if ((data[pos]) && (data[pos] < 84)) entry->note = data[pos] + 35;
- else entry->mask &= ~IT_ENTRY_NOTE;
- }
- pos++;
- }
-
- if (flags & 0x40) {
- entry->mask |= IT_ENTRY_INSTRUMENT;
- entry->instrument = data[pos++] + 1;
- }
-
- if (flags & 0x20) {
- entry->mask |= IT_ENTRY_VOLPAN;
- entry->volpan = (data[pos++] + 1) >> 1;
- }
-
- if (flags & 0x10) {
- entry->mask |= IT_ENTRY_EFFECT;
- length = data[pos+1];
- switch (data[pos]) {
- case 1:
- entry->effect = IT_VOLUME_SLIDE;
- if (version == PSMV_OLD) entry->effectvalue = ((length&0x1e)<<3) | 0xF;
- else if (version == PSMV_NEW) entry->effectvalue = (length<<4) | 0xF;
- break;
-
- case 2:
- entry->effect = IT_VOLUME_SLIDE;
- if (version == PSMV_OLD) entry->effectvalue = (length << 3) & 0xF0;
- else if (version == PSMV_NEW) entry->effectvalue = (length << 4) & 0xF0;
- break;
-
- case 3:
- entry->effect = IT_VOLUME_SLIDE;
- if (version == PSMV_OLD) entry->effectvalue = (length >> 1) | 0xF0;
- else if (version == PSMV_NEW) entry->effectvalue = length | 0xF0;
- break;
-
- case 4:
- entry->effect = IT_VOLUME_SLIDE;
- if (version == PSMV_OLD) entry->effectvalue = (length >> 1) & 0xF;
- else if (version == PSMV_NEW) entry->effectvalue = length & 0xF;
- break;
-
- case 12:
- entry->effect = IT_PORTAMENTO_UP;
- if (version == PSMV_OLD) {
- if (length < 4) entry->effectvalue = length | 0xF0;
- else entry->effectvalue = length >> 2;
- } else if (version == PSMV_NEW) {
- entry->effectvalue = length;
- }
- break;
-
- case 14:
- entry->effect = IT_PORTAMENTO_DOWN;
- if (version == PSMV_OLD) {
- if (length < 4) entry->effectvalue = length | 0xF0;
- else entry->effectvalue = length >> 2;
- } else if (version == PSMV_NEW) {
- entry->effectvalue = length;
- }
- break;
-
- case 15:
- entry->effect = IT_TONE_PORTAMENTO;
- if (version == PSMV_OLD) entry->effectvalue = length >> 2;
- else if (version == PSMV_NEW) entry->effectvalue = length;
- break;
-
- case 0x15:
- entry->effect = IT_VIBRATO;
- entry->effectvalue = length;
- break;
-
- case 0x18:
- entry->effect = IT_VOLSLIDE_VIBRATO;
- entry->effectvalue = length;
- break;
-
- case 0x29:
- entry->effect = IT_SET_SAMPLE_OFFSET;
- entry->effectvalue = data[pos+2];
- pos += 2;
- break;
-
- case 0x2A:
- entry->effect = IT_RETRIGGER_NOTE;
- entry->effectvalue = length;
- break;
-
- case 0x33:
-#if 0
- entry->effect = IT_POSITION_JUMP;
- entry->effectvalue = data[pos+2];
-#else
- entry->mask &= ~IT_ENTRY_EFFECT;
-#endif
- pos++;
- break;
-
- case 0x34:
- entry->effect = IT_BREAK_TO_ROW;
- entry->effectvalue = length;
- break;
-
- case 0x3D:
- entry->effect = IT_SET_SPEED;
- entry->effectvalue = length;
- break;
-
- case 0x3E:
- if (length >= 0x20) {
- entry->effect = IT_SET_SONG_TEMPO;
- entry->effectvalue = length;
- } else {
- entry->mask &= ~IT_ENTRY_EFFECT;
- }
- break;
-
- case 0x47:
- entry->effect = IT_ARPEGGIO;
- entry->effectvalue = length;
- break;
-
- default:
- return -1;
- }
- pos += 2;
- }
- if (entry->mask) entry++;
- }
- }
-
- while (row < nrows) {
- IT_SET_END_ROW(entry);
- entry++;
- row++;
- }
-
- pattern->n_entries = entry - pattern->entry;
- if (!pattern->n_entries) return -1;
-
- return 0;
-}
-
-
-static void free_chunks(PSMCHUNK * chunk, int count) {
- int n;
-
- for (n = 0; n < count; n++) {
- if (chunk[n].data)
- free(chunk[n].data);
- }
-
- free(chunk);
-}
-
-static void dumb_it_optimize_orders(DUMB_IT_SIGDATA * sigdata);
-
-static int pattcmp( const unsigned char *, const unsigned char *, size_t );
-
-static DUMB_IT_SIGDATA *it_psm_load_sigdata(DUMBFILE *f, int * ver, int subsong)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- PSMCHUNK *chunk;
- int n_chunks = 0;
-
- PSMCHUNK *songchunk;
- int n_song_chunks = 0;
-
- PSMEVENT *event = NULL;
- int n_events = 0;
-
- unsigned char * ptr;
-
- int n, length, o;
-
- int found;
-
- int n_patterns = 0;
-
- int first_pattern_line = -1;
- int first_pattern;
-
- int speed, bpm;
- unsigned char pan[64];
- int vol[32];
-
- if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',' ')) goto error;
-
- length = dumbfile_igetl(f);
-
- if (dumbfile_mgetl(f) != DUMB_ID('F','I','L','E')) goto error;
-
- chunk = calloc(768, sizeof(*chunk));
-
- while (length >= 8) {
- chunk[n_chunks].id = dumbfile_mgetl(f);
- n = dumbfile_igetl(f);
- length -= 8;
- if (n < 0 || n > length)
- goto error_fc;
- chunk[n_chunks].len = n;
- if (n) {
- ptr = malloc(n);
- if (!ptr) goto error_fc;
- if (dumbfile_getnc(ptr, n, f) < n)
- {
- free(ptr);
- goto error_fc;
- }
- chunk[n_chunks].data = ptr;
- }
- n_chunks++;
- length -= n;
- }
-
- if (!n_chunks) goto error_fc;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) goto error_fc;
-
- sigdata->n_patterns = 0;
- sigdata->n_samples = 0;
- sigdata->name[0] = 0;
-
- found = 0;
-
- for (n = 0; n < n_chunks; n++) {
- PSMCHUNK * c = &chunk[n];
- switch(c->id) {
- case DUMB_ID('S','D','F','T'):
- /* song data format? */
- if ((found & 1) || (c->len != 8) || memcmp(c->data, "MAINSONG", 8)) goto error_sd;
- found |= 1;
- break;
-
- case DUMB_ID('S','O','N','G'):
- if (/*(found & 2) ||*/ (c->len < 11) /*|| memcmp(c->data, "MAINSONG", 8)*/) goto error_sd;
- found |= 2;
- break;
-
- case DUMB_ID('D','S','M','P'):
- sigdata->n_samples++;
- break;
-
- case DUMB_ID('T','I','T','L'):
- length = min(sizeof(sigdata->name) - 1, c->len);
- memcpy(sigdata->name, c->data, length);
- sigdata->name[length] = 0;
- }
- }
-
- if (found != 3 || !sigdata->n_samples) goto error_sd;
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_instruments = 0;
- sigdata->n_orders = 0;
-
- for (n = 0; n < n_chunks; n++) {
- PSMCHUNK * c = &chunk[n];
- if (c->id == DUMB_ID('S','O','N','G')) {
- if (subsong == 0) break;
- subsong--;
- }
- }
-
- if (n == n_chunks) return NULL;
- subsong = n;
-
- /*for (n = 0; n < n_chunks; n++) {
- PSMCHUNK * c = &chunk[n];
- if (c->id == DUMB_ID('S','O','N','G')) {*/
- {
- PSMCHUNK * c = &chunk[subsong];
- {
- ptr = c->data;
- if (ptr[10] > 32) goto error_usd;
- sigdata->n_pchannels = ptr[10];
- length = c->len - 11;
- ptr += 11;
- songchunk = 0;
- if (length >= 8) {
- songchunk = malloc(128 * sizeof(*songchunk));
- if (!songchunk) goto error_usd;
- while (length >= 8) {
- songchunk[n_song_chunks].id = DUMB_ID(ptr[0], ptr[1], ptr[2], ptr[3]);
- n = ptr[4] | (ptr[5] << 8) | (ptr[6] << 16) | (ptr[7] << 24);
- length -= 8;
- if (n > length) goto error_sc;
- songchunk[n_song_chunks].len = n;
- songchunk[n_song_chunks].data = ptr + 8;
- n_song_chunks++;
- length -= n;
- ptr += 8 + n;
- }
- }
- /*break;*/
- }
- }
-
- if (!n_song_chunks) goto error_sc;
-
- found = 0;
-
- for (n = 0; n < n_song_chunks; n++) {
- PSMCHUNK * c = &songchunk[n];
-
- if (c->id == DUMB_ID('D','A','T','E')) {
- /* date of the library build / format spec */
- if (c->len == 6) {
- length = c->len;
- ptr = c->data;
- while (length > 0) {
- if (*ptr >= '0' && *ptr <= '9') {
- found = (found * 10) + (*ptr - '0');
- } else {
- found = 0;
- break;
- }
- ptr++;
- length--;
- }
- }
- break;
- }
- }
-
- /*
- if (found != 940506 &&
- found != 940509 &&
- found != 940510 &&
- found != 940530 &&
- found != 940629 &&
- found != PSMV_OLD &&
- found != 941011 &&
- found != PSMV_NEW &&
- found != 940906 &&
- found != 940903 &&
- found != 940914 &&
- found != 941213 &&
- found != 800211) /* WTF?
- goto error_sc;
- */
-
- *ver = found;
-
- if (found == 800211 ||
- found == PSMV_NEW ||
- found == 940903 ||
- found == 940906 ||
- found == 940914 ||
- found == 941213) found = PSMV_NEW;
- else found = PSMV_OLD;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
- sigdata->channel_pan[n ] = 16;
- sigdata->channel_pan[n+1] = 48;
- sigdata->channel_pan[n+2] = 48;
- sigdata->channel_pan[n+3] = 16;
- }
-
- for (n = 0; n < n_song_chunks; n++) {
- PSMCHUNK * c = &songchunk[n];
-
- switch (c->id) {
- case DUMB_ID('O','P','L','H'):
- if (c->len < 2) goto error_sc;
- ptr = c->data;
- o = ptr[0] | (ptr[1] << 8);
- if (!o) goto error_sc;
- event = malloc(o * sizeof(*event));
- if (!event) goto error_sc;
- length = c->len - 2;
- ptr += 2;
- while ((length > 0) && (n_events < o)) {
- event[n_events].type = *ptr;
- switch (*ptr) {
- case PSM_EVENT_END:
- ptr++;
- length--;
- break;
-
- case PSM_EVENT_PLAY_PATTERN:
- if (found == PSMV_OLD) {
- if (length < 5) goto error_ev;
- memcpy(event[n_events].data, ptr + 1, 4);
- ptr += 5;
- length -= 5;
- } else if (found == PSMV_NEW) {
- if (length < 9) goto error_ev;
- memcpy(event[n_events].data, ptr + 1, 8);
- ptr += 9;
- length -= 9;
- }
- break;
-
- case PSM_EVENT_SET_SPEED:
- case PSM_EVENT_SET_BPM:
- if (length < 2) goto error_ev;
- event[n_events].data[0] = ptr[1];
- ptr += 2;
- length -= 2;
- break;
-
- case PSM_EVENT_JUMP_TO_LINE:
- case PSM_EVENT_CHANGE_VOL:
- if (length < 3) goto error_ev;
- memcpy(event[n_events].data, ptr + 1, 2);
- ptr += 3;
- length -= 3;
- break;
-
- case PSM_EVENT_SAMPLE_MAP_TABLE:
- if (length < 7) goto error_ev;
- memcpy(event[n_events].data, ptr + 1, 6);
- ptr += 7;
- length -= 7;
- break;
-
- case PSM_EVENT_CHANGE_PAN:
- if (length < 4) goto error_ev;
- memcpy(event[n_events].data, ptr + 1, 3);
- ptr += 4;
- length -= 4;
- break;
-
- default:
- goto error_ev;
- }
- n_events++;
- }
- break;
-
- case DUMB_ID('P','P','A','N'):
- length = c->len;
- if (length & 1) goto error_ev;
- ptr = c->data;
- o = 0;
- while (length > 0) {
- switch (ptr[0]) {
- case 0:
- sigdata->channel_pan[o] = ((((int)(signed char)ptr[1]) * 32) / 127) + 32;
- break;
- case 2:
- sigdata->channel_pan[o] = IT_SURROUND;
- break;
- case 4:
- sigdata->channel_pan[o] = 32;
- break;
- }
- ptr += 2;
- length -= 2;
- if (++o >= DUMB_IT_N_CHANNELS) break;
- }
- break;
-
- /*
- case DUMB_ID('P','A','T','T'):
- case DUMB_ID('D','S','A','M'):
- */
- }
- }
-
- sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
-
- sigdata->global_volume = 128;
- sigdata->speed = 6;
- sigdata->tempo = 125;
- sigdata->mixing_volume = 48;
- sigdata->pan_separation = 128;
-
- speed = 0;
- bpm = 0;
- memset(pan, 255, sizeof(pan));
- memset(vol, 255, sizeof(vol));
-
- sigdata->n_patterns = n_events;
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) goto error_ev;
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
-
- for (n = 0; n < n_events; n++) {
- PSMEVENT * e = &event[n];
- switch (e->type) {
- case PSM_EVENT_END:
- n = n_events;
- break;
-
- case PSM_EVENT_PLAY_PATTERN:
- for (o = 0; o < n_chunks; o++) {
- PSMCHUNK * c = &chunk[o];
- if (c->id == DUMB_ID('P','B','O','D')) {
- ptr = c->data;
- length = c->len;
- if (found == PSMV_OLD) {
- if (length < 8) goto error_ev;
- if (!pattcmp(ptr + 4, e->data, 4)) {
- if (it_psm_process_pattern(&sigdata->pattern[n_patterns], ptr, length, speed, bpm, pan, vol, found)) goto error_ev;
- if (first_pattern_line < 0) {
- first_pattern_line = n;
- first_pattern = o;
- }
- e->data[0] = n_patterns;
- e->data[1] = n_patterns >> 8;
- n_patterns++;
- break;
- }
- } else if (found == PSMV_NEW) {
- if (length < 12) goto error_ev;
- if (!pattcmp(ptr + 4, e->data, 8)) {
- if (it_psm_process_pattern(&sigdata->pattern[n_patterns], ptr, length, speed, bpm, pan, vol, found)) goto error_ev;
- if (first_pattern_line < 0) {
- first_pattern_line = n;
- first_pattern = o;
- }
- e->data[0] = n_patterns;
- e->data[1] = n_patterns >> 8;
- n_patterns++;
- break;
- }
- }
- }
- }
- if (o == n_chunks) goto error_ev;
-
- speed = 0;
- bpm = 0;
- memset(pan, 255, sizeof(pan));
- memset(vol, 255, sizeof(vol));
-
- e->type = PSM_EVENT_END;
- break;
-
- case PSM_EVENT_JUMP_TO_LINE:
- o = e->data[0] | (e->data[1] << 8);
- if (o >= n_events) goto error_ev;
- if (o == 0) {
- /* whew! easy case! */
- sigdata->restart_position = 0;
- n = n_events;
- } else if (o == n) {
- /* freeze */
- n = n_events;
- } else if (o > n) {
- /* jump ahead, setting played event numbers to zero will prevent endless looping */
- n = o - 1;
- } else if (o >= first_pattern_line) {
- /* another semi-easy case */
- sigdata->restart_position = event[o].data[0] | (event[o].data[1] << 8);
- n = n_events;
- } else {
- /* crud, try to simulate rerunning all of the commands from the indicated
- * line up to the first pattern, then dupe the first pattern again.
- */
- /*
- PSMCHUNK * c = &chunk[first_pattern];
-
- for (; o < first_pattern_line; o++) {
- PSMEVENT * ev = &event[o];
- switch (ev->type) {
- case PSM_EVENT_SET_SPEED:
- speed = ev->data[0];
- break;
- case PSM_EVENT_SET_BPM:
- bpm = ev->data[0];
- break;
- case PSM_EVENT_CHANGE_PAN:
- if (ev->data[0] > 31) goto error_ev;
- pan[ev->data[0] * 2] = ev->data[1];
- pan[ev->data[0] * 2 + 1] = ev->data[2];
- break;
- case PSM_EVENT_CHANGE_VOL:
- if (ev->data[0] > 31) goto error_ev;
- vol[ev->data[0]] = ev->data[1];
- break;
- }
- }
-
- if (it_psm_process_pattern(&sigdata->pattern[n_patterns], c->data, c->len, speed, bpm, pan, vol, found)) goto error_ev;
- n_patterns++;
- sigdata->restart_position = 1;
- n = n_events;
-
- Eh, what the hell? PSM has no panning commands anyway.
- */
- sigdata->restart_position = 0;
- n = n_events;
- }
- e->type = PSM_EVENT_END;
- break;
-
- case PSM_EVENT_SET_SPEED:
- speed = e->data[0];
- break;
-
- case PSM_EVENT_SET_BPM:
- bpm = e->data[0];
- break;
-
- case PSM_EVENT_CHANGE_PAN:
- o = e->data[0];
- if (o > 31) goto error_ev;
- pan[o * 2] = e->data[1];
- pan[o * 2 + 1] = e->data[2];
- break;
-
- case PSM_EVENT_CHANGE_VOL:
- o = e->data[0];
- if (o > 31) goto error_ev;
- vol[o] = e->data[1];
- break;
-
- case PSM_EVENT_SAMPLE_MAP_TABLE:
- if (e->data[0] != 0 || e->data[1] != 0xFF ||
- e->data[2] != 0 || e->data[3] != 0 ||
- e->data[4] != 1 || e->data[5] != 0)
- goto error_ev;
- break;
- }
- }
-
- if (n_patterns > 256) goto error_ev;
-
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) goto error_ev;
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
-
- o = 0;
- for (n = 0; n < n_chunks; n++) {
- PSMCHUNK * c = &chunk[n];
- if (c->id == DUMB_ID('D','S','M','P')) {
- if (it_psm_process_sample(&sigdata->sample[o], c->data, c->len, o, found)) goto error_ev;
- o++;
- }
- }
-
- sigdata->n_orders = n_patterns;
- sigdata->n_patterns = n_patterns;
-
- sigdata->order = malloc(n_patterns);
-
- for (n = 0; n < n_patterns; n++) {
- sigdata->order[n] = n;
- }
-
- free(event);
- free(songchunk);
- free_chunks(chunk, n_chunks);
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- dumb_it_optimize_orders(sigdata);
-
- return sigdata;
-
-error_ev:
- free(event);
-error_sc:
- if (songchunk) free(songchunk);
-error_usd:
- _dumb_it_unload_sigdata(sigdata);
- goto error_fc;
-error_sd:
- free(sigdata);
-error_fc:
- free_chunks(chunk, n_chunks);
-error:
- return NULL;
-}
-
-static int it_order_compare(const void *e1, const void *e2) {
- if (*((const char *)e1) < *((const char *)e2))
- return -1;
-
- if (*((const char *)e1) > *((const char *)e2))
- return 1;
-
- return 0;
-}
-
-static int it_optimize_compare(const void *e1, const void *e2) {
- if (((const IT_ENTRY *)e1)->channel < ((const IT_ENTRY *)e2)->channel)
- return -1;
-
- if (((const IT_ENTRY *)e1)->channel > ((const IT_ENTRY *)e2)->channel)
- return 1;
-
- return 0;
-}
-
-static int it_entry_compare(const IT_ENTRY * e1, const IT_ENTRY * e2) {
- if (IT_IS_END_ROW(e1) && IT_IS_END_ROW(e2)) return 1;
- if (e1->channel != e2->channel) return 0;
- if (e1->mask != e2->mask) return 0;
- if ((e1->mask & IT_ENTRY_NOTE) && (e1->note != e2->note)) return 0;
- if ((e1->mask & IT_ENTRY_INSTRUMENT) && (e1->instrument != e2->instrument)) return 0;
- if ((e1->mask & IT_ENTRY_VOLPAN) && (e1->volpan != e2->volpan)) return 0;
- if ((e1->mask & IT_ENTRY_EFFECT) && ((e1->effect != e2->effect) || (e1->effectvalue != e2->effectvalue))) return 0;
- return 1;
-}
-
-/*
-static void dumb_it_optimize_pattern(IT_PATTERN * pattern) {
- IT_ENTRY * entry, * end;
- IT_ENTRY * rowstart, * rowend;
- IT_ENTRY * current;
-
- if (!pattern->n_entries || !pattern->entry) return;
-
- current = entry = pattern->entry;
- end = entry + pattern->n_entries;
-
- while (entry < end) {
- rowstart = entry;
- while (!IT_IS_END_ROW(entry)) entry++;
- rowend = entry;
- if (rowend > rowstart + 1)
- qsort(rowstart, rowend - rowstart, sizeof(IT_ENTRY), &it_optimize_compare);
- entry = rowstart;
- while (entry < rowend) {
- if (!(entry->mask)) {}
- else if (it_entry_compare(entry, current)) {}
- else if (!(current->mask) ||
- ((entry->channel == current->channel) &&
- ((entry->mask | current->mask) == (entry->mask ^ current->mask)))) {
- current->mask |= entry->mask;
- if (entry->mask & IT_ENTRY_NOTE) current->note = entry->note;
- if (entry->mask & IT_ENTRY_INSTRUMENT) current->instrument = entry->instrument;
- if (entry->mask & IT_ENTRY_VOLPAN) current->volpan = entry->volpan;
- if (entry->mask & IT_ENTRY_EFFECT) {
- current->effect = entry->effect;
- current->effectvalue = entry->effectvalue;
- }
- } else {
- if (++current < entry) *current = *entry;
- }
- entry++;
- }
- if (++current < entry) *current = *entry;
- entry++;
- }
-
- current++;
-
- if (current < end) {
- IT_ENTRY * opt;
- pattern->n_entries = current - pattern->entry;
- opt = realloc(pattern->entry, pattern->n_entries * sizeof(*pattern->entry));
- if (opt) pattern->entry = opt;
- }
-}
-*/
-
-static int it_pattern_compare(const IT_PATTERN * p1, const IT_PATTERN * p2) {
- IT_ENTRY * e1, * end;
- IT_ENTRY * e2;
-
- if (p1 == p2) return 1;
- if (p1->n_entries != p2->n_entries) return 0;
-
- e1 = p1->entry; end = e1 + p1->n_entries;
- e2 = p2->entry;
-
- while (e1 < end) {
- if (!it_entry_compare(e1, e2)) return 0;
- e1++; e2++;
- }
-
- return 1;
-}
-
-static void dumb_it_optimize_orders(DUMB_IT_SIGDATA * sigdata) {
- int n, o, p;
-
- int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253;
-
- unsigned char * order_list;
- int n_patterns;
-
- IT_PATTERN * pattern;
-
- if (!sigdata->n_orders || !sigdata->n_patterns) return;
-
- n_patterns = 0;
- order_list = malloc(sigdata->n_orders);
-
- if (!order_list) return;
-
- for (n = 0; n < sigdata->n_orders; n++) {
- if (sigdata->order[n] < sigdata->n_patterns) {
- for (o = 0; o < n_patterns; o++) {
- if (sigdata->order[n] == order_list[o]) break;
- }
- if (o == n_patterns) {
- order_list[n_patterns++] = sigdata->order[n];
- }
- }
- }
-
- if (!n_patterns) {
- free(order_list);
- return;
- }
-
- /*for (n = 0; n < n_patterns; n++) {
- dumb_it_optimize_pattern(&sigdata->pattern[order_list[n]]);
- }*/
-
- for (n = 0; n < n_patterns; n++) {
- for (o = n + 1; o < n_patterns; o++) {
- if ((order_list[n] != order_list[o]) &&
- it_pattern_compare(&sigdata->pattern[order_list[n]], &sigdata->pattern[order_list[o]])) {
- for (p = 0; p < sigdata->n_orders; p++) {
- if (sigdata->order[p] == order_list[o]) {
- sigdata->order[p] = order_list[n];
- }
- }
- for (p = o + 1; p < n_patterns; p++) {
- if (order_list[p] == order_list[o]) {
- order_list[p] = order_list[n];
- }
- }
- order_list[o] = order_list[n];
- }
- }
- }
-
- qsort(order_list, n_patterns, sizeof(*order_list), &it_order_compare);
-
- for (n = 0, o = 0; n < n_patterns; n++) {
- if (order_list[n] != order_list[o]) {
- if (++o < n) order_list[o] = order_list[n];
- }
- }
-
- n_patterns = o + 1;
-
- pattern = malloc(n_patterns * sizeof(*pattern));
- if (!pattern) {
- free(order_list);
- return;
- }
-
- for (n = 0; n < n_patterns; n++) {
- pattern[n] = sigdata->pattern[order_list[n]];
- }
-
- for (n = 0; n < sigdata->n_patterns; n++) {
- for (o = 0; o < n_patterns; o++) {
- if (order_list[o] == n) break;
- }
- if (o == n_patterns) {
- if (sigdata->pattern[n].entry)
- free(sigdata->pattern[n].entry);
- }
- }
-
- free(sigdata->pattern);
- sigdata->pattern = pattern;
- sigdata->n_patterns = n_patterns;
-
- for (n = 0; n < sigdata->n_orders; n++) {
- for (o = 0; o < n_patterns; o++) {
- if (sigdata->order[n] == order_list[o]) {
- sigdata->order[n] = o;
- break;
- }
- }
- }
-
- free(order_list);
-}
-
-int dumb_get_psm_subsong_count(DUMBFILE *f) {
- int length, subsongs;
- long l;
-
- if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',' ')) return 0;
-
- length = dumbfile_igetl(f);
-
- if (dumbfile_mgetl(f) != DUMB_ID('F','I','L','E')) return 0;
-
- subsongs = 0;
-
- while (length >= 8 && !dumbfile_error(f)) {
- if (dumbfile_mgetl(f) == DUMB_ID('S','O','N','G')) subsongs++;
- l = dumbfile_igetl(f);
- dumbfile_skip(f, l);
- length -= l + 8;
- }
-
- if (dumbfile_error(f)) return 0;
-
- return subsongs;
-}
-
-
-
-/* Eww */
-int pattcmp( const unsigned char * a, const unsigned char * b, size_t l )
-{
- int i, j, na, nb;
- char * p;
-
- i = memcmp( a, b, l );
- if ( !i ) return i;
-
- /* damnit */
-
- for ( i = 0; i < l; ++i )
- {
- if ( a [i] >= '0' && a [i] <= '9' ) break;
- }
-
- if ( i < l )
- {
- na = strtoul( a + i, &p, 10 );
- if ( (const unsigned char *)p == a + i ) return 1;
- }
-
- for ( j = 0; j < l; ++j )
- {
- if ( b [j] >= '0' && b [j] <= '9' ) break;
- }
-
- if ( j < l )
- {
- nb = strtoul( b + j, &p, 10 );
- if ( (const unsigned char *)p == b + j ) return -1;
- }
-
- if ( i < j ) return -1;
- else if ( j > i ) return 1;
-
- i = memcmp( a, b, j );
- if ( i ) return i;
-
- return na - nb;
-}
-
-
-
-DUH *dumb_read_psm_quick(DUMBFILE *f, int subsong)
-{
- sigdata_t *sigdata;
- int ver;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_psm_load_sigdata(f, &ver, subsong);
-
- if (!sigdata)
- return NULL;
-
- {
- int n_tags = 2;
- char version[16];
- const char *tag[3][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "PSM";
- if ( ver )
- {
- tag[2][0] = "FORMATVERSION";
- snprintf (version, 10, "%d", ver);
- tag[2][1] = (const char *) &version;
- ++n_tags;
- }
- return make_duh(-1, n_tags, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readpsm.c - Code to read a Protracker Studio / / \ \
+ * module from an open file. | < / \_
+ * | \/ /\ /
+ * By Chris Moeller. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+
+#define PSMV_OLD 940730
+#define PSMV_NEW 940902
+
+typedef struct _PSMCHUNK
+{
+ int id;
+ int len;
+ unsigned char * data;
+} PSMCHUNK;
+
+typedef struct _PSMEVENT
+{
+ int type;
+ unsigned char data[8];
+} PSMEVENT;
+
+#define PSM_EVENT_END 0
+#define PSM_EVENT_PLAY_PATTERN 1
+#define PSM_EVENT_JUMP_TO_LINE 4
+#define PSM_EVENT_SET_SPEED 7
+#define PSM_EVENT_SET_BPM 8
+#define PSM_EVENT_SAMPLE_MAP_TABLE 12
+#define PSM_EVENT_CHANGE_PAN 13
+#define PSM_EVENT_CHANGE_VOL 14
+
+static int it_psm_process_sample(IT_SAMPLE * sample, const unsigned char * data, int len, int id, int version) {
+ int flags;
+ int insno;
+ int length;
+ int loopstart;
+ int loopend;
+ int panpos;
+ int defvol;
+ int samplerate;
+
+ if (len < 0x60) return -1;
+
+ flags = data[0];
+
+ if (version == PSMV_OLD) {
+ memcpy(sample->name, data + 0x0D, 34);
+ sample->name[34] = 0;
+
+ insno = data[0x34] | (data[0x35] << 8);
+ length = data[0x36] | (data[0x37] << 8) | (data[0x38] << 16) | (data[0x39] << 24);
+ loopstart = data[0x3A] | (data[0x3B] << 8) | (data[0x3C] << 16) | (data[0x3D] << 24);
+ loopend = data[0x3E] | (data[0x3F] << 8) | (data[0x40] << 16) | (data[0x41] << 24);
+ panpos = data[0x43];
+ defvol = data[0x44];
+ samplerate = data[0x49] | (data[0x4A] << 8) | (data[0x4B] << 16) | (data[0x4C] << 24);
+ } else if (version == PSMV_NEW) {
+ memcpy(sample->name, data + 0x11, 34);
+ sample->name[34] = 0;
+
+ insno = data[0x38] | (data[0x39] << 8);
+ length = data[0x3A] | (data[0x3B] << 8) | (data[0x3C] << 16) | (data[0x3D] << 24);
+ loopstart = data[0x3E] | (data[0x3F] << 8) | (data[0x40] << 16) | (data[0x41] << 24);
+ loopend = data[0x42] | (data[0x43] << 8) | (data[0x44] << 16) | (data[0x45] << 24);
+ panpos = data[0x48];
+ defvol = data[0x49];
+ samplerate = data[0x4E] | (data[0x4F] << 8) | (data[0x50] << 16) | (data[0x51] << 24);
+ }
+
+ if (insno != id) return -1;
+
+ if (!length) {
+ sample->flags &= ~IT_SAMPLE_EXISTS;
+ return 0;
+ }
+
+ if ((length > len - 0x60) || ((flags & 0x7F) != 0)) return -1;
+
+ sample->flags = IT_SAMPLE_EXISTS;
+ sample->length = length;
+ sample->loop_start = loopstart;
+ sample->loop_end = loopend;
+ sample->C5_speed = samplerate;
+ sample->default_volume = defvol >> 1;
+ sample->default_pan = 0;
+ sample->filename[0] = 0;
+ sample->global_volume = 64;
+ sample->vibrato_speed = 0;
+ sample->vibrato_depth = 0;
+ sample->vibrato_rate = 0;
+ sample->vibrato_waveform = IT_VIBRATO_SINE;
+ sample->finetune = 0;
+ sample->max_resampling_quality = -1;
+
+ if (flags & 0x80) {
+ if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) &&
+ ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end)) {
+ sample->length = sample->loop_end;
+ sample->flags |= IT_SAMPLE_LOOP;
+ }
+ }
+
+ sample->data = malloc(sample->length);
+ if (!sample->data)
+ return -1;
+
+ flags = 0;
+ data += 0x60;
+
+ for (insno = 0; insno < sample->length; insno++) {
+ flags += (signed char)(*data++);
+ ((signed char *)sample->data)[insno] = flags;
+ }
+
+ return 0;
+}
+
+static int it_psm_process_pattern(IT_PATTERN * pattern, const unsigned char * data, int len, int speed, int bpm, const unsigned char * pan, const int * vol, int version) {
+ int length, nrows, row, rowlen, pos;
+ unsigned flags, chan;
+ IT_ENTRY * entry;
+
+ length = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+ if (len > length) len = length;
+
+ if (version == PSMV_OLD) {
+ if (len < 10) return -1;
+ data += 8;
+ len -= 8;
+ } else if (version == PSMV_NEW) {
+ if (len < 14) return -1;
+ data += 12;
+ len -= 12;
+ }
+
+ nrows = data[0] | (data[1] << 8);
+
+ if (!nrows) return 0;
+
+ pattern->n_rows = nrows;
+
+ data += 2;
+ len -= 2;
+
+ pattern->n_entries = 0;
+
+ row = 0;
+ pos = 2;
+ rowlen = data[0] | (data[1] << 8);
+
+ while ((row < nrows) && (pos < len)) {
+ if (pos >= rowlen) {
+ row++;
+ rowlen += data[pos] | (data[pos+1] << 8);
+ pos += 2;
+ continue;
+ }
+
+ flags = data[pos++];
+ chan = data[pos++];
+
+ if (chan > 63) return -1;
+
+ if (flags & 0xF0) {
+ pattern->n_entries++;
+ if (flags & 0x80) pos++;
+ if (flags & 0x40) pos++;
+ if (flags & 0x20) pos++;
+ if (flags & 0x10) {
+ switch (data[pos]) {
+ case 0x29:
+ pos++;
+ case 0x33:
+ pos++;
+ default:
+ pos += 2;
+ }
+ }
+ }
+ }
+
+ if (!pattern->n_entries) return 0;
+
+ pattern->n_entries += nrows;
+ if (speed) pattern->n_entries++;
+ if (bpm >= 0x20) pattern->n_entries++;
+
+ for (pos = 0; pos < 32; pos++) {
+ if (!(pan[pos*2+1] & 0xF9)) pattern->n_entries++;
+ if (vol[pos] != -1) pattern->n_entries++;
+ }
+
+ pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
+ if (!pattern->entry) return -1;
+
+ entry = pattern->entry;
+
+ if (speed) {
+ entry->channel = 0;
+ entry->mask = IT_ENTRY_EFFECT;
+ entry->effect = IT_SET_SPEED;
+ entry->effectvalue = speed;
+ entry++;
+ }
+
+ if (bpm >= 0x20) {
+ entry->channel = 0;
+ entry->mask = IT_ENTRY_EFFECT;
+ entry->effect = IT_SET_SONG_TEMPO;
+ entry->effectvalue = bpm;
+ entry++;
+ }
+
+ for (pos = 0; pos < 32; pos++) {
+ if (!(pan[pos*2+1] & 0xF9)) {
+ entry->channel = pos;
+ entry->mask = IT_ENTRY_EFFECT;
+ switch (pan[pos*2+1]) {
+ case 0:
+ entry->effect = IT_SET_PANNING;
+ entry->effectvalue = pan[pos*2] ^ 128;
+ break;
+ case 2:
+ entry->effect = IT_S;
+ entry->effectvalue = EFFECT_VALUE(IT_S_SET_SURROUND_SOUND,1);
+ break;
+ case 4:
+ entry->effect = IT_SET_PANNING;
+ entry->effectvalue = 128;
+ break;
+ }
+ entry++;
+ }
+ if (vol[pos] != -1) {
+ entry->channel = pos;
+ entry->mask = IT_ENTRY_EFFECT;
+ entry->effect = IT_SET_CHANNEL_VOLUME;
+ entry->effectvalue = (vol[pos] + 2) >> 2;
+ entry++;
+ }
+ }
+
+ row = 0;
+ pos = 2;
+ rowlen = data[0] | (data[1] << 8);
+
+ while ((row < nrows) && (pos < len)) {
+ if (pos >= rowlen) {
+ IT_SET_END_ROW(entry);
+ entry++;
+ row++;
+ rowlen += data[pos] | (data[pos+1] << 8);
+ pos += 2;
+ continue;
+ }
+
+ flags = data[pos++];
+ entry->channel = data[pos++];
+ entry->mask = 0;
+
+ if (flags & 0xF0) {
+ if (flags & 0x80) {
+ entry->mask |= IT_ENTRY_NOTE;
+ if (version == PSMV_OLD) {
+ if ((data[pos] < 0x80)) entry->note = (data[pos]>>4)*12+(data[pos]&0x0f)+12;
+ else entry->mask &= ~IT_ENTRY_NOTE;
+ } else if (version == PSMV_NEW) {
+ if ((data[pos]) && (data[pos] < 84)) entry->note = data[pos] + 35;
+ else entry->mask &= ~IT_ENTRY_NOTE;
+ }
+ pos++;
+ }
+
+ if (flags & 0x40) {
+ entry->mask |= IT_ENTRY_INSTRUMENT;
+ entry->instrument = data[pos++] + 1;
+ }
+
+ if (flags & 0x20) {
+ entry->mask |= IT_ENTRY_VOLPAN;
+ entry->volpan = (data[pos++] + 1) >> 1;
+ }
+
+ if (flags & 0x10) {
+ entry->mask |= IT_ENTRY_EFFECT;
+ length = data[pos+1];
+ switch (data[pos]) {
+ case 1:
+ entry->effect = IT_VOLUME_SLIDE;
+ if (version == PSMV_OLD) entry->effectvalue = ((length&0x1e)<<3) | 0xF;
+ else if (version == PSMV_NEW) entry->effectvalue = (length<<4) | 0xF;
+ break;
+
+ case 2:
+ entry->effect = IT_VOLUME_SLIDE;
+ if (version == PSMV_OLD) entry->effectvalue = (length << 3) & 0xF0;
+ else if (version == PSMV_NEW) entry->effectvalue = (length << 4) & 0xF0;
+ break;
+
+ case 3:
+ entry->effect = IT_VOLUME_SLIDE;
+ if (version == PSMV_OLD) entry->effectvalue = (length >> 1) | 0xF0;
+ else if (version == PSMV_NEW) entry->effectvalue = length | 0xF0;
+ break;
+
+ case 4:
+ entry->effect = IT_VOLUME_SLIDE;
+ if (version == PSMV_OLD) entry->effectvalue = (length >> 1) & 0xF;
+ else if (version == PSMV_NEW) entry->effectvalue = length & 0xF;
+ break;
+
+ case 12:
+ entry->effect = IT_PORTAMENTO_UP;
+ if (version == PSMV_OLD) {
+ if (length < 4) entry->effectvalue = length | 0xF0;
+ else entry->effectvalue = length >> 2;
+ } else if (version == PSMV_NEW) {
+ entry->effectvalue = length;
+ }
+ break;
+
+ case 14:
+ entry->effect = IT_PORTAMENTO_DOWN;
+ if (version == PSMV_OLD) {
+ if (length < 4) entry->effectvalue = length | 0xF0;
+ else entry->effectvalue = length >> 2;
+ } else if (version == PSMV_NEW) {
+ entry->effectvalue = length;
+ }
+ break;
+
+ case 15:
+ entry->effect = IT_TONE_PORTAMENTO;
+ if (version == PSMV_OLD) entry->effectvalue = length >> 2;
+ else if (version == PSMV_NEW) entry->effectvalue = length;
+ break;
+
+ case 0x15:
+ entry->effect = IT_VIBRATO;
+ entry->effectvalue = length;
+ break;
+
+ case 0x18:
+ entry->effect = IT_VOLSLIDE_VIBRATO;
+ entry->effectvalue = length;
+ break;
+
+ case 0x29:
+ entry->effect = IT_SET_SAMPLE_OFFSET;
+ entry->effectvalue = data[pos+2];
+ pos += 2;
+ break;
+
+ case 0x2A:
+ entry->effect = IT_RETRIGGER_NOTE;
+ entry->effectvalue = length;
+ break;
+
+ case 0x33:
+#if 0
+ entry->effect = IT_POSITION_JUMP;
+ entry->effectvalue = data[pos+2];
+#else
+ entry->mask &= ~IT_ENTRY_EFFECT;
+#endif
+ pos++;
+ break;
+
+ case 0x34:
+ entry->effect = IT_BREAK_TO_ROW;
+ entry->effectvalue = length;
+ break;
+
+ case 0x3D:
+ entry->effect = IT_SET_SPEED;
+ entry->effectvalue = length;
+ break;
+
+ case 0x3E:
+ if (length >= 0x20) {
+ entry->effect = IT_SET_SONG_TEMPO;
+ entry->effectvalue = length;
+ } else {
+ entry->mask &= ~IT_ENTRY_EFFECT;
+ }
+ break;
+
+ case 0x47:
+ entry->effect = IT_ARPEGGIO;
+ entry->effectvalue = length;
+ break;
+
+ default:
+ return -1;
+ }
+ pos += 2;
+ }
+ if (entry->mask) entry++;
+ }
+ }
+
+ while (row < nrows) {
+ IT_SET_END_ROW(entry);
+ entry++;
+ row++;
+ }
+
+ pattern->n_entries = entry - pattern->entry;
+ if (!pattern->n_entries) return -1;
+
+ return 0;
+}
+
+
+static void free_chunks(PSMCHUNK * chunk, int count) {
+ int n;
+
+ for (n = 0; n < count; n++) {
+ if (chunk[n].data)
+ free(chunk[n].data);
+ }
+
+ free(chunk);
+}
+
+static void dumb_it_optimize_orders(DUMB_IT_SIGDATA * sigdata);
+
+static int pattcmp( const unsigned char *, const unsigned char *, size_t );
+
+static DUMB_IT_SIGDATA *it_psm_load_sigdata(DUMBFILE *f, int * ver, int subsong)
+{
+ DUMB_IT_SIGDATA *sigdata;
+
+ PSMCHUNK *chunk;
+ int n_chunks = 0;
+
+ PSMCHUNK *songchunk;
+ int n_song_chunks = 0;
+
+ PSMEVENT *event = NULL;
+ int n_events = 0;
+
+ unsigned char * ptr;
+
+ int n, length, o;
+
+ int found;
+
+ int n_patterns = 0;
+
+ int first_pattern_line = -1;
+ int first_pattern;
+
+ int speed, bpm;
+ unsigned char pan[64];
+ int vol[32];
+
+ if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',' ')) goto error;
+
+ length = dumbfile_igetl(f);
+
+ if (dumbfile_mgetl(f) != DUMB_ID('F','I','L','E')) goto error;
+
+ chunk = calloc(768, sizeof(*chunk));
+
+ while (length >= 8) {
+ chunk[n_chunks].id = dumbfile_mgetl(f);
+ n = dumbfile_igetl(f);
+ length -= 8;
+ if (n < 0 || n > length)
+ goto error_fc;
+ chunk[n_chunks].len = n;
+ if (n) {
+ ptr = malloc(n);
+ if (!ptr) goto error_fc;
+ if (dumbfile_getnc(ptr, n, f) < n)
+ {
+ free(ptr);
+ goto error_fc;
+ }
+ chunk[n_chunks].data = ptr;
+ }
+ n_chunks++;
+ length -= n;
+ }
+
+ if (!n_chunks) goto error_fc;
+
+ sigdata = malloc(sizeof(*sigdata));
+ if (!sigdata) goto error_fc;
+
+ sigdata->n_patterns = 0;
+ sigdata->n_samples = 0;
+ sigdata->name[0] = 0;
+
+ found = 0;
+
+ for (n = 0; n < n_chunks; n++) {
+ PSMCHUNK * c = &chunk[n];
+ switch(c->id) {
+ case DUMB_ID('S','D','F','T'):
+ /* song data format? */
+ if ((found & 1) || (c->len != 8) || memcmp(c->data, "MAINSONG", 8)) goto error_sd;
+ found |= 1;
+ break;
+
+ case DUMB_ID('S','O','N','G'):
+ if (/*(found & 2) ||*/ (c->len < 11) /*|| memcmp(c->data, "MAINSONG", 8)*/) goto error_sd;
+ found |= 2;
+ break;
+
+ case DUMB_ID('D','S','M','P'):
+ sigdata->n_samples++;
+ break;
+
+ case DUMB_ID('T','I','T','L'):
+ length = min(sizeof(sigdata->name) - 1, c->len);
+ memcpy(sigdata->name, c->data, length);
+ sigdata->name[length] = 0;
+ }
+ }
+
+ if (found != 3 || !sigdata->n_samples) goto error_sd;
+
+ sigdata->song_message = NULL;
+ sigdata->order = NULL;
+ sigdata->instrument = NULL;
+ sigdata->sample = NULL;
+ sigdata->pattern = NULL;
+ sigdata->midi = NULL;
+ sigdata->checkpoint = NULL;
+
+ sigdata->n_instruments = 0;
+ sigdata->n_orders = 0;
+
+ for (n = 0; n < n_chunks; n++) {
+ PSMCHUNK * c = &chunk[n];
+ if (c->id == DUMB_ID('S','O','N','G')) {
+ if (subsong == 0) break;
+ subsong--;
+ }
+ }
+
+ if (n == n_chunks) return NULL;
+ subsong = n;
+
+ /*for (n = 0; n < n_chunks; n++) {
+ PSMCHUNK * c = &chunk[n];
+ if (c->id == DUMB_ID('S','O','N','G')) {*/
+ {
+ PSMCHUNK * c = &chunk[subsong];
+ {
+ ptr = c->data;
+ if (ptr[10] > 32) goto error_usd;
+ sigdata->n_pchannels = ptr[10];
+ length = c->len - 11;
+ ptr += 11;
+ songchunk = 0;
+ if (length >= 8) {
+ songchunk = malloc(128 * sizeof(*songchunk));
+ if (!songchunk) goto error_usd;
+ while (length >= 8) {
+ songchunk[n_song_chunks].id = DUMB_ID(ptr[0], ptr[1], ptr[2], ptr[3]);
+ n = ptr[4] | (ptr[5] << 8) | (ptr[6] << 16) | (ptr[7] << 24);
+ length -= 8;
+ if (n > length) goto error_sc;
+ songchunk[n_song_chunks].len = n;
+ songchunk[n_song_chunks].data = ptr + 8;
+ n_song_chunks++;
+ length -= n;
+ ptr += 8 + n;
+ }
+ }
+ /*break;*/
+ }
+ }
+
+ if (!n_song_chunks) goto error_sc;
+
+ found = 0;
+
+ for (n = 0; n < n_song_chunks; n++) {
+ PSMCHUNK * c = &songchunk[n];
+
+ if (c->id == DUMB_ID('D','A','T','E')) {
+ /* date of the library build / format spec */
+ if (c->len == 6) {
+ length = c->len;
+ ptr = c->data;
+ while (length > 0) {
+ if (*ptr >= '0' && *ptr <= '9') {
+ found = (found * 10) + (*ptr - '0');
+ } else {
+ found = 0;
+ break;
+ }
+ ptr++;
+ length--;
+ }
+ }
+ break;
+ }
+ }
+
+ /*
+ if (found != 940506 &&
+ found != 940509 &&
+ found != 940510 &&
+ found != 940530 &&
+ found != 940629 &&
+ found != PSMV_OLD &&
+ found != 941011 &&
+ found != PSMV_NEW &&
+ found != 940906 &&
+ found != 940903 &&
+ found != 940914 &&
+ found != 941213 &&
+ found != 800211) /* WTF?
+ goto error_sc;
+ */
+
+ *ver = found;
+
+ if (found == 800211 ||
+ found == PSMV_NEW ||
+ found == 940903 ||
+ found == 940906 ||
+ found == 940914 ||
+ found == 941213) found = PSMV_NEW;
+ else found = PSMV_OLD;
+
+ memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
+
+ for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
+ sigdata->channel_pan[n ] = 16;
+ sigdata->channel_pan[n+1] = 48;
+ sigdata->channel_pan[n+2] = 48;
+ sigdata->channel_pan[n+3] = 16;
+ }
+
+ for (n = 0; n < n_song_chunks; n++) {
+ PSMCHUNK * c = &songchunk[n];
+
+ switch (c->id) {
+ case DUMB_ID('O','P','L','H'):
+ if (c->len < 2) goto error_sc;
+ ptr = c->data;
+ o = ptr[0] | (ptr[1] << 8);
+ if (!o) goto error_sc;
+ event = malloc(o * sizeof(*event));
+ if (!event) goto error_sc;
+ length = c->len - 2;
+ ptr += 2;
+ while ((length > 0) && (n_events < o)) {
+ event[n_events].type = *ptr;
+ switch (*ptr) {
+ case PSM_EVENT_END:
+ ptr++;
+ length--;
+ break;
+
+ case PSM_EVENT_PLAY_PATTERN:
+ if (found == PSMV_OLD) {
+ if (length < 5) goto error_ev;
+ memcpy(event[n_events].data, ptr + 1, 4);
+ ptr += 5;
+ length -= 5;
+ } else if (found == PSMV_NEW) {
+ if (length < 9) goto error_ev;
+ memcpy(event[n_events].data, ptr + 1, 8);
+ ptr += 9;
+ length -= 9;
+ }
+ break;
+
+ case PSM_EVENT_SET_SPEED:
+ case PSM_EVENT_SET_BPM:
+ if (length < 2) goto error_ev;
+ event[n_events].data[0] = ptr[1];
+ ptr += 2;
+ length -= 2;
+ break;
+
+ case PSM_EVENT_JUMP_TO_LINE:
+ case PSM_EVENT_CHANGE_VOL:
+ if (length < 3) goto error_ev;
+ memcpy(event[n_events].data, ptr + 1, 2);
+ ptr += 3;
+ length -= 3;
+ break;
+
+ case PSM_EVENT_SAMPLE_MAP_TABLE:
+ if (length < 7) goto error_ev;
+ memcpy(event[n_events].data, ptr + 1, 6);
+ ptr += 7;
+ length -= 7;
+ break;
+
+ case PSM_EVENT_CHANGE_PAN:
+ if (length < 4) goto error_ev;
+ memcpy(event[n_events].data, ptr + 1, 3);
+ ptr += 4;
+ length -= 4;
+ break;
+
+ default:
+ goto error_ev;
+ }
+ n_events++;
+ }
+ break;
+
+ case DUMB_ID('P','P','A','N'):
+ length = c->len;
+ if (length & 1) goto error_ev;
+ ptr = c->data;
+ o = 0;
+ while (length > 0) {
+ switch (ptr[0]) {
+ case 0:
+ sigdata->channel_pan[o] = ((((int)(signed char)ptr[1]) * 32) / 127) + 32;
+ break;
+ case 2:
+ sigdata->channel_pan[o] = IT_SURROUND;
+ break;
+ case 4:
+ sigdata->channel_pan[o] = 32;
+ break;
+ }
+ ptr += 2;
+ length -= 2;
+ if (++o >= DUMB_IT_N_CHANNELS) break;
+ }
+ break;
+
+ /*
+ case DUMB_ID('P','A','T','T'):
+ case DUMB_ID('D','S','A','M'):
+ */
+ }
+ }
+
+ sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
+
+ sigdata->global_volume = 128;
+ sigdata->speed = 6;
+ sigdata->tempo = 125;
+ sigdata->mixing_volume = 48;
+ sigdata->pan_separation = 128;
+
+ speed = 0;
+ bpm = 0;
+ memset(pan, 255, sizeof(pan));
+ memset(vol, 255, sizeof(vol));
+
+ sigdata->n_patterns = n_events;
+ sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
+ if (!sigdata->pattern) goto error_ev;
+ for (n = 0; n < sigdata->n_patterns; n++)
+ sigdata->pattern[n].entry = NULL;
+
+ for (n = 0; n < n_events; n++) {
+ PSMEVENT * e = &event[n];
+ switch (e->type) {
+ case PSM_EVENT_END:
+ n = n_events;
+ break;
+
+ case PSM_EVENT_PLAY_PATTERN:
+ for (o = 0; o < n_chunks; o++) {
+ PSMCHUNK * c = &chunk[o];
+ if (c->id == DUMB_ID('P','B','O','D')) {
+ ptr = c->data;
+ length = c->len;
+ if (found == PSMV_OLD) {
+ if (length < 8) goto error_ev;
+ if (!pattcmp(ptr + 4, e->data, 4)) {
+ if (it_psm_process_pattern(&sigdata->pattern[n_patterns], ptr, length, speed, bpm, pan, vol, found)) goto error_ev;
+ if (first_pattern_line < 0) {
+ first_pattern_line = n;
+ first_pattern = o;
+ }
+ e->data[0] = n_patterns;
+ e->data[1] = n_patterns >> 8;
+ n_patterns++;
+ break;
+ }
+ } else if (found == PSMV_NEW) {
+ if (length < 12) goto error_ev;
+ if (!pattcmp(ptr + 4, e->data, 8)) {
+ if (it_psm_process_pattern(&sigdata->pattern[n_patterns], ptr, length, speed, bpm, pan, vol, found)) goto error_ev;
+ if (first_pattern_line < 0) {
+ first_pattern_line = n;
+ first_pattern = o;
+ }
+ e->data[0] = n_patterns;
+ e->data[1] = n_patterns >> 8;
+ n_patterns++;
+ break;
+ }
+ }
+ }
+ }
+ if (o == n_chunks) goto error_ev;
+
+ speed = 0;
+ bpm = 0;
+ memset(pan, 255, sizeof(pan));
+ memset(vol, 255, sizeof(vol));
+
+ e->type = PSM_EVENT_END;
+ break;
+
+ case PSM_EVENT_JUMP_TO_LINE:
+ o = e->data[0] | (e->data[1] << 8);
+ if (o >= n_events) goto error_ev;
+ if (o == 0) {
+ /* whew! easy case! */
+ sigdata->restart_position = 0;
+ n = n_events;
+ } else if (o == n) {
+ /* freeze */
+ n = n_events;
+ } else if (o > n) {
+ /* jump ahead, setting played event numbers to zero will prevent endless looping */
+ n = o - 1;
+ } else if (o >= first_pattern_line) {
+ /* another semi-easy case */
+ sigdata->restart_position = event[o].data[0] | (event[o].data[1] << 8);
+ n = n_events;
+ } else {
+ /* crud, try to simulate rerunning all of the commands from the indicated
+ * line up to the first pattern, then dupe the first pattern again.
+ */
+ /*
+ PSMCHUNK * c = &chunk[first_pattern];
+
+ for (; o < first_pattern_line; o++) {
+ PSMEVENT * ev = &event[o];
+ switch (ev->type) {
+ case PSM_EVENT_SET_SPEED:
+ speed = ev->data[0];
+ break;
+ case PSM_EVENT_SET_BPM:
+ bpm = ev->data[0];
+ break;
+ case PSM_EVENT_CHANGE_PAN:
+ if (ev->data[0] > 31) goto error_ev;
+ pan[ev->data[0] * 2] = ev->data[1];
+ pan[ev->data[0] * 2 + 1] = ev->data[2];
+ break;
+ case PSM_EVENT_CHANGE_VOL:
+ if (ev->data[0] > 31) goto error_ev;
+ vol[ev->data[0]] = ev->data[1];
+ break;
+ }
+ }
+
+ if (it_psm_process_pattern(&sigdata->pattern[n_patterns], c->data, c->len, speed, bpm, pan, vol, found)) goto error_ev;
+ n_patterns++;
+ sigdata->restart_position = 1;
+ n = n_events;
+
+ Eh, what the hell? PSM has no panning commands anyway.
+ */
+ sigdata->restart_position = 0;
+ n = n_events;
+ }
+ e->type = PSM_EVENT_END;
+ break;
+
+ case PSM_EVENT_SET_SPEED:
+ speed = e->data[0];
+ break;
+
+ case PSM_EVENT_SET_BPM:
+ bpm = e->data[0];
+ break;
+
+ case PSM_EVENT_CHANGE_PAN:
+ o = e->data[0];
+ if (o > 31) goto error_ev;
+ pan[o * 2] = e->data[1];
+ pan[o * 2 + 1] = e->data[2];
+ break;
+
+ case PSM_EVENT_CHANGE_VOL:
+ o = e->data[0];
+ if (o > 31) goto error_ev;
+ vol[o] = e->data[1];
+ break;
+
+ case PSM_EVENT_SAMPLE_MAP_TABLE:
+ if (e->data[0] != 0 || e->data[1] != 0xFF ||
+ e->data[2] != 0 || e->data[3] != 0 ||
+ e->data[4] != 1 || e->data[5] != 0)
+ goto error_ev;
+ break;
+ }
+ }
+
+ if (n_patterns > 256) goto error_ev;
+
+ sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
+ if (!sigdata->sample) goto error_ev;
+ for (n = 0; n < sigdata->n_samples; n++)
+ sigdata->sample[n].data = NULL;
+
+ o = 0;
+ for (n = 0; n < n_chunks; n++) {
+ PSMCHUNK * c = &chunk[n];
+ if (c->id == DUMB_ID('D','S','M','P')) {
+ if (it_psm_process_sample(&sigdata->sample[o], c->data, c->len, o, found)) goto error_ev;
+ o++;
+ }
+ }
+
+ sigdata->n_orders = n_patterns;
+ sigdata->n_patterns = n_patterns;
+
+ sigdata->order = malloc(n_patterns);
+
+ for (n = 0; n < n_patterns; n++) {
+ sigdata->order[n] = n;
+ }
+
+ free(event);
+ free(songchunk);
+ free_chunks(chunk, n_chunks);
+
+ _dumb_it_fix_invalid_orders(sigdata);
+
+ dumb_it_optimize_orders(sigdata);
+
+ return sigdata;
+
+error_ev:
+ free(event);
+error_sc:
+ if (songchunk) free(songchunk);
+error_usd:
+ _dumb_it_unload_sigdata(sigdata);
+ goto error_fc;
+error_sd:
+ free(sigdata);
+error_fc:
+ free_chunks(chunk, n_chunks);
+error:
+ return NULL;
+}
+
+static int it_order_compare(const void *e1, const void *e2) {
+ if (*((const char *)e1) < *((const char *)e2))
+ return -1;
+
+ if (*((const char *)e1) > *((const char *)e2))
+ return 1;
+
+ return 0;
+}
+
+static int it_optimize_compare(const void *e1, const void *e2) {
+ if (((const IT_ENTRY *)e1)->channel < ((const IT_ENTRY *)e2)->channel)
+ return -1;
+
+ if (((const IT_ENTRY *)e1)->channel > ((const IT_ENTRY *)e2)->channel)
+ return 1;
+
+ return 0;
+}
+
+static int it_entry_compare(const IT_ENTRY * e1, const IT_ENTRY * e2) {
+ if (IT_IS_END_ROW(e1) && IT_IS_END_ROW(e2)) return 1;
+ if (e1->channel != e2->channel) return 0;
+ if (e1->mask != e2->mask) return 0;
+ if ((e1->mask & IT_ENTRY_NOTE) && (e1->note != e2->note)) return 0;
+ if ((e1->mask & IT_ENTRY_INSTRUMENT) && (e1->instrument != e2->instrument)) return 0;
+ if ((e1->mask & IT_ENTRY_VOLPAN) && (e1->volpan != e2->volpan)) return 0;
+ if ((e1->mask & IT_ENTRY_EFFECT) && ((e1->effect != e2->effect) || (e1->effectvalue != e2->effectvalue))) return 0;
+ return 1;
+}
+
+/*
+static void dumb_it_optimize_pattern(IT_PATTERN * pattern) {
+ IT_ENTRY * entry, * end;
+ IT_ENTRY * rowstart, * rowend;
+ IT_ENTRY * current;
+
+ if (!pattern->n_entries || !pattern->entry) return;
+
+ current = entry = pattern->entry;
+ end = entry + pattern->n_entries;
+
+ while (entry < end) {
+ rowstart = entry;
+ while (!IT_IS_END_ROW(entry)) entry++;
+ rowend = entry;
+ if (rowend > rowstart + 1)
+ qsort(rowstart, rowend - rowstart, sizeof(IT_ENTRY), &it_optimize_compare);
+ entry = rowstart;
+ while (entry < rowend) {
+ if (!(entry->mask)) {}
+ else if (it_entry_compare(entry, current)) {}
+ else if (!(current->mask) ||
+ ((entry->channel == current->channel) &&
+ ((entry->mask | current->mask) == (entry->mask ^ current->mask)))) {
+ current->mask |= entry->mask;
+ if (entry->mask & IT_ENTRY_NOTE) current->note = entry->note;
+ if (entry->mask & IT_ENTRY_INSTRUMENT) current->instrument = entry->instrument;
+ if (entry->mask & IT_ENTRY_VOLPAN) current->volpan = entry->volpan;
+ if (entry->mask & IT_ENTRY_EFFECT) {
+ current->effect = entry->effect;
+ current->effectvalue = entry->effectvalue;
+ }
+ } else {
+ if (++current < entry) *current = *entry;
+ }
+ entry++;
+ }
+ if (++current < entry) *current = *entry;
+ entry++;
+ }
+
+ current++;
+
+ if (current < end) {
+ IT_ENTRY * opt;
+ pattern->n_entries = current - pattern->entry;
+ opt = realloc(pattern->entry, pattern->n_entries * sizeof(*pattern->entry));
+ if (opt) pattern->entry = opt;
+ }
+}
+*/
+
+static int it_pattern_compare(const IT_PATTERN * p1, const IT_PATTERN * p2) {
+ IT_ENTRY * e1, * end;
+ IT_ENTRY * e2;
+
+ if (p1 == p2) return 1;
+ if (p1->n_entries != p2->n_entries) return 0;
+
+ e1 = p1->entry; end = e1 + p1->n_entries;
+ e2 = p2->entry;
+
+ while (e1 < end) {
+ if (!it_entry_compare(e1, e2)) return 0;
+ e1++; e2++;
+ }
+
+ return 1;
+}
+
+static void dumb_it_optimize_orders(DUMB_IT_SIGDATA * sigdata) {
+ int n, o, p;
+
+ int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253;
+
+ unsigned char * order_list;
+ int n_patterns;
+
+ IT_PATTERN * pattern;
+
+ if (!sigdata->n_orders || !sigdata->n_patterns) return;
+
+ n_patterns = 0;
+ order_list = malloc(sigdata->n_orders);
+
+ if (!order_list) return;
+
+ for (n = 0; n < sigdata->n_orders; n++) {
+ if (sigdata->order[n] < sigdata->n_patterns) {
+ for (o = 0; o < n_patterns; o++) {
+ if (sigdata->order[n] == order_list[o]) break;
+ }
+ if (o == n_patterns) {
+ order_list[n_patterns++] = sigdata->order[n];
+ }
+ }
+ }
+
+ if (!n_patterns) {
+ free(order_list);
+ return;
+ }
+
+ /*for (n = 0; n < n_patterns; n++) {
+ dumb_it_optimize_pattern(&sigdata->pattern[order_list[n]]);
+ }*/
+
+ for (n = 0; n < n_patterns; n++) {
+ for (o = n + 1; o < n_patterns; o++) {
+ if ((order_list[n] != order_list[o]) &&
+ it_pattern_compare(&sigdata->pattern[order_list[n]], &sigdata->pattern[order_list[o]])) {
+ for (p = 0; p < sigdata->n_orders; p++) {
+ if (sigdata->order[p] == order_list[o]) {
+ sigdata->order[p] = order_list[n];
+ }
+ }
+ for (p = o + 1; p < n_patterns; p++) {
+ if (order_list[p] == order_list[o]) {
+ order_list[p] = order_list[n];
+ }
+ }
+ order_list[o] = order_list[n];
+ }
+ }
+ }
+
+ qsort(order_list, n_patterns, sizeof(*order_list), &it_order_compare);
+
+ for (n = 0, o = 0; n < n_patterns; n++) {
+ if (order_list[n] != order_list[o]) {
+ if (++o < n) order_list[o] = order_list[n];
+ }
+ }
+
+ n_patterns = o + 1;
+
+ pattern = malloc(n_patterns * sizeof(*pattern));
+ if (!pattern) {
+ free(order_list);
+ return;
+ }
+
+ for (n = 0; n < n_patterns; n++) {
+ pattern[n] = sigdata->pattern[order_list[n]];
+ }
+
+ for (n = 0; n < sigdata->n_patterns; n++) {
+ for (o = 0; o < n_patterns; o++) {
+ if (order_list[o] == n) break;
+ }
+ if (o == n_patterns) {
+ if (sigdata->pattern[n].entry)
+ free(sigdata->pattern[n].entry);
+ }
+ }
+
+ free(sigdata->pattern);
+ sigdata->pattern = pattern;
+ sigdata->n_patterns = n_patterns;
+
+ for (n = 0; n < sigdata->n_orders; n++) {
+ for (o = 0; o < n_patterns; o++) {
+ if (sigdata->order[n] == order_list[o]) {
+ sigdata->order[n] = o;
+ break;
+ }
+ }
+ }
+
+ free(order_list);
+}
+
+int dumb_get_psm_subsong_count(DUMBFILE *f) {
+ int length, subsongs;
+ long l;
+
+ if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',' ')) return 0;
+
+ length = dumbfile_igetl(f);
+
+ if (dumbfile_mgetl(f) != DUMB_ID('F','I','L','E')) return 0;
+
+ subsongs = 0;
+
+ while (length >= 8 && !dumbfile_error(f)) {
+ if (dumbfile_mgetl(f) == DUMB_ID('S','O','N','G')) subsongs++;
+ l = dumbfile_igetl(f);
+ dumbfile_skip(f, l);
+ length -= l + 8;
+ }
+
+ if (dumbfile_error(f)) return 0;
+
+ return subsongs;
+}
+
+
+
+/* Eww */
+int pattcmp( const unsigned char * a, const unsigned char * b, size_t l )
+{
+ int i, j, na, nb;
+ char * p;
+
+ i = memcmp( a, b, l );
+ if ( !i ) return i;
+
+ /* damnit */
+
+ for ( i = 0; i < l; ++i )
+ {
+ if ( a [i] >= '0' && a [i] <= '9' ) break;
+ }
+
+ if ( i < l )
+ {
+ na = strtoul( a + i, &p, 10 );
+ if ( (const unsigned char *)p == a + i ) return 1;
+ }
+
+ for ( j = 0; j < l; ++j )
+ {
+ if ( b [j] >= '0' && b [j] <= '9' ) break;
+ }
+
+ if ( j < l )
+ {
+ nb = strtoul( b + j, &p, 10 );
+ if ( (const unsigned char *)p == b + j ) return -1;
+ }
+
+ if ( i < j ) return -1;
+ else if ( j > i ) return 1;
+
+ i = memcmp( a, b, j );
+ if ( i ) return i;
+
+ return na - nb;
+}
+
+
+
+DUH *dumb_read_psm_quick(DUMBFILE *f, int subsong)
+{
+ sigdata_t *sigdata;
+ int ver;
+
+ DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
+
+ sigdata = it_psm_load_sigdata(f, &ver, subsong);
+
+ if (!sigdata)
+ return NULL;
+
+ {
+ int n_tags = 2;
+ char version[16];
+ const char *tag[3][2];
+ tag[0][0] = "TITLE";
+ tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+ tag[1][0] = "FORMAT";
+ tag[1][1] = "PSM";
+ if ( ver )
+ {
+ tag[2][0] = "FORMATVERSION";
+ snprintf (version, 10, "%d", ver);
+ tag[2][1] = (const char *) &version;
+ ++n_tags;
+ }
+ return make_duh(-1, n_tags, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/readptm.c b/plugins/dumb/dumb-kode54/src/it/readptm.c
index d8c77297..cae73edf 100644
--- a/plugins/dumb/dumb-kode54/src/it/readptm.c
+++ b/plugins/dumb/dumb-kode54/src/it/readptm.c
@@ -1,574 +1,574 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readptm.c - Code to read a Poly Tracker v2.03 / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. Based on reads3m.c \_ / > /
- * by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-// IT_STEREO... :o
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/** WARNING: this is duplicated in itread.c */
-static int it_seek(DUMBFILE *f, long offset)
-{
- long pos = dumbfile_pos(f);
-
- if (pos > offset)
- return -1;
-
- if (pos < offset)
- if (dumbfile_skip(f, offset - pos))
- return -1;
-
- return 0;
-}
-
-
-
-static int it_ptm_read_sample_header(IT_SAMPLE *sample, long *offset, DUMBFILE *f)
-{
- int flags;
-
- flags = dumbfile_getc(f);
-
- dumbfile_getnc(sample->filename, 12, f);
- sample->filename[12] = 0;
-
- sample->default_volume = dumbfile_getc(f);
-
- sample->C5_speed = dumbfile_igetw(f) << 1;
-
- dumbfile_skip(f, 2); /* segment */
-
- *offset = dumbfile_igetl(f);
-
- sample->length = dumbfile_igetl(f);
- sample->loop_start = dumbfile_igetl(f);
- sample->loop_end = dumbfile_igetl(f);
-
- /* GUSBegin, GUSLStart, GUSLEnd, GUSLoop, reserverd */
- dumbfile_skip(f, 4+4+4+1+1);
-
- dumbfile_getnc(sample->name, 28, f);
- sample->name[28] = 0;
-
- /*
- if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','S'))
- return -1;
- */
-
- /* BLAH! Shit likes to have broken or missing sample IDs */
- dumbfile_skip(f, 4);
-
- if ((flags & 3) == 0) {
- /* Looks like no sample */
- sample->flags &= ~IT_SAMPLE_EXISTS;
- return dumbfile_error(f);
- }
-
- sample->global_volume = 64;
-
- sample->flags = IT_SAMPLE_EXISTS;
- if (flags & 4) sample->flags |= IT_SAMPLE_LOOP;
- if (flags & 8) sample->flags |= IT_SAMPLE_PINGPONG_LOOP;
-
- if (flags & 16) {
- sample->flags |= IT_SAMPLE_16BIT;
-
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- }
-
- if (sample->loop_end) sample->loop_end--;
-
- sample->default_pan = 0; // 0 = don't use, or 160 = centre?
-
- if (sample->length <= 0)
- sample->flags &= ~IT_SAMPLE_EXISTS;
- else if (sample->flags & IT_SAMPLE_LOOP) {
- if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
- sample->flags &= ~IT_SAMPLE_LOOP;
- else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
- sample->flags &= ~IT_SAMPLE_LOOP;
- else
- sample->length = sample->loop_end;
- }
-
-
- //Do we need to set all these?
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = IT_VIBRATO_SINE;
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-
-static int it_ptm_read_byte(DUMBFILE *f)
-{
- int meh = dumbfile_getc(f);
- if (meh < 0) return 0;
- return meh;
-}
-
-static int it_ptm_read_sample_data(IT_SAMPLE *sample, int last, DUMBFILE *f)
-{
- long n;
- int s;
-
- sample->data = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
- if (!sample->data)
- return -1;
-
- s = 0;
-
- if (sample->flags & IT_SAMPLE_16BIT) {
- unsigned char a, b;
- for (n = 0; n < sample->length; n++) {
- a = s += (signed char) it_ptm_read_byte(f);
- b = s += (signed char) it_ptm_read_byte(f);
- ((short *)sample->data)[n] = a | (b << 8);
- }
- } else {
- for (n = 0; n < sample->length; n++) {
- s += (signed char) it_ptm_read_byte(f);
- ((signed char *)sample->data)[n] = s;
- }
- }
-
- if (dumbfile_error(f) && !last)
- return -1;
-
- return 0;
-}
-
-
-
-static int it_ptm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer, int length)
-{
- int buflen = 0;
- int bufpos = 0;
- int effect, effectvalue;
-
- IT_ENTRY *entry;
-
- unsigned char channel;
-
- if (!length)
- return -1;
-
- pattern->n_rows = 0;
- pattern->n_entries = 0;
-
- /* Read in the pattern data, little by little, and work out how many
- * entries we need room for. Sorry, but this is just so funny...
- */
- for (;;) {
- unsigned char b = buffer[buflen++] = dumbfile_getc(f);
-
-#if 1
- static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5};
- channel = b & 31;
- b >>= 5;
- pattern->n_entries++;
- if (b) {
- if (buflen + used[b] >= 65536) return -1;
- dumbfile_getnc(buffer + buflen, used[b], f);
- buflen += used[b];
- } else {
- /* End of row */
- if (++pattern->n_rows == 64) break;
- if (buflen >= 65536) return -1;
- }
-#else
- if (b == 0) {
- /* End of row */
- pattern->n_entries++;
- if (++pattern->n_rows == 64) break;
- if (buflen >= 65536) return -1;
- } else {
- static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5};
- channel = b & 31;
- b >>= 5;
- if (b) {
- pattern->n_entries++;
- if (buflen + used[b] >= 65536) return -1;
- dumbfile_getnc(buffer + buflen, used[b], f);
- buflen += used[b];
- }
- }
-#endif
-
- /* We have ensured that buflen < 65536 at this point, so it is safe
- * to iterate and read at least one more byte without checking.
- * However, now would be a good time to check for errors reading from
- * the file.
- */
-
- if (dumbfile_error(f))
- return -1;
-
- /* Great. We ran out of data, but there should be data for more rows.
- * Fill the rest with null data...
- */
- if (buflen >= length && pattern->n_rows < 64)
- {
- while (pattern->n_rows < 64)
- {
- if (buflen >= 65536) return -1;
- buffer[buflen++] = 0;
- pattern->n_entries++;
- pattern->n_rows++;
- }
- break;
- }
- }
-
- pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
-
- if (!pattern->entry)
- return -1;
-
- entry = pattern->entry;
-
- while (bufpos < buflen) {
- unsigned char b = buffer[bufpos++];
-
- if (b == 0)
- {
- /* End of row */
- IT_SET_END_ROW(entry);
- entry++;
- continue;
- }
-
- channel = b & 31;
-
- if (b & 224) {
- entry->mask = 0;
- entry->channel = channel;
-
- if (b & 32) {
- unsigned char n = buffer[bufpos++];
- if (n == 254 || (n >= 1 && n <= 120)) {
- if (n == 254)
- entry->note = IT_NOTE_CUT;
- else
- entry->note = n - 1;
- entry->mask |= IT_ENTRY_NOTE;
- }
-
- entry->instrument = buffer[bufpos++];
- if (entry->instrument)
- entry->mask |= IT_ENTRY_INSTRUMENT;
- }
-
- if (b & 64) {
- effect = buffer[bufpos++];
- effectvalue = buffer[bufpos++];
- _dumb_it_ptm_convert_effect(effect, effectvalue, entry);
- }
-
- if (b & 128) {
- entry->volpan = buffer[bufpos++];
- if (entry->volpan <= 64)
- entry->mask |= IT_ENTRY_VOLPAN;
- }
-
- entry++;
- }
- }
-
- ASSERT(entry == pattern->entry + pattern->n_entries);
-
- return 0;
-}
-
-
-
-/** WARNING: this is duplicated in itread.c - also bad practice to use the same struct name unless they are unified in a header */
-/* Currently we assume the sample data are stored after the sample headers in
- * module files. This assumption may be unjustified; let me know if you have
- * trouble.
- */
-
-#define PTM_COMPONENT_INSTRUMENT 1
-#define PTM_COMPONENT_PATTERN 2
-#define PTM_COMPONENT_SAMPLE 3
-
-typedef struct PTM_COMPONENT
-{
- unsigned char type;
- unsigned char n;
- long offset;
-}
-PTM_COMPONENT;
-
-
-
-static int ptm_component_compare(const void *e1, const void *e2)
-{
- return ((const PTM_COMPONENT *)e1)->offset -
- ((const PTM_COMPONENT *)e2)->offset;
-}
-
-
-
-static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- PTM_COMPONENT *component;
- int n_components = 0;
-
- int n;
-
- unsigned char *buffer;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) return NULL;
-
- /* Skip song name. */
- dumbfile_getnc(sigdata->name, 28, f);
- sigdata->name[28] = 0;
-
- if (dumbfile_getc(f) != 0x1A || dumbfile_igetw(f) != 0x203) {
- free(sigdata);
- return NULL;
- }
-
- dumbfile_skip(f, 1);
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_orders = dumbfile_igetw(f);
- sigdata->n_instruments = 0;
- sigdata->n_samples = dumbfile_igetw(f);
- sigdata->n_patterns = dumbfile_igetw(f);
-
- if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_samples > 255 || sigdata->n_patterns > 128) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->n_pchannels = dumbfile_igetw(f);
-
- if (dumbfile_igetw(f) != 0) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- dumbfile_skip(f, 2);
-
- if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','F')) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- dumbfile_skip(f, 16);
-
- sigdata->order = malloc(sigdata->n_orders);
- if (!sigdata->order) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (sigdata->n_samples) {
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
- }
-
- if (sigdata->n_patterns) {
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
- }
-
- /** WARNING: which ones? */
- sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_A_PTM;
-
- sigdata->global_volume = 128;
- sigdata->speed = 6;
- sigdata->tempo = 125;
- sigdata->mixing_volume = 48;
-
- /* Panning positions for 32 channels */
- {
- int i;
- for (i = 0; i < 32; i++) {
- int c = dumbfile_getc(f);
- if (c <= 15) {
- sigdata->channel_volume[i] = 64;
- sigdata->channel_pan[i] = c;
- } else {
- /** WARNING: this could be improved if we support channel muting... */
- sigdata->channel_volume[i] = 0;
- sigdata->channel_pan[i] = 7;
- }
- }
- }
-
- /* Orders, byte each, length = sigdata->n_orders (should be even) */
- dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
- sigdata->restart_position = 0;
-
- component = malloc(768*sizeof(*component));
- if (!component) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (it_seek(f, 352)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (n = 0; n < sigdata->n_patterns; n++) {
- component[n_components].type = PTM_COMPONENT_PATTERN;
- component[n_components].n = n;
- component[n_components].offset = dumbfile_igetw(f) << 4;
- n_components++;
- }
-
- if (it_seek(f, 608)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (n = 0; n < sigdata->n_samples; n++) {
- if (it_ptm_read_sample_header(&sigdata->sample[n], &component[n_components].offset, f)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- if (!(sigdata->sample[n].flags & IT_SAMPLE_EXISTS)) continue;
- component[n_components].type = PTM_COMPONENT_SAMPLE;
- component[n_components].n = n;
- n_components++;
- }
-
- qsort(component, n_components, sizeof(PTM_COMPONENT), &ptm_component_compare);
-
- {
- int i;
- for (i = 0; i < 32; i++) {
- sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3;
- sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7;
- if (sigdata->channel_pan[i] > 64) sigdata->channel_pan[i] = 64;
- }
- }
-
- sigdata->pan_separation = 128;
-
- if (dumbfile_error(f)) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- buffer = malloc(65536);
- if (!buffer) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (n = 0; n < n_components; n++) {
- if (it_seek(f, component[n].offset)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- switch (component[n].type) {
-
- case PTM_COMPONENT_PATTERN:
- if (it_ptm_read_pattern(&sigdata->pattern[component[n].n], f, buffer, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- break;
-
- case PTM_COMPONENT_SAMPLE:
- if (it_ptm_read_sample_data(&sigdata->sample[component[n].n], (n + 1 == n_components), f)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
- }
-
- free(buffer);
- free(component);
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-static char hexdigit(int in)
-{
- if (in < 10) return in + '0';
- else return in + 'A' - 10;
-}
-
-DUH *dumb_read_ptm_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_ptm_load_sigdata(f);
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "PTM";
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readptm.c - Code to read a Poly Tracker v2.03 / / \ \
+ * module from an open file. | < / \_
+ * | \/ /\ /
+ * By Chris Moeller. Based on reads3m.c \_ / > /
+ * by entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+// IT_STEREO... :o
+#include <stdlib.h>
+#include <string.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/** WARNING: this is duplicated in itread.c */
+static int it_seek(DUMBFILE *f, long offset)
+{
+ long pos = dumbfile_pos(f);
+
+ if (pos > offset)
+ return -1;
+
+ if (pos < offset)
+ if (dumbfile_skip(f, offset - pos))
+ return -1;
+
+ return 0;
+}
+
+
+
+static int it_ptm_read_sample_header(IT_SAMPLE *sample, long *offset, DUMBFILE *f)
+{
+ int flags;
+
+ flags = dumbfile_getc(f);
+
+ dumbfile_getnc(sample->filename, 12, f);
+ sample->filename[12] = 0;
+
+ sample->default_volume = dumbfile_getc(f);
+
+ sample->C5_speed = dumbfile_igetw(f) << 1;
+
+ dumbfile_skip(f, 2); /* segment */
+
+ *offset = dumbfile_igetl(f);
+
+ sample->length = dumbfile_igetl(f);
+ sample->loop_start = dumbfile_igetl(f);
+ sample->loop_end = dumbfile_igetl(f);
+
+ /* GUSBegin, GUSLStart, GUSLEnd, GUSLoop, reserverd */
+ dumbfile_skip(f, 4+4+4+1+1);
+
+ dumbfile_getnc(sample->name, 28, f);
+ sample->name[28] = 0;
+
+ /*
+ if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','S'))
+ return -1;
+ */
+
+ /* BLAH! Shit likes to have broken or missing sample IDs */
+ dumbfile_skip(f, 4);
+
+ if ((flags & 3) == 0) {
+ /* Looks like no sample */
+ sample->flags &= ~IT_SAMPLE_EXISTS;
+ return dumbfile_error(f);
+ }
+
+ sample->global_volume = 64;
+
+ sample->flags = IT_SAMPLE_EXISTS;
+ if (flags & 4) sample->flags |= IT_SAMPLE_LOOP;
+ if (flags & 8) sample->flags |= IT_SAMPLE_PINGPONG_LOOP;
+
+ if (flags & 16) {
+ sample->flags |= IT_SAMPLE_16BIT;
+
+ sample->length >>= 1;
+ sample->loop_start >>= 1;
+ sample->loop_end >>= 1;
+ }
+
+ if (sample->loop_end) sample->loop_end--;
+
+ sample->default_pan = 0; // 0 = don't use, or 160 = centre?
+
+ if (sample->length <= 0)
+ sample->flags &= ~IT_SAMPLE_EXISTS;
+ else if (sample->flags & IT_SAMPLE_LOOP) {
+ if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
+ sample->flags &= ~IT_SAMPLE_LOOP;
+ else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
+ sample->flags &= ~IT_SAMPLE_LOOP;
+ else
+ sample->length = sample->loop_end;
+ }
+
+
+ //Do we need to set all these?
+ sample->vibrato_speed = 0;
+ sample->vibrato_depth = 0;
+ sample->vibrato_rate = 0;
+ sample->vibrato_waveform = IT_VIBRATO_SINE;
+ sample->finetune = 0;
+ sample->max_resampling_quality = -1;
+
+ return dumbfile_error(f);
+}
+
+
+static int it_ptm_read_byte(DUMBFILE *f)
+{
+ int meh = dumbfile_getc(f);
+ if (meh < 0) return 0;
+ return meh;
+}
+
+static int it_ptm_read_sample_data(IT_SAMPLE *sample, int last, DUMBFILE *f)
+{
+ long n;
+ int s;
+
+ sample->data = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
+ if (!sample->data)
+ return -1;
+
+ s = 0;
+
+ if (sample->flags & IT_SAMPLE_16BIT) {
+ unsigned char a, b;
+ for (n = 0; n < sample->length; n++) {
+ a = s += (signed char) it_ptm_read_byte(f);
+ b = s += (signed char) it_ptm_read_byte(f);
+ ((short *)sample->data)[n] = a | (b << 8);
+ }
+ } else {
+ for (n = 0; n < sample->length; n++) {
+ s += (signed char) it_ptm_read_byte(f);
+ ((signed char *)sample->data)[n] = s;
+ }
+ }
+
+ if (dumbfile_error(f) && !last)
+ return -1;
+
+ return 0;
+}
+
+
+
+static int it_ptm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer, int length)
+{
+ int buflen = 0;
+ int bufpos = 0;
+ int effect, effectvalue;
+
+ IT_ENTRY *entry;
+
+ unsigned char channel;
+
+ if (!length)
+ return -1;
+
+ pattern->n_rows = 0;
+ pattern->n_entries = 0;
+
+ /* Read in the pattern data, little by little, and work out how many
+ * entries we need room for. Sorry, but this is just so funny...
+ */
+ for (;;) {
+ unsigned char b = buffer[buflen++] = dumbfile_getc(f);
+
+#if 1
+ static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5};
+ channel = b & 31;
+ b >>= 5;
+ pattern->n_entries++;
+ if (b) {
+ if (buflen + used[b] >= 65536) return -1;
+ dumbfile_getnc(buffer + buflen, used[b], f);
+ buflen += used[b];
+ } else {
+ /* End of row */
+ if (++pattern->n_rows == 64) break;
+ if (buflen >= 65536) return -1;
+ }
+#else
+ if (b == 0) {
+ /* End of row */
+ pattern->n_entries++;
+ if (++pattern->n_rows == 64) break;
+ if (buflen >= 65536) return -1;
+ } else {
+ static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5};
+ channel = b & 31;
+ b >>= 5;
+ if (b) {
+ pattern->n_entries++;
+ if (buflen + used[b] >= 65536) return -1;
+ dumbfile_getnc(buffer + buflen, used[b], f);
+ buflen += used[b];
+ }
+ }
+#endif
+
+ /* We have ensured that buflen < 65536 at this point, so it is safe
+ * to iterate and read at least one more byte without checking.
+ * However, now would be a good time to check for errors reading from
+ * the file.
+ */
+
+ if (dumbfile_error(f))
+ return -1;
+
+ /* Great. We ran out of data, but there should be data for more rows.
+ * Fill the rest with null data...
+ */
+ if (buflen >= length && pattern->n_rows < 64)
+ {
+ while (pattern->n_rows < 64)
+ {
+ if (buflen >= 65536) return -1;
+ buffer[buflen++] = 0;
+ pattern->n_entries++;
+ pattern->n_rows++;
+ }
+ break;
+ }
+ }
+
+ pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
+
+ if (!pattern->entry)
+ return -1;
+
+ entry = pattern->entry;
+
+ while (bufpos < buflen) {
+ unsigned char b = buffer[bufpos++];
+
+ if (b == 0)
+ {
+ /* End of row */
+ IT_SET_END_ROW(entry);
+ entry++;
+ continue;
+ }
+
+ channel = b & 31;
+
+ if (b & 224) {
+ entry->mask = 0;
+ entry->channel = channel;
+
+ if (b & 32) {
+ unsigned char n = buffer[bufpos++];
+ if (n == 254 || (n >= 1 && n <= 120)) {
+ if (n == 254)
+ entry->note = IT_NOTE_CUT;
+ else
+ entry->note = n - 1;
+ entry->mask |= IT_ENTRY_NOTE;
+ }
+
+ entry->instrument = buffer[bufpos++];
+ if (entry->instrument)
+ entry->mask |= IT_ENTRY_INSTRUMENT;
+ }
+
+ if (b & 64) {
+ effect = buffer[bufpos++];
+ effectvalue = buffer[bufpos++];
+ _dumb_it_ptm_convert_effect(effect, effectvalue, entry);
+ }
+
+ if (b & 128) {
+ entry->volpan = buffer[bufpos++];
+ if (entry->volpan <= 64)
+ entry->mask |= IT_ENTRY_VOLPAN;
+ }
+
+ entry++;
+ }
+ }
+
+ ASSERT(entry == pattern->entry + pattern->n_entries);
+
+ return 0;
+}
+
+
+
+/** WARNING: this is duplicated in itread.c - also bad practice to use the same struct name unless they are unified in a header */
+/* Currently we assume the sample data are stored after the sample headers in
+ * module files. This assumption may be unjustified; let me know if you have
+ * trouble.
+ */
+
+#define PTM_COMPONENT_INSTRUMENT 1
+#define PTM_COMPONENT_PATTERN 2
+#define PTM_COMPONENT_SAMPLE 3
+
+typedef struct PTM_COMPONENT
+{
+ unsigned char type;
+ unsigned char n;
+ long offset;
+}
+PTM_COMPONENT;
+
+
+
+static int ptm_component_compare(const void *e1, const void *e2)
+{
+ return ((const PTM_COMPONENT *)e1)->offset -
+ ((const PTM_COMPONENT *)e2)->offset;
+}
+
+
+
+static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f)
+{
+ DUMB_IT_SIGDATA *sigdata;
+
+ PTM_COMPONENT *component;
+ int n_components = 0;
+
+ int n;
+
+ unsigned char *buffer;
+
+ sigdata = malloc(sizeof(*sigdata));
+ if (!sigdata) return NULL;
+
+ /* Skip song name. */
+ dumbfile_getnc(sigdata->name, 28, f);
+ sigdata->name[28] = 0;
+
+ if (dumbfile_getc(f) != 0x1A || dumbfile_igetw(f) != 0x203) {
+ free(sigdata);
+ return NULL;
+ }
+
+ dumbfile_skip(f, 1);
+
+ sigdata->song_message = NULL;
+ sigdata->order = NULL;
+ sigdata->instrument = NULL;
+ sigdata->sample = NULL;
+ sigdata->pattern = NULL;
+ sigdata->midi = NULL;
+ sigdata->checkpoint = NULL;
+
+ sigdata->n_orders = dumbfile_igetw(f);
+ sigdata->n_instruments = 0;
+ sigdata->n_samples = dumbfile_igetw(f);
+ sigdata->n_patterns = dumbfile_igetw(f);
+
+ if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_samples > 255 || sigdata->n_patterns > 128) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ sigdata->n_pchannels = dumbfile_igetw(f);
+
+ if (dumbfile_igetw(f) != 0) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ dumbfile_skip(f, 2);
+
+ if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','F')) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ dumbfile_skip(f, 16);
+
+ sigdata->order = malloc(sigdata->n_orders);
+ if (!sigdata->order) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ if (sigdata->n_samples) {
+ sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
+ if (!sigdata->sample) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (n = 0; n < sigdata->n_samples; n++)
+ sigdata->sample[n].data = NULL;
+ }
+
+ if (sigdata->n_patterns) {
+ sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
+ if (!sigdata->pattern) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (n = 0; n < sigdata->n_patterns; n++)
+ sigdata->pattern[n].entry = NULL;
+ }
+
+ /** WARNING: which ones? */
+ sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_A_PTM;
+
+ sigdata->global_volume = 128;
+ sigdata->speed = 6;
+ sigdata->tempo = 125;
+ sigdata->mixing_volume = 48;
+
+ /* Panning positions for 32 channels */
+ {
+ int i;
+ for (i = 0; i < 32; i++) {
+ int c = dumbfile_getc(f);
+ if (c <= 15) {
+ sigdata->channel_volume[i] = 64;
+ sigdata->channel_pan[i] = c;
+ } else {
+ /** WARNING: this could be improved if we support channel muting... */
+ sigdata->channel_volume[i] = 0;
+ sigdata->channel_pan[i] = 7;
+ }
+ }
+ }
+
+ /* Orders, byte each, length = sigdata->n_orders (should be even) */
+ dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
+ sigdata->restart_position = 0;
+
+ component = malloc(768*sizeof(*component));
+ if (!component) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ if (it_seek(f, 352)) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ for (n = 0; n < sigdata->n_patterns; n++) {
+ component[n_components].type = PTM_COMPONENT_PATTERN;
+ component[n_components].n = n;
+ component[n_components].offset = dumbfile_igetw(f) << 4;
+ n_components++;
+ }
+
+ if (it_seek(f, 608)) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ for (n = 0; n < sigdata->n_samples; n++) {
+ if (it_ptm_read_sample_header(&sigdata->sample[n], &component[n_components].offset, f)) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ if (!(sigdata->sample[n].flags & IT_SAMPLE_EXISTS)) continue;
+ component[n_components].type = PTM_COMPONENT_SAMPLE;
+ component[n_components].n = n;
+ n_components++;
+ }
+
+ qsort(component, n_components, sizeof(PTM_COMPONENT), &ptm_component_compare);
+
+ {
+ int i;
+ for (i = 0; i < 32; i++) {
+ sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3;
+ sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7;
+ if (sigdata->channel_pan[i] > 64) sigdata->channel_pan[i] = 64;
+ }
+ }
+
+ sigdata->pan_separation = 128;
+
+ if (dumbfile_error(f)) {
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ buffer = malloc(65536);
+ if (!buffer) {
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ for (n = 0; n < n_components; n++) {
+ if (it_seek(f, component[n].offset)) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ switch (component[n].type) {
+
+ case PTM_COMPONENT_PATTERN:
+ if (it_ptm_read_pattern(&sigdata->pattern[component[n].n], f, buffer, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0)) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ break;
+
+ case PTM_COMPONENT_SAMPLE:
+ if (it_ptm_read_sample_data(&sigdata->sample[component[n].n], (n + 1 == n_components), f)) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ }
+ }
+
+ free(buffer);
+ free(component);
+
+ _dumb_it_fix_invalid_orders(sigdata);
+
+ return sigdata;
+}
+
+static char hexdigit(int in)
+{
+ if (in < 10) return in + '0';
+ else return in + 'A' - 10;
+}
+
+DUH *dumb_read_ptm_quick(DUMBFILE *f)
+{
+ sigdata_t *sigdata;
+
+ DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
+
+ sigdata = it_ptm_load_sigdata(f);
+
+ if (!sigdata)
+ return NULL;
+
+ {
+ const char *tag[2][2];
+ tag[0][0] = "TITLE";
+ tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+ tag[1][0] = "FORMAT";
+ tag[1][1] = "PTM";
+ return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/readriff.c b/plugins/dumb/dumb-kode54/src/it/readriff.c
index cc1e82fb..10bd884a 100644
--- a/plugins/dumb/dumb-kode54/src/it/readriff.c
+++ b/plugins/dumb/dumb-kode54/src/it/readriff.c
@@ -1,73 +1,73 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readriff.c - Code to read a RIFF module file / / \ \
- * from memory. | < / \_
- * | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-#include "internal/riff.h"
-
-
-DUH *dumb_read_riff_amff( struct riff * stream );
-DUH *dumb_read_riff_am( struct riff * stream );
-DUH *dumb_read_riff_dsmf( struct riff * stream );
-
-/* dumb_read_riff_quick(): reads a RIFF file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must pass
- * the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_read_riff_quick( DUMBFILE * f )
-{
- DUH * duh;
- struct riff * stream;
-
- {
- unsigned char * buffer = 0;
- unsigned size = 0;
- long read;
- do
- {
- buffer = realloc( buffer, 32768 + size );
- if ( ! buffer ) return 0;
- read = dumbfile_getnc( buffer + size, 32768, f );
- if ( read < 0 )
- {
- free( buffer );
- return 0;
- }
- size += read;
- }
- while ( read == 32768 );
- stream = riff_parse( buffer, size, 1 );
- if ( ! stream ) stream = riff_parse( buffer, size, 0 );
- free( buffer );
- }
-
- if ( ! stream ) return 0;
-
- if ( stream->type == DUMB_ID( 'A', 'M', ' ', ' ' ) )
- duh = dumb_read_riff_am( stream );
- else if ( stream->type == DUMB_ID( 'A', 'M', 'F', 'F' ) )
- duh = dumb_read_riff_amff( stream );
- else if ( stream->type == DUMB_ID( 'D', 'S', 'M', 'F' ) )
- duh = dumb_read_riff_dsmf( stream );
- else duh = 0;
-
- riff_free( stream );
-
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readriff.c - Code to read a RIFF module file / / \ \
+ * from memory. | < / \_
+ * | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+#include "internal/riff.h"
+
+
+DUH *dumb_read_riff_amff( struct riff * stream );
+DUH *dumb_read_riff_am( struct riff * stream );
+DUH *dumb_read_riff_dsmf( struct riff * stream );
+
+/* dumb_read_riff_quick(): reads a RIFF file into a DUH struct, returning a
+ * pointer to the DUH struct. When you have finished with it, you must pass
+ * the pointer to unload_duh() so that the memory can be freed.
+ */
+DUH *dumb_read_riff_quick( DUMBFILE * f )
+{
+ DUH * duh;
+ struct riff * stream;
+
+ {
+ unsigned char * buffer = 0;
+ unsigned size = 0;
+ long read;
+ do
+ {
+ buffer = realloc( buffer, 32768 + size );
+ if ( ! buffer ) return 0;
+ read = dumbfile_getnc( buffer + size, 32768, f );
+ if ( read < 0 )
+ {
+ free( buffer );
+ return 0;
+ }
+ size += read;
+ }
+ while ( read == 32768 );
+ stream = riff_parse( buffer, size, 1 );
+ if ( ! stream ) stream = riff_parse( buffer, size, 0 );
+ free( buffer );
+ }
+
+ if ( ! stream ) return 0;
+
+ if ( stream->type == DUMB_ID( 'A', 'M', ' ', ' ' ) )
+ duh = dumb_read_riff_am( stream );
+ else if ( stream->type == DUMB_ID( 'A', 'M', 'F', 'F' ) )
+ duh = dumb_read_riff_amff( stream );
+ else if ( stream->type == DUMB_ID( 'D', 'S', 'M', 'F' ) )
+ duh = dumb_read_riff_dsmf( stream );
+ else duh = 0;
+
+ riff_free( stream );
+
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/reads3m.c b/plugins/dumb/dumb-kode54/src/it/reads3m.c
index 0dac8331..77a70f7a 100644
--- a/plugins/dumb/dumb-kode54/src/it/reads3m.c
+++ b/plugins/dumb/dumb-kode54/src/it/reads3m.c
@@ -1,864 +1,864 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * reads3m.c - Code to read a ScreamTracker 3 / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-// IT_STEREO... :o
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-//#define S3M_BROKEN_OVERLAPPED_SAMPLES
-
-/** WARNING: this is duplicated in itread.c */
-static int it_seek(DUMBFILE *f, long offset)
-{
- long pos = dumbfile_pos(f);
-
- if (pos > offset) {
- return -1;
- }
-
- if (pos < offset)
- if (dumbfile_skip(f, offset - pos))
- return -1;
-
- return 0;
-}
-
-
-
-static int it_s3m_read_sample_header(IT_SAMPLE *sample, long *offset, unsigned char *pack, int cwtv, DUMBFILE *f)
-{
- unsigned char type;
- int flags;
-
- type = dumbfile_getc(f);
-
- dumbfile_getnc(sample->filename, 12, f);
- sample->filename[12] = 0;
-
- if (type > 1) {
- /** WARNING: no adlib support */
- dumbfile_skip(f, 3 + 12 + 1 + 1 + 2 + 2 + 2 + 12);
- dumbfile_getnc(sample->name, 28, f);
- sample->name[28] = 0;
- dumbfile_skip(f, 4);
- sample->flags &= ~IT_SAMPLE_EXISTS;
- return -1; // return error so that another plugin could pick that file up
- }
-
- *offset = dumbfile_getc(f) << 20;
- *offset += dumbfile_igetw(f) << 4;
-
- sample->length = dumbfile_igetl(f);
- sample->loop_start = dumbfile_igetl(f);
- sample->loop_end = dumbfile_igetl(f);
-
- sample->default_volume = dumbfile_getc(f);
-
- dumbfile_skip(f, 1);
-
- flags = dumbfile_getc(f);
-
- if (flags < 0 || (flags != 0 && flags != 4))
- /* Sample is packed apparently (or error reading from file). We don't
- * know how to read packed samples.
- */
- return -1;
-
- *pack = flags;
-
- flags = dumbfile_getc(f);
-
- sample->C5_speed = dumbfile_igetl(f) << 1;
-
- /* Skip four unused bytes and three internal variables. */
- dumbfile_skip(f, 4+2+2+4);
-
- dumbfile_getnc(sample->name, 28, f);
- sample->name[28] = 0;
-
- if (type == 0 || sample->length <= 0) {
- /* Looks like no-existy. Anyway, there's for sure no 'SCRS' ... */
- sample->flags &= ~IT_SAMPLE_EXISTS;
- return dumbfile_error(f);
- }
-
- if (dumbfile_mgetl(f) != DUMB_ID('S','C','R','S'))
- return -1;
-
- sample->global_volume = 64;
-
- sample->flags = IT_SAMPLE_EXISTS;
- if (flags & 1) sample->flags |= IT_SAMPLE_LOOP;
-
- /* The ST3 TECH.DOC is unclear on this, but IMAGO Orpheus is not. Piece of crap. */
-
- if (flags & 2) {
- sample->flags |= IT_SAMPLE_STEREO;
-
- if ((cwtv & 0xF000) == 0x2000) {
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- }
- }
-
- if (flags & 4) {
- sample->flags |= IT_SAMPLE_16BIT;
-
- if ((cwtv & 0xF000) == 0x2000) {
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- }
- }
-
- sample->default_pan = 0; // 0 = don't use, or 160 = centre?
-
- if (sample->flags & IT_SAMPLE_LOOP) {
- if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
- /*sample->flags &= ~IT_SAMPLE_LOOP;*/
- sample->loop_end = sample->length;
- else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
- sample->flags &= ~IT_SAMPLE_LOOP;
- else
- /* ScreamTracker seems not to save what comes after the loop end
- * point, but rather to assume it is a duplicate of what comes at
- * the loop start point. I am not completely sure of this though.
- * It is easy to evade; simply truncate the sample.
- */
- sample->length = sample->loop_end;
- }
-
-
- //Do we need to set all these?
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = IT_VIBRATO_SINE;
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-
-
-static int it_s3m_read_sample_data(IT_SAMPLE *sample, int ffi, unsigned char pack, DUMBFILE *f)
-{
- long n;
-
- long datasize = sample->length;
- if (sample->flags & IT_SAMPLE_STEREO) datasize <<= 1;
-
- sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
- if (!sample->data)
- return -1;
-
- if (pack == 4) {
- if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
- return -1;
- }
- else if (sample->flags & IT_SAMPLE_STEREO) {
- if (sample->flags & IT_SAMPLE_16BIT) {
- for (n = 0; n < datasize; n += 2)
- ((short *)sample->data)[n] = dumbfile_igetw(f);
- for (n = 1; n < datasize; n += 2)
- ((short *)sample->data)[n] = dumbfile_igetw(f);
- } else {
- for (n = 0; n < datasize; n += 2)
- ((signed char *)sample->data)[n] = dumbfile_getc(f);
- for (n = 1; n < datasize; n += 2)
- ((signed char *)sample->data)[n] = dumbfile_getc(f);
- }
- } else if (sample->flags & IT_SAMPLE_16BIT)
- for (n = 0; n < sample->length; n++)
- ((short *)sample->data)[n] = dumbfile_igetw(f);
- else
- for (n = 0; n < sample->length; n++)
- ((signed char *)sample->data)[n] = dumbfile_getc(f);
-
- if (dumbfile_error(f))
- return -1;
-
- if (ffi != 1) {
- /* Convert to signed. */
- if (sample->flags & IT_SAMPLE_16BIT)
- for (n = 0; n < datasize; n++)
- ((short *)sample->data)[n] ^= 0x8000;
- else
- for (n = 0; n < datasize; n++)
- ((signed char *)sample->data)[n] ^= 0x80;
- }
-
- return 0;
-}
-
-
-
-static int it_s3m_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer, int maxlen)
-{
- int length;
- int buflen = 0;
- int bufpos = 0;
-
- IT_ENTRY *entry;
-
- unsigned char channel;
-
- /* Haha, this is hilarious!
- *
- * Well, after some experimentation, it seems that different S3M writers
- * define the format in different ways. The S3M docs say that the first
- * two bytes hold the "length of [the] packed pattern", and the packed
- * pattern data follow. Judging by the contents of ARMANI.S3M, packaged
- * with ScreamTracker itself, the measure of length _includes_ the two
- * bytes used to store the length; in other words, we should read
- * (length - 2) more bytes. However, aryx.s3m, packaged with ModPlug
- * Tracker, excludes these two bytes, so (length) more bytes must be
- * read.
- *
- * Call me crazy, but I just find it insanely funny that the format was
- * misunderstood in this way :D
- *
- * Now we can't just risk reading two extra bytes, because then we
- * overshoot, and DUMBFILEs don't support backward seeking (for a good
- * reason). Luckily, there is a way. We can read the data little by
- * little, and stop when we have 64 rows in memory. Provided we protect
- * against buffer overflow, this method should work with all sensibly
- * written S3M files. If you find one for which it does not work, please
- * let me know at entheh@users.sf.net so I can look at it.
- */
-
- /* Discard the length. */
- /* read at most length bytes, in case of retarded crap */
- length = dumbfile_igetw(f);
-
- if (maxlen)
- {
- maxlen -= 2;
- if (length > maxlen) length = maxlen;
- }
-
- if (dumbfile_error(f) || !length)
- return -1;
-
- pattern->n_rows = 0;
- pattern->n_entries = 0;
-
- /* Read in the pattern data, little by little, and work out how many
- * entries we need room for. Sorry, but this is just so funny...
- */
- for (;;) {
- unsigned char b = buffer[buflen++] = dumbfile_getc(f);
-
-#if 1
- static const unsigned char used[8] = {0, 2, 1, 3, 2, 4, 3, 5};
- channel = b & 31;
- b >>= 5;
- pattern->n_entries++;
- if (b) {
- if (buflen + used[b] >= 65536) return -1;
- if (buflen + used[b] <= length)
- dumbfile_getnc(buffer + buflen, used[b], f);
- else
- memset(buffer + buflen, 0, used[b]);
- buflen += used[b];
- } else {
- /* End of row */
- if (++pattern->n_rows == 64) break;
- if (buflen >= 65536) return -1;
- }
-#else
- if (b == 0) {
- /* End of row */
- pattern->n_entries++;
- if (++pattern->n_rows == 64) break;
- if (buflen >= 65536) return -1;
- } else {
- static const unsigned char used[8] = {0, 2, 1, 3, 2, 4, 3, 5};
- channel = b & 31;
- b >>= 5;
- if (b) {
- pattern->n_entries++;
- if (buflen + used[b] >= 65536) return -1;
- dumbfile_getnc(buffer + buflen, used[b], f);
- buflen += used[b];
- }
- }
-#endif
-
- /* We have ensured that buflen < 65536 at this point, so it is safe
- * to iterate and read at least one more byte without checking.
- * However, now would be a good time to check for errors reading from
- * the file.
- */
-
- if (dumbfile_error(f))
- return -1;
-
- /* Great. We ran out of data, but there should be data for more rows.
- * Fill the rest with null data...
- */
- if (buflen >= length && pattern->n_rows < 64)
- {
- while (pattern->n_rows < 64)
- {
- if (buflen >= 65536) return -1;
- buffer[buflen++] = 0;
- pattern->n_entries++;
- pattern->n_rows++;
- }
- break;
- }
- }
-
- pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
-
- if (!pattern->entry)
- return -1;
-
- entry = pattern->entry;
-
- while (bufpos < buflen) {
- unsigned char b = buffer[bufpos++];
-
-#if 1
- if (!(b & ~31))
-#else
- if (b == 0)
-#endif
- {
- /* End of row */
- IT_SET_END_ROW(entry);
- entry++;
- continue;
- }
-
- channel = b & 31;
-
- if (b & 224) {
- entry->mask = 0;
- entry->channel = channel;
-
- if (b & 32) {
- unsigned char n = buffer[bufpos++];
- if (n != 255) {
- if (n == 254)
- entry->note = IT_NOTE_CUT;
- else
- entry->note = (n >> 4) * 12 + (n & 15);
- entry->mask |= IT_ENTRY_NOTE;
- }
-
- entry->instrument = buffer[bufpos++];
- if (entry->instrument)
- entry->mask |= IT_ENTRY_INSTRUMENT;
- }
-
- if (b & 64) {
- entry->volpan = buffer[bufpos++];
- if (entry->volpan != 255)
- entry->mask |= IT_ENTRY_VOLPAN;
- }
-
- if (b & 128) {
- entry->effect = buffer[bufpos++];
- entry->effectvalue = buffer[bufpos++];
- // XXX woot
- if (entry->effect && entry->effect < IT_MIDI_MACRO /*!= 255*/) {
- entry->mask |= IT_ENTRY_EFFECT;
- switch (entry->effect) {
- case IT_BREAK_TO_ROW:
- entry->effectvalue -= (entry->effectvalue >> 4) * 6;
- break;
-
- case IT_SET_CHANNEL_VOLUME:
- case IT_CHANNEL_VOLUME_SLIDE:
- case IT_PANNING_SLIDE:
- case IT_GLOBAL_VOLUME_SLIDE:
- case IT_PANBRELLO:
- case IT_MIDI_MACRO:
- entry->mask &= ~IT_ENTRY_EFFECT;
- break;
-
- case IT_S:
- switch (entry->effectvalue >> 4) {
- case IT_S_SET_PANBRELLO_WAVEFORM:
- case IT_S_FINE_PATTERN_DELAY:
- case IT_S7:
- case IT_S_SET_SURROUND_SOUND:
- case IT_S_SET_MIDI_MACRO:
- entry->mask &= ~IT_ENTRY_EFFECT;
- break;
- }
- break;
- }
- }
- /** WARNING: ARGH! CONVERT TEH EFFECTS!@~ */
- }
-
- entry++;
- }
- }
-
- ASSERT(entry == pattern->entry + pattern->n_entries);
-
- return 0;
-}
-
-
-
-/** WARNING: this is duplicated in itread.c - also bad practice to use the same struct name unless they are unified in a header */
-/* Currently we assume the sample data are stored after the sample headers in
- * module files. This assumption may be unjustified; let me know if you have
- * trouble.
- */
-
-#define S3M_COMPONENT_INSTRUMENT 1
-#define S3M_COMPONENT_PATTERN 2
-#define S3M_COMPONENT_SAMPLE 3
-
-typedef struct S3M_COMPONENT
-{
- unsigned char type;
- unsigned char n;
- long offset;
- short sampfirst; /* component[sampfirst] = first sample data after this */
- short sampnext; /* sampnext is used to create linked lists of sample data */
-}
-S3M_COMPONENT;
-
-
-
-static int s3m_component_compare(const void *e1, const void *e2)
-{
- return ((const S3M_COMPONENT *)e1)->offset -
- ((const S3M_COMPONENT *)e2)->offset;
-}
-
-
-
-static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- int flags, ffi;
- int default_pan_present;
-
- int master_volume;
-
- unsigned char sample_pack[256];
-
- S3M_COMPONENT *component;
- int n_components = 0;
-
- int n;
-
- unsigned char *buffer;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) return NULL;
-
- dumbfile_getnc(sigdata->name, 28, f);
- sigdata->name[28] = 0;
-
- n = dumbfile_getc(f);
-
- if (n != 0x1A && n != 0) {
- free(sigdata);
- return NULL;
- }
-
- if (dumbfile_getc(f) != 16) {
- free(sigdata);
- return NULL;
- }
-
- dumbfile_skip(f, 2);
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_orders = dumbfile_igetw(f);
- sigdata->n_instruments = 0;
- sigdata->n_samples = dumbfile_igetw(f);
- sigdata->n_patterns = dumbfile_igetw(f);
-
- if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_samples > 256 || sigdata->n_patterns > 256) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->order = malloc(sigdata->n_orders);
- if (!sigdata->order) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (sigdata->n_samples) {
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
- }
-
- if (sigdata->n_patterns) {
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
- }
-
- flags = dumbfile_igetw(f);
-
- *cwtv = dumbfile_igetw(f);
-
- if (*cwtv == 0x1300) {
- /** WARNING: volume slides on every frame */
- }
-
- ffi = dumbfile_igetw(f);
-
- /** WARNING: which ones? */
- sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
-
- if (dumbfile_mgetl(f) != DUMB_ID('S','C','R','M')) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->global_volume = dumbfile_getc(f) << 1;
- if ( !sigdata->global_volume || sigdata->global_volume > 128 ) sigdata->global_volume = 128;
- sigdata->speed = dumbfile_getc(f);
- if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
- sigdata->tempo = dumbfile_getc(f);
- master_volume = dumbfile_getc(f); // 7 bits; +128 for stereo
- //what do we do with master_volume? it's not the same as mixing volume...
- sigdata->mixing_volume = 48;
-
- if (master_volume & 128) sigdata->flags |= IT_STEREO;
-
- /* Skip GUS Ultra Click Removal byte. */
- dumbfile_getc(f);
-
- default_pan_present = dumbfile_getc(f);
-
- dumbfile_skip(f, 8);
-
- /* Skip Special Custom Data Pointer. */
- /** WARNING: investigate this? */
- dumbfile_igetw(f);
-
- sigdata->n_pchannels = 0;
- /* Channel settings for 32 channels, 255=unused, +128=disabled */
- {
- int i;
- for (i = 0; i < 32; i++) {
- int c = dumbfile_getc(f);
- if (!(c & (128 | 16))) { /* +128=disabled, +16=Adlib */
- if (sigdata->n_pchannels < i + 1) sigdata->n_pchannels = i + 1;
- sigdata->channel_volume[i] = 64;
- sigdata->channel_pan[i] = c & 8 ? 12 : 3;
- /** WARNING: ah, but it should be 7 for mono... */
- } else {
- /** WARNING: this could be improved if we support channel muting... */
- sigdata->channel_volume[i] = 0;
- sigdata->channel_pan[i] = 7;
- }
- }
- }
-
- /* Orders, byte each, length = sigdata->n_orders (should be even) */
- dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
- sigdata->restart_position = 0;
-
- component = malloc(768*sizeof(*component));
- if (!component) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (n = 0; n < sigdata->n_samples; n++) {
- component[n_components].type = S3M_COMPONENT_SAMPLE;
- component[n_components].n = n;
- component[n_components].offset = dumbfile_igetw(f) << 4;
- component[n_components].sampfirst = -1;
- n_components++;
- }
-
- for (n = 0; n < sigdata->n_patterns; n++) {
- long offset = dumbfile_igetw(f) << 4;
- if (offset) {
- component[n_components].type = S3M_COMPONENT_PATTERN;
- component[n_components].n = n;
- component[n_components].offset = offset;
- component[n_components].sampfirst = -1;
- n_components++;
- } else {
- /** WARNING: Empty 64-row pattern ... ? (this does happen!) */
- sigdata->pattern[n].n_rows = 64;
- sigdata->pattern[n].n_entries = 0;
- }
- }
-
- qsort(component, n_components, sizeof(S3M_COMPONENT), &s3m_component_compare);
-
- /* I found a really dumb S3M file that claimed to contain default pan
- * data but didn't contain any. Programs would load it by reading part of
- * the first instrument header, assuming the data to be default pan
- * positions, and then rereading the instrument module. We cannot do this
- * without obfuscating the file input model, so we insert an extra check
- * here that we won't overrun the start of the first component.
- */
- if (default_pan_present == 252 && component[0].offset >= dumbfile_pos(f) + 32) {
- /* Channel default pan positions */
- int i;
- for (i = 0; i < 32; i++) {
- int c = dumbfile_getc(f);
- if (c & 32)
- sigdata->channel_pan[i] = c & 15;
- }
- }
-
- {
- int i;
- for (i = 0; i < 32; i++) {
- sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3;
- sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7;
- }
- }
-
- sigdata->pan_separation = 128;
-
- if (dumbfile_error(f)) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- buffer = malloc(65536);
- if (!buffer) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- /* Voila, I must deal with a very dumb S3M myself. This file refers to the same file offset twice
- * for two different patterns. Solution: Eliminate it.
- */
-
- for (n = 0; n < n_components; n++) {
- if (component[n].type == S3M_COMPONENT_PATTERN) {
- int m;
- for (m = n + 1; m < n_components; m++) {
- if (component[m].type == S3M_COMPONENT_PATTERN) {
- if (component[n].offset == component[m].offset) {
- int o, pattern;
- pattern = component[m].n;
- n_components--;
- for (o = m; o < n_components; o++) {
- component[o] = component[o + 1];
- }
- for (o = 0; o < sigdata->n_orders; o++) {
- if (sigdata->order[o] == pattern) {
- sigdata->order[o] = component[n].n;
- }
- }
- sigdata->pattern[pattern].n_rows = 64;
- sigdata->pattern[pattern].n_entries = 0;
- m--;
- } else
- break;
- }
- }
- }
- }
-
- for (n = 0; n < n_components; n++) {
- long offset;
- int m;
-#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
- int last;
-#endif
-
- if (it_seek(f, component[n].offset)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- switch (component[n].type) {
-
- case S3M_COMPONENT_PATTERN:
- if (it_s3m_read_pattern(&sigdata->pattern[component[n].n], f, buffer, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- break;
-
- case S3M_COMPONENT_SAMPLE:
- {
- int err = it_s3m_read_sample_header(&sigdata->sample[component[n].n], &offset, &sample_pack[component[n].n], *cwtv, f);
- if (err) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
-
- if (sigdata->sample[component[n].n].flags & IT_SAMPLE_EXISTS) {
- short *sample;
-
- for (m = n + 1; m < n_components; m++)
- if (component[m].offset > offset)
- break;
- m--;
-
- sample = &component[m].sampfirst;
-
- while (*sample >= 0 && component[*sample].offset <= offset)
- sample = &component[*sample].sampnext;
-
- component[n].sampnext = *sample;
- *sample = n;
-
- component[n].offset = offset;
- }
- }
-
- m = component[n].sampfirst;
-
-#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
- last = -1;
-#endif
-
- while (m >= 0) {
- // XXX
-#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
- if ( last >= 0 ) {
- if ( dumbfile_pos( f ) > component[m].offset ) {
- IT_SAMPLE * s1 = &sigdata->sample[component[last].n];
- IT_SAMPLE * s2 = &sigdata->sample[component[m].n];
- if ( ( s1->flags | s2->flags ) & ( IT_SAMPLE_16BIT | IT_SAMPLE_STEREO ) ) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- if ( component[m].offset >= component[last].offset &&
- component[m].offset + s2->length <= component[last].offset + s1->length ) {
- s2->left = malloc( s2->length );
- if ( ! s2->left ) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- memcpy( s2->left, ( const char * ) s1->left + component[m].offset - component[last].offset, s2->length );
- last = -1;
- }
- }
- } else last = 0;
-
- if ( last >= 0 ) {
-#endif
- if (it_seek(f, component[m].offset)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (it_s3m_read_sample_data(&sigdata->sample[component[m].n], ffi, sample_pack[component[m].n], f)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
-#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
- last = m;
- }
-#endif
-
- m = component[m].sampnext;
- }
- }
-
- free(buffer);
- free(component);
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-static char hexdigit(int in)
-{
- if (in < 10) return in + '0';
- else return in + 'A' - 10;
-}
-
-DUH *dumb_read_s3m_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
- int cwtv;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_s3m_load_sigdata(f, &cwtv);
-
- if (!sigdata)
- return NULL;
-
- {
- char version[8];
- const char *tag[3][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "S3M";
- tag[2][0] = "TRACKERVERSION";
- version[0] = hexdigit((cwtv >> 8) & 15);
- version[1] = '.';
- version[2] = hexdigit((cwtv >> 4) & 15);
- version[3] = hexdigit(cwtv & 15);
- version[4] = 0;
- tag[2][1] = (const char *) &version;
- return make_duh(-1, 3, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * reads3m.c - Code to read a ScreamTracker 3 / / \ \
+ * module from an open file. | < / \_
+ * | \/ /\ /
+ * By entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+// IT_STEREO... :o
+#include <stdlib.h>
+#include <string.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+
+//#define S3M_BROKEN_OVERLAPPED_SAMPLES
+
+/** WARNING: this is duplicated in itread.c */
+static int it_seek(DUMBFILE *f, long offset)
+{
+ long pos = dumbfile_pos(f);
+
+ if (pos > offset) {
+ return -1;
+ }
+
+ if (pos < offset)
+ if (dumbfile_skip(f, offset - pos))
+ return -1;
+
+ return 0;
+}
+
+
+
+static int it_s3m_read_sample_header(IT_SAMPLE *sample, long *offset, unsigned char *pack, int cwtv, DUMBFILE *f)
+{
+ unsigned char type;
+ int flags;
+
+ type = dumbfile_getc(f);
+
+ dumbfile_getnc(sample->filename, 12, f);
+ sample->filename[12] = 0;
+
+ if (type > 1) {
+ /** WARNING: no adlib support */
+ dumbfile_skip(f, 3 + 12 + 1 + 1 + 2 + 2 + 2 + 12);
+ dumbfile_getnc(sample->name, 28, f);
+ sample->name[28] = 0;
+ dumbfile_skip(f, 4);
+ sample->flags &= ~IT_SAMPLE_EXISTS;
+ return -1; // return error so that another plugin could pick that file up
+ }
+
+ *offset = dumbfile_getc(f) << 20;
+ *offset += dumbfile_igetw(f) << 4;
+
+ sample->length = dumbfile_igetl(f);
+ sample->loop_start = dumbfile_igetl(f);
+ sample->loop_end = dumbfile_igetl(f);
+
+ sample->default_volume = dumbfile_getc(f);
+
+ dumbfile_skip(f, 1);
+
+ flags = dumbfile_getc(f);
+
+ if (flags < 0 || (flags != 0 && flags != 4))
+ /* Sample is packed apparently (or error reading from file). We don't
+ * know how to read packed samples.
+ */
+ return -1;
+
+ *pack = flags;
+
+ flags = dumbfile_getc(f);
+
+ sample->C5_speed = dumbfile_igetl(f) << 1;
+
+ /* Skip four unused bytes and three internal variables. */
+ dumbfile_skip(f, 4+2+2+4);
+
+ dumbfile_getnc(sample->name, 28, f);
+ sample->name[28] = 0;
+
+ if (type == 0 || sample->length <= 0) {
+ /* Looks like no-existy. Anyway, there's for sure no 'SCRS' ... */
+ sample->flags &= ~IT_SAMPLE_EXISTS;
+ return dumbfile_error(f);
+ }
+
+ if (dumbfile_mgetl(f) != DUMB_ID('S','C','R','S'))
+ return -1;
+
+ sample->global_volume = 64;
+
+ sample->flags = IT_SAMPLE_EXISTS;
+ if (flags & 1) sample->flags |= IT_SAMPLE_LOOP;
+
+ /* The ST3 TECH.DOC is unclear on this, but IMAGO Orpheus is not. Piece of crap. */
+
+ if (flags & 2) {
+ sample->flags |= IT_SAMPLE_STEREO;
+
+ if ((cwtv & 0xF000) == 0x2000) {
+ sample->length >>= 1;
+ sample->loop_start >>= 1;
+ sample->loop_end >>= 1;
+ }
+ }
+
+ if (flags & 4) {
+ sample->flags |= IT_SAMPLE_16BIT;
+
+ if ((cwtv & 0xF000) == 0x2000) {
+ sample->length >>= 1;
+ sample->loop_start >>= 1;
+ sample->loop_end >>= 1;
+ }
+ }
+
+ sample->default_pan = 0; // 0 = don't use, or 160 = centre?
+
+ if (sample->flags & IT_SAMPLE_LOOP) {
+ if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
+ /*sample->flags &= ~IT_SAMPLE_LOOP;*/
+ sample->loop_end = sample->length;
+ else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
+ sample->flags &= ~IT_SAMPLE_LOOP;
+ else
+ /* ScreamTracker seems not to save what comes after the loop end
+ * point, but rather to assume it is a duplicate of what comes at
+ * the loop start point. I am not completely sure of this though.
+ * It is easy to evade; simply truncate the sample.
+ */
+ sample->length = sample->loop_end;
+ }
+
+
+ //Do we need to set all these?
+ sample->vibrato_speed = 0;
+ sample->vibrato_depth = 0;
+ sample->vibrato_rate = 0;
+ sample->vibrato_waveform = IT_VIBRATO_SINE;
+ sample->finetune = 0;
+ sample->max_resampling_quality = -1;
+
+ return dumbfile_error(f);
+}
+
+
+
+static int it_s3m_read_sample_data(IT_SAMPLE *sample, int ffi, unsigned char pack, DUMBFILE *f)
+{
+ long n;
+
+ long datasize = sample->length;
+ if (sample->flags & IT_SAMPLE_STEREO) datasize <<= 1;
+
+ sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
+ if (!sample->data)
+ return -1;
+
+ if (pack == 4) {
+ if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
+ return -1;
+ }
+ else if (sample->flags & IT_SAMPLE_STEREO) {
+ if (sample->flags & IT_SAMPLE_16BIT) {
+ for (n = 0; n < datasize; n += 2)
+ ((short *)sample->data)[n] = dumbfile_igetw(f);
+ for (n = 1; n < datasize; n += 2)
+ ((short *)sample->data)[n] = dumbfile_igetw(f);
+ } else {
+ for (n = 0; n < datasize; n += 2)
+ ((signed char *)sample->data)[n] = dumbfile_getc(f);
+ for (n = 1; n < datasize; n += 2)
+ ((signed char *)sample->data)[n] = dumbfile_getc(f);
+ }
+ } else if (sample->flags & IT_SAMPLE_16BIT)
+ for (n = 0; n < sample->length; n++)
+ ((short *)sample->data)[n] = dumbfile_igetw(f);
+ else
+ for (n = 0; n < sample->length; n++)
+ ((signed char *)sample->data)[n] = dumbfile_getc(f);
+
+ if (dumbfile_error(f))
+ return -1;
+
+ if (ffi != 1) {
+ /* Convert to signed. */
+ if (sample->flags & IT_SAMPLE_16BIT)
+ for (n = 0; n < datasize; n++)
+ ((short *)sample->data)[n] ^= 0x8000;
+ else
+ for (n = 0; n < datasize; n++)
+ ((signed char *)sample->data)[n] ^= 0x80;
+ }
+
+ return 0;
+}
+
+
+
+static int it_s3m_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer, int maxlen)
+{
+ int length;
+ int buflen = 0;
+ int bufpos = 0;
+
+ IT_ENTRY *entry;
+
+ unsigned char channel;
+
+ /* Haha, this is hilarious!
+ *
+ * Well, after some experimentation, it seems that different S3M writers
+ * define the format in different ways. The S3M docs say that the first
+ * two bytes hold the "length of [the] packed pattern", and the packed
+ * pattern data follow. Judging by the contents of ARMANI.S3M, packaged
+ * with ScreamTracker itself, the measure of length _includes_ the two
+ * bytes used to store the length; in other words, we should read
+ * (length - 2) more bytes. However, aryx.s3m, packaged with ModPlug
+ * Tracker, excludes these two bytes, so (length) more bytes must be
+ * read.
+ *
+ * Call me crazy, but I just find it insanely funny that the format was
+ * misunderstood in this way :D
+ *
+ * Now we can't just risk reading two extra bytes, because then we
+ * overshoot, and DUMBFILEs don't support backward seeking (for a good
+ * reason). Luckily, there is a way. We can read the data little by
+ * little, and stop when we have 64 rows in memory. Provided we protect
+ * against buffer overflow, this method should work with all sensibly
+ * written S3M files. If you find one for which it does not work, please
+ * let me know at entheh@users.sf.net so I can look at it.
+ */
+
+ /* Discard the length. */
+ /* read at most length bytes, in case of retarded crap */
+ length = dumbfile_igetw(f);
+
+ if (maxlen)
+ {
+ maxlen -= 2;
+ if (length > maxlen) length = maxlen;
+ }
+
+ if (dumbfile_error(f) || !length)
+ return -1;
+
+ pattern->n_rows = 0;
+ pattern->n_entries = 0;
+
+ /* Read in the pattern data, little by little, and work out how many
+ * entries we need room for. Sorry, but this is just so funny...
+ */
+ for (;;) {
+ unsigned char b = buffer[buflen++] = dumbfile_getc(f);
+
+#if 1
+ static const unsigned char used[8] = {0, 2, 1, 3, 2, 4, 3, 5};
+ channel = b & 31;
+ b >>= 5;
+ pattern->n_entries++;
+ if (b) {
+ if (buflen + used[b] >= 65536) return -1;
+ if (buflen + used[b] <= length)
+ dumbfile_getnc(buffer + buflen, used[b], f);
+ else
+ memset(buffer + buflen, 0, used[b]);
+ buflen += used[b];
+ } else {
+ /* End of row */
+ if (++pattern->n_rows == 64) break;
+ if (buflen >= 65536) return -1;
+ }
+#else
+ if (b == 0) {
+ /* End of row */
+ pattern->n_entries++;
+ if (++pattern->n_rows == 64) break;
+ if (buflen >= 65536) return -1;
+ } else {
+ static const unsigned char used[8] = {0, 2, 1, 3, 2, 4, 3, 5};
+ channel = b & 31;
+ b >>= 5;
+ if (b) {
+ pattern->n_entries++;
+ if (buflen + used[b] >= 65536) return -1;
+ dumbfile_getnc(buffer + buflen, used[b], f);
+ buflen += used[b];
+ }
+ }
+#endif
+
+ /* We have ensured that buflen < 65536 at this point, so it is safe
+ * to iterate and read at least one more byte without checking.
+ * However, now would be a good time to check for errors reading from
+ * the file.
+ */
+
+ if (dumbfile_error(f))
+ return -1;
+
+ /* Great. We ran out of data, but there should be data for more rows.
+ * Fill the rest with null data...
+ */
+ if (buflen >= length && pattern->n_rows < 64)
+ {
+ while (pattern->n_rows < 64)
+ {
+ if (buflen >= 65536) return -1;
+ buffer[buflen++] = 0;
+ pattern->n_entries++;
+ pattern->n_rows++;
+ }
+ break;
+ }
+ }
+
+ pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
+
+ if (!pattern->entry)
+ return -1;
+
+ entry = pattern->entry;
+
+ while (bufpos < buflen) {
+ unsigned char b = buffer[bufpos++];
+
+#if 1
+ if (!(b & ~31))
+#else
+ if (b == 0)
+#endif
+ {
+ /* End of row */
+ IT_SET_END_ROW(entry);
+ entry++;
+ continue;
+ }
+
+ channel = b & 31;
+
+ if (b & 224) {
+ entry->mask = 0;
+ entry->channel = channel;
+
+ if (b & 32) {
+ unsigned char n = buffer[bufpos++];
+ if (n != 255) {
+ if (n == 254)
+ entry->note = IT_NOTE_CUT;
+ else
+ entry->note = (n >> 4) * 12 + (n & 15);
+ entry->mask |= IT_ENTRY_NOTE;
+ }
+
+ entry->instrument = buffer[bufpos++];
+ if (entry->instrument)
+ entry->mask |= IT_ENTRY_INSTRUMENT;
+ }
+
+ if (b & 64) {
+ entry->volpan = buffer[bufpos++];
+ if (entry->volpan != 255)
+ entry->mask |= IT_ENTRY_VOLPAN;
+ }
+
+ if (b & 128) {
+ entry->effect = buffer[bufpos++];
+ entry->effectvalue = buffer[bufpos++];
+ // XXX woot
+ if (entry->effect && entry->effect < IT_MIDI_MACRO /*!= 255*/) {
+ entry->mask |= IT_ENTRY_EFFECT;
+ switch (entry->effect) {
+ case IT_BREAK_TO_ROW:
+ entry->effectvalue -= (entry->effectvalue >> 4) * 6;
+ break;
+
+ case IT_SET_CHANNEL_VOLUME:
+ case IT_CHANNEL_VOLUME_SLIDE:
+ case IT_PANNING_SLIDE:
+ case IT_GLOBAL_VOLUME_SLIDE:
+ case IT_PANBRELLO:
+ case IT_MIDI_MACRO:
+ entry->mask &= ~IT_ENTRY_EFFECT;
+ break;
+
+ case IT_S:
+ switch (entry->effectvalue >> 4) {
+ case IT_S_SET_PANBRELLO_WAVEFORM:
+ case IT_S_FINE_PATTERN_DELAY:
+ case IT_S7:
+ case IT_S_SET_SURROUND_SOUND:
+ case IT_S_SET_MIDI_MACRO:
+ entry->mask &= ~IT_ENTRY_EFFECT;
+ break;
+ }
+ break;
+ }
+ }
+ /** WARNING: ARGH! CONVERT TEH EFFECTS!@~ */
+ }
+
+ entry++;
+ }
+ }
+
+ ASSERT(entry == pattern->entry + pattern->n_entries);
+
+ return 0;
+}
+
+
+
+/** WARNING: this is duplicated in itread.c - also bad practice to use the same struct name unless they are unified in a header */
+/* Currently we assume the sample data are stored after the sample headers in
+ * module files. This assumption may be unjustified; let me know if you have
+ * trouble.
+ */
+
+#define S3M_COMPONENT_INSTRUMENT 1
+#define S3M_COMPONENT_PATTERN 2
+#define S3M_COMPONENT_SAMPLE 3
+
+typedef struct S3M_COMPONENT
+{
+ unsigned char type;
+ unsigned char n;
+ long offset;
+ short sampfirst; /* component[sampfirst] = first sample data after this */
+ short sampnext; /* sampnext is used to create linked lists of sample data */
+}
+S3M_COMPONENT;
+
+
+
+static int s3m_component_compare(const void *e1, const void *e2)
+{
+ return ((const S3M_COMPONENT *)e1)->offset -
+ ((const S3M_COMPONENT *)e2)->offset;
+}
+
+
+
+static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv)
+{
+ DUMB_IT_SIGDATA *sigdata;
+
+ int flags, ffi;
+ int default_pan_present;
+
+ int master_volume;
+
+ unsigned char sample_pack[256];
+
+ S3M_COMPONENT *component;
+ int n_components = 0;
+
+ int n;
+
+ unsigned char *buffer;
+
+ sigdata = malloc(sizeof(*sigdata));
+ if (!sigdata) return NULL;
+
+ dumbfile_getnc(sigdata->name, 28, f);
+ sigdata->name[28] = 0;
+
+ n = dumbfile_getc(f);
+
+ if (n != 0x1A && n != 0) {
+ free(sigdata);
+ return NULL;
+ }
+
+ if (dumbfile_getc(f) != 16) {
+ free(sigdata);
+ return NULL;
+ }
+
+ dumbfile_skip(f, 2);
+
+ sigdata->song_message = NULL;
+ sigdata->order = NULL;
+ sigdata->instrument = NULL;
+ sigdata->sample = NULL;
+ sigdata->pattern = NULL;
+ sigdata->midi = NULL;
+ sigdata->checkpoint = NULL;
+
+ sigdata->n_orders = dumbfile_igetw(f);
+ sigdata->n_instruments = 0;
+ sigdata->n_samples = dumbfile_igetw(f);
+ sigdata->n_patterns = dumbfile_igetw(f);
+
+ if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_samples > 256 || sigdata->n_patterns > 256) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ sigdata->order = malloc(sigdata->n_orders);
+ if (!sigdata->order) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ if (sigdata->n_samples) {
+ sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
+ if (!sigdata->sample) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (n = 0; n < sigdata->n_samples; n++)
+ sigdata->sample[n].data = NULL;
+ }
+
+ if (sigdata->n_patterns) {
+ sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
+ if (!sigdata->pattern) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (n = 0; n < sigdata->n_patterns; n++)
+ sigdata->pattern[n].entry = NULL;
+ }
+
+ flags = dumbfile_igetw(f);
+
+ *cwtv = dumbfile_igetw(f);
+
+ if (*cwtv == 0x1300) {
+ /** WARNING: volume slides on every frame */
+ }
+
+ ffi = dumbfile_igetw(f);
+
+ /** WARNING: which ones? */
+ sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
+
+ if (dumbfile_mgetl(f) != DUMB_ID('S','C','R','M')) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ sigdata->global_volume = dumbfile_getc(f) << 1;
+ if ( !sigdata->global_volume || sigdata->global_volume > 128 ) sigdata->global_volume = 128;
+ sigdata->speed = dumbfile_getc(f);
+ if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
+ sigdata->tempo = dumbfile_getc(f);
+ master_volume = dumbfile_getc(f); // 7 bits; +128 for stereo
+ //what do we do with master_volume? it's not the same as mixing volume...
+ sigdata->mixing_volume = 48;
+
+ if (master_volume & 128) sigdata->flags |= IT_STEREO;
+
+ /* Skip GUS Ultra Click Removal byte. */
+ dumbfile_getc(f);
+
+ default_pan_present = dumbfile_getc(f);
+
+ dumbfile_skip(f, 8);
+
+ /* Skip Special Custom Data Pointer. */
+ /** WARNING: investigate this? */
+ dumbfile_igetw(f);
+
+ sigdata->n_pchannels = 0;
+ /* Channel settings for 32 channels, 255=unused, +128=disabled */
+ {
+ int i;
+ for (i = 0; i < 32; i++) {
+ int c = dumbfile_getc(f);
+ if (!(c & (128 | 16))) { /* +128=disabled, +16=Adlib */
+ if (sigdata->n_pchannels < i + 1) sigdata->n_pchannels = i + 1;
+ sigdata->channel_volume[i] = 64;
+ sigdata->channel_pan[i] = c & 8 ? 12 : 3;
+ /** WARNING: ah, but it should be 7 for mono... */
+ } else {
+ /** WARNING: this could be improved if we support channel muting... */
+ sigdata->channel_volume[i] = 0;
+ sigdata->channel_pan[i] = 7;
+ }
+ }
+ }
+
+ /* Orders, byte each, length = sigdata->n_orders (should be even) */
+ dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
+ sigdata->restart_position = 0;
+
+ component = malloc(768*sizeof(*component));
+ if (!component) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ for (n = 0; n < sigdata->n_samples; n++) {
+ component[n_components].type = S3M_COMPONENT_SAMPLE;
+ component[n_components].n = n;
+ component[n_components].offset = dumbfile_igetw(f) << 4;
+ component[n_components].sampfirst = -1;
+ n_components++;
+ }
+
+ for (n = 0; n < sigdata->n_patterns; n++) {
+ long offset = dumbfile_igetw(f) << 4;
+ if (offset) {
+ component[n_components].type = S3M_COMPONENT_PATTERN;
+ component[n_components].n = n;
+ component[n_components].offset = offset;
+ component[n_components].sampfirst = -1;
+ n_components++;
+ } else {
+ /** WARNING: Empty 64-row pattern ... ? (this does happen!) */
+ sigdata->pattern[n].n_rows = 64;
+ sigdata->pattern[n].n_entries = 0;
+ }
+ }
+
+ qsort(component, n_components, sizeof(S3M_COMPONENT), &s3m_component_compare);
+
+ /* I found a really dumb S3M file that claimed to contain default pan
+ * data but didn't contain any. Programs would load it by reading part of
+ * the first instrument header, assuming the data to be default pan
+ * positions, and then rereading the instrument module. We cannot do this
+ * without obfuscating the file input model, so we insert an extra check
+ * here that we won't overrun the start of the first component.
+ */
+ if (default_pan_present == 252 && component[0].offset >= dumbfile_pos(f) + 32) {
+ /* Channel default pan positions */
+ int i;
+ for (i = 0; i < 32; i++) {
+ int c = dumbfile_getc(f);
+ if (c & 32)
+ sigdata->channel_pan[i] = c & 15;
+ }
+ }
+
+ {
+ int i;
+ for (i = 0; i < 32; i++) {
+ sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3;
+ sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7;
+ }
+ }
+
+ sigdata->pan_separation = 128;
+
+ if (dumbfile_error(f)) {
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ buffer = malloc(65536);
+ if (!buffer) {
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ /* Voila, I must deal with a very dumb S3M myself. This file refers to the same file offset twice
+ * for two different patterns. Solution: Eliminate it.
+ */
+
+ for (n = 0; n < n_components; n++) {
+ if (component[n].type == S3M_COMPONENT_PATTERN) {
+ int m;
+ for (m = n + 1; m < n_components; m++) {
+ if (component[m].type == S3M_COMPONENT_PATTERN) {
+ if (component[n].offset == component[m].offset) {
+ int o, pattern;
+ pattern = component[m].n;
+ n_components--;
+ for (o = m; o < n_components; o++) {
+ component[o] = component[o + 1];
+ }
+ for (o = 0; o < sigdata->n_orders; o++) {
+ if (sigdata->order[o] == pattern) {
+ sigdata->order[o] = component[n].n;
+ }
+ }
+ sigdata->pattern[pattern].n_rows = 64;
+ sigdata->pattern[pattern].n_entries = 0;
+ m--;
+ } else
+ break;
+ }
+ }
+ }
+ }
+
+ for (n = 0; n < n_components; n++) {
+ long offset;
+ int m;
+#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
+ int last;
+#endif
+
+ if (it_seek(f, component[n].offset)) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ switch (component[n].type) {
+
+ case S3M_COMPONENT_PATTERN:
+ if (it_s3m_read_pattern(&sigdata->pattern[component[n].n], f, buffer, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0)) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ break;
+
+ case S3M_COMPONENT_SAMPLE:
+ {
+ int err = it_s3m_read_sample_header(&sigdata->sample[component[n].n], &offset, &sample_pack[component[n].n], *cwtv, f);
+ if (err) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ }
+
+ if (sigdata->sample[component[n].n].flags & IT_SAMPLE_EXISTS) {
+ short *sample;
+
+ for (m = n + 1; m < n_components; m++)
+ if (component[m].offset > offset)
+ break;
+ m--;
+
+ sample = &component[m].sampfirst;
+
+ while (*sample >= 0 && component[*sample].offset <= offset)
+ sample = &component[*sample].sampnext;
+
+ component[n].sampnext = *sample;
+ *sample = n;
+
+ component[n].offset = offset;
+ }
+ }
+
+ m = component[n].sampfirst;
+
+#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
+ last = -1;
+#endif
+
+ while (m >= 0) {
+ // XXX
+#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
+ if ( last >= 0 ) {
+ if ( dumbfile_pos( f ) > component[m].offset ) {
+ IT_SAMPLE * s1 = &sigdata->sample[component[last].n];
+ IT_SAMPLE * s2 = &sigdata->sample[component[m].n];
+ if ( ( s1->flags | s2->flags ) & ( IT_SAMPLE_16BIT | IT_SAMPLE_STEREO ) ) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ if ( component[m].offset >= component[last].offset &&
+ component[m].offset + s2->length <= component[last].offset + s1->length ) {
+ s2->left = malloc( s2->length );
+ if ( ! s2->left ) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ memcpy( s2->left, ( const char * ) s1->left + component[m].offset - component[last].offset, s2->length );
+ last = -1;
+ }
+ }
+ } else last = 0;
+
+ if ( last >= 0 ) {
+#endif
+ if (it_seek(f, component[m].offset)) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ if (it_s3m_read_sample_data(&sigdata->sample[component[m].n], ffi, sample_pack[component[m].n], f)) {
+ free(buffer);
+ free(component);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
+ last = m;
+ }
+#endif
+
+ m = component[m].sampnext;
+ }
+ }
+
+ free(buffer);
+ free(component);
+
+ _dumb_it_fix_invalid_orders(sigdata);
+
+ return sigdata;
+}
+
+static char hexdigit(int in)
+{
+ if (in < 10) return in + '0';
+ else return in + 'A' - 10;
+}
+
+DUH *dumb_read_s3m_quick(DUMBFILE *f)
+{
+ sigdata_t *sigdata;
+ int cwtv;
+
+ DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
+
+ sigdata = it_s3m_load_sigdata(f, &cwtv);
+
+ if (!sigdata)
+ return NULL;
+
+ {
+ char version[8];
+ const char *tag[3][2];
+ tag[0][0] = "TITLE";
+ tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+ tag[1][0] = "FORMAT";
+ tag[1][1] = "S3M";
+ tag[2][0] = "TRACKERVERSION";
+ version[0] = hexdigit((cwtv >> 8) & 15);
+ version[1] = '.';
+ version[2] = hexdigit((cwtv >> 4) & 15);
+ version[3] = hexdigit(cwtv & 15);
+ version[4] = 0;
+ tag[2][1] = (const char *) &version;
+ return make_duh(-1, 3, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/reads3m2.c b/plugins/dumb/dumb-kode54/src/it/reads3m2.c
index 0499eecd..c9447c26 100644
--- a/plugins/dumb/dumb-kode54/src/it/reads3m2.c
+++ b/plugins/dumb/dumb-kode54/src/it/reads3m2.c
@@ -1,29 +1,29 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * reads3m2.c - Function to read a ScreamTracker 3 / / \ \
- * module from an open file and do an | < / \_
- * initial run-through. | \/ /\ /
- * \_ / > /
- * Split off from reads3m.c by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_read_s3m(DUMBFILE *f)
-{
- DUH *duh = dumb_read_s3m_quick(f);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * reads3m2.c - Function to read a ScreamTracker 3 / / \ \
+ * module from an open file and do an | < / \_
+ * initial run-through. | \/ /\ /
+ * \_ / > /
+ * Split off from reads3m.c by entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_read_s3m(DUMBFILE *f)
+{
+ DUH *duh = dumb_read_s3m_quick(f);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/readstm.c b/plugins/dumb/dumb-kode54/src/it/readstm.c
index 5972a0f7..edfa4c19 100644
--- a/plugins/dumb/dumb-kode54/src/it/readstm.c
+++ b/plugins/dumb/dumb-kode54/src/it/readstm.c
@@ -1,397 +1,397 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readstm.c - Code to read a ScreamTracker 2 / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-// IT_STEREO... :o
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-/** WARNING: this is duplicated in itread.c */
-static int it_seek(DUMBFILE *f, long offset)
-{
- long pos = dumbfile_pos(f);
-
- if (pos > offset) {
- return -1;
- }
-
- if (pos < offset)
- if (dumbfile_skip(f, offset - pos))
- return -1;
-
- return 0;
-}
-
-static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f )
-{
- dumbfile_getnc( sample->filename, 12, f );
- sample->filename[12] = 0;
-
- memcpy( sample->name, sample->filename, 13 );
-
- dumbfile_skip( f, 2 + 2 );
-
- sample->length = dumbfile_igetw( f );
- sample->loop_start = dumbfile_igetw( f );
- sample->loop_end = dumbfile_igetw( f );
-
- sample->default_volume = dumbfile_getc( f );
-
- dumbfile_skip( f, 1 );
-
- sample->C5_speed = dumbfile_igetw( f ) << 3;
-
- dumbfile_skip( f, 6 );
-
- if ( sample->length < 4 || !sample->default_volume ) {
- /* Looks like no-existy. */
- sample->flags &= ~IT_SAMPLE_EXISTS;
- sample->length = 0;
- return dumbfile_error( f );
- }
-
- sample->flags = IT_SAMPLE_EXISTS;
- sample->global_volume = 64;
- sample->default_pan = 0; // 0 = don't use, or 160 = centre?
-
- if ( ( sample->loop_start < sample->length ) &&
- ( sample->loop_end > sample->loop_start ) &&
- ( sample->loop_end != 0xFFFF ) ) {
- sample->flags |= IT_SAMPLE_LOOP;
- if ( sample->loop_end > sample->length ) sample->loop_end = sample->length;
- }
-
- //Do we need to set all these?
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = IT_VIBRATO_SINE;
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-static int it_stm_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f )
-{
- long n;
-
- if ( ! sample->length ) return 0;
-
- n = dumbfile_pos( f );
- if ( n & 15 ) {
- if ( dumbfile_skip( f, 16 - ( n & 15 ) ) )
- return -1;
- }
-
- sample->data = malloc( sample->length );
- if (!sample->data)
- return -1;
-
- if ( dumbfile_getnc( sample->data, sample->length, f ) != sample->length )
- return -1;
-
- return 0;
-}
-
-static int it_stm_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer )
-{
- int pos;
- int channel;
- int row;
- IT_ENTRY *entry;
-
- pattern->n_rows = 64;
-
- if ( dumbfile_getnc( buffer, 64 * 4 * 4, f ) != 64 * 4 * 4 )
- return -1;
-
- pattern->n_entries = 64;
- pos = 0;
- for ( row = 0; row < 64; ++row ) {
- for ( channel = 0; channel < 4; ++channel ) {
- if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] )
- ++pattern->n_entries;
- pos += 4;
- }
- }
-
- pattern->entry = malloc( pattern->n_entries * sizeof( *pattern->entry ) );
- if ( !pattern->entry )
- return -1;
-
- entry = pattern->entry;
- pos = 0;
- for ( row = 0; row < 64; ++row ) {
- for ( channel = 0; channel < 4; ++channel ) {
- if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) {
- unsigned note;
- note = buffer[ pos + 0 ];
- entry->channel = channel;
- entry->mask = 0;
- entry->instrument = buffer[ pos + 1 ] >> 3;
- entry->volpan = ( buffer[ pos + 1 ] & 0x07 ) + ( buffer[ pos + 2 ] >> 1 );
- entry->effect = buffer[ pos + 2 ] & 0x0F;
- entry->effectvalue = buffer[ pos + 3 ];
- if ( entry->instrument && entry->instrument < 32 )
- entry->mask |= IT_ENTRY_INSTRUMENT;
- if ( note == 0xFC || note == 0xFE ) {
- entry->mask |= IT_ENTRY_NOTE;
- entry->note = IT_NOTE_CUT;
- }
- if ( note < 251 ) {
- entry->mask |= IT_ENTRY_NOTE;
- entry->note = ( note >> 4 ) * 12 + ( note & 0x0F );
- }
- if ( entry->volpan <= 64 )
- entry->mask |= IT_ENTRY_VOLPAN;
- entry->mask |= IT_ENTRY_EFFECT;
- switch ( entry->effect ) {
- case IT_SET_SPEED:
- entry->effectvalue >>= 4;
- break;
-
- case IT_BREAK_TO_ROW:
- entry->effectvalue -= (entry->effectvalue >> 4) * 6;
- break;
-
- case IT_JUMP_TO_ORDER:
- case IT_VOLUME_SLIDE:
- case IT_PORTAMENTO_DOWN:
- case IT_PORTAMENTO_UP:
- case IT_TONE_PORTAMENTO:
- case IT_VIBRATO:
- case IT_TREMOR:
- case IT_ARPEGGIO:
- case IT_VOLSLIDE_VIBRATO:
- case IT_VOLSLIDE_TONEPORTA:
- break;
-
- default:
- entry->mask &= ~IT_ENTRY_EFFECT;
- break;
- }
- if ( entry->mask ) ++entry;
- }
- pos += 4;
- }
- IT_SET_END_ROW(entry);
- ++entry;
- }
-
- pattern->n_entries = entry - pattern->entry;
-
- return 0;
-}
-
-
-
-static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- char tracker_name[ 8 ];
-
- int n;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) return NULL;
-
- /* Skip song name. */
- dumbfile_getnc(sigdata->name, 20, f);
- sigdata->name[20] = 0;
-
- dumbfile_getnc(tracker_name, 8, f);
- n = dumbfile_getc(f);
- if ( n != 0x02 && n != 0x1A && n != 0x1B )
- {
- free( sigdata );
- return NULL;
- }
- if ( dumbfile_getc(f) != 2 ) /* only support modules */
- {
- free( sigdata );
- return NULL;
- }
- if ( strncasecmp( tracker_name, "!Scream!", 8 ) &&
- strncasecmp( tracker_name, "BMOD2STM", 8 ) &&
- strncasecmp( tracker_name, "WUZAMOD!", 8 ) )
- {
- free( sigdata );
- return NULL;
- }
-
- /* *version = dumbfile_mgetw(f); */
- dumbfile_skip( f, 2 );
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_instruments = 0;
- sigdata->n_samples = 31;
- sigdata->n_pchannels = 4;
-
- sigdata->tempo = 125;
- sigdata->mixing_volume = 48;
- sigdata->pan_separation = 128;
-
- /** WARNING: which ones? */
- sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
-
- sigdata->speed = dumbfile_getc(f) >> 4;
- if ( sigdata->speed < 1 ) sigdata->speed = 1;
- sigdata->n_patterns = dumbfile_getc(f);
- sigdata->global_volume = dumbfile_getc(f) << 1;
- if ( sigdata->global_volume > 128 ) sigdata->global_volume = 128;
-
- dumbfile_skip(f, 13);
-
- if ( dumbfile_error(f) || sigdata->n_patterns < 1 || sigdata->n_patterns > 99 ) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
-
- if (sigdata->n_patterns) {
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
- }
-
- memset( sigdata->channel_volume, 64, 4 );
- sigdata->channel_pan[ 0 ] = 48;
- sigdata->channel_pan[ 1 ] = 16;
- sigdata->channel_pan[ 2 ] = 48;
- sigdata->channel_pan[ 3 ] = 16;
-
- for ( n = 0; n < sigdata->n_samples; ++n ) {
- if ( it_stm_read_sample_header( &sigdata->sample[ n ], f ) ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- }
-
- sigdata->order = malloc( 128 );
- if ( !sigdata->order ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
-
- /* Orders, byte each, length = sigdata->n_orders (should be even) */
- dumbfile_getnc( sigdata->order, 128, f );
- sigdata->restart_position = 0;
-
- for ( n = 127; n >= 0; --n ) {
- if ( sigdata->order[ n ] < sigdata->n_patterns ) break;
- }
- if ( n < 0 ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- sigdata->n_orders = n + 1;
-
- for ( n = 0; n < 128; ++n ) {
- if ( sigdata->order[ n ] >= 99 ) sigdata->order[ n ] = 0xFF;
- }
-
- if ( sigdata->n_patterns ) {
- unsigned char * buffer = malloc( 64 * 4 * 4 );
- if ( ! buffer ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- for ( n = 0; n < sigdata->n_patterns; ++n ) {
- if ( it_stm_read_pattern( &sigdata->pattern[ n ], f, buffer ) ) {
- free( buffer );
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- }
- free( buffer );
- }
-
- for ( n = 0; n < sigdata->n_samples; ++n ) {
- if ( it_stm_read_sample_data( &sigdata->sample[ n ], f ) ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- }
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-/*static char hexdigit(int in)
-{
- if (in < 10) return in + '0';
- else return in + 'A' - 10;
-}*/
-
-DUH *dumb_read_stm_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
- /*int ver;*/
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_stm_load_sigdata(f /*, &ver*/);
-
- if (!sigdata)
- return NULL;
-
- {
- /*char version[16];*/
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "STM";
- /*version[0] = 'S';
- version[1] = 'T';
- version[2] = 'M';
- version[3] = ' ';
- version[4] = 'v';
- version[5] = hexdigit((ver >> 8) & 15);
- version[6] = '.';
- version[7] = hexdigit((ver >> 4) & 15);
- version[8] = hexdigit(ver & 15);
- version[9] = 0;
- tag[1][1] = (const char *) &version;*/
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readstm.c - Code to read a ScreamTracker 2 / / \ \
+ * module from an open file. | < / \_
+ * | \/ /\ /
+ * By Chris Moeller. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+// IT_STEREO... :o
+#include <stdlib.h>
+#include <string.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+
+/** WARNING: this is duplicated in itread.c */
+static int it_seek(DUMBFILE *f, long offset)
+{
+ long pos = dumbfile_pos(f);
+
+ if (pos > offset) {
+ return -1;
+ }
+
+ if (pos < offset)
+ if (dumbfile_skip(f, offset - pos))
+ return -1;
+
+ return 0;
+}
+
+static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f )
+{
+ dumbfile_getnc( sample->filename, 12, f );
+ sample->filename[12] = 0;
+
+ memcpy( sample->name, sample->filename, 13 );
+
+ dumbfile_skip( f, 2 + 2 );
+
+ sample->length = dumbfile_igetw( f );
+ sample->loop_start = dumbfile_igetw( f );
+ sample->loop_end = dumbfile_igetw( f );
+
+ sample->default_volume = dumbfile_getc( f );
+
+ dumbfile_skip( f, 1 );
+
+ sample->C5_speed = dumbfile_igetw( f ) << 3;
+
+ dumbfile_skip( f, 6 );
+
+ if ( sample->length < 4 || !sample->default_volume ) {
+ /* Looks like no-existy. */
+ sample->flags &= ~IT_SAMPLE_EXISTS;
+ sample->length = 0;
+ return dumbfile_error( f );
+ }
+
+ sample->flags = IT_SAMPLE_EXISTS;
+ sample->global_volume = 64;
+ sample->default_pan = 0; // 0 = don't use, or 160 = centre?
+
+ if ( ( sample->loop_start < sample->length ) &&
+ ( sample->loop_end > sample->loop_start ) &&
+ ( sample->loop_end != 0xFFFF ) ) {
+ sample->flags |= IT_SAMPLE_LOOP;
+ if ( sample->loop_end > sample->length ) sample->loop_end = sample->length;
+ }
+
+ //Do we need to set all these?
+ sample->vibrato_speed = 0;
+ sample->vibrato_depth = 0;
+ sample->vibrato_rate = 0;
+ sample->vibrato_waveform = IT_VIBRATO_SINE;
+ sample->finetune = 0;
+ sample->max_resampling_quality = -1;
+
+ return dumbfile_error(f);
+}
+
+static int it_stm_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f )
+{
+ long n;
+
+ if ( ! sample->length ) return 0;
+
+ n = dumbfile_pos( f );
+ if ( n & 15 ) {
+ if ( dumbfile_skip( f, 16 - ( n & 15 ) ) )
+ return -1;
+ }
+
+ sample->data = malloc( sample->length );
+ if (!sample->data)
+ return -1;
+
+ if ( dumbfile_getnc( sample->data, sample->length, f ) != sample->length )
+ return -1;
+
+ return 0;
+}
+
+static int it_stm_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer )
+{
+ int pos;
+ int channel;
+ int row;
+ IT_ENTRY *entry;
+
+ pattern->n_rows = 64;
+
+ if ( dumbfile_getnc( buffer, 64 * 4 * 4, f ) != 64 * 4 * 4 )
+ return -1;
+
+ pattern->n_entries = 64;
+ pos = 0;
+ for ( row = 0; row < 64; ++row ) {
+ for ( channel = 0; channel < 4; ++channel ) {
+ if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] )
+ ++pattern->n_entries;
+ pos += 4;
+ }
+ }
+
+ pattern->entry = malloc( pattern->n_entries * sizeof( *pattern->entry ) );
+ if ( !pattern->entry )
+ return -1;
+
+ entry = pattern->entry;
+ pos = 0;
+ for ( row = 0; row < 64; ++row ) {
+ for ( channel = 0; channel < 4; ++channel ) {
+ if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) {
+ unsigned note;
+ note = buffer[ pos + 0 ];
+ entry->channel = channel;
+ entry->mask = 0;
+ entry->instrument = buffer[ pos + 1 ] >> 3;
+ entry->volpan = ( buffer[ pos + 1 ] & 0x07 ) + ( buffer[ pos + 2 ] >> 1 );
+ entry->effect = buffer[ pos + 2 ] & 0x0F;
+ entry->effectvalue = buffer[ pos + 3 ];
+ if ( entry->instrument && entry->instrument < 32 )
+ entry->mask |= IT_ENTRY_INSTRUMENT;
+ if ( note == 0xFC || note == 0xFE ) {
+ entry->mask |= IT_ENTRY_NOTE;
+ entry->note = IT_NOTE_CUT;
+ }
+ if ( note < 251 ) {
+ entry->mask |= IT_ENTRY_NOTE;
+ entry->note = ( note >> 4 ) * 12 + ( note & 0x0F );
+ }
+ if ( entry->volpan <= 64 )
+ entry->mask |= IT_ENTRY_VOLPAN;
+ entry->mask |= IT_ENTRY_EFFECT;
+ switch ( entry->effect ) {
+ case IT_SET_SPEED:
+ entry->effectvalue >>= 4;
+ break;
+
+ case IT_BREAK_TO_ROW:
+ entry->effectvalue -= (entry->effectvalue >> 4) * 6;
+ break;
+
+ case IT_JUMP_TO_ORDER:
+ case IT_VOLUME_SLIDE:
+ case IT_PORTAMENTO_DOWN:
+ case IT_PORTAMENTO_UP:
+ case IT_TONE_PORTAMENTO:
+ case IT_VIBRATO:
+ case IT_TREMOR:
+ case IT_ARPEGGIO:
+ case IT_VOLSLIDE_VIBRATO:
+ case IT_VOLSLIDE_TONEPORTA:
+ break;
+
+ default:
+ entry->mask &= ~IT_ENTRY_EFFECT;
+ break;
+ }
+ if ( entry->mask ) ++entry;
+ }
+ pos += 4;
+ }
+ IT_SET_END_ROW(entry);
+ ++entry;
+ }
+
+ pattern->n_entries = entry - pattern->entry;
+
+ return 0;
+}
+
+
+
+static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/)
+{
+ DUMB_IT_SIGDATA *sigdata;
+
+ char tracker_name[ 8 ];
+
+ int n;
+
+ sigdata = malloc(sizeof(*sigdata));
+ if (!sigdata) return NULL;
+
+ /* Skip song name. */
+ dumbfile_getnc(sigdata->name, 20, f);
+ sigdata->name[20] = 0;
+
+ dumbfile_getnc(tracker_name, 8, f);
+ n = dumbfile_getc(f);
+ if ( n != 0x02 && n != 0x1A && n != 0x1B )
+ {
+ free( sigdata );
+ return NULL;
+ }
+ if ( dumbfile_getc(f) != 2 ) /* only support modules */
+ {
+ free( sigdata );
+ return NULL;
+ }
+ if ( strncasecmp( tracker_name, "!Scream!", 8 ) &&
+ strncasecmp( tracker_name, "BMOD2STM", 8 ) &&
+ strncasecmp( tracker_name, "WUZAMOD!", 8 ) )
+ {
+ free( sigdata );
+ return NULL;
+ }
+
+ /* *version = dumbfile_mgetw(f); */
+ dumbfile_skip( f, 2 );
+
+ sigdata->song_message = NULL;
+ sigdata->order = NULL;
+ sigdata->instrument = NULL;
+ sigdata->sample = NULL;
+ sigdata->pattern = NULL;
+ sigdata->midi = NULL;
+ sigdata->checkpoint = NULL;
+
+ sigdata->n_instruments = 0;
+ sigdata->n_samples = 31;
+ sigdata->n_pchannels = 4;
+
+ sigdata->tempo = 125;
+ sigdata->mixing_volume = 48;
+ sigdata->pan_separation = 128;
+
+ /** WARNING: which ones? */
+ sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
+
+ sigdata->speed = dumbfile_getc(f) >> 4;
+ if ( sigdata->speed < 1 ) sigdata->speed = 1;
+ sigdata->n_patterns = dumbfile_getc(f);
+ sigdata->global_volume = dumbfile_getc(f) << 1;
+ if ( sigdata->global_volume > 128 ) sigdata->global_volume = 128;
+
+ dumbfile_skip(f, 13);
+
+ if ( dumbfile_error(f) || sigdata->n_patterns < 1 || sigdata->n_patterns > 99 ) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
+ if (!sigdata->sample) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (n = 0; n < sigdata->n_samples; n++)
+ sigdata->sample[n].data = NULL;
+
+ if (sigdata->n_patterns) {
+ sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
+ if (!sigdata->pattern) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (n = 0; n < sigdata->n_patterns; n++)
+ sigdata->pattern[n].entry = NULL;
+ }
+
+ memset( sigdata->channel_volume, 64, 4 );
+ sigdata->channel_pan[ 0 ] = 48;
+ sigdata->channel_pan[ 1 ] = 16;
+ sigdata->channel_pan[ 2 ] = 48;
+ sigdata->channel_pan[ 3 ] = 16;
+
+ for ( n = 0; n < sigdata->n_samples; ++n ) {
+ if ( it_stm_read_sample_header( &sigdata->sample[ n ], f ) ) {
+ _dumb_it_unload_sigdata( sigdata );
+ return NULL;
+ }
+ }
+
+ sigdata->order = malloc( 128 );
+ if ( !sigdata->order ) {
+ _dumb_it_unload_sigdata( sigdata );
+ return NULL;
+ }
+
+ /* Orders, byte each, length = sigdata->n_orders (should be even) */
+ dumbfile_getnc( sigdata->order, 128, f );
+ sigdata->restart_position = 0;
+
+ for ( n = 127; n >= 0; --n ) {
+ if ( sigdata->order[ n ] < sigdata->n_patterns ) break;
+ }
+ if ( n < 0 ) {
+ _dumb_it_unload_sigdata( sigdata );
+ return NULL;
+ }
+ sigdata->n_orders = n + 1;
+
+ for ( n = 0; n < 128; ++n ) {
+ if ( sigdata->order[ n ] >= 99 ) sigdata->order[ n ] = 0xFF;
+ }
+
+ if ( sigdata->n_patterns ) {
+ unsigned char * buffer = malloc( 64 * 4 * 4 );
+ if ( ! buffer ) {
+ _dumb_it_unload_sigdata( sigdata );
+ return NULL;
+ }
+ for ( n = 0; n < sigdata->n_patterns; ++n ) {
+ if ( it_stm_read_pattern( &sigdata->pattern[ n ], f, buffer ) ) {
+ free( buffer );
+ _dumb_it_unload_sigdata( sigdata );
+ return NULL;
+ }
+ }
+ free( buffer );
+ }
+
+ for ( n = 0; n < sigdata->n_samples; ++n ) {
+ if ( it_stm_read_sample_data( &sigdata->sample[ n ], f ) ) {
+ _dumb_it_unload_sigdata( sigdata );
+ return NULL;
+ }
+ }
+
+ _dumb_it_fix_invalid_orders(sigdata);
+
+ return sigdata;
+}
+
+/*static char hexdigit(int in)
+{
+ if (in < 10) return in + '0';
+ else return in + 'A' - 10;
+}*/
+
+DUH *dumb_read_stm_quick(DUMBFILE *f)
+{
+ sigdata_t *sigdata;
+ /*int ver;*/
+
+ DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
+
+ sigdata = it_stm_load_sigdata(f /*, &ver*/);
+
+ if (!sigdata)
+ return NULL;
+
+ {
+ /*char version[16];*/
+ const char *tag[2][2];
+ tag[0][0] = "TITLE";
+ tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+ tag[1][0] = "FORMAT";
+ tag[1][1] = "STM";
+ /*version[0] = 'S';
+ version[1] = 'T';
+ version[2] = 'M';
+ version[3] = ' ';
+ version[4] = 'v';
+ version[5] = hexdigit((ver >> 8) & 15);
+ version[6] = '.';
+ version[7] = hexdigit((ver >> 4) & 15);
+ version[8] = hexdigit(ver & 15);
+ version[9] = 0;
+ tag[1][1] = (const char *) &version;*/
+ return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/readstm2.c b/plugins/dumb/dumb-kode54/src/it/readstm2.c
index c336b2a3..dab2c9b7 100644
--- a/plugins/dumb/dumb-kode54/src/it/readstm2.c
+++ b/plugins/dumb/dumb-kode54/src/it/readstm2.c
@@ -1,29 +1,29 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readstm2.c - Function to read a ScreamTracker 2 / / \ \
- * module from an open file and do an | < / \_
- * initial run-through. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_read_stm(DUMBFILE *f)
-{
- DUH *duh = dumb_read_stm_quick(f);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readstm2.c - Function to read a ScreamTracker 2 / / \ \
+ * module from an open file and do an | < / \_
+ * initial run-through. | \/ /\ /
+ * \_ / > /
+ * By Chris Moeller. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_read_stm(DUMBFILE *f)
+{
+ DUH *duh = dumb_read_stm_quick(f);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/readxm.c b/plugins/dumb/dumb-kode54/src/it/readxm.c
index c76d0f3e..7ceed801 100644
--- a/plugins/dumb/dumb-kode54/src/it/readxm.c
+++ b/plugins/dumb/dumb-kode54/src/it/readxm.c
@@ -1,1210 +1,1216 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readxm.c - Code to read a Fast Tracker II / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * By Julien Cugniere. Some bits of code taken \_ / > /
- * from reads3m.c. | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/** TODO:
-
- * XM_TREMOLO doesn't sound quite right...
- * XM_SET_ENVELOPE_POSITION todo.
-
- * VIBRATO conversion needs to be checked (sample/effect/volume). Plus check
- that effect memory is correct when using XM_VOLSLIDE_VIBRATO.
- - sample vibrato (instrument vibrato) is now handled correctly. - entheh
-
- * XM_E_SET_VIBRATO/TREMOLO_CONTROL: effectvalue&4 -> don't retrig wave when
- a new instrument is played. In retrigger_note()?. Is it worth implementing?
-
- * Lossy fadeout approximation. 0..31 converted to 0 --> won't fade at all.
-
- * Replace DUMB's sawtooth by ramp_down/ramp_up. Update XM loader.
-
- * A lot of things need to be reset when the end of the song is reached.
-
- * It seems that IT and XM don't behave the same way when dealing with
- mixed loops. When IT encounters multiple SBx (x>0) commands on the same
- row, it decrements the loop count for all, but only execute the loop of
- the last one (highest channel). FT2 only decrements the loop count of the
- last one. Not that I know of any modules using so convoluted combinations!
-
- * Maybe we could remove patterns that don't appear in the order table ? Or
- provide a function to "optimize" a DUMB_IT_SIGDATA ?
-
-*/
-
-
-
-#define XM_LINEAR_FREQUENCY 1 /* otherwise, use amiga slides */
-
-#define XM_ENTRY_PACKED 128
-#define XM_ENTRY_NOTE 1
-#define XM_ENTRY_INSTRUMENT 2
-#define XM_ENTRY_VOLUME 4
-#define XM_ENTRY_EFFECT 8
-#define XM_ENTRY_EFFECTVALUE 16
-
-#define XM_NOTE_OFF 97
-
-#define XM_ENVELOPE_ON 1
-#define XM_ENVELOPE_SUSTAIN 2
-#define XM_ENVELOPE_LOOP 4
-
-#define XM_SAMPLE_NO_LOOP 0
-#define XM_SAMPLE_FORWARD_LOOP 1
-#define XM_SAMPLE_PINGPONG_LOOP 2
-#define XM_SAMPLE_16BIT 16
-#define XM_SAMPLE_STEREO 32
-
-#define XM_VIBRATO_SINE 0
-#define XM_VIBRATO_SQUARE 1
-#define XM_VIBRATO_RAMP_DOWN 2
-#define XM_VIBRATO_RAMP_UP 3
-
-
-
-/* Probably useless :) */
-const char xm_convert_vibrato[] = {
- IT_VIBRATO_SINE,
- IT_VIBRATO_XM_SQUARE,
- IT_VIBRATO_RAMP_DOWN,
- IT_VIBRATO_RAMP_UP,
- IT_VIBRATO_RANDOM
-};
-
-
-
-#define XM_MAX_SAMPLES_PER_INSTRUMENT 16
-
-
-
-/* Extra data that doesn't fit inside IT_INSTRUMENT */
-typedef struct XM_INSTRUMENT_EXTRA
-{
- int n_samples;
- int vibrato_type;
- int vibrato_sweep; /* 0-0xFF */
- int vibrato_depth; /* 0-0x0F */
- int vibrato_speed; /* 0-0x3F */
-}
-XM_INSTRUMENT_EXTRA;
-
-
-
-/* Frees the original block if it can't resize it or if size is 0, and acts
- * as malloc if ptr is NULL.
- */
-static void *safe_realloc(void *ptr, size_t size)
-{
- if (ptr == NULL)
- return malloc(size);
-
- if (size == 0) {
- free(ptr);
- return NULL;
- } else {
- void *new_block = realloc(ptr, size);
- if (!new_block)
- free(ptr);
- return new_block;
- }
-}
-
-
-
-/* The interpretation of the XM volume column is left to the player. Here, we
- * just filter bad values.
- */
-// This function is so tiny now, should we inline it?
-static void it_xm_convert_volume(int volume, IT_ENTRY *entry)
-{
- entry->mask |= IT_ENTRY_VOLPAN;
- entry->volpan = volume;
-
- switch (volume >> 4) {
- case 0xA: /* set vibrato speed */
- case 0xB: /* vibrato */
- case 0xF: /* tone porta */
- case 0x6: /* vol slide up */
- case 0x7: /* vol slide down */
- case 0x8: /* fine vol slide up */
- case 0x9: /* fine vol slide down */
- case 0xC: /* set panning */
- case 0xD: /* pan slide left */
- case 0xE: /* pan slide right */
- case 0x1: /* set volume */
- case 0x2: /* set volume */
- case 0x3: /* set volume */
- case 0x4: /* set volume */
- break;
-
- case 0x5:
- if (volume == 0x50)
- break; /* set volume */
- /* else fall through */
-
- default:
- entry->mask &= ~IT_ENTRY_VOLPAN;
- break;
- }
-}
-
-
-
-static int it_xm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer, int version)
-{
- int size;
- int pos;
- int channel;
- int row;
- int effect, effectvalue;
- IT_ENTRY *entry;
-
- /* pattern header size */
- if (dumbfile_igetl(f) != ( version == 0x0102 ? 0x08 : 0x09 ) ) {
- TRACE("XM error: unexpected pattern header size\n");
- return -1;
- }
-
- /* pattern data packing type */
- if (dumbfile_getc(f) != 0) {
- TRACE("XM error: unexpected pattern packing type\n");
- return -1;
- }
-
- if ( version == 0x0102 )
- pattern->n_rows = dumbfile_getc(f) + 1;
- else
- pattern->n_rows = dumbfile_igetw(f); /* 1..256 */
- size = dumbfile_igetw(f);
- pattern->n_entries = 0;
-
- if (dumbfile_error(f))
- return -1;
-
- if (size == 0)
- return 0;
-
- if (size > 1280 * n_channels) {
- TRACE("XM error: pattern data size > %d bytes\n", 1280 * n_channels);
- return -1;
- }
-
- if (dumbfile_getnc(buffer, size, f) < size)
- return -1;
-
- /* compute number of entries */
- pattern->n_entries = 0;
- pos = channel = row = 0;
- while (pos < size) {
- if (!(buffer[pos] & XM_ENTRY_PACKED) || (buffer[pos] & 31))
- pattern->n_entries++;
-
- channel++;
- if (channel >= n_channels) {
- channel = 0;
- row++;
- pattern->n_entries++;
- }
-
- if (buffer[pos] & XM_ENTRY_PACKED) {
- static const char offset[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5 };
- pos += 1 + offset[buffer[pos] & 31];
- } else {
- pos += 5;
- }
- }
-
- if (row > pattern->n_rows) {
- TRACE("XM error: wrong number of rows in pattern data\n");
- return -1;
- }
-
- /* Whoops, looks like some modules may be short, a few channels, maybe even rows... */
-
- while (row < pattern->n_rows)
- {
- pattern->n_entries++;
- row++;
- }
-
- pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
- if (!pattern->entry)
- return -1;
-
- /* read the entries */
- entry = pattern->entry;
- pos = channel = row = 0;
- while (pos < size) {
- unsigned char mask;
-
- if (buffer[pos] & XM_ENTRY_PACKED)
- mask = buffer[pos++] & 31;
- else
- mask = 31;
-
- if (mask) {
- ASSERT(entry < pattern->entry + pattern->n_entries);
-
- entry->channel = channel;
- entry->mask = 0;
-
- if (mask & XM_ENTRY_NOTE) {
- int note = buffer[pos++]; /* 1-96 <=> C0-B7 */
- entry->note = (note == XM_NOTE_OFF) ? (IT_NOTE_OFF) : (note-1);
- entry->mask |= IT_ENTRY_NOTE;
- }
-
- if (mask & XM_ENTRY_INSTRUMENT) {
- entry->instrument = buffer[pos++]; /* 1-128 */
- entry->mask |= IT_ENTRY_INSTRUMENT;
- }
-
- if (mask & XM_ENTRY_VOLUME)
- it_xm_convert_volume(buffer[pos++], entry);
-
- effect = effectvalue = 0;
- if (mask & XM_ENTRY_EFFECT) effect = buffer[pos++];
- if (mask & XM_ENTRY_EFFECTVALUE) effectvalue = buffer[pos++];
- _dumb_it_xm_convert_effect(effect, effectvalue, entry, 0);
-
- entry++;
- }
-
- channel++;
- if (channel >= n_channels) {
- channel = 0;
- row++;
- IT_SET_END_ROW(entry);
- entry++;
- }
- }
-
- while (row < pattern->n_rows)
- {
- row++;
- IT_SET_END_ROW(entry);
- entry++;
- }
-
- return 0;
-}
-
-
-
-static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data, int y_offset)
-{
- int i, pos;
-
- if (envelope->n_nodes > 12) {
- /* XXX
- TRACE("XM error: wrong number of envelope nodes (%d)\n", envelope->n_nodes);
- envelope->n_nodes = 0;
- return -1; */
- envelope->n_nodes = 12;
- }
-
- if (envelope->sus_loop_start >= 12) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP;
- if (envelope->loop_end >= 12) envelope->loop_end = 0;
- if (envelope->loop_start >= envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON;
-
- pos = 0;
- for (i = 0; i < envelope->n_nodes; i++) {
- envelope->node_t[i] = data[pos++];
- if (data[pos] > 64) {
- TRACE("XM error: out-of-range envelope node (node_y[%d]=%d)\n", i, data[pos]);
- envelope->n_nodes = 0;
- return -1;
- }
- envelope->node_y[i] = (signed char)(data[pos++] + y_offset);
- }
-
- return 0;
-}
-
-
-
-static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA *extra, DUMBFILE *f)
-{
- unsigned long size, bytes_read;
- unsigned short vol_points[24];
- unsigned short pan_points[24];
- int i, type;
-
- /* Header size. Tends to be more than the actual size of the structure.
- * So unread bytes must be skipped before reading the first sample
- * header.
- */
- size = dumbfile_igetl(f);
-
- dumbfile_getnc(instrument->name, 22, f);
- instrument->name[22] = 0;
- instrument->filename[0] = 0;
- dumbfile_skip(f, 1); /* Instrument type. Should be 0, but seems random. */
- extra->n_samples = dumbfile_igetw(f);
-
- if (dumbfile_error(f) || (unsigned int)extra->n_samples > XM_MAX_SAMPLES_PER_INSTRUMENT)
- return -1;
-
- bytes_read = 4 + 22 + 1 + 2;
-
- if (extra->n_samples) {
- /* sample header size */
- dumbfile_skip(f, 4); // XXX can't be trusted, as there are trackers that write the wrong value here
- /*i = dumbfile_igetl(f);
- if (i && i != 0x28) { // XXX some crap with 0 here
- TRACE("XM error: unexpected sample header size\n");
- return -1;
- }*/
-
- /* sample map */
- for (i = 0; i < 96; i++) {
- instrument->map_sample[i] = dumbfile_getc(f) + 1;
- instrument->map_note[i] = i;
- }
-
- if (dumbfile_error(f))
- return 1;
-
- /* volume/panning envelopes */
- for (i = 0; i < 24; i++)
- vol_points[i] = dumbfile_igetw(f);
- for (i = 0; i < 24; i++)
- pan_points[i] = dumbfile_igetw(f);
-
- instrument->volume_envelope.n_nodes = dumbfile_getc(f);
- instrument->pan_envelope.n_nodes = dumbfile_getc(f);
-
- if (dumbfile_error(f))
- return -1;
-
- instrument->volume_envelope.sus_loop_start = dumbfile_getc(f);
- instrument->volume_envelope.loop_start = dumbfile_getc(f);
- instrument->volume_envelope.loop_end = dumbfile_getc(f);
-
- instrument->pan_envelope.sus_loop_start = dumbfile_getc(f);
- instrument->pan_envelope.loop_start = dumbfile_getc(f);
- instrument->pan_envelope.loop_end = dumbfile_getc(f);
-
- /* The envelope handler for XM files won't use sus_loop_end. */
-
- type = dumbfile_getc(f);
- instrument->volume_envelope.flags = 0;
- if ((type & XM_ENVELOPE_ON) && instrument->volume_envelope.n_nodes)
- instrument->volume_envelope.flags |= IT_ENVELOPE_ON;
- if (type & XM_ENVELOPE_LOOP) instrument->volume_envelope.flags |= IT_ENVELOPE_LOOP_ON;
-#if 1
- if (type & XM_ENVELOPE_SUSTAIN) instrument->volume_envelope.flags |= IT_ENVELOPE_SUSTAIN_LOOP;
-#else // This is now handled in itrender.c
- /* let's avoid fading out when reaching the last envelope node */
- if (!(type & XM_ENVELOPE_LOOP)) {
- instrument->volume_envelope.loop_start = instrument->volume_envelope.n_nodes-1;
- instrument->volume_envelope.loop_end = instrument->volume_envelope.n_nodes-1;
- }
- instrument->volume_envelope.flags |= IT_ENVELOPE_LOOP_ON;
-#endif
-
- type = dumbfile_getc(f);
- instrument->pan_envelope.flags = 0;
- if ((type & XM_ENVELOPE_ON) && instrument->pan_envelope.n_nodes)
- instrument->pan_envelope.flags |= IT_ENVELOPE_ON;
- if (type & XM_ENVELOPE_LOOP) instrument->pan_envelope.flags |= IT_ENVELOPE_LOOP_ON; // should this be here?
- if (type & XM_ENVELOPE_SUSTAIN) instrument->pan_envelope.flags |= IT_ENVELOPE_SUSTAIN_LOOP;
-
- if (it_xm_make_envelope(&instrument->volume_envelope, vol_points, 0) != 0) {
- TRACE("XM error: volume envelope\n");
- if (instrument->volume_envelope.flags & IT_ENVELOPE_ON) return -1;
- }
-
- if (it_xm_make_envelope(&instrument->pan_envelope, pan_points, -32) != 0) {
- TRACE("XM error: pan envelope\n");
- if (instrument->pan_envelope.flags & IT_ENVELOPE_ON) return -1;
- }
-
- instrument->pitch_envelope.flags = 0;
-
- extra->vibrato_type = dumbfile_getc(f);
- extra->vibrato_sweep = dumbfile_getc(f);
- extra->vibrato_depth = dumbfile_getc(f);
- extra->vibrato_speed = dumbfile_getc(f);
-
- if (dumbfile_error(f) || extra->vibrato_type > 4) // XXX
- return -1;
-
- /** WARNING: lossy approximation */
- instrument->fadeout = (dumbfile_igetw(f)*128 + 64)/0xFFF;
-
- dumbfile_skip(f, 2); /* reserved */
-
- bytes_read += 4 + 96 + 48 + 48 + 14*1 + 2 + 2;
- } else
- for (i = 0; i < 96; i++)
- instrument->map_sample[i] = 0;
-
- if (dumbfile_skip(f, size - bytes_read))
- return -1;
-
- instrument->new_note_action = NNA_NOTE_CUT;
- instrument->dup_check_type = DCT_OFF;
- instrument->dup_check_action = DCA_NOTE_CUT;
- instrument->pp_separation = 0;
- instrument->pp_centre = 60; /* C-5 */
- instrument->global_volume = 128;
- instrument->default_pan = 32;
- instrument->random_volume = 0;
- instrument->random_pan = 0;
- instrument->filter_cutoff = 0;
- instrument->filter_resonance = 0;
-
- return 0;
-}
-
-
-
-/* I (entheh) have two XM files saved by a very naughty program. After a
- * 16-bit sample, it saved a rogue byte. The length of the sample was indeed
- * an odd number, incremented to include the rogue byte.
- *
- * In this function we are converting sample lengths and loop points so they
- * are measured in samples. This means we forget about the extra bytes, and
- * they don't get skipped. So we fail trying to read the next instrument.
- *
- * To get around this, this function returns the number of rogue bytes that
- * won't be accounted for by reading sample->length samples. It returns a
- * negative number on failure.
- */
-static int it_xm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
-{
- int type;
- int relative_note_number; /* relative to C4 */
- int finetune;
- int roguebytes;
- int roguebytesmask;
- int reserved;
-
- sample->length = dumbfile_igetl(f);
- sample->loop_start = dumbfile_igetl(f);
- sample->loop_end = sample->loop_start + dumbfile_igetl(f);
- sample->global_volume = 64;
- sample->default_volume = dumbfile_getc(f);
- finetune = (signed char)dumbfile_getc(f); /* -128..127 <=> -1 semitone .. +127/128 of a semitone */
- type = dumbfile_getc(f);
- sample->default_pan = dumbfile_getc(f); /* 0-255 */
- relative_note_number = (signed char)dumbfile_getc(f);
-
- /*dumbfile_skip(f, 1); /* reserved */
- reserved = dumbfile_getc(f);
-
- dumbfile_getnc(sample->name, 22, f);
- sample->name[22] = 0;
-
- sample->filename[0] = 0;
-
- if (dumbfile_error(f))
- return -1;
-
- sample->C5_speed = (long)(16726.0*pow(DUMB_SEMITONE_BASE, relative_note_number) /**pow(DUMB_PITCH_BASE, )*/ );
- sample->finetune = finetune*2;
-
- sample->flags = IT_SAMPLE_EXISTS;
-
- if (reserved == 0xAD &&
- (!(type & (XM_SAMPLE_16BIT | XM_SAMPLE_STEREO))))
- {
- /* F U Olivier Lapicque */
- roguebytes = 4;
- roguebytesmask = 4 << 2;
- }
- else
- {
- roguebytes = (int)sample->length;
- roguebytesmask = 3;
- }
-
- if (type & XM_SAMPLE_16BIT) {
- sample->flags |= IT_SAMPLE_16BIT;
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- } else
- roguebytesmask >>= 1;
-
- if (type & XM_SAMPLE_STEREO) {
- sample->flags |= IT_SAMPLE_STEREO;
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- } else
- roguebytesmask >>= 1;
-
- roguebytes &= roguebytesmask;
-
- if ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end) {
- if (type & XM_SAMPLE_FORWARD_LOOP) sample->flags |= IT_SAMPLE_LOOP;
- if (type & XM_SAMPLE_PINGPONG_LOOP) sample->flags |= IT_SAMPLE_LOOP | IT_SAMPLE_PINGPONG_LOOP;
- }
-
- if (sample->length <= 0)
- sample->flags &= ~IT_SAMPLE_EXISTS;
- else if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
- sample->flags &= ~IT_SAMPLE_LOOP;
- else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
- sample->flags &= ~IT_SAMPLE_LOOP;
-
- return roguebytes;
-}
-
-
-
-static int it_xm_read_sample_data(IT_SAMPLE *sample, unsigned char roguebytes, DUMBFILE *f)
-{
- int old;
- long i;
- long truncated_size;
- int n_channels;
- long datasize;
-
- if (!(sample->flags & IT_SAMPLE_EXISTS))
- return dumbfile_skip(f, roguebytes);
-
- /* let's get rid of the sample data coming after the end of the loop */
- if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length && roguebytes != 4) {
- truncated_size = sample->length - sample->loop_end;
- sample->length = sample->loop_end;
- } else {
- truncated_size = 0;
- }
-
- n_channels = sample->flags & IT_SAMPLE_STEREO ? 2 : 1;
- datasize = sample->length * n_channels;
-
- sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
- if (!sample->data)
- return -1;
-
- if (roguebytes == 4)
- {
- if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
- return -1;
- roguebytes = 0;
- }
- else
- {
- /* sample data is stored as signed delta values */
- old = 0;
- if (sample->flags & IT_SAMPLE_16BIT)
- for (i = 0; i < sample->length; i++)
- ((short *)sample->data)[i*n_channels] = old += dumbfile_igetw(f);
- else
- for (i = 0; i < sample->length; i++)
- ((signed char *)sample->data)[i*n_channels] = old += dumbfile_getc(f);
- }
-
- /* skip truncated data */
- dumbfile_skip(f, (sample->flags & IT_SAMPLE_16BIT) ? (2*truncated_size) : (truncated_size));
-
- if (sample->flags & IT_SAMPLE_STEREO) {
- old = 0;
- if (sample->flags & IT_SAMPLE_16BIT)
- for (i = 1; i < datasize; i += 2)
- ((short *)sample->data)[i] = old += dumbfile_igetw(f);
- else
- for (i = 1; i < datasize; i += 2)
- ((signed char *)sample->data)[i] = old += dumbfile_getc(f);
-
- /* skip truncated data */
- dumbfile_skip(f, (sample->flags & IT_SAMPLE_16BIT) ? (2*truncated_size) : (truncated_size));
- }
-
- dumbfile_skip(f, roguebytes);
-
- if (dumbfile_error(f))
- return -1;
-
- return 0;
-}
-
-
-
-/* "Real programmers don't document. If it was hard to write,
- * it should be hard to understand."
- *
- * (Never trust the documentation provided with a tracker.
- * Real files are the only truth...)
- */
-static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
-{
- DUMB_IT_SIGDATA *sigdata;
- char id_text[18];
-
- int header_size;
- int flags;
- int n_channels;
- int total_samples;
- int i, j;
-
- /* check ID text */
- if (dumbfile_getnc(id_text, 17, f) < 17)
- return NULL;
- id_text[17] = 0;
- if (strcmp(id_text, "Extended Module: ") != 0) {
- TRACE("XM error: Not an Extended Module\n");
- return NULL;
- }
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata)
- return NULL;
-
- /* song name */
- if (dumbfile_getnc(sigdata->name, 20, f) < 20) {
- free(sigdata);
- return NULL;
- }
- sigdata->name[20] = 0;
-
- if (dumbfile_getc(f) != 0x1A) {
- TRACE("XM error: 0x1A not found\n");
- free(sigdata);
- return NULL;
- }
-
- /* tracker name */
- if (dumbfile_skip(f, 20)) {
- free(sigdata);
- return NULL;
- }
-
- /* version number */
- * version = dumbfile_igetw(f);
- if (* version > 0x0104 || * version < 0x0102) {
- TRACE("XM error: wrong format version\n");
- free(sigdata);
- return NULL;
- }
-
- /*
- ------------------
- --- Header ---
- ------------------
- */
-
- /* header size */
- header_size = dumbfile_igetl(f);
- if (header_size < (4 + 2*8 + 1) || header_size > 0x114) {
- TRACE("XM error: unexpected header size\n");
- free(sigdata);
- return NULL;
- }
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_samples = 0;
- sigdata->n_orders = dumbfile_igetw(f);
- sigdata->restart_position = dumbfile_igetw(f);
- n_channels = dumbfile_igetw(f); /* max 32 but we'll be lenient */
- sigdata->n_pchannels = n_channels;
- sigdata->n_patterns = dumbfile_igetw(f);
- sigdata->n_instruments = dumbfile_igetw(f); /* max 128 */ /* XXX upped to 256 */
- flags = dumbfile_igetw(f);
- sigdata->speed = dumbfile_igetw(f);
- if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
- sigdata->tempo = dumbfile_igetw(f);
-
- /* sanity checks */
- // XXX
- i = header_size - 4 - 2 * 8; /* Maximum number of orders expected */
- if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_orders > i || sigdata->n_patterns > 256 || sigdata->n_instruments > 256 || n_channels > DUMB_IT_N_CHANNELS) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- //if (sigdata->restart_position >= sigdata->n_orders)
- //sigdata->restart_position = 0;
-
- /* order table */
- sigdata->order = malloc(sigdata->n_orders*sizeof(*sigdata->order));
- if (!sigdata->order) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
- dumbfile_skip(f, i - sigdata->n_orders);
-
- if (dumbfile_error(f)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if ( * version > 0x103 ) {
- /*
- --------------------
- --- Patterns ---
- --------------------
- */
-
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++)
- sigdata->pattern[i].entry = NULL;
-
- {
- unsigned char *buffer = malloc(1280 * n_channels); /* 256 rows * 5 bytes */
- if (!buffer) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++) {
- if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, buffer, * version) != 0) {
- free(buffer);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
- free(buffer);
- }
-
- /*
- -----------------------------------
- --- Instruments and Samples ---
- -----------------------------------
- */
-
- sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
- if (!sigdata->instrument) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- /* With XM, samples are not global, they're part of an instrument. In a
- * file, each instrument is stored with its samples. Because of this, I
- * don't know how to find how many samples are present in the file. Thus
- * I have to do n_instruments reallocation on sigdata->sample.
- * Looking at FT2, it doesn't seem possible to have more than 16 samples
- * per instrument (even though n_samples is stored as 2 bytes). So maybe
- * we could allocate a 128*16 array of samples, and shrink it back to the
- * correct size when we know it?
- * Alternatively, I could allocate samples by blocks of N (still O(n)),
- * or double the number of allocated samples when I need more (O(log n)).
- */
- total_samples = 0;
- sigdata->sample = NULL;
-
- for (i = 0; i < sigdata->n_instruments; i++) {
- XM_INSTRUMENT_EXTRA extra;
-
- if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) {
- // XXX
- if ( ! i )
- {
- TRACE("XM error: instrument %d\n", i+1);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- else
- {
- sigdata->n_instruments = i;
- break;
- }
- }
-
- if (extra.n_samples) {
- unsigned char roguebytes[XM_MAX_SAMPLES_PER_INSTRUMENT];
-
- /* adjust instrument sample map (make indices absolute) */
- for (j = 0; j < 96; j++)
- sigdata->instrument[i].map_sample[j] += total_samples;
-
- sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples));
- if (!sigdata->sample) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (j = total_samples; j < total_samples+extra.n_samples; j++)
- sigdata->sample[j].data = NULL;
-
- /* read instrument's samples */
- for (j = 0; j < extra.n_samples; j++) {
- IT_SAMPLE *sample = &sigdata->sample[total_samples+j];
- int b = it_xm_read_sample_header(sample, f);
- if (b < 0) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- roguebytes[j] = b;
- // Any reason why these can't be set inside it_xm_read_sample_header()?
- sample->vibrato_speed = extra.vibrato_speed;
- sample->vibrato_depth = extra.vibrato_depth;
- sample->vibrato_rate = extra.vibrato_sweep;
- /* Rate and sweep don't match, but the difference is
- * accounted for in itrender.c.
- */
- sample->vibrato_waveform = xm_convert_vibrato[extra.vibrato_type];
- sample->max_resampling_quality = -1;
- }
- for (j = 0; j < extra.n_samples; j++) {
- if (it_xm_read_sample_data(&sigdata->sample[total_samples+j], roguebytes[j], f) != 0) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
- total_samples += extra.n_samples;
- }
- }
-
- sigdata->n_samples = total_samples;
- } else {
- // ahboy! old layout!
- // first instruments and sample headers, then patterns, then sample data!
-
- /*
- -----------------------------------
- --- Instruments and Samples ---
- -----------------------------------
- */
-
- unsigned char * roguebytes = malloc( sigdata->n_instruments * XM_MAX_SAMPLES_PER_INSTRUMENT );
- if (!roguebytes) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
- if (!sigdata->instrument) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- total_samples = 0;
- sigdata->sample = NULL;
-
- for (i = 0; i < sigdata->n_instruments; i++) {
- XM_INSTRUMENT_EXTRA extra;
-
- if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) {
- TRACE("XM error: instrument %d\n", i+1);
- free(roguebytes);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (extra.n_samples) {
- /* adjust instrument sample map (make indices absolute) */
- for (j = 0; j < 96; j++)
- sigdata->instrument[i].map_sample[j] += total_samples;
-
- sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples));
- if (!sigdata->sample) {
- free(roguebytes);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (j = total_samples; j < total_samples+extra.n_samples; j++)
- sigdata->sample[j].data = NULL;
-
- /* read instrument's samples */
- for (j = 0; j < extra.n_samples; j++) {
- IT_SAMPLE *sample = &sigdata->sample[total_samples+j];
- int b = it_xm_read_sample_header(sample, f);
- if (b < 0) {
- free(roguebytes);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- roguebytes[total_samples+j] = b;
- // Any reason why these can't be set inside it_xm_read_sample_header()?
- sample->vibrato_speed = extra.vibrato_speed;
- sample->vibrato_depth = extra.vibrato_depth;
- sample->vibrato_rate = extra.vibrato_sweep;
- /* Rate and sweep don't match, but the difference is
- * accounted for in itrender.c.
- */
- sample->vibrato_waveform = xm_convert_vibrato[extra.vibrato_type];
- sample->max_resampling_quality = -1;
- }
- total_samples += extra.n_samples;
- }
- }
-
- sigdata->n_samples = total_samples;
-
- /*
- --------------------
- --- Patterns ---
- --------------------
- */
-
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- free(roguebytes);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++)
- sigdata->pattern[i].entry = NULL;
-
- {
- unsigned char *buffer = malloc(1280 * n_channels); /* 256 rows * 5 bytes */
- if (!buffer) {
- free(roguebytes);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++) {
- if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, buffer, * version) != 0) {
- free(buffer);
- free(roguebytes);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
- free(buffer);
- }
-
- // and now we load the sample data
- for (j = 0; j < total_samples; j++) {
- if (it_xm_read_sample_data(&sigdata->sample[j], roguebytes[j], f) != 0) {
- free(roguebytes);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
-
- free(roguebytes);
- }
-
-
- sigdata->flags = IT_WAS_AN_XM | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO | IT_USE_INSTRUMENTS;
- // Are we OK with IT_COMPATIBLE_GXX off?
- //
- // When specifying note + instr + tone portamento, and an old note is still playing (even after note off):
- // - If Compatible Gxx is on, the new note will be triggered only if the instrument _changes_.
- // - If Compatible Gxx is off, the new note will always be triggered, provided the instrument is specified.
- // - FT2 seems to do the latter (unconfirmed).
-
- // Err, wait. XM playback has its own code. The change made to the IT
- // playbackc code didn't affect XM playback. Forget this then. There's
- // still a bug in XM playback though, and it'll need some investigation...
- // tomorrow...
-
- // UPDATE: IT_COMPATIBLE_GXX is required to be on, so that tone porta has
- // separate memory from portamento.
-
- if (flags & XM_LINEAR_FREQUENCY)
- sigdata->flags |= IT_LINEAR_SLIDES;
-
- sigdata->global_volume = 128;
- sigdata->mixing_volume = 48;
- sigdata->pan_separation = 128;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
- memset(sigdata->channel_pan, 32, DUMB_IT_N_CHANNELS);
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-
-
-#if 0 // no fucking way, dude!
-
-/* The length returned is the time required to play from the beginning of the
- * file to the last row of the last order (which is when the player will
- * loop). Depending on the song, the sound might stop sooner.
- * Due to fixed point roundoffs, I think this is only reliable to the second.
- * Full precision could be achieved by using a double during the computation,
- * or maybe a LONG_LONG.
- */
-long it_compute_length(const DUMB_IT_SIGDATA *sigdata)
-{
- IT_PATTERN *pattern;
- int tempo, speed;
- int loop_start[IT_N_CHANNELS];
- char loop_count[IT_N_CHANNELS];
- int order, entry;
- int row_first_entry = 0;
- int jump, jump_dest;
- int delay, fine_delay;
- int i;
- long t;
-
- if (!sigdata)
- return 0;
-
- tempo = sigdata->tempo;
- speed = sigdata->speed;
- order = entry = 0;
- jump = jump_dest = 0;
- t = 0;
-
- /* for each PATTERN */
- for (order = 0; order < sigdata->n_orders; order++) {
-
- if (sigdata->order[order] == IT_ORDER_END) break;
- if (sigdata->order[order] == IT_ORDER_SKIP) continue;
-
- for (i = 0; i < IT_N_CHANNELS; i++)
- loop_count[i] = -1;
-
- pattern = &sigdata->pattern[ sigdata->order[order] ];
- entry = 0;
- if (jump == IT_BREAK_TO_ROW) {
- int row = 0;
- while (row < jump_dest)
- if (pattern->entry[entry++].channel >= IT_N_CHANNELS)
- row++;
- }
-
- /* for each ROW */
- while (entry < pattern->n_entries) {
- row_first_entry = entry;
- delay = fine_delay = 0;
- jump = 0;
-
- /* for each note NOTE */
- while (entry < pattern->n_entries && pattern->entry[entry].channel < IT_N_CHANNELS) {
- int value = pattern->entry[entry].effectvalue;
- int channel = pattern->entry[entry].channel;
-
- switch (pattern->entry[entry].effect) {
-
- case IT_SET_SPEED: speed = value; break;
-
- case IT_JUMP_TO_ORDER:
- if (value <= order) /* infinite loop */
- return 0;
- jump = IT_JUMP_TO_ORDER;
- jump_dest = value;
- break;
-
- case IT_BREAK_TO_ROW:
- jump = IT_BREAK_TO_ROW;
- jump_dest = value;
- break;
-
- case IT_S:
- switch (HIGH(value)) {
- case IT_S_PATTERN_DELAY: delay = LOW(value); break;
- case IT_S_FINE_PATTERN_DELAY: fine_delay = LOW(value); break;
- case IT_S_PATTERN_LOOP:
- if (LOW(value) == 0) {
- loop_start[channel] = row_first_entry;
- } else {
- if (loop_count[channel] == -1)
- loop_count[channel] = LOW(value);
-
- if (loop_count[channel]) {
- jump = IT_S_PATTERN_LOOP;
- jump_dest = loop_start[channel];
- }
- loop_count[channel]--;
- }
- break;
- }
- break;
-
- case IT_SET_SONG_TEMPO:
- switch (HIGH(value)) { /* slides happen every non-row frames */
- case 0: tempo = tempo - LOW(value)*(speed-1); break;
- case 1: tempo = tempo + LOW(value)*(speed-1); break;
- default: tempo = value;
- }
- tempo = MID(32, tempo, 255);
- break;
- }
-
- entry++;
- }
-
- /* end of ROW */
- entry++;
- t += TICK_TIME_DIVIDEND * (speed*(1+delay) + fine_delay) / tempo;
-
- if (jump == IT_JUMP_TO_ORDER) {
- order = jump_dest - 1;
- break;
- } else if (jump == IT_BREAK_TO_ROW)
- break;
- else if (jump == IT_S_PATTERN_LOOP)
- entry = jump_dest - 1;
- }
-
- /* end of PATTERN */
- }
-
- return t;
-}
-
-#endif /* 0 */
-
-
-static char hexdigit(int in)
-{
- if (in < 10) return in + '0';
- else return in + 'A' - 10;
-}
-
-DUH *dumb_read_xm_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
- int ver;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_xm_load_sigdata(f, &ver);
-
- if (!sigdata)
- return NULL;
-
- {
- char version[16];
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- version[0] = 'X';
- version[1] = 'M';
- version[2] = ' ';
- version[3] = 'v';
- version[4] = hexdigit( ( ver >> 8 ) & 15 );
- version[5] = '.';
- version[6] = hexdigit( ( ver >> 4 ) & 15 );
- version[7] = hexdigit( ver & 15 );
- version[8] = 0;
- tag[1][1] = ( const char * ) & version;
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readxm.c - Code to read a Fast Tracker II / / \ \
+ * module from an open file. | < / \_
+ * | \/ /\ /
+ * By Julien Cugniere. Some bits of code taken \_ / > /
+ * from reads3m.c. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/** TODO:
+
+ * XM_TREMOLO doesn't sound quite right...
+ * XM_E_SET_FINETUNE done but not tested yet.
+ * XM_SET_ENVELOPE_POSITION todo.
+
+ * VIBRATO conversion needs to be checked (sample/effect/volume). Plus check
+ that effect memory is correct when using XM_VOLSLIDE_VIBRATO.
+ - sample vibrato (instrument vibrato) is now handled correctly. - entheh
+
+ * XM_E_SET_VIBRATO/TREMOLO_CONTROL: effectvalue&4 -> don't retrig wave when
+ a new instrument is played. In retrigger_note()?. Is it worth implementing?
+
+ * Lossy fadeout approximation. 0..31 converted to 0 --> won't fade at all.
+
+ * Replace DUMB's sawtooth by ramp_down/ramp_up. Update XM loader.
+
+ * A lot of things need to be reset when the end of the song is reached.
+
+ * It seems that IT and XM don't behave the same way when dealing with
+ mixed loops. When IT encounters multiple SBx (x>0) commands on the same
+ row, it decrements the loop count for all, but only execute the loop of
+ the last one (highest channel). FT2 only decrements the loop count of the
+ last one. Not that I know of any modules using so convoluted combinations!
+
+ * Maybe we could remove patterns that don't appear in the order table ? Or
+ provide a function to "optimize" a DUMB_IT_SIGDATA ?
+
+*/
+
+
+
+#define XM_LINEAR_FREQUENCY 1 /* otherwise, use amiga slides */
+
+#define XM_ENTRY_PACKED 128
+#define XM_ENTRY_NOTE 1
+#define XM_ENTRY_INSTRUMENT 2
+#define XM_ENTRY_VOLUME 4
+#define XM_ENTRY_EFFECT 8
+#define XM_ENTRY_EFFECTVALUE 16
+
+#define XM_NOTE_OFF 97
+
+#define XM_ENVELOPE_ON 1
+#define XM_ENVELOPE_SUSTAIN 2
+#define XM_ENVELOPE_LOOP 4
+
+#define XM_SAMPLE_NO_LOOP 0
+#define XM_SAMPLE_FORWARD_LOOP 1
+#define XM_SAMPLE_PINGPONG_LOOP 2
+#define XM_SAMPLE_16BIT 16
+#define XM_SAMPLE_STEREO 32
+
+#define XM_VIBRATO_SINE 0
+#define XM_VIBRATO_SQUARE 1
+#define XM_VIBRATO_RAMP_DOWN 2
+#define XM_VIBRATO_RAMP_UP 3
+
+
+
+/* Probably useless :) */
+const char xm_convert_vibrato[] = {
+ IT_VIBRATO_SINE,
+ IT_VIBRATO_XM_SQUARE,
+ IT_VIBRATO_RAMP_DOWN,
+ IT_VIBRATO_RAMP_UP,
+ IT_VIBRATO_RANDOM
+};
+
+
+
+#define XM_MAX_SAMPLES_PER_INSTRUMENT 16
+
+
+
+/* Extra data that doesn't fit inside IT_INSTRUMENT */
+typedef struct XM_INSTRUMENT_EXTRA
+{
+ int n_samples;
+ int vibrato_type;
+ int vibrato_sweep; /* 0-0xFF */
+ int vibrato_depth; /* 0-0x0F */
+ int vibrato_speed; /* 0-0x3F */
+}
+XM_INSTRUMENT_EXTRA;
+
+
+
+/* Frees the original block if it can't resize it or if size is 0, and acts
+ * as malloc if ptr is NULL.
+ */
+static void *safe_realloc(void *ptr, size_t size)
+{
+ if (ptr == NULL)
+ return malloc(size);
+
+ if (size == 0) {
+ free(ptr);
+ return NULL;
+ } else {
+ void *new_block = realloc(ptr, size);
+ if (!new_block)
+ free(ptr);
+ return new_block;
+ }
+}
+
+
+
+/* The interpretation of the XM volume column is left to the player. Here, we
+ * just filter bad values.
+ */
+// This function is so tiny now, should we inline it?
+static void it_xm_convert_volume(int volume, IT_ENTRY *entry)
+{
+ entry->mask |= IT_ENTRY_VOLPAN;
+ entry->volpan = volume;
+
+ switch (volume >> 4) {
+ case 0xA: /* set vibrato speed */
+ case 0xB: /* vibrato */
+ case 0xF: /* tone porta */
+ case 0x6: /* vol slide up */
+ case 0x7: /* vol slide down */
+ case 0x8: /* fine vol slide up */
+ case 0x9: /* fine vol slide down */
+ case 0xC: /* set panning */
+ case 0xD: /* pan slide left */
+ case 0xE: /* pan slide right */
+ case 0x1: /* set volume */
+ case 0x2: /* set volume */
+ case 0x3: /* set volume */
+ case 0x4: /* set volume */
+ break;
+
+ case 0x5:
+ if (volume == 0x50)
+ break; /* set volume */
+ /* else fall through */
+
+ default:
+ entry->mask &= ~IT_ENTRY_VOLPAN;
+ break;
+ }
+}
+
+
+
+static int it_xm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer, int version)
+{
+ int size;
+ int pos;
+ int channel;
+ int row;
+ int effect, effectvalue;
+ IT_ENTRY *entry;
+
+ /* pattern header size */
+ if (dumbfile_igetl(f) != ( version == 0x0102 ? 0x08 : 0x09 ) ) {
+ TRACE("XM error: unexpected pattern header size\n");
+ return -1;
+ }
+
+ /* pattern data packing type */
+ if (dumbfile_getc(f) != 0) {
+ TRACE("XM error: unexpected pattern packing type\n");
+ return -1;
+ }
+
+ if ( version == 0x0102 )
+ pattern->n_rows = dumbfile_getc(f) + 1;
+ else
+ pattern->n_rows = dumbfile_igetw(f); /* 1..256 */
+ size = dumbfile_igetw(f);
+ pattern->n_entries = 0;
+
+ if (dumbfile_error(f))
+ return -1;
+
+ if (size == 0)
+ return 0;
+
+ if (size > 1280 * n_channels) {
+ TRACE("XM error: pattern data size > %d bytes\n", 1280 * n_channels);
+ return -1;
+ }
+
+ if (dumbfile_getnc(buffer, size, f) < size)
+ return -1;
+
+ /* compute number of entries */
+ pattern->n_entries = 0;
+ pos = channel = row = 0;
+ while (pos < size) {
+ if (!(buffer[pos] & XM_ENTRY_PACKED) || (buffer[pos] & 31))
+ pattern->n_entries++;
+
+ channel++;
+ if (channel >= n_channels) {
+ channel = 0;
+ row++;
+ pattern->n_entries++;
+ }
+
+ if (buffer[pos] & XM_ENTRY_PACKED) {
+ static const char offset[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5 };
+ pos += 1 + offset[buffer[pos] & 31];
+ } else {
+ pos += 5;
+ }
+ }
+
+ if (row > pattern->n_rows) {
+ TRACE("XM error: wrong number of rows in pattern data\n");
+ return -1;
+ }
+
+ /* Whoops, looks like some modules may be short, a few channels, maybe even rows... */
+
+ while (row < pattern->n_rows)
+ {
+ pattern->n_entries++;
+ row++;
+ }
+
+ pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
+ if (!pattern->entry)
+ return -1;
+
+ /* read the entries */
+ entry = pattern->entry;
+ pos = channel = row = 0;
+ while (pos < size) {
+ unsigned char mask;
+
+ if (buffer[pos] & XM_ENTRY_PACKED)
+ mask = buffer[pos++] & 31;
+ else
+ mask = 31;
+
+ if (mask) {
+ ASSERT(entry < pattern->entry + pattern->n_entries);
+
+ entry->channel = channel;
+ entry->mask = 0;
+
+ if (mask & XM_ENTRY_NOTE) {
+ int note = buffer[pos++]; /* 1-96 <=> C0-B7 */
+ entry->note = (note == XM_NOTE_OFF) ? (IT_NOTE_OFF) : (note-1);
+ entry->mask |= IT_ENTRY_NOTE;
+ }
+
+ if (mask & XM_ENTRY_INSTRUMENT) {
+ entry->instrument = buffer[pos++]; /* 1-128 */
+ entry->mask |= IT_ENTRY_INSTRUMENT;
+ }
+
+ if (mask & XM_ENTRY_VOLUME)
+ it_xm_convert_volume(buffer[pos++], entry);
+
+ effect = effectvalue = 0;
+ if (mask & XM_ENTRY_EFFECT) effect = buffer[pos++];
+ if (mask & XM_ENTRY_EFFECTVALUE) effectvalue = buffer[pos++];
+ _dumb_it_xm_convert_effect(effect, effectvalue, entry, 0);
+
+ entry++;
+ }
+
+ channel++;
+ if (channel >= n_channels) {
+ channel = 0;
+ row++;
+ IT_SET_END_ROW(entry);
+ entry++;
+ }
+ }
+
+ while (row < pattern->n_rows)
+ {
+ row++;
+ IT_SET_END_ROW(entry);
+ entry++;
+ }
+
+ return 0;
+}
+
+
+
+static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data, int y_offset)
+{
+ int i, pos;
+
+ if (envelope->n_nodes > 12) {
+ /* XXX
+ TRACE("XM error: wrong number of envelope nodes (%d)\n", envelope->n_nodes);
+ envelope->n_nodes = 0;
+ return -1; */
+ envelope->n_nodes = 12;
+ }
+
+ if (envelope->sus_loop_start >= 12) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP;
+ if (envelope->loop_end >= 12) envelope->loop_end = 0;
+ if (envelope->loop_start >= envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON;
+
+ pos = 0;
+ for (i = 0; i < envelope->n_nodes; i++) {
+ envelope->node_t[i] = data[pos++];
+ if (data[pos] > 64) {
+ TRACE("XM error: out-of-range envelope node (node_y[%d]=%d)\n", i, data[pos]);
+ envelope->n_nodes = 0;
+ return -1;
+ }
+ envelope->node_y[i] = (signed char)(data[pos++] + y_offset);
+ }
+
+ return 0;
+}
+
+
+
+static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA *extra, DUMBFILE *f)
+{
+ unsigned long size, bytes_read;
+ unsigned short vol_points[24];
+ unsigned short pan_points[24];
+ int i, type;
+
+ /* Header size. Tends to be more than the actual size of the structure.
+ * So unread bytes must be skipped before reading the first sample
+ * header.
+ */
+ size = dumbfile_igetl(f);
+
+ dumbfile_getnc(instrument->name, 22, f);
+ instrument->name[22] = 0;
+ instrument->filename[0] = 0;
+ dumbfile_skip(f, 1); /* Instrument type. Should be 0, but seems random. */
+ extra->n_samples = dumbfile_igetw(f);
+
+ if (dumbfile_error(f) || (unsigned int)extra->n_samples > XM_MAX_SAMPLES_PER_INSTRUMENT)
+ return -1;
+
+ bytes_read = 4 + 22 + 1 + 2;
+
+ if (extra->n_samples) {
+ /* sample header size */
+ dumbfile_skip(f, 4); // XXX can't be trusted, as there are trackers that write the wrong value here
+ /*i = dumbfile_igetl(f);
+ if (i && i != 0x28) { // XXX some crap with 0 here
+ TRACE("XM error: unexpected sample header size\n");
+ return -1;
+ }*/
+
+ /* sample map */
+ for (i = 0; i < 96; i++) {
+ instrument->map_sample[i] = dumbfile_getc(f) + 1;
+ instrument->map_note[i] = i;
+ }
+
+ if (dumbfile_error(f))
+ return 1;
+
+ /* volume/panning envelopes */
+ for (i = 0; i < 24; i++)
+ vol_points[i] = dumbfile_igetw(f);
+ for (i = 0; i < 24; i++)
+ pan_points[i] = dumbfile_igetw(f);
+
+ instrument->volume_envelope.n_nodes = dumbfile_getc(f);
+ instrument->pan_envelope.n_nodes = dumbfile_getc(f);
+
+ if (dumbfile_error(f))
+ return -1;
+
+ instrument->volume_envelope.sus_loop_start = dumbfile_getc(f);
+ instrument->volume_envelope.loop_start = dumbfile_getc(f);
+ instrument->volume_envelope.loop_end = dumbfile_getc(f);
+
+ instrument->pan_envelope.sus_loop_start = dumbfile_getc(f);
+ instrument->pan_envelope.loop_start = dumbfile_getc(f);
+ instrument->pan_envelope.loop_end = dumbfile_getc(f);
+
+ /* The envelope handler for XM files won't use sus_loop_end. */
+
+ type = dumbfile_getc(f);
+ instrument->volume_envelope.flags = 0;
+ if ((type & XM_ENVELOPE_ON) && instrument->volume_envelope.n_nodes)
+ instrument->volume_envelope.flags |= IT_ENVELOPE_ON;
+ if (type & XM_ENVELOPE_LOOP) instrument->volume_envelope.flags |= IT_ENVELOPE_LOOP_ON;
+#if 1
+ if (type & XM_ENVELOPE_SUSTAIN) instrument->volume_envelope.flags |= IT_ENVELOPE_SUSTAIN_LOOP;
+#else // This is now handled in itrender.c
+ /* let's avoid fading out when reaching the last envelope node */
+ if (!(type & XM_ENVELOPE_LOOP)) {
+ instrument->volume_envelope.loop_start = instrument->volume_envelope.n_nodes-1;
+ instrument->volume_envelope.loop_end = instrument->volume_envelope.n_nodes-1;
+ }
+ instrument->volume_envelope.flags |= IT_ENVELOPE_LOOP_ON;
+#endif
+
+ type = dumbfile_getc(f);
+ instrument->pan_envelope.flags = 0;
+ if ((type & XM_ENVELOPE_ON) && instrument->pan_envelope.n_nodes)
+ instrument->pan_envelope.flags |= IT_ENVELOPE_ON;
+ if (type & XM_ENVELOPE_LOOP) instrument->pan_envelope.flags |= IT_ENVELOPE_LOOP_ON; // should this be here?
+ if (type & XM_ENVELOPE_SUSTAIN) instrument->pan_envelope.flags |= IT_ENVELOPE_SUSTAIN_LOOP;
+
+ if (it_xm_make_envelope(&instrument->volume_envelope, vol_points, 0) != 0) {
+ TRACE("XM error: volume envelope\n");
+ if (instrument->volume_envelope.flags & IT_ENVELOPE_ON) return -1;
+ }
+
+ if (it_xm_make_envelope(&instrument->pan_envelope, pan_points, -32) != 0) {
+ TRACE("XM error: pan envelope\n");
+ if (instrument->pan_envelope.flags & IT_ENVELOPE_ON) return -1;
+ }
+
+ instrument->pitch_envelope.flags = 0;
+
+ extra->vibrato_type = dumbfile_getc(f);
+ extra->vibrato_sweep = dumbfile_getc(f);
+ extra->vibrato_depth = dumbfile_getc(f);
+ extra->vibrato_speed = dumbfile_getc(f);
+
+ if (dumbfile_error(f) || extra->vibrato_type > 4) // XXX
+ return -1;
+
+ /** WARNING: lossy approximation */
+ instrument->fadeout = (dumbfile_igetw(f)*128 + 64)/0xFFF;
+
+ dumbfile_skip(f, 2); /* reserved */
+
+ bytes_read += 4 + 96 + 48 + 48 + 14*1 + 2 + 2;
+ } else
+ for (i = 0; i < 96; i++)
+ instrument->map_sample[i] = 0;
+
+ if (dumbfile_skip(f, size - bytes_read))
+ return -1;
+
+ instrument->new_note_action = NNA_NOTE_CUT;
+ instrument->dup_check_type = DCT_OFF;
+ instrument->dup_check_action = DCA_NOTE_CUT;
+ instrument->pp_separation = 0;
+ instrument->pp_centre = 60; /* C-5 */
+ instrument->global_volume = 128;
+ instrument->default_pan = 32;
+ instrument->random_volume = 0;
+ instrument->random_pan = 0;
+ instrument->filter_cutoff = 0;
+ instrument->filter_resonance = 0;
+
+ return 0;
+}
+
+
+
+/* I (entheh) have two XM files saved by a very naughty program. After a
+ * 16-bit sample, it saved a rogue byte. The length of the sample was indeed
+ * an odd number, incremented to include the rogue byte.
+ *
+ * In this function we are converting sample lengths and loop points so they
+ * are measured in samples. This means we forget about the extra bytes, and
+ * they don't get skipped. So we fail trying to read the next instrument.
+ *
+ * To get around this, this function returns the number of rogue bytes that
+ * won't be accounted for by reading sample->length samples. It returns a
+ * negative number on failure.
+ */
+static int it_xm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
+{
+ int type;
+ int relative_note_number; /* relative to C4 */
+ int finetune;
+ int roguebytes;
+ int roguebytesmask;
+ int reserved;
+
+ sample->length = dumbfile_igetl(f);
+ sample->loop_start = dumbfile_igetl(f);
+ sample->loop_end = sample->loop_start + dumbfile_igetl(f);
+ sample->global_volume = 64;
+ sample->default_volume = dumbfile_getc(f);
+ finetune = (signed char)dumbfile_getc(f); /* -128..127 <=> -1 semitone .. +127/128 of a semitone */
+ type = dumbfile_getc(f);
+ sample->default_pan = dumbfile_getc(f); /* 0-255 */
+ relative_note_number = (signed char)dumbfile_getc(f);
+
+ reserved = dumbfile_getc(f);
+
+ dumbfile_getnc(sample->name, 22, f);
+ sample->name[22] = 0;
+
+ sample->filename[0] = 0;
+
+ if (dumbfile_error(f))
+ return -1;
+
+ sample->C5_speed = (long)(16726.0*pow(DUMB_SEMITONE_BASE, relative_note_number) /**pow(DUMB_PITCH_BASE, )*/ );
+ sample->finetune = finetune*2;
+
+ sample->flags = IT_SAMPLE_EXISTS;
+
+ if (reserved == 0xAD &&
+ (!(type & (XM_SAMPLE_16BIT | XM_SAMPLE_STEREO))))
+ {
+ /* F U Olivier Lapicque */
+ roguebytes = 4;
+ roguebytesmask = 4 << 2;
+ }
+ else
+ {
+ roguebytes = (int)sample->length;
+ roguebytesmask = 3;
+ }
+
+ if (type & XM_SAMPLE_16BIT) {
+ sample->flags |= IT_SAMPLE_16BIT;
+ sample->length >>= 1;
+ sample->loop_start >>= 1;
+ sample->loop_end >>= 1;
+ } else
+ roguebytesmask >>= 1;
+
+ if (type & XM_SAMPLE_STEREO) {
+ sample->flags |= IT_SAMPLE_STEREO;
+ sample->length >>= 1;
+ sample->loop_start >>= 1;
+ sample->loop_end >>= 1;
+ } else
+ roguebytesmask >>= 1;
+
+ roguebytes &= roguebytesmask;
+
+ if ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end) {
+ if (type & XM_SAMPLE_FORWARD_LOOP) sample->flags |= IT_SAMPLE_LOOP;
+ if (type & XM_SAMPLE_PINGPONG_LOOP) sample->flags |= IT_SAMPLE_LOOP | IT_SAMPLE_PINGPONG_LOOP;
+ }
+
+ if (sample->length <= 0)
+ sample->flags &= ~IT_SAMPLE_EXISTS;
+ else if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
+ sample->flags &= ~IT_SAMPLE_LOOP;
+ else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
+ sample->flags &= ~IT_SAMPLE_LOOP;
+
+ return roguebytes;
+}
+
+
+
+static int it_xm_read_sample_data(IT_SAMPLE *sample, unsigned char roguebytes, DUMBFILE *f)
+{
+ int old;
+ long i;
+ long truncated_size;
+ int n_channels;
+ long datasize;
+
+ if (!(sample->flags & IT_SAMPLE_EXISTS))
+ return dumbfile_skip(f, roguebytes);
+
+ /* let's get rid of the sample data coming after the end of the loop */
+ if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length && roguebytes != 4) {
+ truncated_size = sample->length - sample->loop_end;
+ sample->length = sample->loop_end;
+ } else {
+ truncated_size = 0;
+ }
+
+ n_channels = sample->flags & IT_SAMPLE_STEREO ? 2 : 1;
+ datasize = sample->length * n_channels;
+
+ sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
+ if (!sample->data)
+ return -1;
+
+ if (roguebytes == 4)
+ {
+ if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
+ return -1;
+ roguebytes = 0;
+ }
+ else
+ {
+ /* sample data is stored as signed delta values */
+ old = 0;
+ if (sample->flags & IT_SAMPLE_16BIT)
+ for (i = 0; i < sample->length; i++)
+ ((short *)sample->data)[i*n_channels] = old += dumbfile_igetw(f);
+ else
+ for (i = 0; i < sample->length; i++)
+ ((signed char *)sample->data)[i*n_channels] = old += dumbfile_getc(f);
+ }
+
+ /* skip truncated data */
+ dumbfile_skip(f, (sample->flags & IT_SAMPLE_16BIT) ? (2*truncated_size) : (truncated_size));
+
+ if (sample->flags & IT_SAMPLE_STEREO) {
+ old = 0;
+ if (sample->flags & IT_SAMPLE_16BIT)
+ for (i = 1; i < datasize; i += 2)
+ ((short *)sample->data)[i] = old += dumbfile_igetw(f);
+ else
+ for (i = 1; i < datasize; i += 2)
+ ((signed char *)sample->data)[i] = old += dumbfile_getc(f);
+
+ /* skip truncated data */
+ dumbfile_skip(f, (sample->flags & IT_SAMPLE_16BIT) ? (2*truncated_size) : (truncated_size));
+ }
+
+ dumbfile_skip(f, roguebytes);
+
+ if (dumbfile_error(f))
+ return -1;
+
+ return 0;
+}
+
+
+
+/* "Real programmers don't document. If it was hard to write,
+ * it should be hard to understand."
+ *
+ * (Never trust the documentation provided with a tracker.
+ * Real files are the only truth...)
+ */
+static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
+{
+ DUMB_IT_SIGDATA *sigdata;
+ char id_text[18];
+
+ int header_size;
+ int flags;
+ int n_channels;
+ int total_samples;
+ int i, j;
+
+ /* check ID text */
+ if (dumbfile_getnc(id_text, 17, f) < 17)
+ return NULL;
+ id_text[17] = 0;
+ if (strcmp(id_text, "Extended Module: ") != 0) {
+ TRACE("XM error: Not an Extended Module\n");
+ return NULL;
+ }
+
+ sigdata = malloc(sizeof(*sigdata));
+ if (!sigdata)
+ return NULL;
+
+ sigdata = malloc(sizeof(*sigdata));
+ if (!sigdata)
+ return NULL;
+
+ /* song name */
+ if (dumbfile_getnc(sigdata->name, 20, f) < 20) {
+ free(sigdata);
+ return NULL;
+ }
+ sigdata->name[20] = 0;
+
+ if (dumbfile_getc(f) != 0x1A) {
+ TRACE("XM error: 0x1A not found\n");
+ free(sigdata);
+ return NULL;
+ }
+
+ /* tracker name */
+ if (dumbfile_skip(f, 20)) {
+ free(sigdata);
+ return NULL;
+ }
+
+ /* version number */
+ * version = dumbfile_igetw(f);
+ if (* version > 0x0104 || * version < 0x0102) {
+ TRACE("XM error: wrong format version\n");
+ free(sigdata);
+ return NULL;
+ }
+
+ /*
+ ------------------
+ --- Header ---
+ ------------------
+ */
+
+ /* header size */
+ header_size = dumbfile_igetl(f);
+ if (header_size < (4 + 2*8 + 1) || header_size > 0x114) {
+ TRACE("XM error: unexpected header size\n");
+ free(sigdata);
+ return NULL;
+ }
+
+ sigdata->song_message = NULL;
+ sigdata->order = NULL;
+ sigdata->instrument = NULL;
+ sigdata->sample = NULL;
+ sigdata->pattern = NULL;
+ sigdata->midi = NULL;
+ sigdata->checkpoint = NULL;
+
+ sigdata->n_samples = 0;
+ sigdata->n_orders = dumbfile_igetw(f);
+ sigdata->restart_position = dumbfile_igetw(f);
+ n_channels = dumbfile_igetw(f); /* max 32 but we'll be lenient */
+ sigdata->n_pchannels = n_channels;
+ sigdata->n_patterns = dumbfile_igetw(f);
+ sigdata->n_instruments = dumbfile_igetw(f); /* max 128 */ /* XXX upped to 256 */
+ flags = dumbfile_igetw(f);
+ sigdata->speed = dumbfile_igetw(f);
+ if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
+ sigdata->tempo = dumbfile_igetw(f);
+
+ /* sanity checks */
+ // XXX
+ i = header_size - 4 - 2 * 8; /* Maximum number of orders expected */
+ if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_orders > i || sigdata->n_patterns > 256 || sigdata->n_instruments > 256 || n_channels > DUMB_IT_N_CHANNELS) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ //if (sigdata->restart_position >= sigdata->n_orders)
+ //sigdata->restart_position = 0;
+
+ /* order table */
+ sigdata->order = malloc(sigdata->n_orders*sizeof(*sigdata->order));
+ if (!sigdata->order) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
+ dumbfile_skip(f, i - sigdata->n_orders);
+
+ if (dumbfile_error(f)) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ if ( * version > 0x103 ) {
+ /*
+ --------------------
+ --- Patterns ---
+ --------------------
+ */
+
+ sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
+ if (!sigdata->pattern) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (i = 0; i < sigdata->n_patterns; i++)
+ sigdata->pattern[i].entry = NULL;
+
+ {
+ unsigned char *buffer = malloc(1280 * n_channels); /* 256 rows * 5 bytes */
+ if (!buffer) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (i = 0; i < sigdata->n_patterns; i++) {
+ if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, buffer, * version) != 0) {
+ free(buffer);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ }
+ free(buffer);
+ }
+
+ /*
+ -----------------------------------
+ --- Instruments and Samples ---
+ -----------------------------------
+ */
+
+ sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
+ if (!sigdata->instrument) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ /* With XM, samples are not global, they're part of an instrument. In a
+ * file, each instrument is stored with its samples. Because of this, I
+ * don't know how to find how many samples are present in the file. Thus
+ * I have to do n_instruments reallocation on sigdata->sample.
+ * Looking at FT2, it doesn't seem possible to have more than 16 samples
+ * per instrument (even though n_samples is stored as 2 bytes). So maybe
+ * we could allocate a 128*16 array of samples, and shrink it back to the
+ * correct size when we know it?
+ * Alternatively, I could allocate samples by blocks of N (still O(n)),
+ * or double the number of allocated samples when I need more (O(log n)).
+ */
+ total_samples = 0;
+ sigdata->sample = NULL;
+
+ for (i = 0; i < sigdata->n_instruments; i++) {
+ XM_INSTRUMENT_EXTRA extra;
+
+ if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) {
+ // XXX
+ if ( ! i )
+ {
+ TRACE("XM error: instrument %d\n", i+1);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ else
+ {
+ sigdata->n_instruments = i;
+ break;
+ }
+ }
+
+ if (extra.n_samples) {
+ unsigned char roguebytes[XM_MAX_SAMPLES_PER_INSTRUMENT];
+
+ /* adjust instrument sample map (make indices absolute) */
+ for (j = 0; j < 96; j++)
+ sigdata->instrument[i].map_sample[j] += total_samples;
+
+ sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples));
+ if (!sigdata->sample) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (j = total_samples; j < total_samples+extra.n_samples; j++)
+ sigdata->sample[j].data = NULL;
+
+ /* read instrument's samples */
+ for (j = 0; j < extra.n_samples; j++) {
+ IT_SAMPLE *sample = &sigdata->sample[total_samples+j];
+ int b = it_xm_read_sample_header(sample, f);
+ if (b < 0) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ roguebytes[j] = b;
+ // Any reason why these can't be set inside it_xm_read_sample_header()?
+ sample->vibrato_speed = extra.vibrato_speed;
+ sample->vibrato_depth = extra.vibrato_depth;
+ sample->vibrato_rate = extra.vibrato_sweep;
+ /* Rate and sweep don't match, but the difference is
+ * accounted for in itrender.c.
+ */
+ sample->vibrato_waveform = xm_convert_vibrato[extra.vibrato_type];
+ sample->max_resampling_quality = -1;
+ }
+ for (j = 0; j < extra.n_samples; j++) {
+ if (it_xm_read_sample_data(&sigdata->sample[total_samples+j], roguebytes[j], f) != 0) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ }
+ total_samples += extra.n_samples;
+ }
+ }
+
+ sigdata->n_samples = total_samples;
+ } else {
+ // ahboy! old layout!
+ // first instruments and sample headers, then patterns, then sample data!
+
+ /*
+ -----------------------------------
+ --- Instruments and Samples ---
+ -----------------------------------
+ */
+
+ unsigned char * roguebytes = malloc( sigdata->n_instruments * XM_MAX_SAMPLES_PER_INSTRUMENT );
+ if (!roguebytes) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
+ if (!sigdata->instrument) {
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+
+ total_samples = 0;
+ sigdata->sample = NULL;
+
+ for (i = 0; i < sigdata->n_instruments; i++) {
+ XM_INSTRUMENT_EXTRA extra;
+
+ if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) {
+ TRACE("XM error: instrument %d\n", i+1);
+ free(roguebytes);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (j = total_samples; j < total_samples+extra.n_samples; j++)
+ sigdata->sample[j].data = NULL;
+
+ if (extra.n_samples) {
+ /* adjust instrument sample map (make indices absolute) */
+ for (j = 0; j < 96; j++)
+ sigdata->instrument[i].map_sample[j] += total_samples;
+
+ sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples));
+ if (!sigdata->sample) {
+ free(roguebytes);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (j = total_samples; j < total_samples+extra.n_samples; j++)
+ sigdata->sample[j].data = NULL;
+
+ /* read instrument's samples */
+ for (j = 0; j < extra.n_samples; j++) {
+ IT_SAMPLE *sample = &sigdata->sample[total_samples+j];
+ int b = it_xm_read_sample_header(sample, f);
+ if (b < 0) {
+ free(roguebytes);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ roguebytes[total_samples+j] = b;
+ // Any reason why these can't be set inside it_xm_read_sample_header()?
+ sample->vibrato_speed = extra.vibrato_speed;
+ sample->vibrato_depth = extra.vibrato_depth;
+ sample->vibrato_rate = extra.vibrato_sweep;
+ /* Rate and sweep don't match, but the difference is
+ * accounted for in itrender.c.
+ */
+ sample->vibrato_waveform = xm_convert_vibrato[extra.vibrato_type];
+ sample->max_resampling_quality = -1;
+ }
+ total_samples += extra.n_samples;
+ }
+ }
+
+ sigdata->n_samples = total_samples;
+
+ /*
+ --------------------
+ --- Patterns ---
+ --------------------
+ */
+
+ sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
+ if (!sigdata->pattern) {
+ free(roguebytes);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (i = 0; i < sigdata->n_patterns; i++)
+ sigdata->pattern[i].entry = NULL;
+
+ {
+ unsigned char *buffer = malloc(1280 * n_channels); /* 256 rows * 5 bytes */
+ if (!buffer) {
+ free(roguebytes);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ for (i = 0; i < sigdata->n_patterns; i++) {
+ if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, buffer, * version) != 0) {
+ free(buffer);
+ free(roguebytes);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ }
+ free(buffer);
+ }
+
+ // and now we load the sample data
+ for (j = 0; j < total_samples; j++) {
+ if (it_xm_read_sample_data(&sigdata->sample[j], roguebytes[j], f) != 0) {
+ free(roguebytes);
+ _dumb_it_unload_sigdata(sigdata);
+ return NULL;
+ }
+ }
+
+ free(roguebytes);
+ }
+
+
+ sigdata->flags = IT_WAS_AN_XM | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO | IT_USE_INSTRUMENTS;
+ // Are we OK with IT_COMPATIBLE_GXX off?
+ //
+ // When specifying note + instr + tone portamento, and an old note is still playing (even after note off):
+ // - If Compatible Gxx is on, the new note will be triggered only if the instrument _changes_.
+ // - If Compatible Gxx is off, the new note will always be triggered, provided the instrument is specified.
+ // - FT2 seems to do the latter (unconfirmed).
+
+ // Err, wait. XM playback has its own code. The change made to the IT
+ // playbackc code didn't affect XM playback. Forget this then. There's
+ // still a bug in XM playback though, and it'll need some investigation...
+ // tomorrow...
+
+ // UPDATE: IT_COMPATIBLE_GXX is required to be on, so that tone porta has
+ // separate memory from portamento.
+
+ if (flags & XM_LINEAR_FREQUENCY)
+ sigdata->flags |= IT_LINEAR_SLIDES;
+
+ sigdata->global_volume = 128;
+ sigdata->mixing_volume = 48;
+ sigdata->pan_separation = 128;
+
+ memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
+ memset(sigdata->channel_pan, 32, DUMB_IT_N_CHANNELS);
+
+ _dumb_it_fix_invalid_orders(sigdata);
+
+ return sigdata;
+}
+
+
+
+#if 0 // no fucking way, dude!
+
+/* The length returned is the time required to play from the beginning of the
+ * file to the last row of the last order (which is when the player will
+ * loop). Depending on the song, the sound might stop sooner.
+ * Due to fixed point roundoffs, I think this is only reliable to the second.
+ * Full precision could be achieved by using a double during the computation,
+ * or maybe a LONG_LONG.
+ */
+long it_compute_length(const DUMB_IT_SIGDATA *sigdata)
+{
+ IT_PATTERN *pattern;
+ int tempo, speed;
+ int loop_start[IT_N_CHANNELS];
+ char loop_count[IT_N_CHANNELS];
+ int order, entry;
+ int row_first_entry = 0;
+ int jump, jump_dest;
+ int delay, fine_delay;
+ int i;
+ long t;
+
+ if (!sigdata)
+ return 0;
+
+ tempo = sigdata->tempo;
+ speed = sigdata->speed;
+ order = entry = 0;
+ jump = jump_dest = 0;
+ t = 0;
+
+ /* for each PATTERN */
+ for (order = 0; order < sigdata->n_orders; order++) {
+
+ if (sigdata->order[order] == IT_ORDER_END) break;
+ if (sigdata->order[order] == IT_ORDER_SKIP) continue;
+
+ for (i = 0; i < IT_N_CHANNELS; i++)
+ loop_count[i] = -1;
+
+ pattern = &sigdata->pattern[ sigdata->order[order] ];
+ entry = 0;
+ if (jump == IT_BREAK_TO_ROW) {
+ int row = 0;
+ while (row < jump_dest)
+ if (pattern->entry[entry++].channel >= IT_N_CHANNELS)
+ row++;
+ }
+
+ /* for each ROW */
+ while (entry < pattern->n_entries) {
+ row_first_entry = entry;
+ delay = fine_delay = 0;
+ jump = 0;
+
+ /* for each note NOTE */
+ while (entry < pattern->n_entries && pattern->entry[entry].channel < IT_N_CHANNELS) {
+ int value = pattern->entry[entry].effectvalue;
+ int channel = pattern->entry[entry].channel;
+
+ switch (pattern->entry[entry].effect) {
+
+ case IT_SET_SPEED: speed = value; break;
+
+ case IT_JUMP_TO_ORDER:
+ if (value <= order) /* infinite loop */
+ return 0;
+ jump = IT_JUMP_TO_ORDER;
+ jump_dest = value;
+ break;
+
+ case IT_BREAK_TO_ROW:
+ jump = IT_BREAK_TO_ROW;
+ jump_dest = value;
+ break;
+
+ case IT_S:
+ switch (HIGH(value)) {
+ case IT_S_PATTERN_DELAY: delay = LOW(value); break;
+ case IT_S_FINE_PATTERN_DELAY: fine_delay = LOW(value); break;
+ case IT_S_PATTERN_LOOP:
+ if (LOW(value) == 0) {
+ loop_start[channel] = row_first_entry;
+ } else {
+ if (loop_count[channel] == -1)
+ loop_count[channel] = LOW(value);
+
+ if (loop_count[channel]) {
+ jump = IT_S_PATTERN_LOOP;
+ jump_dest = loop_start[channel];
+ }
+ loop_count[channel]--;
+ }
+ break;
+ }
+ break;
+
+ case IT_SET_SONG_TEMPO:
+ switch (HIGH(value)) { /* slides happen every non-row frames */
+ case 0: tempo = tempo - LOW(value)*(speed-1); break;
+ case 1: tempo = tempo + LOW(value)*(speed-1); break;
+ default: tempo = value;
+ }
+ tempo = MID(32, tempo, 255);
+ break;
+ }
+
+ entry++;
+ }
+
+ /* end of ROW */
+ entry++;
+ t += TICK_TIME_DIVIDEND * (speed*(1+delay) + fine_delay) / tempo;
+
+ if (jump == IT_JUMP_TO_ORDER) {
+ order = jump_dest - 1;
+ break;
+ } else if (jump == IT_BREAK_TO_ROW)
+ break;
+ else if (jump == IT_S_PATTERN_LOOP)
+ entry = jump_dest - 1;
+ }
+
+ /* end of PATTERN */
+ }
+
+ return t;
+}
+
+#endif /* 0 */
+
+
+static char hexdigit(int in)
+{
+ if (in < 10) return in + '0';
+ else return in + 'A' - 10;
+}
+
+DUH *dumb_read_xm_quick(DUMBFILE *f)
+{
+ sigdata_t *sigdata;
+ int ver;
+
+ DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
+
+ sigdata = it_xm_load_sigdata(f, &ver);
+
+ if (!sigdata)
+ return NULL;
+
+ {
+ char version[16];
+ const char *tag[2][2];
+ tag[0][0] = "TITLE";
+ tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+ tag[1][0] = "FORMAT";
+ version[0] = 'X';
+ version[1] = 'M';
+ version[2] = ' ';
+ version[3] = 'v';
+ version[4] = hexdigit( ( ver >> 8 ) & 15 );
+ version[5] = '.';
+ version[6] = hexdigit( ( ver >> 4 ) & 15 );
+ version[7] = hexdigit( ver & 15 );
+ version[8] = 0;
+ tag[1][1] = ( const char * ) & version;
+ return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/readxm2.c b/plugins/dumb/dumb-kode54/src/it/readxm2.c
index c79f753f..b678bd2d 100644
--- a/plugins/dumb/dumb-kode54/src/it/readxm2.c
+++ b/plugins/dumb/dumb-kode54/src/it/readxm2.c
@@ -1,29 +1,29 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readxm2.c - Function to read a Fast Tracker II / / \ \
- * module from an open file and do an | < / \_
- * initial run-through. | \/ /\ /
- * \_ / > /
- * Split off from readxm.c by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_read_xm(DUMBFILE *f)
-{
- DUH *duh = dumb_read_xm_quick(f);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * readxm2.c - Function to read a Fast Tracker II / / \ \
+ * module from an open file and do an | < / \_
+ * initial run-through. | \/ /\ /
+ * \_ / > /
+ * Split off from readxm.c by entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_read_xm(DUMBFILE *f)
+{
+ DUH *duh = dumb_read_xm_quick(f);
+ dumb_it_do_initial_runthrough(duh);
+ return duh;
+}
diff --git a/plugins/dumb/dumb-kode54/src/it/xmeffect.c b/plugins/dumb/dumb-kode54/src/it/xmeffect.c
index 2187a0b3..143bd804 100644
--- a/plugins/dumb/dumb-kode54/src/it/xmeffect.c
+++ b/plugins/dumb/dumb-kode54/src/it/xmeffect.c
@@ -1,243 +1,243 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * xmeffect.c - Code for converting MOD/XM / / \ \
- * effects to IT effects. | < / \_
- * | \/ /\ /
- * By Julien Cugniere. Ripped out of readxm.c \_ / > /
- * by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-#if 0
-unsigned char **_dumb_malloc2(int w, int h)
-{
- unsigned char **line = malloc(h * sizeof(*line));
- int i;
- if (!line) return NULL;
-
- line[0] = malloc(w * h * sizeof(*line[0]));
- if (!line[0]) {
- free(line);
- return NULL;
- }
-
- for (i = 1; i < h; i++)
- line[i] = line[i-1] + w;
-
- memset(line[0], 0, w*h);
-
- return line;
-}
-
-
-
-void _dumb_free2(unsigned char **line)
-{
- if (line) {
- if (line[0])
- free(line[0]);
- free(line);
- }
-}
-
-
-
-/* Effects having a memory. 2 means that the two parts of the effectvalue
- * should be handled separately.
- */
-static const char xm_has_memory[] = {
-/* 0 1 2 3 4 5 6 7 8 9 A B C D (E) F G H K L P R T (X) */
- 0, 1, 1, 1, 2, 1, 1, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
-
-/* E0 E1 E2 E3 E4 E5 E6 E7 E9 EA EB EC ED EE X1 X2 */
- 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-#endif
-
-
-
-/* Effects marked with 'special' are handled specifically in itrender.c */
-void _dumb_it_xm_convert_effect(int effect, int value, IT_ENTRY *entry, int mod)
-{
-const int log = 0;
-
- if ((!effect && !value) || (effect >= XM_N_EFFECTS))
- return;
-
-if (log) printf("%c%02X", (effect<10)?('0'+effect):('A'+effect-10), value);
-
- /* Linearisation of the effect number... */
- if (effect == XM_E) {
- effect = EBASE + HIGH(value);
- value = LOW(value);
- } else if (effect == XM_X) {
- effect = XBASE + HIGH(value);
- value = LOW(value);
- }
-
-if (log) printf(" - %2d %02X", effect, value);
-
-#if 0 // This should be handled in itrender.c!
- /* update effect memory */
- switch (xm_has_memory[effect]) {
- case 1:
- if (!value)
- value = memory[entry->channel][effect];
- else
- memory[entry->channel][effect] = value;
- break;
-
- case 2:
- if (!HIGH(value))
- SET_HIGH(value, HIGH(memory[entry->channel][effect]));
- else
- SET_HIGH(memory[entry->channel][effect], HIGH(value));
-
- if (!LOW(value))
- SET_LOW(value, LOW(memory[entry->channel][effect]));
- else
- SET_LOW(memory[entry->channel][effect], LOW(value));
- break;
- }
-#endif
-
- /* convert effect */
- entry->mask |= IT_ENTRY_EFFECT;
- switch (effect) {
-
- case XM_APPREGIO: effect = IT_ARPEGGIO; break;
- case XM_VIBRATO: effect = IT_VIBRATO; break;
- case XM_TONE_PORTAMENTO: effect = IT_TONE_PORTAMENTO; break;
- case XM_TREMOLO: effect = IT_TREMOLO; break;
- case XM_SET_PANNING: effect = IT_SET_PANNING; break;
- case XM_SAMPLE_OFFSET: effect = IT_SET_SAMPLE_OFFSET; break;
- case XM_POSITION_JUMP: effect = IT_JUMP_TO_ORDER; break;
- case XM_MULTI_RETRIG: effect = IT_RETRIGGER_NOTE; break;
- case XM_TREMOR: effect = IT_TREMOR; break;
- case XM_PORTAMENTO_UP: effect = IT_XM_PORTAMENTO_UP; break;
- case XM_PORTAMENTO_DOWN: effect = IT_XM_PORTAMENTO_DOWN; break;
- case XM_SET_CHANNEL_VOLUME: effect = IT_SET_CHANNEL_VOLUME; break; /* special */
- case XM_VOLSLIDE_TONEPORTA: effect = IT_VOLSLIDE_TONEPORTA; break; /* special */
- case XM_VOLSLIDE_VIBRATO: effect = IT_VOLSLIDE_VIBRATO; break; /* special */
-
- case XM_PATTERN_BREAK:
- effect = IT_BREAK_TO_ROW;
- value = BCD_TO_NORMAL(value);
- if (value > 63) value = 0; /* FT2, maybe ProTracker? */
- break;
-
- case XM_VOLUME_SLIDE: /* special */
- effect = IT_VOLUME_SLIDE;
- value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
- break;
-
- case XM_PANNING_SLIDE:
- effect = IT_PANNING_SLIDE;
- //value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
- value = HIGH(value) ? EFFECT_VALUE(0, HIGH(value)) : EFFECT_VALUE(LOW(value), 0);
- break;
-
- case XM_GLOBAL_VOLUME_SLIDE: /* special */
- effect = IT_GLOBAL_VOLUME_SLIDE;
- value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
- break;
-
- case XM_SET_TEMPO_BPM:
- if (mod) effect = (value <= 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
- else effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
- break;
-
- case XM_SET_GLOBAL_VOLUME:
- effect = IT_SET_GLOBAL_VOLUME;
- value *= 2;
- break;
-
- case XM_KEY_OFF:
- effect = IT_XM_KEY_OFF;
- break;
-
- case XM_SET_ENVELOPE_POSITION:
- effect = IT_XM_SET_ENVELOPE_POSITION;
- break;
-
- case EBASE+XM_E_SET_FILTER: effect = SBASE+IT_S_SET_FILTER; break;
- case EBASE+XM_E_SET_GLISSANDO_CONTROL: effect = SBASE+IT_S_SET_GLISSANDO_CONTROL; break; /** TODO */
- case EBASE+XM_E_SET_FINETUNE: effect = SBASE+IT_S_FINETUNE; break;
- case EBASE+XM_E_SET_LOOP: effect = SBASE+IT_S_PATTERN_LOOP; break;
- case EBASE+XM_E_NOTE_CUT: effect = SBASE+IT_S_DELAYED_NOTE_CUT; break;
- case EBASE+XM_E_NOTE_DELAY: effect = SBASE+IT_S_NOTE_DELAY; break;
- case EBASE+XM_E_PATTERN_DELAY: effect = SBASE+IT_S_PATTERN_DELAY; break;
- case EBASE+XM_E_SET_PANNING: effect = SBASE+IT_S_SET_PAN; break;
- case EBASE+XM_E_FINE_VOLSLIDE_UP: effect = IT_XM_FINE_VOLSLIDE_UP; break;
- case EBASE+XM_E_FINE_VOLSLIDE_DOWN: effect = IT_XM_FINE_VOLSLIDE_DOWN; break;
-
- case EBASE + XM_E_FINE_PORTA_UP:
- effect = IT_PORTAMENTO_UP;
- value = EFFECT_VALUE(0xF, value);
- break;
-
- case EBASE + XM_E_FINE_PORTA_DOWN:
- effect = IT_PORTAMENTO_DOWN;
- value = EFFECT_VALUE(0xF, value);
- break;
-
- case EBASE + XM_E_RETRIG_NOTE:
- effect = IT_XM_RETRIGGER_NOTE;
- value = EFFECT_VALUE(0, value);
- break;
-
- case EBASE + XM_E_SET_VIBRATO_CONTROL:
- effect = SBASE+IT_S_SET_VIBRATO_WAVEFORM;
- value &= ~4;
- break;
-
- case EBASE + XM_E_SET_TREMOLO_CONTROL:
- effect = SBASE+IT_S_SET_TREMOLO_WAVEFORM;
- value &= ~4;
- break;
-
- case XBASE + XM_X_EXTRAFINE_PORTA_UP:
- effect = IT_PORTAMENTO_UP;
- value = EFFECT_VALUE(0xE, value);
- break;
-
- case XBASE + XM_X_EXTRAFINE_PORTA_DOWN:
- effect = IT_PORTAMENTO_DOWN;
- value = EFFECT_VALUE(0xE, value);
- break;
-
- default:
- /* user effect (often used in demos for synchronisation) */
- entry->mask &= ~IT_ENTRY_EFFECT;
- }
-
-if (log) printf(" - %2d %02X", effect, value);
-
- /* Inverse linearisation... */
- if (effect >= SBASE && effect < SBASE+16) {
- value = EFFECT_VALUE(effect-SBASE, value);
- effect = IT_S;
- }
-
-if (log) printf(" - %c%02X\n", 'A'+effect-1, value);
-
- entry->effect = effect;
- entry->effectvalue = value;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * xmeffect.c - Code for converting MOD/XM / / \ \
+ * effects to IT effects. | < / \_
+ * | \/ /\ /
+ * By Julien Cugniere. Ripped out of readxm.c \_ / > /
+ * by entheh. | \ / /
+ * | ' /
+ * \__/
+ */
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dumb.h"
+#include "internal/it.h"
+
+#if 0
+unsigned char **_dumb_malloc2(int w, int h)
+{
+ unsigned char **line = malloc(h * sizeof(*line));
+ int i;
+ if (!line) return NULL;
+
+ line[0] = malloc(w * h * sizeof(*line[0]));
+ if (!line[0]) {
+ free(line);
+ return NULL;
+ }
+
+ for (i = 1; i < h; i++)
+ line[i] = line[i-1] + w;
+
+ memset(line[0], 0, w*h);
+
+ return line;
+}
+
+
+
+void _dumb_free2(unsigned char **line)
+{
+ if (line) {
+ if (line[0])
+ free(line[0]);
+ free(line);
+ }
+}
+
+
+
+/* Effects having a memory. 2 means that the two parts of the effectvalue
+ * should be handled separately.
+ */
+static const char xm_has_memory[] = {
+/* 0 1 2 3 4 5 6 7 8 9 A B C D (E) F G H K L P R T (X) */
+ 0, 1, 1, 1, 2, 1, 1, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* E0 E1 E2 E3 E4 E5 E6 E7 E9 EA EB EC ED EE X1 X2 */
+ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+#endif
+
+
+
+/* Effects marked with 'special' are handled specifically in itrender.c */
+void _dumb_it_xm_convert_effect(int effect, int value, IT_ENTRY *entry, int mod)
+{
+const int log = 0;
+
+ if ((!effect && !value) || (effect >= XM_N_EFFECTS))
+ return;
+
+if (log) printf("%c%02X", (effect<10)?('0'+effect):('A'+effect-10), value);
+
+ /* Linearisation of the effect number... */
+ if (effect == XM_E) {
+ effect = EBASE + HIGH(value);
+ value = LOW(value);
+ } else if (effect == XM_X) {
+ effect = XBASE + HIGH(value);
+ value = LOW(value);
+ }
+
+if (log) printf(" - %2d %02X", effect, value);
+
+#if 0 // This should be handled in itrender.c!
+ /* update effect memory */
+ switch (xm_has_memory[effect]) {
+ case 1:
+ if (!value)
+ value = memory[entry->channel][effect];
+ else
+ memory[entry->channel][effect] = value;
+ break;
+
+ case 2:
+ if (!HIGH(value))
+ SET_HIGH(value, HIGH(memory[entry->channel][effect]));
+ else
+ SET_HIGH(memory[entry->channel][effect], HIGH(value));
+
+ if (!LOW(value))
+ SET_LOW(value, LOW(memory[entry->channel][effect]));
+ else
+ SET_LOW(memory[entry->channel][effect], LOW(value));
+ break;
+ }
+#endif
+
+ /* convert effect */
+ entry->mask |= IT_ENTRY_EFFECT;
+ switch (effect) {
+
+ case XM_APPREGIO: effect = IT_ARPEGGIO; break;
+ case XM_VIBRATO: effect = IT_VIBRATO; break;
+ case XM_TONE_PORTAMENTO: effect = IT_TONE_PORTAMENTO; break;
+ case XM_TREMOLO: effect = IT_TREMOLO; break;
+ case XM_SET_PANNING: effect = IT_SET_PANNING; break;
+ case XM_SAMPLE_OFFSET: effect = IT_SET_SAMPLE_OFFSET; break;
+ case XM_POSITION_JUMP: effect = IT_JUMP_TO_ORDER; break;
+ case XM_MULTI_RETRIG: effect = IT_RETRIGGER_NOTE; break;
+ case XM_TREMOR: effect = IT_TREMOR; break;
+ case XM_PORTAMENTO_UP: effect = IT_XM_PORTAMENTO_UP; break;
+ case XM_PORTAMENTO_DOWN: effect = IT_XM_PORTAMENTO_DOWN; break;
+ case XM_SET_CHANNEL_VOLUME: effect = IT_SET_CHANNEL_VOLUME; break; /* special */
+ case XM_VOLSLIDE_TONEPORTA: effect = IT_VOLSLIDE_TONEPORTA; break; /* special */
+ case XM_VOLSLIDE_VIBRATO: effect = IT_VOLSLIDE_VIBRATO; break; /* special */
+
+ case XM_PATTERN_BREAK:
+ effect = IT_BREAK_TO_ROW;
+ value = BCD_TO_NORMAL(value);
+ if (value > 63) value = 0; /* FT2, maybe ProTracker? */
+ break;
+
+ case XM_VOLUME_SLIDE: /* special */
+ effect = IT_VOLUME_SLIDE;
+ value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
+ break;
+
+ case XM_PANNING_SLIDE:
+ effect = IT_PANNING_SLIDE;
+ //value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
+ value = HIGH(value) ? EFFECT_VALUE(0, HIGH(value)) : EFFECT_VALUE(LOW(value), 0);
+ break;
+
+ case XM_GLOBAL_VOLUME_SLIDE: /* special */
+ effect = IT_GLOBAL_VOLUME_SLIDE;
+ value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
+ break;
+
+ case XM_SET_TEMPO_BPM:
+ if (mod) effect = (value <= 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
+ else effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
+ break;
+
+ case XM_SET_GLOBAL_VOLUME:
+ effect = IT_SET_GLOBAL_VOLUME;
+ value *= 2;
+ break;
+
+ case XM_KEY_OFF:
+ effect = IT_XM_KEY_OFF;
+ break;
+
+ case XM_SET_ENVELOPE_POSITION:
+ effect = IT_XM_SET_ENVELOPE_POSITION;
+ break;
+
+ case EBASE+XM_E_SET_FILTER: effect = SBASE+IT_S_SET_FILTER; break;
+ case EBASE+XM_E_SET_GLISSANDO_CONTROL: effect = SBASE+IT_S_SET_GLISSANDO_CONTROL; break; /** TODO */
+ case EBASE+XM_E_SET_FINETUNE: effect = SBASE+IT_S_FINETUNE; break;
+ case EBASE+XM_E_SET_LOOP: effect = SBASE+IT_S_PATTERN_LOOP; break;
+ case EBASE+XM_E_NOTE_CUT: effect = SBASE+IT_S_DELAYED_NOTE_CUT; break;
+ case EBASE+XM_E_NOTE_DELAY: effect = SBASE+IT_S_NOTE_DELAY; break;
+ case EBASE+XM_E_PATTERN_DELAY: effect = SBASE+IT_S_PATTERN_DELAY; break;
+ case EBASE+XM_E_SET_PANNING: effect = SBASE+IT_S_SET_PAN; break;
+ case EBASE+XM_E_FINE_VOLSLIDE_UP: effect = IT_XM_FINE_VOLSLIDE_UP; break;
+ case EBASE+XM_E_FINE_VOLSLIDE_DOWN: effect = IT_XM_FINE_VOLSLIDE_DOWN; break;
+
+ case EBASE + XM_E_FINE_PORTA_UP:
+ effect = IT_PORTAMENTO_UP;
+ value = EFFECT_VALUE(0xF, value);
+ break;
+
+ case EBASE + XM_E_FINE_PORTA_DOWN:
+ effect = IT_PORTAMENTO_DOWN;
+ value = EFFECT_VALUE(0xF, value);
+ break;
+
+ case EBASE + XM_E_RETRIG_NOTE:
+ effect = IT_XM_RETRIGGER_NOTE;
+ value = EFFECT_VALUE(0, value);
+ break;
+
+ case EBASE + XM_E_SET_VIBRATO_CONTROL:
+ effect = SBASE+IT_S_SET_VIBRATO_WAVEFORM;
+ value &= ~4;
+ break;
+
+ case EBASE + XM_E_SET_TREMOLO_CONTROL:
+ effect = SBASE+IT_S_SET_TREMOLO_WAVEFORM;
+ value &= ~4;
+ break;
+
+ case XBASE + XM_X_EXTRAFINE_PORTA_UP:
+ effect = IT_PORTAMENTO_UP;
+ value = EFFECT_VALUE(0xE, value);
+ break;
+
+ case XBASE + XM_X_EXTRAFINE_PORTA_DOWN:
+ effect = IT_PORTAMENTO_DOWN;
+ value = EFFECT_VALUE(0xE, value);
+ break;
+
+ default:
+ /* user effect (often used in demos for synchronisation) */
+ entry->mask &= ~IT_ENTRY_EFFECT;
+ }
+
+if (log) printf(" - %2d %02X", effect, value);
+
+ /* Inverse linearisation... */
+ if (effect >= SBASE && effect < SBASE+16) {
+ value = EFFECT_VALUE(effect-SBASE, value);
+ effect = IT_S;
+ }
+
+if (log) printf(" - %c%02X\n", 'A'+effect-1, value);
+
+ entry->effect = effect;
+ entry->effectvalue = value;
+}
diff --git a/plugins/dumb/dumb-kode54/src/sigtypes/combine.c b/plugins/dumb/dumb-kode54/src/sigtypes/combine.c
index 497f085c..842359a1 100644
--- a/plugins/dumb/dumb-kode54/src/sigtypes/combine.c
+++ b/plugins/dumb/dumb-kode54/src/sigtypes/combine.c
@@ -1,243 +1,243 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * combine.c - The combining (COMB) signal type. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * This takes multiple monaural signals and | \ / /
- * combines them into a single multichannel | ' /
- * signal. It assumes the correct number of \__/
- * channels is passed. An ASSERT() is in place
- * to check the number of channels when you
- * compile with -DDEBUGMODE. As an exception, if one channel is passed the
- * signals are all mixed together.
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-
-
-
-#define SIGTYPE_COMBINING DUMB_ID('C','O','M','B')
-
-
-
-typedef struct COMBINING_SIGNAL
-{
- int n_signals;
- int sig[ZERO_SIZE];
-}
-COMBINING_SIGNAL;
-
-
-
-typedef struct COMBINING_SAMPINFO
-{
- int n_signals;
- int downmix;
- DUH_SIGNAL_SAMPINFO *csampinfo[ZERO_SIZE];
-}
-COMBINING_SAMPINFO;
-
-
-
-static void *combining_load_signal(DUH *duh, DUMBFILE *file)
-{
- COMBINING_SIGNAL *signal;
- int n_signals;
-
- (void)duh;
-
- n_signals = dumbfile_getc(file);
-
- /* No point in combining only one signal! */
- if (dumbfile_error(file) || n_signals <= 1)
- return NULL;
-
- signal = malloc(sizeof(*signal) + n_signals * sizeof(*signal->sig));
- if (!signal)
- return NULL;
-
- signal->n_signals = n_signals;
-
- {
- int n;
- for (n = 0; n < signal->n_signals; n++) {
- signal->sig[n] = dumbfile_igetl(file);
- if (dumbfile_error(file)) {
- free(signal);
- return NULL;
- }
- }
- }
-
- return signal;
-}
-
-
-
-static void *combining_start_samples(DUH *duh, void *signal, int n_channels, long pos)
-{
-#define signal ((COMBINING_SIGNAL *)signal)
-
- COMBINING_SAMPINFO *sampinfo;
-
- sampinfo = malloc(sizeof(*sampinfo) + signal->n_signals * sizeof(*sampinfo->csampinfo));
- if (!sampinfo)
- return NULL;
-
- sampinfo->n_signals = signal->n_signals;
- if (n_channels == 1)
- sampinfo->downmix = 1;
- else if (n_channels == signal->n_signals)
- sampinfo->downmix = 0;
- else {
- TRACE("Combining signal discrepancy: %d signals, %d channels.\n", signal->n_signals, n_channels);
- free(sampinfo);
- return NULL;
- }
-
- {
- int worthwhile = 0;
-
- {
- int n;
- for (n = 0; n < signal->n_signals; n++) {
- sampinfo->csampinfo[n] = duh_signal_start_samples(duh, signal->sig[n], 1, pos);
- if (sampinfo->csampinfo[n])
- worthwhile = 1;
- }
- }
-
- if (!worthwhile) {
- free(sampinfo);
- return NULL;
- }
- }
-
- return sampinfo;
-
-#undef signal
-}
-
-
-
-static long combining_render_samples(
- void *sampinfo,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
-#define sampinfo ((COMBINING_SAMPINFO *)sampinfo)
-
- long max_size;
-
- int n;
-
- if (sampinfo->downmix)
- volume /= sampinfo->n_signals;
-
- max_size = duh_signal_render_samples(sampinfo->csampinfo[0], volume, delta, size, samples);
-
- if (sampinfo->downmix) {
-
- long s;
- long sz;
-
- sample_t *sampbuf = malloc(size * sizeof(sample_t));
-
- if (!sampbuf)
- return 0;
-
- for (n = 1; n < sampinfo->n_signals; n++) {
- sz = duh_signal_render_samples(sampinfo->csampinfo[n], volume, delta, size, &sampbuf);
- if (sz > max_size) {
- for (s = max_size; s < sz; s++)
- samples[0][s] = sampbuf[s];
- sz = max_size;
- max_size = s;
- }
- for (s = 0; s < sz; s++)
- samples[0][s] += sampbuf[s];
- }
-
- free(sampbuf);
-
- } else {
-
- long *sz = malloc(size * sizeof(*sz));
- long s;
-
- if (!sz)
- return 0;
-
- sz[0] = max_size;
-
- for (n = 1; n < sampinfo->n_signals; n++) {
- sz[n] = duh_signal_render_samples(sampinfo->csampinfo[n], volume, delta, size, samples + n);
- if (sz[n] > max_size)
- max_size = sz[n];
- }
-
- for (n = 0; n < sampinfo->n_signals; n++)
- for (s = sz[n]; s < max_size; s++)
- samples[n][s] = 0;
-
- free(sz);
-
- }
-
- return max_size;
-
-#undef sampinfo
-}
-
-
-
-static void combining_end_samples(void *sampinfo)
-{
-#define sampinfo ((COMBINING_SAMPINFO *)sampinfo)
-
- int n;
-
- for (n = 0; n < sampinfo->n_signals; n++)
- duh_signal_end_samples(sampinfo->csampinfo[n]);
-
- free(sampinfo);
-
-#undef sampinfo
-}
-
-
-
-static void combining_unload_signal(void *signal)
-{
- free(signal);
-}
-
-
-
-static DUH_SIGTYPE_DESC sigtype_combining = {
- SIGTYPE_COMBINING,
- &combining_load_signal,
- &combining_start_samples,
- NULL,
- &combining_render_samples,
- &combining_end_samples,
- &combining_unload_signal
-};
-
-
-void dumb_register_sigtype_combining(void)
-{
- dumb_register_sigtype(&sigtype_combining);
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * combine.c - The combining (COMB) signal type. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * This takes multiple monaural signals and | \ / /
+ * combines them into a single multichannel | ' /
+ * signal. It assumes the correct number of \__/
+ * channels is passed. An ASSERT() is in place
+ * to check the number of channels when you
+ * compile with -DDEBUGMODE. As an exception, if one channel is passed the
+ * signals are all mixed together.
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+
+
+
+#define SIGTYPE_COMBINING DUMB_ID('C','O','M','B')
+
+
+
+typedef struct COMBINING_SIGNAL
+{
+ int n_signals;
+ int sig[ZERO_SIZE];
+}
+COMBINING_SIGNAL;
+
+
+
+typedef struct COMBINING_SAMPINFO
+{
+ int n_signals;
+ int downmix;
+ DUH_SIGNAL_SAMPINFO *csampinfo[ZERO_SIZE];
+}
+COMBINING_SAMPINFO;
+
+
+
+static void *combining_load_signal(DUH *duh, DUMBFILE *file)
+{
+ COMBINING_SIGNAL *signal;
+ int n_signals;
+
+ (void)duh;
+
+ n_signals = dumbfile_getc(file);
+
+ /* No point in combining only one signal! */
+ if (dumbfile_error(file) || n_signals <= 1)
+ return NULL;
+
+ signal = malloc(sizeof(*signal) + n_signals * sizeof(*signal->sig));
+ if (!signal)
+ return NULL;
+
+ signal->n_signals = n_signals;
+
+ {
+ int n;
+ for (n = 0; n < signal->n_signals; n++) {
+ signal->sig[n] = dumbfile_igetl(file);
+ if (dumbfile_error(file)) {
+ free(signal);
+ return NULL;
+ }
+ }
+ }
+
+ return signal;
+}
+
+
+
+static void *combining_start_samples(DUH *duh, void *signal, int n_channels, long pos)
+{
+#define signal ((COMBINING_SIGNAL *)signal)
+
+ COMBINING_SAMPINFO *sampinfo;
+
+ sampinfo = malloc(sizeof(*sampinfo) + signal->n_signals * sizeof(*sampinfo->csampinfo));
+ if (!sampinfo)
+ return NULL;
+
+ sampinfo->n_signals = signal->n_signals;
+ if (n_channels == 1)
+ sampinfo->downmix = 1;
+ else if (n_channels == signal->n_signals)
+ sampinfo->downmix = 0;
+ else {
+ TRACE("Combining signal discrepancy: %d signals, %d channels.\n", signal->n_signals, n_channels);
+ free(sampinfo);
+ return NULL;
+ }
+
+ {
+ int worthwhile = 0;
+
+ {
+ int n;
+ for (n = 0; n < signal->n_signals; n++) {
+ sampinfo->csampinfo[n] = duh_signal_start_samples(duh, signal->sig[n], 1, pos);
+ if (sampinfo->csampinfo[n])
+ worthwhile = 1;
+ }
+ }
+
+ if (!worthwhile) {
+ free(sampinfo);
+ return NULL;
+ }
+ }
+
+ return sampinfo;
+
+#undef signal
+}
+
+
+
+static long combining_render_samples(
+ void *sampinfo,
+ float volume, float delta,
+ long size, sample_t **samples
+)
+{
+#define sampinfo ((COMBINING_SAMPINFO *)sampinfo)
+
+ long max_size;
+
+ int n;
+
+ if (sampinfo->downmix)
+ volume /= sampinfo->n_signals;
+
+ max_size = duh_signal_render_samples(sampinfo->csampinfo[0], volume, delta, size, samples);
+
+ if (sampinfo->downmix) {
+
+ long s;
+ long sz;
+
+ sample_t *sampbuf = malloc(size * sizeof(sample_t));
+
+ if (!sampbuf)
+ return 0;
+
+ for (n = 1; n < sampinfo->n_signals; n++) {
+ sz = duh_signal_render_samples(sampinfo->csampinfo[n], volume, delta, size, &sampbuf);
+ if (sz > max_size) {
+ for (s = max_size; s < sz; s++)
+ samples[0][s] = sampbuf[s];
+ sz = max_size;
+ max_size = s;
+ }
+ for (s = 0; s < sz; s++)
+ samples[0][s] += sampbuf[s];
+ }
+
+ free(sampbuf);
+
+ } else {
+
+ long *sz = malloc(size * sizeof(*sz));
+ long s;
+
+ if (!sz)
+ return 0;
+
+ sz[0] = max_size;
+
+ for (n = 1; n < sampinfo->n_signals; n++) {
+ sz[n] = duh_signal_render_samples(sampinfo->csampinfo[n], volume, delta, size, samples + n);
+ if (sz[n] > max_size)
+ max_size = sz[n];
+ }
+
+ for (n = 0; n < sampinfo->n_signals; n++)
+ for (s = sz[n]; s < max_size; s++)
+ samples[n][s] = 0;
+
+ free(sz);
+
+ }
+
+ return max_size;
+
+#undef sampinfo
+}
+
+
+
+static void combining_end_samples(void *sampinfo)
+{
+#define sampinfo ((COMBINING_SAMPINFO *)sampinfo)
+
+ int n;
+
+ for (n = 0; n < sampinfo->n_signals; n++)
+ duh_signal_end_samples(sampinfo->csampinfo[n]);
+
+ free(sampinfo);
+
+#undef sampinfo
+}
+
+
+
+static void combining_unload_signal(void *signal)
+{
+ free(signal);
+}
+
+
+
+static DUH_SIGTYPE_DESC sigtype_combining = {
+ SIGTYPE_COMBINING,
+ &combining_load_signal,
+ &combining_start_samples,
+ NULL,
+ &combining_render_samples,
+ &combining_end_samples,
+ &combining_unload_signal
+};
+
+
+void dumb_register_sigtype_combining(void)
+{
+ dumb_register_sigtype(&sigtype_combining);
+}
diff --git a/plugins/dumb/dumb-kode54/src/sigtypes/sample.c b/plugins/dumb/dumb-kode54/src/sigtypes/sample.c
index 4695de91..d810958e 100644
--- a/plugins/dumb/dumb-kode54/src/sigtypes/sample.c
+++ b/plugins/dumb/dumb-kode54/src/sigtypes/sample.c
@@ -1,340 +1,340 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * sample.c - The sample (SAMP) signal type. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * This only supports monaural samples. For | \ / /
- * multiple channels, use multiple samples and | ' /
- * a combining signal (COMB). \__/
- */
-
-/* NOTE: filters need not be credited yet, as they will be moved elsewhere. */
-/** WARNING don't forget to move these filters somewhere */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-
-
-/** WARNING move these things somewhere useful, for DUH writing - this applies to other signal types too */
-#define SIGTYPE_SAMPLE DUMB_ID('S','A','M','P')
-
-
-
-#define SAMPFLAG_16BIT 1 /* sample in file is 16 bit, rather than 8 bit */
-#define SAMPFLAG_LOOP 2 /* loop indefinitely */
-#define SAMPFLAG_XLOOP 4 /* loop x times; only relevant if LOOP not set */
-#define SAMPFLAG_PINGPONG 8 /* loop back and forth, if LOOP or XLOOP set */
-
-
-/* SAMPPARAM_N_LOOPS: add 'value' iterations to the loop. 'value' is assumed
- * to be positive.
- */
-#define SAMPPARAM_N_LOOPS 0
-
-
-
-typedef struct SAMPLE_SIGDATA
-{
- long size;
- int flags;
- long loop_start;
- long loop_end;
- sample_t *samples;
-}
-SAMPLE_SIGDATA;
-
-
-
-typedef struct SAMPLE_SIGRENDERER
-{
- SAMPLE_SIGDATA *sigdata;
- int n_channels;
- DUMB_RESAMPLER r;
- int n_loops;
-}
-SAMPLE_SIGRENDERER;
-
-
-
-static sigdata_t *sample_load_sigdata(DUH *duh, DUMBFILE *file)
-{
- SAMPLE_SIGDATA *sigdata;
- long size;
- long n;
- int flags;
-
- (void)duh;
-
- size = dumbfile_igetl(file);
-
- if (dumbfile_error(file) || size <= 0)
- return NULL;
-
- flags = dumbfile_getc(file);
- if (flags < 0)
- return NULL;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata)
- return NULL;
-
- sigdata->samples = malloc(size * sizeof(sample_t));
- if (!sigdata->samples) {
- free(sigdata);
- return NULL;
- }
-
- sigdata->size = size;
- sigdata->flags = flags;
-
- if (sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP)) {
- sigdata->loop_start = dumbfile_igetl(file);
-
- if (dumbfile_error(file) || (unsigned long)sigdata->loop_start >= (unsigned long)size) {
- free(sigdata->samples);
- free(sigdata);
- return NULL;
- }
-
- if (sigdata->flags & SAMPFLAG_LOOP)
- sigdata->loop_end = size;
- else {
- sigdata->loop_end = dumbfile_igetl(file);
-
- if (dumbfile_error(file) || sigdata->loop_end <= sigdata->loop_start || sigdata->loop_end > size) {
- free(sigdata->samples);
- free(sigdata);
- return NULL;
- }
- }
- } else {
- sigdata->loop_start = 0;
- sigdata->loop_end = size;
- }
-
- if (sigdata->flags & SAMPFLAG_16BIT) {
- for (n = 0; n < size; n++) {
- int m = dumbfile_igetw(file);
- if (m < 0) {
- free(sigdata->samples);
- free(sigdata);
- return NULL;
- }
- sigdata->samples[n] = (int)(signed short)m << 8;
- }
- } else {
- for (n = 0; n < size; n++) {
- int m = dumbfile_getc(file);
- if (m < 0) {
- free(sigdata->samples);
- free(sigdata);
- return NULL;
- }
- sigdata->samples[n] = (int)(signed char)m << 16;
- }
- }
-
- return sigdata;
-}
-
-
-
-static void sample_pickup(DUMB_RESAMPLER *r, void *data)
-{
- SAMPLE_SIGRENDERER *sigrenderer = data;
-
- if (!(sigrenderer->sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP))) {
- r->dir = 0;
- return;
- }
-
- if (!(sigrenderer->sigdata->flags & SAMPFLAG_LOOP) && sigrenderer->n_loops == 0) {
- r->dir = 0;
- return;
- }
-
- if (sigrenderer->sigdata->flags & SAMPFLAG_PINGPONG) {
- if (r->dir < 0) {
- r->pos = (r->start << 1) - 1 - r->pos;
- r->subpos ^= 65535;
- r->dir = 1;
- } else {
- r->pos = (r->end << 1) - 1 - r->pos;
- r->subpos ^= 65535;
- r->dir = -1;
- }
- } else
- r->pos -= r->end - r->start;
-
- if (!(sigrenderer->sigdata->flags & SAMPFLAG_LOOP)) {
- if (sigrenderer->n_loops > 0) {
- sigrenderer->n_loops--;
- if (sigrenderer->n_loops == 0) {
- r->start = 0;
- r->end = sigrenderer->sigdata->size;
- }
- }
- }
-}
-
-
-
-static sigrenderer_t *sample_start_sigrenderer(DUH *duh, sigdata_t *data, int n_channels, long pos)
-{
- SAMPLE_SIGDATA *sigdata = data;
- SAMPLE_SIGRENDERER *sigrenderer;
-
- (void)duh;
-
- sigrenderer = malloc(sizeof(*sigrenderer));
- if (!sigrenderer) return NULL;
-
- sigrenderer->sigdata = data;
- sigrenderer->n_channels = n_channels;
- dumb_reset_resampler(&sigrenderer->r, sigdata->samples, pos, 0, sigdata->size);
- sigrenderer->r.pickup = &sample_pickup;
- sigrenderer->r.pickup_data = sigrenderer;
- sigrenderer->n_loops = 0;
-
- return sigrenderer;
-}
-
-
-
-#if 0
-/* The name says it all ;-) */
-static void sample_cheap_low_pass_filter(sample *src, long size, float max_freq) {
-
- long i;
- float fact = max_freq / 44100.0f;
-
- for (i = 0; i < size-1; i++) {
- float d = src[i+1] - src[i];
- if (d > fact)
- src[i+1] += fact - d;
- else if (d < -fact)
- src[i+1] += -d - fact;
- }
-
- return;
-}
-
-
-
-/* Dithering with noise shaping filter. Set shape = 0 for no shaping. */
-static void sample_dither_filter(float *src, long size, float shape) {
- float r1 = 0, r2 = 0;
- float s1 = 0, s2 = 0; /* Feedback buffer */
- float o = 0.5f / 255;
- float tmp;
- int i;
-
- for (i = 0; i < size; i++) {
- r2 = r1;
- r1 = rand() / (float)RAND_MAX;
-
- tmp = src[i] + shape * (s1 + s1 - s2);
- src[i] = tmp + o * (r1 - r2);
- src[i] = MID(-1.0f, src[i], 1.0f);
-
- s2 = s1;
- s1 = tmp - src[i];
- }
- return;
-}
-#endif
-
-
-
-static void sample_sigrenderer_set_sigparam(sigrenderer_t *data, unsigned char id, long value)
-{
- SAMPLE_SIGRENDERER *sigrenderer = data;
-
- if (id == SAMPPARAM_N_LOOPS) {
- if ((sigrenderer->sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP)) == SAMPFLAG_XLOOP) {
- sigrenderer->n_loops += value;
- sigrenderer->r.start = sigrenderer->n_loops ? sigrenderer->sigdata->loop_start : 0;
- sigrenderer->r.end = sigrenderer->n_loops ? sigrenderer->sigdata->loop_end : sigrenderer->sigdata->size;
- }
- }
-}
-
-
-
-static long sample_sigrenderer_get_samples(
- sigrenderer_t *data,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
- SAMPLE_SIGRENDERER *sigrenderer = data;
-
- DUMB_RESAMPLER initial_r = sigrenderer->r;
-
- long s = dumb_resample(&sigrenderer->r, samples[0], size, volume, delta);
-
- int n;
- for (n = 1; n < sigrenderer->n_channels; n++) {
- sigrenderer->r = initial_r;
- dumb_resample(&sigrenderer->r, samples[n], size, volume, delta);
- }
-
- return s;
-}
-
-
-
-static void sample_sigrenderer_get_current_sample(sigrenderer_t *data, float volume, sample_t *samples)
-{
- SAMPLE_SIGRENDERER *sigrenderer = data;
- int n;
- for (n = 0; n < sigrenderer->n_channels; n++)
- samples[n] = dumb_resample_get_current_sample(&sigrenderer->r, volume);
-}
-
-
-
-static void sample_end_sigrenderer(sigrenderer_t *sigrenderer)
-{
- free(sigrenderer);
-}
-
-
-
-static void sample_unload_sigdata(sigdata_t *data)
-{
- SAMPLE_SIGDATA *sigdata = data;
- free(sigdata->samples);
- free(data);
-}
-
-
-
-static DUH_SIGTYPE_DESC sigtype_sample = {
- SIGTYPE_SAMPLE,
- &sample_load_sigdata,
- &sample_start_sigrenderer,
- &sample_sigrenderer_set_sigparam,
- &sample_sigrenderer_get_samples,
- &sample_sigrenderer_get_current_sample,
- &sample_end_sigrenderer,
- &sample_unload_sigdata
-};
-
-
-
-void dumb_register_sigtype_sample(void)
-{
- dumb_register_sigtype(&sigtype_sample);
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * sample.c - The sample (SAMP) signal type. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * This only supports monaural samples. For | \ / /
+ * multiple channels, use multiple samples and | ' /
+ * a combining signal (COMB). \__/
+ */
+
+/* NOTE: filters need not be credited yet, as they will be moved elsewhere. */
+/** WARNING don't forget to move these filters somewhere */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dumb.h"
+
+
+/** WARNING move these things somewhere useful, for DUH writing - this applies to other signal types too */
+#define SIGTYPE_SAMPLE DUMB_ID('S','A','M','P')
+
+
+
+#define SAMPFLAG_16BIT 1 /* sample in file is 16 bit, rather than 8 bit */
+#define SAMPFLAG_LOOP 2 /* loop indefinitely */
+#define SAMPFLAG_XLOOP 4 /* loop x times; only relevant if LOOP not set */
+#define SAMPFLAG_PINGPONG 8 /* loop back and forth, if LOOP or XLOOP set */
+
+
+/* SAMPPARAM_N_LOOPS: add 'value' iterations to the loop. 'value' is assumed
+ * to be positive.
+ */
+#define SAMPPARAM_N_LOOPS 0
+
+
+
+typedef struct SAMPLE_SIGDATA
+{
+ long size;
+ int flags;
+ long loop_start;
+ long loop_end;
+ sample_t *samples;
+}
+SAMPLE_SIGDATA;
+
+
+
+typedef struct SAMPLE_SIGRENDERER
+{
+ SAMPLE_SIGDATA *sigdata;
+ int n_channels;
+ DUMB_RESAMPLER r;
+ int n_loops;
+}
+SAMPLE_SIGRENDERER;
+
+
+
+static sigdata_t *sample_load_sigdata(DUH *duh, DUMBFILE *file)
+{
+ SAMPLE_SIGDATA *sigdata;
+ long size;
+ long n;
+ int flags;
+
+ (void)duh;
+
+ size = dumbfile_igetl(file);
+
+ if (dumbfile_error(file) || size <= 0)
+ return NULL;
+
+ flags = dumbfile_getc(file);
+ if (flags < 0)
+ return NULL;
+
+ sigdata = malloc(sizeof(*sigdata));
+ if (!sigdata)
+ return NULL;
+
+ sigdata->samples = malloc(size * sizeof(sample_t));
+ if (!sigdata->samples) {
+ free(sigdata);
+ return NULL;
+ }
+
+ sigdata->size = size;
+ sigdata->flags = flags;
+
+ if (sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP)) {
+ sigdata->loop_start = dumbfile_igetl(file);
+
+ if (dumbfile_error(file) || (unsigned long)sigdata->loop_start >= (unsigned long)size) {
+ free(sigdata->samples);
+ free(sigdata);
+ return NULL;
+ }
+
+ if (sigdata->flags & SAMPFLAG_LOOP)
+ sigdata->loop_end = size;
+ else {
+ sigdata->loop_end = dumbfile_igetl(file);
+
+ if (dumbfile_error(file) || sigdata->loop_end <= sigdata->loop_start || sigdata->loop_end > size) {
+ free(sigdata->samples);
+ free(sigdata);
+ return NULL;
+ }
+ }
+ } else {
+ sigdata->loop_start = 0;
+ sigdata->loop_end = size;
+ }
+
+ if (sigdata->flags & SAMPFLAG_16BIT) {
+ for (n = 0; n < size; n++) {
+ int m = dumbfile_igetw(file);
+ if (m < 0) {
+ free(sigdata->samples);
+ free(sigdata);
+ return NULL;
+ }
+ sigdata->samples[n] = (int)(signed short)m << 8;
+ }
+ } else {
+ for (n = 0; n < size; n++) {
+ int m = dumbfile_getc(file);
+ if (m < 0) {
+ free(sigdata->samples);
+ free(sigdata);
+ return NULL;
+ }
+ sigdata->samples[n] = (int)(signed char)m << 16;
+ }
+ }
+
+ return sigdata;
+}
+
+
+
+static void sample_pickup(DUMB_RESAMPLER *r, void *data)
+{
+ SAMPLE_SIGRENDERER *sigrenderer = data;
+
+ if (!(sigrenderer->sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP))) {
+ r->dir = 0;
+ return;
+ }
+
+ if (!(sigrenderer->sigdata->flags & SAMPFLAG_LOOP) && sigrenderer->n_loops == 0) {
+ r->dir = 0;
+ return;
+ }
+
+ if (sigrenderer->sigdata->flags & SAMPFLAG_PINGPONG) {
+ if (r->dir < 0) {
+ r->pos = (r->start << 1) - 1 - r->pos;
+ r->subpos ^= 65535;
+ r->dir = 1;
+ } else {
+ r->pos = (r->end << 1) - 1 - r->pos;
+ r->subpos ^= 65535;
+ r->dir = -1;
+ }
+ } else
+ r->pos -= r->end - r->start;
+
+ if (!(sigrenderer->sigdata->flags & SAMPFLAG_LOOP)) {
+ if (sigrenderer->n_loops > 0) {
+ sigrenderer->n_loops--;
+ if (sigrenderer->n_loops == 0) {
+ r->start = 0;
+ r->end = sigrenderer->sigdata->size;
+ }
+ }
+ }
+}
+
+
+
+static sigrenderer_t *sample_start_sigrenderer(DUH *duh, sigdata_t *data, int n_channels, long pos)
+{
+ SAMPLE_SIGDATA *sigdata = data;
+ SAMPLE_SIGRENDERER *sigrenderer;
+
+ (void)duh;
+
+ sigrenderer = malloc(sizeof(*sigrenderer));
+ if (!sigrenderer) return NULL;
+
+ sigrenderer->sigdata = data;
+ sigrenderer->n_channels = n_channels;
+ dumb_reset_resampler(&sigrenderer->r, sigdata->samples, pos, 0, sigdata->size);
+ sigrenderer->r.pickup = &sample_pickup;
+ sigrenderer->r.pickup_data = sigrenderer;
+ sigrenderer->n_loops = 0;
+
+ return sigrenderer;
+}
+
+
+
+#if 0
+/* The name says it all ;-) */
+static void sample_cheap_low_pass_filter(sample *src, long size, float max_freq) {
+
+ long i;
+ float fact = max_freq / 44100.0f;
+
+ for (i = 0; i < size-1; i++) {
+ float d = src[i+1] - src[i];
+ if (d > fact)
+ src[i+1] += fact - d;
+ else if (d < -fact)
+ src[i+1] += -d - fact;
+ }
+
+ return;
+}
+
+
+
+/* Dithering with noise shaping filter. Set shape = 0 for no shaping. */
+static void sample_dither_filter(float *src, long size, float shape) {
+ float r1 = 0, r2 = 0;
+ float s1 = 0, s2 = 0; /* Feedback buffer */
+ float o = 0.5f / 255;
+ float tmp;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ r2 = r1;
+ r1 = rand() / (float)RAND_MAX;
+
+ tmp = src[i] + shape * (s1 + s1 - s2);
+ src[i] = tmp + o * (r1 - r2);
+ src[i] = MID(-1.0f, src[i], 1.0f);
+
+ s2 = s1;
+ s1 = tmp - src[i];
+ }
+ return;
+}
+#endif
+
+
+
+static void sample_sigrenderer_set_sigparam(sigrenderer_t *data, unsigned char id, long value)
+{
+ SAMPLE_SIGRENDERER *sigrenderer = data;
+
+ if (id == SAMPPARAM_N_LOOPS) {
+ if ((sigrenderer->sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP)) == SAMPFLAG_XLOOP) {
+ sigrenderer->n_loops += value;
+ sigrenderer->r.start = sigrenderer->n_loops ? sigrenderer->sigdata->loop_start : 0;
+ sigrenderer->r.end = sigrenderer->n_loops ? sigrenderer->sigdata->loop_end : sigrenderer->sigdata->size;
+ }
+ }
+}
+
+
+
+static long sample_sigrenderer_get_samples(
+ sigrenderer_t *data,
+ float volume, float delta,
+ long size, sample_t **samples
+)
+{
+ SAMPLE_SIGRENDERER *sigrenderer = data;
+
+ DUMB_RESAMPLER initial_r = sigrenderer->r;
+
+ long s = dumb_resample(&sigrenderer->r, samples[0], size, volume, delta);
+
+ int n;
+ for (n = 1; n < sigrenderer->n_channels; n++) {
+ sigrenderer->r = initial_r;
+ dumb_resample(&sigrenderer->r, samples[n], size, volume, delta);
+ }
+
+ return s;
+}
+
+
+
+static void sample_sigrenderer_get_current_sample(sigrenderer_t *data, float volume, sample_t *samples)
+{
+ SAMPLE_SIGRENDERER *sigrenderer = data;
+ int n;
+ for (n = 0; n < sigrenderer->n_channels; n++)
+ samples[n] = dumb_resample_get_current_sample(&sigrenderer->r, volume);
+}
+
+
+
+static void sample_end_sigrenderer(sigrenderer_t *sigrenderer)
+{
+ free(sigrenderer);
+}
+
+
+
+static void sample_unload_sigdata(sigdata_t *data)
+{
+ SAMPLE_SIGDATA *sigdata = data;
+ free(sigdata->samples);
+ free(data);
+}
+
+
+
+static DUH_SIGTYPE_DESC sigtype_sample = {
+ SIGTYPE_SAMPLE,
+ &sample_load_sigdata,
+ &sample_start_sigrenderer,
+ &sample_sigrenderer_set_sigparam,
+ &sample_sigrenderer_get_samples,
+ &sample_sigrenderer_get_current_sample,
+ &sample_end_sigrenderer,
+ &sample_unload_sigdata
+};
+
+
+
+void dumb_register_sigtype_sample(void)
+{
+ dumb_register_sigtype(&sigtype_sample);
+}
diff --git a/plugins/dumb/dumb-kode54/src/sigtypes/sequence.c b/plugins/dumb/dumb-kode54/src/sigtypes/sequence.c
index cfade4d6..38cbe783 100644
--- a/plugins/dumb/dumb-kode54/src/sigtypes/sequence.c
+++ b/plugins/dumb/dumb-kode54/src/sigtypes/sequence.c
@@ -1,592 +1,592 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * sequence.c - The sequence (SEQU) signal type. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-
-
-
-#define SIGTYPE_SEQUENCE DUMB_ID('S','E','Q','U')
-
-
-
-/* We have 256 intervals per semitone, 12 * 256 per octave
- 2 ** (1 / (12 * 256)) = 1.000225659305069791926712241547647863626
-
- pow(DUMB_PITCH_BASE, x) = 1.5
- x = log2(1.5) / log2(DUMB_PITCH_BASE)
- x = log2(1.5) * 12 * 256
- x = 1797.004802
- cf.
- x = 7 * 256 = 1792
-
- so, for the perfect fifth temperament, use an interval of 1797.
-*/
-
-
-
-/* Sequencing format
- * -----------------
- *
- * NOTE: A LOT OF THIS IS NOW REDUNDANT. PLEASE REFER TO duhspecs.txt.
- *
- * When a signal is initiated, it claims a reference number. If any other
- * currently playing signal has the same number, that signal becomes
- * anonymous and inaccessible; that is, if multiple signals were initiated
- * with the same reference, the reference belongs to the most recent.
- *
- * Signals can be stopped, or have their pitch, volume or parameters changed,
- * using the reference number. A signal may stop prematurely if it runs out
- * of data, in which case the reference number becomes void, and operations
- * on it will be ignored. Such a situation will not flag any kind of warning,
- * since it may be the result of inaccuracies when resampling.
- *
- * The sequence consists of a series of commands. All commands begin with a
- * long int, which is the time to wait after the last command (or the
- * beginning of the sequence) before executing this command. 65536 represents
- * one second. A time of -1 (or in fact any negative time) terminates the
- * sequence, but any currently playing signals will continue until they run
- * out. Make sure no non-terminating signals are playing when the sequence
- * ends!
- *
- * The time, if nonnegative, is followed by one byte indicating the type of
- * command. This byte can have the following values:
- *
- * SEQUENCE_START_SIGNAL
- * unsigned char ref; - Reference. Need more than 256? Use two sequences,
- * and get your brain seen to.
- * int sig; - The index of the signal to initiate.
- * long pos; - The position at which to start. 65536 represents one second.
- * unsigned short volume; - Volume. 65535 represents the maximum volume, so
- * you will want to go lower than this if you are
- * playing more than one signal at once.
- * signed short pitch; - Pitch. 0 represents a frequency of 65536 Hz. Scale
- * is logarithmic. Add 256 to increase pitch by one
- * semitone in the even temperament, or add 12*256 to
- * increase pitch by one octave in any temperament
- * (i.e. double the frequency).
- *
- * SEQUENCE_SET_VOLUME
- * unsigned char ref;
- * unsigned short volume;
- *
- * SEQUENCE_SET_PITCH
- * unsigned char ref;
- * signed short pitch;
- *
- * SEQUENCE_SET_PARAMETER
- * unsigned char ref;
- * unsigned char id;
- * long value;
- * - see the description of the set_parameter function pointer for
- * information on 'id' and 'value'.
- *
- * SEQUENCE_STOP_SIGNAL
- * unsigned char ref;
- */
-
-
-
-#define SEQUENCE_START_SIGNAL 0
-#define SEQUENCE_SET_VOLUME 1
-#define SEQUENCE_SET_PITCH 2
-#define SEQUENCE_SET_PARAMETER 3
-#define SEQUENCE_STOP_SIGNAL 4
-
-
-
-typedef struct SEQUENCE_PLAYING
-{
- struct SEQUENCE_PLAYING *next;
-
- DUH_SIGNAL_SAMPINFO *sampinfo;
-
- int ref;
-
- int pitch;
- int volume;
-}
-SEQUENCE_PLAYING;
-
-
-
-typedef struct SEQUENCE_SAMPINFO
-{
- DUH *duh;
-
- int n_channels;
-
- unsigned char *signal;
-
- long time_left;
- int sub_time_left;
-
- SEQUENCE_PLAYING *playing;
-}
-SEQUENCE_SAMPINFO;
-
-
-
-#define sequence_c(signal) ((int)*((*(signal))++))
-
-
-static int sequence_w(unsigned char **signal)
-{
- int v = (*signal)[0] | ((*signal)[1] << 8);
- *signal += 2;
- return v;
-}
-
-
-static long sequence_l(unsigned char **signal)
-{
- long v = (*signal)[0] | ((*signal)[1] << 8) | ((*signal)[2] << 16) | ((*signal)[3] << 24);
- *signal += 4;
- return v;
-}
-
-
-static long sequence_cl(unsigned char **signal)
-{
- long v = sequence_c(signal);
- if (v & 0x80) {
- v &= 0x7F;
- v |= sequence_c(signal) << 7;
- if (v & 0x4000) {
- v &= 0x3FFF;
- v |= sequence_c(signal) << 14;
- if (v & 0x200000) {
- v &= 0x1FFFFF;
- v |= sequence_c(signal) << 21;
- if (v & 0x10000000) {
- v &= 0x0FFFFFFF;
- v |= sequence_c(signal) << 28;
- }
- }
- }
- }
- return v;
-}
-
-
-
-static void *sequence_load_signal(DUH *duh, DUMBFILE *file)
-{
- long size;
- unsigned char *signal;
-
- (void)duh;
-
- size = dumbfile_igetl(file);
- if (dumbfile_error(file) || size <= 0)
- return NULL;
-
- signal = malloc(size);
- if (!signal)
- return NULL;
-
- if (dumbfile_getnc((char *)signal, size, file) < size) {
- free(signal);
- return NULL;
- }
-
- return signal;
-}
-
-
-
-static long render(
- SEQUENCE_SAMPINFO *sampinfo,
- float volume, float delta,
- long pos, long size, sample_t **samples
-)
-{
- sample_t **splptr;
-
- SEQUENCE_PLAYING **playing_p = &sampinfo->playing;
-
- long max_size = 0;
- long part_size;
-
- int n;
- long i;
-
- for (n = 0; n < sampinfo->n_channels; n++)
- memset(samples[n] + pos, 0, size * sizeof(sample_t));
-
- splptr = malloc(sampinfo->n_channels * sizeof(*splptr));
- if (!splptr)
- return 0;
-
- splptr[0] = malloc(sampinfo->n_channels * size * sizeof(sample_t));
- if (!splptr[0]) {
- free(splptr);
- return 0;
- }
-
- for (n = 1; n < sampinfo->n_channels; n++)
- splptr[n] = splptr[n - 1] + size;
-
- while (*playing_p) {
- SEQUENCE_PLAYING *playing = *playing_p;
-
- part_size = duh_signal_render_samples(
- playing->sampinfo,
- volume * (float)playing->volume * (1.0f / 65535.0f),
- (float)(pow(DUMB_PITCH_BASE, playing->pitch) * delta),
- size, splptr
- );
-
- for (n = 0; n < sampinfo->n_channels; n++)
- for (i = 0; i < part_size; i++)
- samples[n][pos+i] += splptr[n][i];
-
- if (part_size > max_size)
- max_size = part_size;
-
- if (part_size < size) {
- *playing_p = playing->next;
- duh_signal_end_samples(playing->sampinfo);
- free(playing);
- } else
- playing_p = &playing->next;
- }
-
- free(splptr[0]);
- free(splptr);
-
- return max_size;
-}
-
-
-
-/* 'offset' is added to the position at which the signal should start. It is
- * currently assumed to be positive, and is currently only used when seeking
- * forwards in the sequence.
- */
-static void sequence_command(SEQUENCE_SAMPINFO *sampinfo, long offset)
-{
- int command = sequence_c(&sampinfo->signal);
-
- if (command == SEQUENCE_START_SIGNAL) {
-
- int ref = sequence_c(&sampinfo->signal);
- int sig = sequence_cl(&sampinfo->signal);
- long pos = sequence_cl(&sampinfo->signal);
- int volume = sequence_w(&sampinfo->signal);
- int pitch = (int)(signed short)sequence_w(&sampinfo->signal);
-
- SEQUENCE_PLAYING *playing = sampinfo->playing;
-
- while (playing) {
- if (playing->ref == ref)
- playing->ref = -1;
- playing = playing->next;
- }
-
- playing = malloc(sizeof(SEQUENCE_PLAYING));
-
- if (playing) {
- playing->sampinfo = duh_signal_start_samples(sampinfo->duh, sig, sampinfo->n_channels, pos + offset);
-
- if (playing->sampinfo) {
- playing->ref = ref;
- playing->pitch = pitch;
- playing->volume = volume;
-
- playing->next = sampinfo->playing;
- sampinfo->playing = playing;
- } else
- free(playing);
- }
-
- } else if (command == SEQUENCE_SET_VOLUME) {
-
- int ref = sequence_c(&sampinfo->signal);
- int volume = sequence_w(&sampinfo->signal);
-
- SEQUENCE_PLAYING *playing = sampinfo->playing;
-
- while (playing) {
- if (playing->ref == ref) {
- playing->volume = volume;
- break;
- }
- playing = playing->next;
- }
-
- } else if (command == SEQUENCE_SET_PITCH) {
-
- int ref = sequence_c(&sampinfo->signal);
- int pitch = (int)(signed short)sequence_w(&sampinfo->signal);
-
- SEQUENCE_PLAYING *playing = sampinfo->playing;
-
- while (playing) {
- if (playing->ref == ref) {
- playing->pitch = pitch;
- break;
- }
- playing = playing->next;
- }
-
- } else if (command == SEQUENCE_SET_PARAMETER) {
-
- int ref = sequence_c(&sampinfo->signal);
- unsigned char id = sequence_c(&sampinfo->signal);
- long value = sequence_l(&sampinfo->signal);
-
- SEQUENCE_PLAYING *playing = sampinfo->playing;
-
- while (playing) {
- if (playing->ref == ref) {
- duh_signal_set_parameter(playing->sampinfo, id, value);
- break;
- }
- playing = playing->next;
- }
-
- } else if (command == SEQUENCE_STOP_SIGNAL) {
-
- int ref = sequence_c(&sampinfo->signal);
-
- SEQUENCE_PLAYING **playing_p = &sampinfo->playing;
-
- while (*playing_p) {
- SEQUENCE_PLAYING *playing = *playing_p;
-
- if (playing->ref == ref) {
- duh_signal_end_samples(playing->sampinfo);
- *playing_p = playing->next;
- free(playing);
- break;
- }
-
- playing_p = &playing->next;
- }
-
- } else {
-
- TRACE("Error in sequence: unknown command %d.\n", command);
- sampinfo->signal = NULL;
-
- }
-}
-
-
-
-static void *sequence_start_samples(DUH *duh, void *signal, int n_channels, long pos)
-{
- SEQUENCE_SAMPINFO *sampinfo;
- long time = sequence_cl((unsigned char **)&signal);
-
- if (time < 0)
- return NULL;
-
- sampinfo = malloc(sizeof(SEQUENCE_SAMPINFO));
- if (!sampinfo)
- return NULL;
-
- sampinfo->duh = duh;
- sampinfo->n_channels = n_channels;
- sampinfo->signal = signal;
- sampinfo->playing = NULL;
-
- /* Seek to 'pos'. */
- while (time < pos) {
- pos -= time;
-
- sequence_command(sampinfo, pos);
-
- time = sequence_cl(&sampinfo->signal);
-
- if (time < 0) {
- sampinfo->signal = NULL;
- return sampinfo;
- }
- }
-
- sampinfo->time_left = time - pos;
- sampinfo->sub_time_left = 0;
-
- return sampinfo;
-}
-
-
-
-static long sequence_render_samples(
- void *sampinfo,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
-
-#define sampinfo ((SEQUENCE_SAMPINFO *)sampinfo)
-
- long pos = 0;
-
- int dt = (int)(delta * 65536.0f + 0.5f);
-
- long todo;
- LONG_LONG t;
-
- while (sampinfo->signal) {
- todo = (long)((((LONG_LONG)sampinfo->time_left << 16) | sampinfo->sub_time_left) / dt);
-
- if (todo >= size)
- break;
-
- if (todo) {
- render(sampinfo, volume, delta, pos, todo, samples);
-
- pos += todo;
- size -= todo;
-
- todo = (long)((((LONG_LONG)sampinfo->time_left << 16) | sampinfo->sub_time_left) / dt);
- t = sampinfo->sub_time_left - (LONG_LONG)todo * dt;
- sampinfo->sub_time_left = (long)t & 65535;
- sampinfo->time_left += (long)(t >> 16);
- }
-
- sequence_command(sampinfo, 0);
-
- todo = sequence_cl(&sampinfo->signal);
-
- if (todo >= 0)
- sampinfo->time_left += todo;
- else
- sampinfo->signal = NULL;
- }
-
- if (sampinfo->signal) {
- render(sampinfo, volume, delta, pos, size, samples);
-
- pos += size;
-
- t = sampinfo->sub_time_left - (LONG_LONG)size * dt;
- sampinfo->sub_time_left = (long)t & 65535;
- sampinfo->time_left += (long)(t >> 16);
- } else
- pos += render(sampinfo, volume, delta, pos, size, samples);
-
- return pos;
-
-
-/** WARNING - remove this... */
-#if 0
- float size_unified = size * delta;
-
- int n;
-
- sample_t **samples2 = malloc(sampinfo->n_channels * sizeof(*samples2));
- memcpy(samples2, samples, sampinfo->n_channels * sizeof(*samples2));
-
- while (sampinfo->signal && sampinfo->time < size_unified) {
-
- {
- long sz = (long)(sampinfo->time / delta);
-
- if (sz)
- render(sampinfo, volume, delta, sz, samples2);
-
- for (n = 0; n < sampinfo->n_channels; n++)
- samples2[n] += sz;
-
- size -= sz;
- pos += sz;
-
- sampinfo->time -= sz * delta;
- }
-
- sequence_command(sampinfo, 0);
-
- {
- long time = sequence_cl(&sampinfo->signal);
-
- if (time >= 0)
- sampinfo->time += (float)time;
- else
- sampinfo->signal = NULL;
- }
-
- size_unified = size * delta;
- }
-
- if (sampinfo->signal) {
- render(sampinfo, volume, delta, size, samples2);
- sampinfo->time -= size_unified;
- pos += size;
- } else
- pos += render(sampinfo, volume, delta, size, samples2);
-
- free(samples2);
-
- return pos;
-#endif
-
-#undef sampinfo
-
-}
-
-
-
-static void sequence_end_samples(void *sampinfo)
-{
- SEQUENCE_PLAYING *playing = ((SEQUENCE_SAMPINFO *)sampinfo)->playing;
-
- while (playing) {
- SEQUENCE_PLAYING *next = playing->next;
-
- duh_signal_end_samples(playing->sampinfo);
- free(playing);
-
- playing = next;
- }
-
- free(sampinfo);
-}
-
-
-
-static void sequence_unload_signal(void *signal)
-{
- free(signal);
-}
-
-
-
-static DUH_SIGTYPE_DESC sigtype_sequence = {
- SIGTYPE_SEQUENCE,
- &sequence_load_signal,
- &sequence_start_samples,
- NULL,
- &sequence_render_samples,
- &sequence_end_samples,
- &sequence_unload_signal
-};
-
-
-
-void dumb_register_sigtype_sequence(void)
-{
- dumb_register_sigtype(&sigtype_sequence);
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * sequence.c - The sequence (SEQU) signal type. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dumb.h"
+
+
+
+#define SIGTYPE_SEQUENCE DUMB_ID('S','E','Q','U')
+
+
+
+/* We have 256 intervals per semitone, 12 * 256 per octave
+ 2 ** (1 / (12 * 256)) = 1.000225659305069791926712241547647863626
+
+ pow(DUMB_PITCH_BASE, x) = 1.5
+ x = log2(1.5) / log2(DUMB_PITCH_BASE)
+ x = log2(1.5) * 12 * 256
+ x = 1797.004802
+ cf.
+ x = 7 * 256 = 1792
+
+ so, for the perfect fifth temperament, use an interval of 1797.
+*/
+
+
+
+/* Sequencing format
+ * -----------------
+ *
+ * NOTE: A LOT OF THIS IS NOW REDUNDANT. PLEASE REFER TO duhspecs.txt.
+ *
+ * When a signal is initiated, it claims a reference number. If any other
+ * currently playing signal has the same number, that signal becomes
+ * anonymous and inaccessible; that is, if multiple signals were initiated
+ * with the same reference, the reference belongs to the most recent.
+ *
+ * Signals can be stopped, or have their pitch, volume or parameters changed,
+ * using the reference number. A signal may stop prematurely if it runs out
+ * of data, in which case the reference number becomes void, and operations
+ * on it will be ignored. Such a situation will not flag any kind of warning,
+ * since it may be the result of inaccuracies when resampling.
+ *
+ * The sequence consists of a series of commands. All commands begin with a
+ * long int, which is the time to wait after the last command (or the
+ * beginning of the sequence) before executing this command. 65536 represents
+ * one second. A time of -1 (or in fact any negative time) terminates the
+ * sequence, but any currently playing signals will continue until they run
+ * out. Make sure no non-terminating signals are playing when the sequence
+ * ends!
+ *
+ * The time, if nonnegative, is followed by one byte indicating the type of
+ * command. This byte can have the following values:
+ *
+ * SEQUENCE_START_SIGNAL
+ * unsigned char ref; - Reference. Need more than 256? Use two sequences,
+ * and get your brain seen to.
+ * int sig; - The index of the signal to initiate.
+ * long pos; - The position at which to start. 65536 represents one second.
+ * unsigned short volume; - Volume. 65535 represents the maximum volume, so
+ * you will want to go lower than this if you are
+ * playing more than one signal at once.
+ * signed short pitch; - Pitch. 0 represents a frequency of 65536 Hz. Scale
+ * is logarithmic. Add 256 to increase pitch by one
+ * semitone in the even temperament, or add 12*256 to
+ * increase pitch by one octave in any temperament
+ * (i.e. double the frequency).
+ *
+ * SEQUENCE_SET_VOLUME
+ * unsigned char ref;
+ * unsigned short volume;
+ *
+ * SEQUENCE_SET_PITCH
+ * unsigned char ref;
+ * signed short pitch;
+ *
+ * SEQUENCE_SET_PARAMETER
+ * unsigned char ref;
+ * unsigned char id;
+ * long value;
+ * - see the description of the set_parameter function pointer for
+ * information on 'id' and 'value'.
+ *
+ * SEQUENCE_STOP_SIGNAL
+ * unsigned char ref;
+ */
+
+
+
+#define SEQUENCE_START_SIGNAL 0
+#define SEQUENCE_SET_VOLUME 1
+#define SEQUENCE_SET_PITCH 2
+#define SEQUENCE_SET_PARAMETER 3
+#define SEQUENCE_STOP_SIGNAL 4
+
+
+
+typedef struct SEQUENCE_PLAYING
+{
+ struct SEQUENCE_PLAYING *next;
+
+ DUH_SIGNAL_SAMPINFO *sampinfo;
+
+ int ref;
+
+ int pitch;
+ int volume;
+}
+SEQUENCE_PLAYING;
+
+
+
+typedef struct SEQUENCE_SAMPINFO
+{
+ DUH *duh;
+
+ int n_channels;
+
+ unsigned char *signal;
+
+ long time_left;
+ int sub_time_left;
+
+ SEQUENCE_PLAYING *playing;
+}
+SEQUENCE_SAMPINFO;
+
+
+
+#define sequence_c(signal) ((int)*((*(signal))++))
+
+
+static int sequence_w(unsigned char **signal)
+{
+ int v = (*signal)[0] | ((*signal)[1] << 8);
+ *signal += 2;
+ return v;
+}
+
+
+static long sequence_l(unsigned char **signal)
+{
+ long v = (*signal)[0] | ((*signal)[1] << 8) | ((*signal)[2] << 16) | ((*signal)[3] << 24);
+ *signal += 4;
+ return v;
+}
+
+
+static long sequence_cl(unsigned char **signal)
+{
+ long v = sequence_c(signal);
+ if (v & 0x80) {
+ v &= 0x7F;
+ v |= sequence_c(signal) << 7;
+ if (v & 0x4000) {
+ v &= 0x3FFF;
+ v |= sequence_c(signal) << 14;
+ if (v & 0x200000) {
+ v &= 0x1FFFFF;
+ v |= sequence_c(signal) << 21;
+ if (v & 0x10000000) {
+ v &= 0x0FFFFFFF;
+ v |= sequence_c(signal) << 28;
+ }
+ }
+ }
+ }
+ return v;
+}
+
+
+
+static void *sequence_load_signal(DUH *duh, DUMBFILE *file)
+{
+ long size;
+ unsigned char *signal;
+
+ (void)duh;
+
+ size = dumbfile_igetl(file);
+ if (dumbfile_error(file) || size <= 0)
+ return NULL;
+
+ signal = malloc(size);
+ if (!signal)
+ return NULL;
+
+ if (dumbfile_getnc((char *)signal, size, file) < size) {
+ free(signal);
+ return NULL;
+ }
+
+ return signal;
+}
+
+
+
+static long render(
+ SEQUENCE_SAMPINFO *sampinfo,
+ float volume, float delta,
+ long pos, long size, sample_t **samples
+)
+{
+ sample_t **splptr;
+
+ SEQUENCE_PLAYING **playing_p = &sampinfo->playing;
+
+ long max_size = 0;
+ long part_size;
+
+ int n;
+ long i;
+
+ for (n = 0; n < sampinfo->n_channels; n++)
+ memset(samples[n] + pos, 0, size * sizeof(sample_t));
+
+ splptr = malloc(sampinfo->n_channels * sizeof(*splptr));
+ if (!splptr)
+ return 0;
+
+ splptr[0] = malloc(sampinfo->n_channels * size * sizeof(sample_t));
+ if (!splptr[0]) {
+ free(splptr);
+ return 0;
+ }
+
+ for (n = 1; n < sampinfo->n_channels; n++)
+ splptr[n] = splptr[n - 1] + size;
+
+ while (*playing_p) {
+ SEQUENCE_PLAYING *playing = *playing_p;
+
+ part_size = duh_signal_render_samples(
+ playing->sampinfo,
+ volume * (float)playing->volume * (1.0f / 65535.0f),
+ (float)(pow(DUMB_PITCH_BASE, playing->pitch) * delta),
+ size, splptr
+ );
+
+ for (n = 0; n < sampinfo->n_channels; n++)
+ for (i = 0; i < part_size; i++)
+ samples[n][pos+i] += splptr[n][i];
+
+ if (part_size > max_size)
+ max_size = part_size;
+
+ if (part_size < size) {
+ *playing_p = playing->next;
+ duh_signal_end_samples(playing->sampinfo);
+ free(playing);
+ } else
+ playing_p = &playing->next;
+ }
+
+ free(splptr[0]);
+ free(splptr);
+
+ return max_size;
+}
+
+
+
+/* 'offset' is added to the position at which the signal should start. It is
+ * currently assumed to be positive, and is currently only used when seeking
+ * forwards in the sequence.
+ */
+static void sequence_command(SEQUENCE_SAMPINFO *sampinfo, long offset)
+{
+ int command = sequence_c(&sampinfo->signal);
+
+ if (command == SEQUENCE_START_SIGNAL) {
+
+ int ref = sequence_c(&sampinfo->signal);
+ int sig = sequence_cl(&sampinfo->signal);
+ long pos = sequence_cl(&sampinfo->signal);
+ int volume = sequence_w(&sampinfo->signal);
+ int pitch = (int)(signed short)sequence_w(&sampinfo->signal);
+
+ SEQUENCE_PLAYING *playing = sampinfo->playing;
+
+ while (playing) {
+ if (playing->ref == ref)
+ playing->ref = -1;
+ playing = playing->next;
+ }
+
+ playing = malloc(sizeof(SEQUENCE_PLAYING));
+
+ if (playing) {
+ playing->sampinfo = duh_signal_start_samples(sampinfo->duh, sig, sampinfo->n_channels, pos + offset);
+
+ if (playing->sampinfo) {
+ playing->ref = ref;
+ playing->pitch = pitch;
+ playing->volume = volume;
+
+ playing->next = sampinfo->playing;
+ sampinfo->playing = playing;
+ } else
+ free(playing);
+ }
+
+ } else if (command == SEQUENCE_SET_VOLUME) {
+
+ int ref = sequence_c(&sampinfo->signal);
+ int volume = sequence_w(&sampinfo->signal);
+
+ SEQUENCE_PLAYING *playing = sampinfo->playing;
+
+ while (playing) {
+ if (playing->ref == ref) {
+ playing->volume = volume;
+ break;
+ }
+ playing = playing->next;
+ }
+
+ } else if (command == SEQUENCE_SET_PITCH) {
+
+ int ref = sequence_c(&sampinfo->signal);
+ int pitch = (int)(signed short)sequence_w(&sampinfo->signal);
+
+ SEQUENCE_PLAYING *playing = sampinfo->playing;
+
+ while (playing) {
+ if (playing->ref == ref) {
+ playing->pitch = pitch;
+ break;
+ }
+ playing = playing->next;
+ }
+
+ } else if (command == SEQUENCE_SET_PARAMETER) {
+
+ int ref = sequence_c(&sampinfo->signal);
+ unsigned char id = sequence_c(&sampinfo->signal);
+ long value = sequence_l(&sampinfo->signal);
+
+ SEQUENCE_PLAYING *playing = sampinfo->playing;
+
+ while (playing) {
+ if (playing->ref == ref) {
+ duh_signal_set_parameter(playing->sampinfo, id, value);
+ break;
+ }
+ playing = playing->next;
+ }
+
+ } else if (command == SEQUENCE_STOP_SIGNAL) {
+
+ int ref = sequence_c(&sampinfo->signal);
+
+ SEQUENCE_PLAYING **playing_p = &sampinfo->playing;
+
+ while (*playing_p) {
+ SEQUENCE_PLAYING *playing = *playing_p;
+
+ if (playing->ref == ref) {
+ duh_signal_end_samples(playing->sampinfo);
+ *playing_p = playing->next;
+ free(playing);
+ break;
+ }
+
+ playing_p = &playing->next;
+ }
+
+ } else {
+
+ TRACE("Error in sequence: unknown command %d.\n", command);
+ sampinfo->signal = NULL;
+
+ }
+}
+
+
+
+static void *sequence_start_samples(DUH *duh, void *signal, int n_channels, long pos)
+{
+ SEQUENCE_SAMPINFO *sampinfo;
+ long time = sequence_cl((unsigned char **)&signal);
+
+ if (time < 0)
+ return NULL;
+
+ sampinfo = malloc(sizeof(SEQUENCE_SAMPINFO));
+ if (!sampinfo)
+ return NULL;
+
+ sampinfo->duh = duh;
+ sampinfo->n_channels = n_channels;
+ sampinfo->signal = signal;
+ sampinfo->playing = NULL;
+
+ /* Seek to 'pos'. */
+ while (time < pos) {
+ pos -= time;
+
+ sequence_command(sampinfo, pos);
+
+ time = sequence_cl(&sampinfo->signal);
+
+ if (time < 0) {
+ sampinfo->signal = NULL;
+ return sampinfo;
+ }
+ }
+
+ sampinfo->time_left = time - pos;
+ sampinfo->sub_time_left = 0;
+
+ return sampinfo;
+}
+
+
+
+static long sequence_render_samples(
+ void *sampinfo,
+ float volume, float delta,
+ long size, sample_t **samples
+)
+{
+
+#define sampinfo ((SEQUENCE_SAMPINFO *)sampinfo)
+
+ long pos = 0;
+
+ int dt = (int)(delta * 65536.0f + 0.5f);
+
+ long todo;
+ LONG_LONG t;
+
+ while (sampinfo->signal) {
+ todo = (long)((((LONG_LONG)sampinfo->time_left << 16) | sampinfo->sub_time_left) / dt);
+
+ if (todo >= size)
+ break;
+
+ if (todo) {
+ render(sampinfo, volume, delta, pos, todo, samples);
+
+ pos += todo;
+ size -= todo;
+
+ todo = (long)((((LONG_LONG)sampinfo->time_left << 16) | sampinfo->sub_time_left) / dt);
+ t = sampinfo->sub_time_left - (LONG_LONG)todo * dt;
+ sampinfo->sub_time_left = (long)t & 65535;
+ sampinfo->time_left += (long)(t >> 16);
+ }
+
+ sequence_command(sampinfo, 0);
+
+ todo = sequence_cl(&sampinfo->signal);
+
+ if (todo >= 0)
+ sampinfo->time_left += todo;
+ else
+ sampinfo->signal = NULL;
+ }
+
+ if (sampinfo->signal) {
+ render(sampinfo, volume, delta, pos, size, samples);
+
+ pos += size;
+
+ t = sampinfo->sub_time_left - (LONG_LONG)size * dt;
+ sampinfo->sub_time_left = (long)t & 65535;
+ sampinfo->time_left += (long)(t >> 16);
+ } else
+ pos += render(sampinfo, volume, delta, pos, size, samples);
+
+ return pos;
+
+
+/** WARNING - remove this... */
+#if 0
+ float size_unified = size * delta;
+
+ int n;
+
+ sample_t **samples2 = malloc(sampinfo->n_channels * sizeof(*samples2));
+ memcpy(samples2, samples, sampinfo->n_channels * sizeof(*samples2));
+
+ while (sampinfo->signal && sampinfo->time < size_unified) {
+
+ {
+ long sz = (long)(sampinfo->time / delta);
+
+ if (sz)
+ render(sampinfo, volume, delta, sz, samples2);
+
+ for (n = 0; n < sampinfo->n_channels; n++)
+ samples2[n] += sz;
+
+ size -= sz;
+ pos += sz;
+
+ sampinfo->time -= sz * delta;
+ }
+
+ sequence_command(sampinfo, 0);
+
+ {
+ long time = sequence_cl(&sampinfo->signal);
+
+ if (time >= 0)
+ sampinfo->time += (float)time;
+ else
+ sampinfo->signal = NULL;
+ }
+
+ size_unified = size * delta;
+ }
+
+ if (sampinfo->signal) {
+ render(sampinfo, volume, delta, size, samples2);
+ sampinfo->time -= size_unified;
+ pos += size;
+ } else
+ pos += render(sampinfo, volume, delta, size, samples2);
+
+ free(samples2);
+
+ return pos;
+#endif
+
+#undef sampinfo
+
+}
+
+
+
+static void sequence_end_samples(void *sampinfo)
+{
+ SEQUENCE_PLAYING *playing = ((SEQUENCE_SAMPINFO *)sampinfo)->playing;
+
+ while (playing) {
+ SEQUENCE_PLAYING *next = playing->next;
+
+ duh_signal_end_samples(playing->sampinfo);
+ free(playing);
+
+ playing = next;
+ }
+
+ free(sampinfo);
+}
+
+
+
+static void sequence_unload_signal(void *signal)
+{
+ free(signal);
+}
+
+
+
+static DUH_SIGTYPE_DESC sigtype_sequence = {
+ SIGTYPE_SEQUENCE,
+ &sequence_load_signal,
+ &sequence_start_samples,
+ NULL,
+ &sequence_render_samples,
+ &sequence_end_samples,
+ &sequence_unload_signal
+};
+
+
+
+void dumb_register_sigtype_sequence(void)
+{
+ dumb_register_sigtype(&sigtype_sequence);
+}
diff --git a/plugins/dumb/dumb-kode54/src/sigtypes/sterpan.c b/plugins/dumb/dumb-kode54/src/sigtypes/sterpan.c
index 22fe5d28..b60c0c5e 100644
--- a/plugins/dumb/dumb-kode54/src/sigtypes/sterpan.c
+++ b/plugins/dumb/dumb-kode54/src/sigtypes/sterpan.c
@@ -1,206 +1,206 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * sterpan.c - The stereo pan (SPAN) signal type. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * This takes a single monaural signal and | \ / /
- * expands it to two channels, applying a | ' /
- * stereo pan in the process. The stereo pan \__/
- * is generated by delaying and damping the
- * channel opposite the sound source. If only
- * one channel is requested of this signal, it will simply chain to the other
- * signal.
- *
- * In order for the delay to work properly, this must be played at 65536 Hz.
- * The pitch at which you want the sample to play can be passed in parameter
- * #1. Parameter #0 specifies the panning position, -256 to 256.
- *
- * NOTE: THIS IS NOT HOW IT WORKS AT THE MOMENT. AT THE MOMENT, THIS ROUTINE
- * SIMPLY VARIES THE VOLUMES.
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-
-
-
-#define SIGTYPE_STEREOPAN DUMB_ID('S','P','A','N')
-
-
-
-#define SPANPARAM_PAN 0
-
-
-
-typedef struct STEREOPAN_SIGNAL
-{
- int sig;
-}
-STEREOPAN_SIGNAL;
-
-
-
-typedef struct STEREOPAN_SAMPINFO
-{
- float pan;
- int stereo;
- DUH_SIGNAL_SAMPINFO *csampinfo;
-}
-STEREOPAN_SAMPINFO;
-
-
-
-static void *stereopan_load_signal(DUH *duh, DUMBFILE *file)
-{
- STEREOPAN_SIGNAL *signal;
-
- (void)duh;
-
- signal = malloc(sizeof(*signal));
-
- if (!signal)
- return NULL;
-
- signal->sig = dumbfile_igetl(file);
-
- if (dumbfile_error(file)) {
- free(signal);
- return NULL;
- }
-
- return signal;
-}
-
-
-
-static void *stereopan_start_samples(DUH *duh, void *signal, int n_channels, long pos)
-{
- STEREOPAN_SAMPINFO *sampinfo;
-
-#define signal ((STEREOPAN_SIGNAL *)signal)
-
- if ((unsigned int)(n_channels - 1) >= 2) {
- TRACE("Stereo pan signal requiring 1 or 2 channels called with %d channels.\n", n_channels);
- return NULL;
- }
-
- sampinfo = malloc(sizeof(*sampinfo));
- if (!sampinfo)
- return NULL;
-
- sampinfo->pan = 0;
-
- sampinfo->stereo = n_channels - 1;
-
- sampinfo->csampinfo = duh_signal_start_samples(duh, signal->sig, 1, pos);
- if (!sampinfo->csampinfo) {
- free(sampinfo);
- return NULL;
- }
-
-#undef signal
-
- return sampinfo;
-}
-
-
-
-static void stereopan_set_parameter(void *sampinfo, unsigned char id, long value)
-{
-#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo)
-
- if (id == SPANPARAM_PAN && value >= -256 && value <= 256)
- sampinfo->pan = value * (1.0f / 256.0f);
-
-#undef sampinfo
-}
-
-
-
-static long stereopan_render_samples(
- void *sampinfo,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
-#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo)
-
- if (!sampinfo->stereo)
- return duh_signal_render_samples(sampinfo->csampinfo, volume, delta, size, samples);
-
- if (sampinfo->pan >= 0) {
- long sz = duh_signal_render_samples(sampinfo->csampinfo, volume * (1.0f + sampinfo->pan), delta, size, samples + 1);
- long s;
- int vol;
-
- volume = (1.0f - sampinfo->pan) / (1.0f + sampinfo->pan);
- vol = (int)(volume * 65536 + 0.5);
-
- for (s = 0; s < sz; s++)
- samples[0][s] = (samples[1][s] * vol) >> 16;
-
- return sz;
- } else {
- long sz = duh_signal_render_samples(sampinfo->csampinfo, volume * (1.0f - sampinfo->pan), delta, size, samples);
- long s;
- int vol;
-
- volume = (1.0f + sampinfo->pan) / (1.0f - sampinfo->pan);
- vol = (int)(volume * 65536 + 0.5);
-
- for (s = 0; s < sz; s++)
- samples[1][s] = (samples[0][s] * vol) >> 16;
-
- return sz;
- }
-
-#undef sampinfo
-}
-
-
-
-static void stereopan_end_samples(void *sampinfo)
-{
-#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo)
-
- duh_signal_end_samples(sampinfo->csampinfo);
- free(sampinfo);
-
-#undef sampinfo
-}
-
-
-
-static void stereopan_unload_signal(void *signal)
-{
- free(signal);
-}
-
-
-
-static DUH_SIGTYPE_DESC sigtype_stereopan = {
- SIGTYPE_STEREOPAN,
- &stereopan_load_signal,
- &stereopan_start_samples,
- &stereopan_set_parameter,
- &stereopan_render_samples,
- &stereopan_end_samples,
- &stereopan_unload_signal
-};
-
-
-
-void dumb_register_sigtype_stereopan(void)
-{
- dumb_register_sigtype(&sigtype_stereopan);
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * sterpan.c - The stereo pan (SPAN) signal type. / / \ \
+ * | < / \_
+ * By entheh. | \/ /\ /
+ * \_ / > /
+ * This takes a single monaural signal and | \ / /
+ * expands it to two channels, applying a | ' /
+ * stereo pan in the process. The stereo pan \__/
+ * is generated by delaying and damping the
+ * channel opposite the sound source. If only
+ * one channel is requested of this signal, it will simply chain to the other
+ * signal.
+ *
+ * In order for the delay to work properly, this must be played at 65536 Hz.
+ * The pitch at which you want the sample to play can be passed in parameter
+ * #1. Parameter #0 specifies the panning position, -256 to 256.
+ *
+ * NOTE: THIS IS NOT HOW IT WORKS AT THE MOMENT. AT THE MOMENT, THIS ROUTINE
+ * SIMPLY VARIES THE VOLUMES.
+ */
+
+#include <stdlib.h>
+
+#include "dumb.h"
+
+
+
+#define SIGTYPE_STEREOPAN DUMB_ID('S','P','A','N')
+
+
+
+#define SPANPARAM_PAN 0
+
+
+
+typedef struct STEREOPAN_SIGNAL
+{
+ int sig;
+}
+STEREOPAN_SIGNAL;
+
+
+
+typedef struct STEREOPAN_SAMPINFO
+{
+ float pan;
+ int stereo;
+ DUH_SIGNAL_SAMPINFO *csampinfo;
+}
+STEREOPAN_SAMPINFO;
+
+
+
+static void *stereopan_load_signal(DUH *duh, DUMBFILE *file)
+{
+ STEREOPAN_SIGNAL *signal;
+
+ (void)duh;
+
+ signal = malloc(sizeof(*signal));
+
+ if (!signal)
+ return NULL;
+
+ signal->sig = dumbfile_igetl(file);
+
+ if (dumbfile_error(file)) {
+ free(signal);
+ return NULL;
+ }
+
+ return signal;
+}
+
+
+
+static void *stereopan_start_samples(DUH *duh, void *signal, int n_channels, long pos)
+{
+ STEREOPAN_SAMPINFO *sampinfo;
+
+#define signal ((STEREOPAN_SIGNAL *)signal)
+
+ if ((unsigned int)(n_channels - 1) >= 2) {
+ TRACE("Stereo pan signal requiring 1 or 2 channels called with %d channels.\n", n_channels);
+ return NULL;
+ }
+
+ sampinfo = malloc(sizeof(*sampinfo));
+ if (!sampinfo)
+ return NULL;
+
+ sampinfo->pan = 0;
+
+ sampinfo->stereo = n_channels - 1;
+
+ sampinfo->csampinfo = duh_signal_start_samples(duh, signal->sig, 1, pos);
+ if (!sampinfo->csampinfo) {
+ free(sampinfo);
+ return NULL;
+ }
+
+#undef signal
+
+ return sampinfo;
+}
+
+
+
+static void stereopan_set_parameter(void *sampinfo, unsigned char id, long value)
+{
+#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo)
+
+ if (id == SPANPARAM_PAN && value >= -256 && value <= 256)
+ sampinfo->pan = value * (1.0f / 256.0f);
+
+#undef sampinfo
+}
+
+
+
+static long stereopan_render_samples(
+ void *sampinfo,
+ float volume, float delta,
+ long size, sample_t **samples
+)
+{
+#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo)
+
+ if (!sampinfo->stereo)
+ return duh_signal_render_samples(sampinfo->csampinfo, volume, delta, size, samples);
+
+ if (sampinfo->pan >= 0) {
+ long sz = duh_signal_render_samples(sampinfo->csampinfo, volume * (1.0f + sampinfo->pan), delta, size, samples + 1);
+ long s;
+ int vol;
+
+ volume = (1.0f - sampinfo->pan) / (1.0f + sampinfo->pan);
+ vol = (int)(volume * 65536 + 0.5);
+
+ for (s = 0; s < sz; s++)
+ samples[0][s] = (samples[1][s] * vol) >> 16;
+
+ return sz;
+ } else {
+ long sz = duh_signal_render_samples(sampinfo->csampinfo, volume * (1.0f - sampinfo->pan), delta, size, samples);
+ long s;
+ int vol;
+
+ volume = (1.0f + sampinfo->pan) / (1.0f - sampinfo->pan);
+ vol = (int)(volume * 65536 + 0.5);
+
+ for (s = 0; s < sz; s++)
+ samples[1][s] = (samples[0][s] * vol) >> 16;
+
+ return sz;
+ }
+
+#undef sampinfo
+}
+
+
+
+static void stereopan_end_samples(void *sampinfo)
+{
+#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo)
+
+ duh_signal_end_samples(sampinfo->csampinfo);
+ free(sampinfo);
+
+#undef sampinfo
+}
+
+
+
+static void stereopan_unload_signal(void *signal)
+{
+ free(signal);
+}
+
+
+
+static DUH_SIGTYPE_DESC sigtype_stereopan = {
+ SIGTYPE_STEREOPAN,
+ &stereopan_load_signal,
+ &stereopan_start_samples,
+ &stereopan_set_parameter,
+ &stereopan_render_samples,
+ &stereopan_end_samples,
+ &stereopan_unload_signal
+};
+
+
+
+void dumb_register_sigtype_stereopan(void)
+{
+ dumb_register_sigtype(&sigtype_stereopan);
+}
diff --git a/plugins/dumb/dumb-kode54/src/tools/it/load_it.cpp b/plugins/dumb/dumb-kode54/src/tools/it/load_it.cpp
index ed88e706..bc749cb5 100644
--- a/plugins/dumb/dumb-kode54/src/tools/it/load_it.cpp
+++ b/plugins/dumb/dumb-kode54/src/tools/it/load_it.cpp
@@ -1,824 +1,824 @@
-#ifdef FORTIFY
-#include "fortify.h"
-#endif
-#include <stdio.h>
-#ifdef MSS
-#include "mss.h"
-#endif
-
-#include <string.h>
-
-#include "allegro.h"
-#include "modulus.h"
-#include "typedef.hpp"
-
-int detect_it(char *f) {
- int sig;
- PACKFILE *fn = pack_fopen(f, "rb");
-
- if (fn == NULL)
- return FALSE;
-
- sig = pack_mgetl(fn);
- if (sig != AL_ID('I','M','P','M')) {
- pack_fclose(fn);
- return FALSE;
- }
- pack_fclose(fn);
-
- return TRUE;
-}
-
-MODULUS *create_it() {
- MODULUS *m = (MODULUS*)malloc(sizeof(MODULUS));
- if (!m)
- return NULL;
- memset(m, 0, sizeof(MODULUS));
- return m;
-}
-
-void destroy_it(MODULUS *j) {
-
- if (song->Music == j)
- stop_it();
-
- //remove patterns:
- for (int i=0; i<j->NumPatterns; i++) {
- free(j->Pattern[i].Note);
- }
- if (j->Pattern)
- free(j->Pattern);
- //remove instruments;
- if (j->Instrument)
- free(j->Instrument);
- //remove samples;
- for (int i=0; i<j->NumSamples; i++) {
- destroy_sample(j->Sample[i].Sample);
- }
- if (j->Sample)
- free(j->Sample);
- //remove orders:
- if (j->Order)
- free(j->Order);
- //remove channels:
- for (int i=0; i<64; i++) {
- if (j->Channel[i].VChannel) {
- MODULUS_VCHANNEL *vchn = song->Music->Channel[i].VChannel;
- MODULUS_VCHANNEL *prev = NULL;
-
- if (!vchn)
- continue;
-
- for (;;) {
- deallocate_voice(vchn->voice);
-
- prev = vchn;
- vchn = vchn->next;
- free(prev);
-
- if (!vchn)
- break;
- }
- }
- }
- free(j);
-}
-
-//#define DEBUG_IT_SIZE
-
-int get_module_size(MODULUS *j) {
- int a, b, c, d = 0, e;
- a = sizeof(MODULUS) + j->NumOrders;
- b = j->NumInstruments * sizeof(MODULUS_INSTRUMENT);
- c = j->NumSamples * sizeof(MODULUS_SAMPLE);
-
- for (int i=0; i<j->NumSamples; i++)
- d += j->Sample[i].SampleLength * (j->Sample[i].Flag & 2 ? sizeof(short) : 1) * (j->Sample[i].Flag & 4 ? 2: 1);
-
- e = 4 + sizeof(MODULUS_PATTERN) * j->NumPatterns;
-
- for (int i=0; i<j->NumPatterns; i++)
- e += j->Pattern[i].NumNotes * sizeof(MODULUS_NOTE);
- #ifdef DEBUG_IT_SIZE
- printf("Base: %i, Instruments(%i): %i, Samples(%i): %i, Data: %i, Patterns(%i): %i\n", a, j->NumInstruments, b, j->NumSamples, c, d, j->NumPatterns, e);
- #endif
-
- return a+b+c+d+e;
-}
-
-#define MAX_IT_CHN 64
-
-//#define DEBUG_HEADER
-//#define DEBUG_INSTRUMENTS
-//#define DEBUG_SAMPLES
-//#define DEBUG_PATTERNS
-
-static dword *sourcebuf = NULL;
-static dword *sourcepos = NULL;
-static byte rembits = 0;
-
-int readblock(PACKFILE *f) {
- long size;
- int c = pack_igetw(f);
- if (c == -1)
- return 0;
- size = c;
-
- sourcebuf = (dword*)malloc(size+4);
- if (!sourcebuf)
- return 0;
-
- c = pack_fread(sourcebuf, size, f);
- if (c < 1) {
- free(sourcebuf);
- sourcebuf = NULL;
- return 0;
- }
- sourcepos = sourcebuf;
- rembits = 32;
- return 1;
-}
-
-void freeblock() {
- if (sourcebuf)
- free(sourcebuf);
- sourcebuf = NULL;
-}
-
-dword readbits(char b) {
- dword val;
- if (b <= rembits) {
- val = *sourcepos & ((1 << b) - 1);
- *sourcepos >>= b;
- rembits -= b;
- }
- else {
- dword nbits = b - rembits;
- val = *sourcepos;
- sourcepos++;
- val |= ((*sourcepos & ((1 << nbits) - 1)) << rembits);
- *sourcepos >>= nbits;
- rembits = 32 - nbits;
- }
- return val;
-}
-
-void decompress8(PACKFILE *f, void *data, int len, int tver) {
- char *destbuf = (char*)data;
- char *destpos = destbuf;
- int blocklen, blockpos;
- byte bitwidth;
- word val;
- char d1, d2;
-
- memset(destbuf, 0, len);
-
- while (len>0) {
- //Read a block of compressed data:
- if (!readblock(f))
- return;
- //Set up a few variables
- blocklen = (len < 0x8000) ? len : 0x8000; //Max block length is 0x8000 bytes
- blockpos = 0;
- bitwidth = 9;
- d1 = d2 = 0;
- //Start the decompression:
- while (blockpos < blocklen) {
- //Read a value:
- val = readbits(bitwidth);
- //Check for bit width change:
-
- if (bitwidth < 7) { //Method 1:
- if (val == (1 << (bitwidth - 1))) {
- val = readbits(3) + 1;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth < 9) { //Method 2
- byte border = (0xFF >> (9 - bitwidth)) - 4;
-
- if (val > border && val <= (border + 8)) {
- val -= border;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth == 9) { //Method 3
- if (val & 0x100) {
- bitwidth = (val + 1) & 0xFF;
- continue;
- }
- }
- else { //Illegal width, abort ?
- freeblock();
- return;
- }
-
- //Expand the value to signed byte:
- char v; //The sample value:
- if (bitwidth < 8) {
- byte shift = 8 - bitwidth;
- v = (val << shift);
- v >>= shift;
- }
- else
- v = (char)val;
-
- //And integrate the sample value
- //(It always has to end with integration doesn't it ? ;-)
- d1 += v;
- d2 += d1;
-
- //Store !
- *destpos = ((tver == 0x215) ? d2 : d1);
- destpos++;
- blockpos++;
- }
- freeblock();
- len -= blocklen;
- }
- return;
-}
-
-void decompress16(PACKFILE *f, void *data, int len, int tver) {
- //make the output buffer:
- short *destbuf = (short*)data;
- short *destpos = destbuf;
- int blocklen, blockpos;
- byte bitwidth;
- long val;
- short d1, d2;
-
- memset(destbuf, 0, len);
-
- while (len>0) {
- //Read a block of compressed data:
- if (!readblock(f))
- return;
- //Set up a few variables
- blocklen = (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes
- blockpos = 0;
- bitwidth = 17;
- d1 = d2 = 0;
- //Start the decompression:
- while (blockpos < blocklen) {
- val = readbits(bitwidth);
- //Check for bit width change:
-
- if (bitwidth < 7) { //Method 1:
- if (val == (1 << (bitwidth - 1))) {
- val = readbits(4) + 1;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth < 17) { //Method 2
- word border = (0xFFFF >> (17 - bitwidth)) - 8;
-
- if (val > border && val <= (border + 16)) {
- val -= border;
- bitwidth = val < bitwidth ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth == 17) { //Method 3
- if (val & 0x10000) {
- bitwidth = (val + 1) & 0xFF;
- continue;
- }
- }
- else { //Illegal width, abort ?
- freeblock();
- return;
- }
-
- //Expand the value to signed byte:
- short v; //The sample value:
- if (bitwidth < 16) {
- byte shift = 16 - bitwidth;
- v = (val << shift);
- v >>= shift;
- }
- else
- v = (short)val;
-
- //And integrate the sample value
- //(It always has to end with integration doesn't it ? ;-)
- d1 += v;
- d2 += d1;
-
- //Store !
- *destpos = ((tver == 0x215) ? d2 : d1);
- destpos++;
- blockpos++;
- }
- freeblock();
- len -= blocklen;
- }
- return;
-}
-
-MODULUS *load_it(char *file) {
- PACKFILE *f;
- MODULUS *j = create_it();
- int tver, tver2, flag, msglen, msgoffs;
- int *insoffs = NULL, *samoffs = NULL, *patoffs = NULL;
-
- if (!j)
- return NULL;
-
- if (!detect_it(file))
- return NULL;
-
- f = pack_fopen(file, "rb");
-
- if (!f) {
- #ifdef DEBUG_HEADER
- printf("Error Opening!\n");
- #endif
- return NULL;
- }
-
- pack_fseek(f, 30);
- pack_igetw(f); //I have no idea...
-
- j->NumOrders = pack_igetw(f);
- j->NumInstruments = pack_igetw(f);
- j->NumSamples = pack_igetw(f);
- j->NumPatterns = pack_igetw(f);
-
- #ifdef DEBUG_HEADER
- printf("Loading IT: %i Orders %i Instruments, %i Samples, %i Patterns\n", j->NumOrders, j->NumInstruments, j->NumSamples, j->NumPatterns);
- #endif
-
- tver = pack_igetw(f);
- j->Version = tver2 = pack_igetw(f);
-
- #ifdef DEBUG_HEADER
- printf("Tracker ver: %X, %X\n", tver, tver2);
- #endif
-
- j->Flags = pack_igetw(f);
- flag = pack_igetw(f);
-
- j->GlobalVolume = pack_getc(f);
- j->MixVolume = pack_getc(f);
- j->Speed = pack_getc(f);
- j->Tempo = pack_getc(f);
- j->PanningSeperation = pack_getc(f);
-
- #ifdef DEBUG_HEADER
- printf("Global Volume: %i, Mixing Volume: %i, Speed: %i, Tempo: %i, PanSep: %i\n", j->GlobalVolume, j->MixVolume, j->Speed, j->Tempo, j->PanningSeperation);
- #endif
-
- pack_getc(f); //Damn....I need more info on this.
-
- msglen = pack_igetw(f);
- msgoffs = pack_igetl(f);
-
- pack_fseek(f, 4);
-
- #ifdef DEBUG_HEADER
- printf("Channel Pan:");
- #endif
-
- for (int i=0; i<MAX_IT_CHN; i++) {
- j->Channel[i].Pan = pack_getc(f);
- #ifdef DEBUG_HEADER
- printf(" %i", j->Channel[i].Pan);
- #endif
- }
- #ifdef DEBUG_HEADER
- printf("\nChannel Vol:");
- #endif
- for (int i=0; i<MAX_IT_CHN; i++) {
- j->Channel[i].Volume = pack_getc(f);
- #ifdef DEBUG_HEADER
- printf(" %i", j->Channel[i].Volume);
- #endif
- }
- #ifdef DEBUG_HEADER
- printf("\n");
- #endif
-
- j->Order = (unsigned char *)malloc(j->NumOrders);
- pack_fread(j->Order, j->NumOrders, f);
-
- if (j->NumInstruments)
- insoffs = (int*)malloc(4 * j->NumInstruments);
- if (j->NumSamples)
- samoffs = (int*)malloc(4 * j->NumSamples);
- if (j->NumPatterns)
- patoffs = (int*)malloc(4 * j->NumPatterns);
-
- pack_fread(insoffs, 4 * j->NumInstruments, f);
- pack_fread(samoffs, 4 * j->NumSamples, f);
- pack_fread(patoffs, 4 * j->NumPatterns, f);
-
- if (flag&1) { //Song message attached
- //Ignore.
- }
- if (flag & 4) { //skip something:
- short u;
- char dummy[8];
- u = pack_igetw(f);
- for (int i=0; i<u; u++)
- pack_fread(dummy, 8, f);
- }
- if (flag & 8) { //MIDI commands ???
- char dummy[33];
- for (int i=0; i<9+16+128; i++)
- pack_fread(dummy, 32, f);
-
- }
-
- if (j->NumInstruments)
- j->Instrument = (MODULUS_INSTRUMENT*)malloc(sizeof(MODULUS_INSTRUMENT) * j->NumInstruments);
- #ifdef DEBUG_INSTRUMENTS
- if (!j->Instrument)
- printf("No Mem for Instruments!\n");
- #endif
-
-
- for (int i=0; i<j->NumInstruments; i++) {
- pack_fclose(f);
- f = pack_fopen(file, "rb");
- #ifdef DEBUG_INSTRUMENTS
- if (!f)
- printf("Error Opening!\n");
- #endif
- pack_fseek(f, insoffs[i] + 17);
-
- j->Instrument[i].NewNoteAction = pack_getc(f);
- j->Instrument[i].DuplicateCheckType = pack_getc(f);
- j->Instrument[i].DuplicateCheckAction = pack_getc(f);
- j->Instrument[i].FadeOut = pack_igetw(f);
- j->Instrument[i].PitchPanSeperation = pack_getc(f);
- j->Instrument[i].PitchPanCenter = pack_getc(f);
- j->Instrument[i].GlobalVolume = pack_getc(f);
- j->Instrument[i].DefaultPan = pack_getc(f);
- #ifdef DEBUG_INSTRUMENTS
- printf("I%02i @ 0x%X, NNA %i, DCT %i, DCA %i, FO %i, PPS %i, PPC %i, GVol %i, DPan %i\n", i, insoffs[i], j->Instrument[i].NewNoteAction, j->Instrument[i].DuplicateCheckType, j->Instrument[i].DuplicateCheckAction, j->Instrument[i].FadeOut, j->Instrument[i].PitchPanSeperation, j->Instrument[i].PitchPanCenter, j->Instrument[i].GlobalVolume, j->Instrument[i].DefaultPan);
- #endif
-
- pack_fseek(f, 38);
-
- for (int k=0; k<120; k++) {
- j->Instrument[i].NoteNote[k] = pack_getc(f);
- j->Instrument[i].NoteSample[k] = pack_getc(f) - 1;
- }
-
- j->Instrument[i].VolumeEnvelope.Flag = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.NumNodes = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.LoopBegin = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.LoopEnd = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.SustainLoopBegin = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.SustainLoopEnd = pack_getc(f);
- for (int k=0; k<j->Instrument[i].VolumeEnvelope.NumNodes; k++) {
- j->Instrument[i].VolumeEnvelope.NodeY[k] = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.NodeTick[k] = pack_igetw(f);
- }
- pack_fseek(f, 75 - j->Instrument[i].VolumeEnvelope.NumNodes * 3);
-
- j->Instrument[i].PanningEnvelope.Flag = pack_getc(f);
- j->Instrument[i].PanningEnvelope.NumNodes = pack_getc(f);
- j->Instrument[i].PanningEnvelope.LoopBegin = pack_getc(f);
- j->Instrument[i].PanningEnvelope.LoopEnd = pack_getc(f);
- j->Instrument[i].PanningEnvelope.SustainLoopBegin = pack_getc(f);
- j->Instrument[i].PanningEnvelope.SustainLoopEnd = pack_getc(f);
- for (int k=0; k<j->Instrument[i].PanningEnvelope.NumNodes; k++) {
- j->Instrument[i].PanningEnvelope.NodeY[k] = pack_getc(f);
- j->Instrument[i].PanningEnvelope.NodeTick[k] = pack_igetw(f);
- }
- pack_fseek(f, 75 - j->Instrument[i].PanningEnvelope.NumNodes * 3);
-
- j->Instrument[i].PitchEnvelope.Flag = pack_getc(f);
- j->Instrument[i].PitchEnvelope.NumNodes = pack_getc(f);
- j->Instrument[i].PitchEnvelope.LoopBegin = pack_getc(f);
- j->Instrument[i].PitchEnvelope.LoopEnd = pack_getc(f);
- j->Instrument[i].PitchEnvelope.SustainLoopBegin = pack_getc(f);
- j->Instrument[i].PitchEnvelope.SustainLoopEnd = pack_getc(f);
- for (int k=0; k<j->Instrument[i].PitchEnvelope.NumNodes; k++) {
- j->Instrument[i].PitchEnvelope.NodeY[k] = pack_getc(f);
- j->Instrument[i].PitchEnvelope.NodeTick[k] = pack_igetw(f);
- }
- }
-
- if (j->NumSamples)
- j->Sample = (MODULUS_SAMPLE*)malloc(sizeof(MODULUS_SAMPLE) * j->NumSamples);
-
- #ifdef DEBUG_SAMPLES
- if (!j->Sample)
- printf("No Mem for Samples!\n");
- #endif
-
- for (int i=0; i<j->NumSamples; i++) {
- int sam_samptr, convert;
-
- pack_fclose(f);
- f = pack_fopen(file, "rb");
- #ifdef DEBUG_SAMPLES
- if (!f)
- printf("Error opening!\n");
- #endif
-
- pack_fseek(f, samoffs[i] + 17);
-
- j->Sample[i].GlobalVolume = pack_getc(f);
- j->Sample[i].Flag = pack_getc(f);
- j->Sample[i].Volume = pack_getc(f);
-
- #ifdef DEBUG_SAMPLES
- printf("S%02i @ 0x%X, Vol: %i/%i, Flag: %i", i, samoffs[i], j->Sample[i].GlobalVolume, j->Sample[i].Volume, j->Sample[i].Flag);
- #endif
-
- pack_fseek(f, 26);
-
- convert = pack_getc(f);
- pack_getc(f); //Panning ?
-
- j->Sample[i].SampleLength = pack_igetl(f);
- j->Sample[i].LoopBegin = pack_igetl(f);
- j->Sample[i].LoopEnd = pack_igetl(f);
- j->Sample[i].C5Speed = pack_igetl(f);
- j->Sample[i].SustainLoopBegin = pack_igetl(f);
- j->Sample[i].SustainLoopEnd = pack_igetl(f);
-
- #ifdef DEBUG_SAMPLES
- printf(", SLen: %i, LpB: %i, LpE: %i, C5S: %i\n", j->Sample[i].SampleLength, j->Sample[i].LoopBegin, j->Sample[i].LoopEnd, j->Sample[i].C5Speed);
- #endif
-
- sam_samptr = pack_igetl(f);
-
- j->Sample[i].VibratoSpeed = pack_getc(f);
- j->Sample[i].VibratoDepth = pack_getc(f);
- j->Sample[i].VibratoRate = pack_getc(f);
- j->Sample[i].VibratoWaveForm = pack_getc(f);
-
- #ifdef DEBUG_SAMPLES
- printf("SusLpB: %i, SusLpE: %i, VibSp: %i, VibDep: %i, VibWav: %i, VibRat: %i\n", j->Sample[i].SustainLoopBegin, j->Sample[i].SustainLoopEnd, j->Sample[i].VibratoSpeed, j->Sample[i].VibratoDepth, j->Sample[i].VibratoWaveForm, j->Sample[i].VibratoRate);
- #endif
-
- if (j->Sample[i].Flag & 1 == 0)
- continue;
-
- pack_fclose(f);
- f = pack_fopen(file, "rb");
- pack_fseek(f, sam_samptr);
-
- int len = j->Sample[i].SampleLength * (j->Sample[i].Flag & 2 ? sizeof(short) : 1) * (j->Sample[i].Flag & 4 ? 2: 1);
-
- #ifdef DEBUG_SAMPLES
- printf("Len: %i, Size: %i KB\n", j->Sample[i].SampleLength, len/1024);
- #endif
-
- SAMPLE *sam = create_sample(j->Sample[i].Flag & 2 ? 16 : 8, j->Sample[i].Flag & 4 ? TRUE : FALSE, j->Sample[i].C5Speed, j->Sample[i].SampleLength);
-
- if (j->Sample[i].Flag & 8) { // If the sample is packed, then we must unpack it
- if (j->Sample[i].Flag & 2)
- decompress16(f, sam->data, j->Sample[i].SampleLength, tver2);
- else
- decompress8(f, sam->data, j->Sample[i].SampleLength, tver2);
- } else {
- pack_fread(sam->data, len, f);
- }
-
- if (j->Sample[i].Flag & SAMPLE_USELOOP) {
- sam->loop_start = j->Sample[i].LoopBegin;
- sam->loop_end = j->Sample[i].LoopEnd;
- }
-
- j->Sample[i].Sample = sam;
-
- void *dat = sam->data;
-
- if (convert & 2) { //Change the byte order for 16-bit samples:
- if (sam->bits == 16) {
- for (int k=0; k<len; k+=2) {
- int l = ((char*)dat)[k];
- ((char*)dat)[k] = ((char*)dat)[k+1];
- ((char*)dat)[k+1] = l;
-
- }
- }
- else {
- for (int k=0; k<len; k+=2) {
- int l = ((char*)dat)[k];
- ((char*)dat)[k] = ((char*)dat)[k+1];
- ((char*)dat)[k+1] = l;
-
- }
- }
- }
- if (convert & 1) { //Convert to unsigned
- if (sam->bits == 8) {
- for (int k=0; k<len; k++) {
- ((char*)dat)[k] ^= 0x80;
- }
- }
- else {
- for (int k=0; k<(len>>1); k++) {
- ((short*)dat)[k] ^= 0x8000;
- }
- }
- }
- }
-
- if (j->NumPatterns)
- j->Pattern = (MODULUS_PATTERN*)malloc(sizeof(MODULUS_PATTERN) * j->NumPatterns);
- unsigned char *buf = (unsigned char*)alloca(65536);
- unsigned char *cmask = (unsigned char*)alloca(64),
- *cnote = (unsigned char*)alloca(64),
- *cinstrument = (unsigned char*)alloca(64),
- *cvol = (unsigned char*)alloca(64),
- *ccom = (unsigned char*)alloca(64),
- *ccomval = (unsigned char*)alloca(64);
-
- for (int i=0; i<j->NumPatterns; i++) {
- int numnotes = 0, len, pos = 0, mask = 0, chn = 0;
-
- memset(cmask, 0, 64);
- memset(cnote, 0, 64);
- memset(cinstrument, 0, 64);
- memset(cvol, 0, 64);
- memset(ccom, 0, 64);
- memset(ccomval, 0, 64);
-
- pack_fclose(f);
- f = pack_fopen(file, "rb");
- pack_fseek(f, patoffs[i]);
-
- len = pack_igetw(f);
- j->Pattern[i].NumRows = pack_igetw(f);
-
- pack_fseek(f, 4);
- pack_fread(buf, len, f);
-
- while (pos < len) {
- int b = buf[pos];
- pos++;
- if (!b) { //If end of row:
- numnotes++;
- continue;
- }
- chn = (b - 1) & 63;
-
- if (b & 128) {
- mask = buf[pos];
- pos++;
- cmask[chn] = mask;
- }
- else
- mask = cmask[chn];
-
- if (mask)
- numnotes++;
- if (mask & 1)
- pos++;
- if (mask & 2)
- pos++;
- if (mask & 4)
- pos++;
- if (mask & 8)
- pos+=2; //Guessing here
- }
- j->Pattern[i].NumNotes = numnotes;
- j->Pattern[i].Note = (MODULUS_NOTE*)malloc(sizeof(MODULUS_NOTE) * numnotes);
- memset(j->Pattern[i].Note, 0, sizeof(MODULUS_NOTE) * numnotes);
-
- pos = 0;
- memset(cmask, 0, 64);
- mask = 0;
- numnotes = 0;
- while (pos < len) {
- int b = buf[pos];
- #ifdef DEBUG_PATTERNS
- printf("NumNote: %i ", numnotes);
- #endif
-
- pos++;
- if (!b) { //If end of row:
- j->Pattern[i].Note[numnotes].Channel = -1;
- numnotes++;
- #ifdef DEBUG_PATTERNS
- printf("Channel: -1\n");
- #endif
- continue;
- }
- chn = (b - 1) & 63;
-
- if (b & 128) {
- mask = buf[pos];
- pos++;
- cmask[chn] = mask;
- }
- else
- mask = cmask[chn];
- #ifdef DEBUG_PATTERNS
- printf("Channel: %i Mask: %i ", chn, mask);
- #endif
-
- if (mask)
- j->Pattern[i].Note[numnotes].Channel = chn;
-
- if (mask & 1) {
- j->Pattern[i].Note[numnotes].Note = buf[pos];
- j->Pattern[i].Note[numnotes].Mask |= 1;
- cnote[chn] = buf[pos];
- #ifdef DEBUG_PATTERNS
- printf("Note: %i ", buf[pos]);
- #endif
- pos++;
- }
- if (mask & 2) {
- j->Pattern[i].Note[numnotes].Instrument = buf[pos];
- j->Pattern[i].Note[numnotes].Mask |= 2;
- cinstrument[chn] = buf[pos];
- #ifdef DEBUG_PATTERNS
- printf("Inst: %i ", buf[pos]);
- #endif
- pos++;
- }
- if (mask & 4) {
- if (buf[pos] <= 64 || (buf[pos] >= 128 && buf[pos] <= 192))
- if (buf[pos] <= 64) {
- j->Pattern[i].Note[numnotes].Volume = buf[pos];
- j->Pattern[i].Note[numnotes].Mask |= 4;
- }
- else {
- j->Pattern[i].Note[numnotes].Panning = buf[pos] - 128;
- j->Pattern[i].Note[numnotes].Mask |= 8;
- }
- #ifdef DEBUG_PATTERNS
- printf("Vol: %i ", buf[pos]);
- #endif
- cvol[chn] = buf[pos];
- pos++;
- }
- if (mask & 8) {
- j->Pattern[i].Note[numnotes].Command = buf[pos];
- j->Pattern[i].Note[numnotes].CommandValue = buf[pos+1];
- j->Pattern[i].Note[numnotes].Mask |= 16;
- ccom[chn] = buf[pos];
- ccomval[chn] = buf[pos+1];
- #ifdef DEBUG_PATTERNS
- printf("Com: %i CommArg: %i ", buf[pos], buf[pos+1]);
- #endif
- pos+=2;
- }
- if (mask & 16) {
- j->Pattern[i].Note[numnotes].Note = cnote[chn];
- j->Pattern[i].Note[numnotes].Mask |= 1;
- #ifdef DEBUG_PATTERNS
- printf("LNote: %i ", cnote[chn]);
- #endif
- }
- if (mask & 32) {
- j->Pattern[i].Note[numnotes].Instrument = cinstrument[chn];
- j->Pattern[i].Note[numnotes].Mask |= 2;
- #ifdef DEBUG_PATTERNS
- printf("LInst: %i ", cinstrument[chn]);
- #endif
- }
- if (mask & 64) {
- if (cvol[chn] <= 64 || (cvol[chn] >= 128 && cvol[chn] <= 192))
- if (cvol[chn] <= 64) {
- j->Pattern[i].Note[numnotes].Volume = cvol[chn];
- j->Pattern[i].Note[numnotes].Mask |= 4;
- }
- else {
- j->Pattern[i].Note[numnotes].Panning = cvol[chn] - 128;
- j->Pattern[i].Note[numnotes].Mask |= 8;
- }
- #ifdef DEBUG_PATTERNS
- printf("LVol: %i ", cvol[chn]);
- #endif
- }
- if (mask & 128) {
- j->Pattern[i].Note[numnotes].Command = ccom[chn];
- j->Pattern[i].Note[numnotes].CommandValue = ccomval[chn];
- j->Pattern[i].Note[numnotes].Mask |= 16;
- #ifdef DEBUG_PATTERNS
- printf("LCom: %i LComArg: %i ", ccom[chn], ccomval[chn]);
- #endif
- }
- #ifdef DEBUG_PATTERNS
- printf("\n");
- #endif
- if (mask)
- numnotes++;
- #ifdef DEBUG_PATTERNS
- rest(1000);
- #endif
- }
- }
- if (insoffs)
- free(insoffs);
- if (samoffs)
- free(samoffs);
- if (patoffs)
- free(patoffs);
-
- return j;
-}
+#ifdef FORTIFY
+#include "fortify.h"
+#endif
+#include <stdio.h>
+#ifdef MSS
+#include "mss.h"
+#endif
+
+#include <string.h>
+
+#include "allegro.h"
+#include "modulus.h"
+#include "typedef.hpp"
+
+int detect_it(char *f) {
+ int sig;
+ PACKFILE *fn = pack_fopen(f, "rb");
+
+ if (fn == NULL)
+ return FALSE;
+
+ sig = pack_mgetl(fn);
+ if (sig != AL_ID('I','M','P','M')) {
+ pack_fclose(fn);
+ return FALSE;
+ }
+ pack_fclose(fn);
+
+ return TRUE;
+}
+
+MODULUS *create_it() {
+ MODULUS *m = (MODULUS*)malloc(sizeof(MODULUS));
+ if (!m)
+ return NULL;
+ memset(m, 0, sizeof(MODULUS));
+ return m;
+}
+
+void destroy_it(MODULUS *j) {
+
+ if (song->Music == j)
+ stop_it();
+
+ //remove patterns:
+ for (int i=0; i<j->NumPatterns; i++) {
+ free(j->Pattern[i].Note);
+ }
+ if (j->Pattern)
+ free(j->Pattern);
+ //remove instruments;
+ if (j->Instrument)
+ free(j->Instrument);
+ //remove samples;
+ for (int i=0; i<j->NumSamples; i++) {
+ destroy_sample(j->Sample[i].Sample);
+ }
+ if (j->Sample)
+ free(j->Sample);
+ //remove orders:
+ if (j->Order)
+ free(j->Order);
+ //remove channels:
+ for (int i=0; i<64; i++) {
+ if (j->Channel[i].VChannel) {
+ MODULUS_VCHANNEL *vchn = song->Music->Channel[i].VChannel;
+ MODULUS_VCHANNEL *prev = NULL;
+
+ if (!vchn)
+ continue;
+
+ for (;;) {
+ deallocate_voice(vchn->voice);
+
+ prev = vchn;
+ vchn = vchn->next;
+ free(prev);
+
+ if (!vchn)
+ break;
+ }
+ }
+ }
+ free(j);
+}
+
+//#define DEBUG_IT_SIZE
+
+int get_module_size(MODULUS *j) {
+ int a, b, c, d = 0, e;
+ a = sizeof(MODULUS) + j->NumOrders;
+ b = j->NumInstruments * sizeof(MODULUS_INSTRUMENT);
+ c = j->NumSamples * sizeof(MODULUS_SAMPLE);
+
+ for (int i=0; i<j->NumSamples; i++)
+ d += j->Sample[i].SampleLength * (j->Sample[i].Flag & 2 ? sizeof(short) : 1) * (j->Sample[i].Flag & 4 ? 2: 1);
+
+ e = 4 + sizeof(MODULUS_PATTERN) * j->NumPatterns;
+
+ for (int i=0; i<j->NumPatterns; i++)
+ e += j->Pattern[i].NumNotes * sizeof(MODULUS_NOTE);
+ #ifdef DEBUG_IT_SIZE
+ printf("Base: %i, Instruments(%i): %i, Samples(%i): %i, Data: %i, Patterns(%i): %i\n", a, j->NumInstruments, b, j->NumSamples, c, d, j->NumPatterns, e);
+ #endif
+
+ return a+b+c+d+e;
+}
+
+#define MAX_IT_CHN 64
+
+//#define DEBUG_HEADER
+//#define DEBUG_INSTRUMENTS
+//#define DEBUG_SAMPLES
+//#define DEBUG_PATTERNS
+
+static dword *sourcebuf = NULL;
+static dword *sourcepos = NULL;
+static byte rembits = 0;
+
+int readblock(PACKFILE *f) {
+ long size;
+ int c = pack_igetw(f);
+ if (c == -1)
+ return 0;
+ size = c;
+
+ sourcebuf = (dword*)malloc(size+4);
+ if (!sourcebuf)
+ return 0;
+
+ c = pack_fread(sourcebuf, size, f);
+ if (c < 1) {
+ free(sourcebuf);
+ sourcebuf = NULL;
+ return 0;
+ }
+ sourcepos = sourcebuf;
+ rembits = 32;
+ return 1;
+}
+
+void freeblock() {
+ if (sourcebuf)
+ free(sourcebuf);
+ sourcebuf = NULL;
+}
+
+dword readbits(char b) {
+ dword val;
+ if (b <= rembits) {
+ val = *sourcepos & ((1 << b) - 1);
+ *sourcepos >>= b;
+ rembits -= b;
+ }
+ else {
+ dword nbits = b - rembits;
+ val = *sourcepos;
+ sourcepos++;
+ val |= ((*sourcepos & ((1 << nbits) - 1)) << rembits);
+ *sourcepos >>= nbits;
+ rembits = 32 - nbits;
+ }
+ return val;
+}
+
+void decompress8(PACKFILE *f, void *data, int len, int tver) {
+ char *destbuf = (char*)data;
+ char *destpos = destbuf;
+ int blocklen, blockpos;
+ byte bitwidth;
+ word val;
+ char d1, d2;
+
+ memset(destbuf, 0, len);
+
+ while (len>0) {
+ //Read a block of compressed data:
+ if (!readblock(f))
+ return;
+ //Set up a few variables
+ blocklen = (len < 0x8000) ? len : 0x8000; //Max block length is 0x8000 bytes
+ blockpos = 0;
+ bitwidth = 9;
+ d1 = d2 = 0;
+ //Start the decompression:
+ while (blockpos < blocklen) {
+ //Read a value:
+ val = readbits(bitwidth);
+ //Check for bit width change:
+
+ if (bitwidth < 7) { //Method 1:
+ if (val == (1 << (bitwidth - 1))) {
+ val = readbits(3) + 1;
+ bitwidth = (val < bitwidth) ? val : val + 1;
+ continue;
+ }
+ }
+ else if (bitwidth < 9) { //Method 2
+ byte border = (0xFF >> (9 - bitwidth)) - 4;
+
+ if (val > border && val <= (border + 8)) {
+ val -= border;
+ bitwidth = (val < bitwidth) ? val : val + 1;
+ continue;
+ }
+ }
+ else if (bitwidth == 9) { //Method 3
+ if (val & 0x100) {
+ bitwidth = (val + 1) & 0xFF;
+ continue;
+ }
+ }
+ else { //Illegal width, abort ?
+ freeblock();
+ return;
+ }
+
+ //Expand the value to signed byte:
+ char v; //The sample value:
+ if (bitwidth < 8) {
+ byte shift = 8 - bitwidth;
+ v = (val << shift);
+ v >>= shift;
+ }
+ else
+ v = (char)val;
+
+ //And integrate the sample value
+ //(It always has to end with integration doesn't it ? ;-)
+ d1 += v;
+ d2 += d1;
+
+ //Store !
+ *destpos = ((tver == 0x215) ? d2 : d1);
+ destpos++;
+ blockpos++;
+ }
+ freeblock();
+ len -= blocklen;
+ }
+ return;
+}
+
+void decompress16(PACKFILE *f, void *data, int len, int tver) {
+ //make the output buffer:
+ short *destbuf = (short*)data;
+ short *destpos = destbuf;
+ int blocklen, blockpos;
+ byte bitwidth;
+ long val;
+ short d1, d2;
+
+ memset(destbuf, 0, len);
+
+ while (len>0) {
+ //Read a block of compressed data:
+ if (!readblock(f))
+ return;
+ //Set up a few variables
+ blocklen = (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes
+ blockpos = 0;
+ bitwidth = 17;
+ d1 = d2 = 0;
+ //Start the decompression:
+ while (blockpos < blocklen) {
+ val = readbits(bitwidth);
+ //Check for bit width change:
+
+ if (bitwidth < 7) { //Method 1:
+ if (val == (1 << (bitwidth - 1))) {
+ val = readbits(4) + 1;
+ bitwidth = (val < bitwidth) ? val : val + 1;
+ continue;
+ }
+ }
+ else if (bitwidth < 17) { //Method 2
+ word border = (0xFFFF >> (17 - bitwidth)) - 8;
+
+ if (val > border && val <= (border + 16)) {
+ val -= border;
+ bitwidth = val < bitwidth ? val : val + 1;
+ continue;
+ }
+ }
+ else if (bitwidth == 17) { //Method 3
+ if (val & 0x10000) {
+ bitwidth = (val + 1) & 0xFF;
+ continue;
+ }
+ }
+ else { //Illegal width, abort ?
+ freeblock();
+ return;
+ }
+
+ //Expand the value to signed byte:
+ short v; //The sample value:
+ if (bitwidth < 16) {
+ byte shift = 16 - bitwidth;
+ v = (val << shift);
+ v >>= shift;
+ }
+ else
+ v = (short)val;
+
+ //And integrate the sample value
+ //(It always has to end with integration doesn't it ? ;-)
+ d1 += v;
+ d2 += d1;
+
+ //Store !
+ *destpos = ((tver == 0x215) ? d2 : d1);
+ destpos++;
+ blockpos++;
+ }
+ freeblock();
+ len -= blocklen;
+ }
+ return;
+}
+
+MODULUS *load_it(char *file) {
+ PACKFILE *f;
+ MODULUS *j = create_it();
+ int tver, tver2, flag, msglen, msgoffs;
+ int *insoffs = NULL, *samoffs = NULL, *patoffs = NULL;
+
+ if (!j)
+ return NULL;
+
+ if (!detect_it(file))
+ return NULL;
+
+ f = pack_fopen(file, "rb");
+
+ if (!f) {
+ #ifdef DEBUG_HEADER
+ printf("Error Opening!\n");
+ #endif
+ return NULL;
+ }
+
+ pack_fseek(f, 30);
+ pack_igetw(f); //I have no idea...
+
+ j->NumOrders = pack_igetw(f);
+ j->NumInstruments = pack_igetw(f);
+ j->NumSamples = pack_igetw(f);
+ j->NumPatterns = pack_igetw(f);
+
+ #ifdef DEBUG_HEADER
+ printf("Loading IT: %i Orders %i Instruments, %i Samples, %i Patterns\n", j->NumOrders, j->NumInstruments, j->NumSamples, j->NumPatterns);
+ #endif
+
+ tver = pack_igetw(f);
+ j->Version = tver2 = pack_igetw(f);
+
+ #ifdef DEBUG_HEADER
+ printf("Tracker ver: %X, %X\n", tver, tver2);
+ #endif
+
+ j->Flags = pack_igetw(f);
+ flag = pack_igetw(f);
+
+ j->GlobalVolume = pack_getc(f);
+ j->MixVolume = pack_getc(f);
+ j->Speed = pack_getc(f);
+ j->Tempo = pack_getc(f);
+ j->PanningSeperation = pack_getc(f);
+
+ #ifdef DEBUG_HEADER
+ printf("Global Volume: %i, Mixing Volume: %i, Speed: %i, Tempo: %i, PanSep: %i\n", j->GlobalVolume, j->MixVolume, j->Speed, j->Tempo, j->PanningSeperation);
+ #endif
+
+ pack_getc(f); //Damn....I need more info on this.
+
+ msglen = pack_igetw(f);
+ msgoffs = pack_igetl(f);
+
+ pack_fseek(f, 4);
+
+ #ifdef DEBUG_HEADER
+ printf("Channel Pan:");
+ #endif
+
+ for (int i=0; i<MAX_IT_CHN; i++) {
+ j->Channel[i].Pan = pack_getc(f);
+ #ifdef DEBUG_HEADER
+ printf(" %i", j->Channel[i].Pan);
+ #endif
+ }
+ #ifdef DEBUG_HEADER
+ printf("\nChannel Vol:");
+ #endif
+ for (int i=0; i<MAX_IT_CHN; i++) {
+ j->Channel[i].Volume = pack_getc(f);
+ #ifdef DEBUG_HEADER
+ printf(" %i", j->Channel[i].Volume);
+ #endif
+ }
+ #ifdef DEBUG_HEADER
+ printf("\n");
+ #endif
+
+ j->Order = (unsigned char *)malloc(j->NumOrders);
+ pack_fread(j->Order, j->NumOrders, f);
+
+ if (j->NumInstruments)
+ insoffs = (int*)malloc(4 * j->NumInstruments);
+ if (j->NumSamples)
+ samoffs = (int*)malloc(4 * j->NumSamples);
+ if (j->NumPatterns)
+ patoffs = (int*)malloc(4 * j->NumPatterns);
+
+ pack_fread(insoffs, 4 * j->NumInstruments, f);
+ pack_fread(samoffs, 4 * j->NumSamples, f);
+ pack_fread(patoffs, 4 * j->NumPatterns, f);
+
+ if (flag&1) { //Song message attached
+ //Ignore.
+ }
+ if (flag & 4) { //skip something:
+ short u;
+ char dummy[8];
+ u = pack_igetw(f);
+ for (int i=0; i<u; u++)
+ pack_fread(dummy, 8, f);
+ }
+ if (flag & 8) { //MIDI commands ???
+ char dummy[33];
+ for (int i=0; i<9+16+128; i++)
+ pack_fread(dummy, 32, f);
+
+ }
+
+ if (j->NumInstruments)
+ j->Instrument = (MODULUS_INSTRUMENT*)malloc(sizeof(MODULUS_INSTRUMENT) * j->NumInstruments);
+ #ifdef DEBUG_INSTRUMENTS
+ if (!j->Instrument)
+ printf("No Mem for Instruments!\n");
+ #endif
+
+
+ for (int i=0; i<j->NumInstruments; i++) {
+ pack_fclose(f);
+ f = pack_fopen(file, "rb");
+ #ifdef DEBUG_INSTRUMENTS
+ if (!f)
+ printf("Error Opening!\n");
+ #endif
+ pack_fseek(f, insoffs[i] + 17);
+
+ j->Instrument[i].NewNoteAction = pack_getc(f);
+ j->Instrument[i].DuplicateCheckType = pack_getc(f);
+ j->Instrument[i].DuplicateCheckAction = pack_getc(f);
+ j->Instrument[i].FadeOut = pack_igetw(f);
+ j->Instrument[i].PitchPanSeperation = pack_getc(f);
+ j->Instrument[i].PitchPanCenter = pack_getc(f);
+ j->Instrument[i].GlobalVolume = pack_getc(f);
+ j->Instrument[i].DefaultPan = pack_getc(f);
+ #ifdef DEBUG_INSTRUMENTS
+ printf("I%02i @ 0x%X, NNA %i, DCT %i, DCA %i, FO %i, PPS %i, PPC %i, GVol %i, DPan %i\n", i, insoffs[i], j->Instrument[i].NewNoteAction, j->Instrument[i].DuplicateCheckType, j->Instrument[i].DuplicateCheckAction, j->Instrument[i].FadeOut, j->Instrument[i].PitchPanSeperation, j->Instrument[i].PitchPanCenter, j->Instrument[i].GlobalVolume, j->Instrument[i].DefaultPan);
+ #endif
+
+ pack_fseek(f, 38);
+
+ for (int k=0; k<120; k++) {
+ j->Instrument[i].NoteNote[k] = pack_getc(f);
+ j->Instrument[i].NoteSample[k] = pack_getc(f) - 1;
+ }
+
+ j->Instrument[i].VolumeEnvelope.Flag = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.NumNodes = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.LoopBegin = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.LoopEnd = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.SustainLoopBegin = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.SustainLoopEnd = pack_getc(f);
+ for (int k=0; k<j->Instrument[i].VolumeEnvelope.NumNodes; k++) {
+ j->Instrument[i].VolumeEnvelope.NodeY[k] = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.NodeTick[k] = pack_igetw(f);
+ }
+ pack_fseek(f, 75 - j->Instrument[i].VolumeEnvelope.NumNodes * 3);
+
+ j->Instrument[i].PanningEnvelope.Flag = pack_getc(f);
+ j->Instrument[i].PanningEnvelope.NumNodes = pack_getc(f);
+ j->Instrument[i].PanningEnvelope.LoopBegin = pack_getc(f);
+ j->Instrument[i].PanningEnvelope.LoopEnd = pack_getc(f);
+ j->Instrument[i].PanningEnvelope.SustainLoopBegin = pack_getc(f);
+ j->Instrument[i].PanningEnvelope.SustainLoopEnd = pack_getc(f);
+ for (int k=0; k<j->Instrument[i].PanningEnvelope.NumNodes; k++) {
+ j->Instrument[i].PanningEnvelope.NodeY[k] = pack_getc(f);
+ j->Instrument[i].PanningEnvelope.NodeTick[k] = pack_igetw(f);
+ }
+ pack_fseek(f, 75 - j->Instrument[i].PanningEnvelope.NumNodes * 3);
+
+ j->Instrument[i].PitchEnvelope.Flag = pack_getc(f);
+ j->Instrument[i].PitchEnvelope.NumNodes = pack_getc(f);
+ j->Instrument[i].PitchEnvelope.LoopBegin = pack_getc(f);
+ j->Instrument[i].PitchEnvelope.LoopEnd = pack_getc(f);
+ j->Instrument[i].PitchEnvelope.SustainLoopBegin = pack_getc(f);
+ j->Instrument[i].PitchEnvelope.SustainLoopEnd = pack_getc(f);
+ for (int k=0; k<j->Instrument[i].PitchEnvelope.NumNodes; k++) {
+ j->Instrument[i].PitchEnvelope.NodeY[k] = pack_getc(f);
+ j->Instrument[i].PitchEnvelope.NodeTick[k] = pack_igetw(f);
+ }
+ }
+
+ if (j->NumSamples)
+ j->Sample = (MODULUS_SAMPLE*)malloc(sizeof(MODULUS_SAMPLE) * j->NumSamples);
+
+ #ifdef DEBUG_SAMPLES
+ if (!j->Sample)
+ printf("No Mem for Samples!\n");
+ #endif
+
+ for (int i=0; i<j->NumSamples; i++) {
+ int sam_samptr, convert;
+
+ pack_fclose(f);
+ f = pack_fopen(file, "rb");
+ #ifdef DEBUG_SAMPLES
+ if (!f)
+ printf("Error opening!\n");
+ #endif
+
+ pack_fseek(f, samoffs[i] + 17);
+
+ j->Sample[i].GlobalVolume = pack_getc(f);
+ j->Sample[i].Flag = pack_getc(f);
+ j->Sample[i].Volume = pack_getc(f);
+
+ #ifdef DEBUG_SAMPLES
+ printf("S%02i @ 0x%X, Vol: %i/%i, Flag: %i", i, samoffs[i], j->Sample[i].GlobalVolume, j->Sample[i].Volume, j->Sample[i].Flag);
+ #endif
+
+ pack_fseek(f, 26);
+
+ convert = pack_getc(f);
+ pack_getc(f); //Panning ?
+
+ j->Sample[i].SampleLength = pack_igetl(f);
+ j->Sample[i].LoopBegin = pack_igetl(f);
+ j->Sample[i].LoopEnd = pack_igetl(f);
+ j->Sample[i].C5Speed = pack_igetl(f);
+ j->Sample[i].SustainLoopBegin = pack_igetl(f);
+ j->Sample[i].SustainLoopEnd = pack_igetl(f);
+
+ #ifdef DEBUG_SAMPLES
+ printf(", SLen: %i, LpB: %i, LpE: %i, C5S: %i\n", j->Sample[i].SampleLength, j->Sample[i].LoopBegin, j->Sample[i].LoopEnd, j->Sample[i].C5Speed);
+ #endif
+
+ sam_samptr = pack_igetl(f);
+
+ j->Sample[i].VibratoSpeed = pack_getc(f);
+ j->Sample[i].VibratoDepth = pack_getc(f);
+ j->Sample[i].VibratoRate = pack_getc(f);
+ j->Sample[i].VibratoWaveForm = pack_getc(f);
+
+ #ifdef DEBUG_SAMPLES
+ printf("SusLpB: %i, SusLpE: %i, VibSp: %i, VibDep: %i, VibWav: %i, VibRat: %i\n", j->Sample[i].SustainLoopBegin, j->Sample[i].SustainLoopEnd, j->Sample[i].VibratoSpeed, j->Sample[i].VibratoDepth, j->Sample[i].VibratoWaveForm, j->Sample[i].VibratoRate);
+ #endif
+
+ if (j->Sample[i].Flag & 1 == 0)
+ continue;
+
+ pack_fclose(f);
+ f = pack_fopen(file, "rb");
+ pack_fseek(f, sam_samptr);
+
+ int len = j->Sample[i].SampleLength * (j->Sample[i].Flag & 2 ? sizeof(short) : 1) * (j->Sample[i].Flag & 4 ? 2: 1);
+
+ #ifdef DEBUG_SAMPLES
+ printf("Len: %i, Size: %i KB\n", j->Sample[i].SampleLength, len/1024);
+ #endif
+
+ SAMPLE *sam = create_sample(j->Sample[i].Flag & 2 ? 16 : 8, j->Sample[i].Flag & 4 ? TRUE : FALSE, j->Sample[i].C5Speed, j->Sample[i].SampleLength);
+
+ if (j->Sample[i].Flag & 8) { // If the sample is packed, then we must unpack it
+ if (j->Sample[i].Flag & 2)
+ decompress16(f, sam->data, j->Sample[i].SampleLength, tver2);
+ else
+ decompress8(f, sam->data, j->Sample[i].SampleLength, tver2);
+ } else {
+ pack_fread(sam->data, len, f);
+ }
+
+ if (j->Sample[i].Flag & SAMPLE_USELOOP) {
+ sam->loop_start = j->Sample[i].LoopBegin;
+ sam->loop_end = j->Sample[i].LoopEnd;
+ }
+
+ j->Sample[i].Sample = sam;
+
+ void *dat = sam->data;
+
+ if (convert & 2) { //Change the byte order for 16-bit samples:
+ if (sam->bits == 16) {
+ for (int k=0; k<len; k+=2) {
+ int l = ((char*)dat)[k];
+ ((char*)dat)[k] = ((char*)dat)[k+1];
+ ((char*)dat)[k+1] = l;
+
+ }
+ }
+ else {
+ for (int k=0; k<len; k+=2) {
+ int l = ((char*)dat)[k];
+ ((char*)dat)[k] = ((char*)dat)[k+1];
+ ((char*)dat)[k+1] = l;
+
+ }
+ }
+ }
+ if (convert & 1) { //Convert to unsigned
+ if (sam->bits == 8) {
+ for (int k=0; k<len; k++) {
+ ((char*)dat)[k] ^= 0x80;
+ }
+ }
+ else {
+ for (int k=0; k<(len>>1); k++) {
+ ((short*)dat)[k] ^= 0x8000;
+ }
+ }
+ }
+ }
+
+ if (j->NumPatterns)
+ j->Pattern = (MODULUS_PATTERN*)malloc(sizeof(MODULUS_PATTERN) * j->NumPatterns);
+ unsigned char *buf = (unsigned char*)alloca(65536);
+ unsigned char *cmask = (unsigned char*)alloca(64),
+ *cnote = (unsigned char*)alloca(64),
+ *cinstrument = (unsigned char*)alloca(64),
+ *cvol = (unsigned char*)alloca(64),
+ *ccom = (unsigned char*)alloca(64),
+ *ccomval = (unsigned char*)alloca(64);
+
+ for (int i=0; i<j->NumPatterns; i++) {
+ int numnotes = 0, len, pos = 0, mask = 0, chn = 0;
+
+ memset(cmask, 0, 64);
+ memset(cnote, 0, 64);
+ memset(cinstrument, 0, 64);
+ memset(cvol, 0, 64);
+ memset(ccom, 0, 64);
+ memset(ccomval, 0, 64);
+
+ pack_fclose(f);
+ f = pack_fopen(file, "rb");
+ pack_fseek(f, patoffs[i]);
+
+ len = pack_igetw(f);
+ j->Pattern[i].NumRows = pack_igetw(f);
+
+ pack_fseek(f, 4);
+ pack_fread(buf, len, f);
+
+ while (pos < len) {
+ int b = buf[pos];
+ pos++;
+ if (!b) { //If end of row:
+ numnotes++;
+ continue;
+ }
+ chn = (b - 1) & 63;
+
+ if (b & 128) {
+ mask = buf[pos];
+ pos++;
+ cmask[chn] = mask;
+ }
+ else
+ mask = cmask[chn];
+
+ if (mask)
+ numnotes++;
+ if (mask & 1)
+ pos++;
+ if (mask & 2)
+ pos++;
+ if (mask & 4)
+ pos++;
+ if (mask & 8)
+ pos+=2; //Guessing here
+ }
+ j->Pattern[i].NumNotes = numnotes;
+ j->Pattern[i].Note = (MODULUS_NOTE*)malloc(sizeof(MODULUS_NOTE) * numnotes);
+ memset(j->Pattern[i].Note, 0, sizeof(MODULUS_NOTE) * numnotes);
+
+ pos = 0;
+ memset(cmask, 0, 64);
+ mask = 0;
+ numnotes = 0;
+ while (pos < len) {
+ int b = buf[pos];
+ #ifdef DEBUG_PATTERNS
+ printf("NumNote: %i ", numnotes);
+ #endif
+
+ pos++;
+ if (!b) { //If end of row:
+ j->Pattern[i].Note[numnotes].Channel = -1;
+ numnotes++;
+ #ifdef DEBUG_PATTERNS
+ printf("Channel: -1\n");
+ #endif
+ continue;
+ }
+ chn = (b - 1) & 63;
+
+ if (b & 128) {
+ mask = buf[pos];
+ pos++;
+ cmask[chn] = mask;
+ }
+ else
+ mask = cmask[chn];
+ #ifdef DEBUG_PATTERNS
+ printf("Channel: %i Mask: %i ", chn, mask);
+ #endif
+
+ if (mask)
+ j->Pattern[i].Note[numnotes].Channel = chn;
+
+ if (mask & 1) {
+ j->Pattern[i].Note[numnotes].Note = buf[pos];
+ j->Pattern[i].Note[numnotes].Mask |= 1;
+ cnote[chn] = buf[pos];
+ #ifdef DEBUG_PATTERNS
+ printf("Note: %i ", buf[pos]);
+ #endif
+ pos++;
+ }
+ if (mask & 2) {
+ j->Pattern[i].Note[numnotes].Instrument = buf[pos];
+ j->Pattern[i].Note[numnotes].Mask |= 2;
+ cinstrument[chn] = buf[pos];
+ #ifdef DEBUG_PATTERNS
+ printf("Inst: %i ", buf[pos]);
+ #endif
+ pos++;
+ }
+ if (mask & 4) {
+ if (buf[pos] <= 64 || (buf[pos] >= 128 && buf[pos] <= 192))
+ if (buf[pos] <= 64) {
+ j->Pattern[i].Note[numnotes].Volume = buf[pos];
+ j->Pattern[i].Note[numnotes].Mask |= 4;
+ }
+ else {
+ j->Pattern[i].Note[numnotes].Panning = buf[pos] - 128;
+ j->Pattern[i].Note[numnotes].Mask |= 8;
+ }
+ #ifdef DEBUG_PATTERNS
+ printf("Vol: %i ", buf[pos]);
+ #endif
+ cvol[chn] = buf[pos];
+ pos++;
+ }
+ if (mask & 8) {
+ j->Pattern[i].Note[numnotes].Command = buf[pos];
+ j->Pattern[i].Note[numnotes].CommandValue = buf[pos+1];
+ j->Pattern[i].Note[numnotes].Mask |= 16;
+ ccom[chn] = buf[pos];
+ ccomval[chn] = buf[pos+1];
+ #ifdef DEBUG_PATTERNS
+ printf("Com: %i CommArg: %i ", buf[pos], buf[pos+1]);
+ #endif
+ pos+=2;
+ }
+ if (mask & 16) {
+ j->Pattern[i].Note[numnotes].Note = cnote[chn];
+ j->Pattern[i].Note[numnotes].Mask |= 1;
+ #ifdef DEBUG_PATTERNS
+ printf("LNote: %i ", cnote[chn]);
+ #endif
+ }
+ if (mask & 32) {
+ j->Pattern[i].Note[numnotes].Instrument = cinstrument[chn];
+ j->Pattern[i].Note[numnotes].Mask |= 2;
+ #ifdef DEBUG_PATTERNS
+ printf("LInst: %i ", cinstrument[chn]);
+ #endif
+ }
+ if (mask & 64) {
+ if (cvol[chn] <= 64 || (cvol[chn] >= 128 && cvol[chn] <= 192))
+ if (cvol[chn] <= 64) {
+ j->Pattern[i].Note[numnotes].Volume = cvol[chn];
+ j->Pattern[i].Note[numnotes].Mask |= 4;
+ }
+ else {
+ j->Pattern[i].Note[numnotes].Panning = cvol[chn] - 128;
+ j->Pattern[i].Note[numnotes].Mask |= 8;
+ }
+ #ifdef DEBUG_PATTERNS
+ printf("LVol: %i ", cvol[chn]);
+ #endif
+ }
+ if (mask & 128) {
+ j->Pattern[i].Note[numnotes].Command = ccom[chn];
+ j->Pattern[i].Note[numnotes].CommandValue = ccomval[chn];
+ j->Pattern[i].Note[numnotes].Mask |= 16;
+ #ifdef DEBUG_PATTERNS
+ printf("LCom: %i LComArg: %i ", ccom[chn], ccomval[chn]);
+ #endif
+ }
+ #ifdef DEBUG_PATTERNS
+ printf("\n");
+ #endif
+ if (mask)
+ numnotes++;
+ #ifdef DEBUG_PATTERNS
+ rest(1000);
+ #endif
+ }
+ }
+ if (insoffs)
+ free(insoffs);
+ if (samoffs)
+ free(samoffs);
+ if (patoffs)
+ free(patoffs);
+
+ return j;
+}
diff --git a/plugins/dumb/dumb-kode54/src/tools/it/modulus.h b/plugins/dumb/dumb-kode54/src/tools/it/modulus.h
index b17d6ff6..e7fd5c91 100644
--- a/plugins/dumb/dumb-kode54/src/tools/it/modulus.h
+++ b/plugins/dumb/dumb-kode54/src/tools/it/modulus.h
@@ -1,193 +1,193 @@
-
-#define MUSIC_IT AL_ID('I','M','P','M')
-
-typedef struct MODULUS_MUSIC_INFO {
- char Name[29];
- int Type;
-} MODULUS_MUSIC_INFO;
-
-#define ENVELOPE_ON 1
-#define ENVELOPE_LOOP_ON 2
-#define ENVELOPE_SUSTAINLOOP 4
-
-typedef struct MODULUS_ENVELOPE {
- unsigned char Flag,
- NumNodes,
- LoopBegin, LoopEnd, SustainLoopBegin, SustainLoopEnd; //in nodes.
- char NodeY[25];
- short NodeTick[25];
-} MODULUS_ENVELOPE;
-
-typedef struct MODULUS_VENVELOPE {
- char CurNode;
- unsigned char CurTick;
- char End;
- //float CVolume;
- MODULUS_ENVELOPE *Envelope;
-} MODULUS_VENVELOPE;
-
-#define NNA_NOTECUT 1
-#define NNA_NOTECONTINUE 2
-#define NNA_NOTEOFF 3
-#define NNA_NOTEFADE 4
-
-#define DCT_OFF 0
-#define DCT_NOTE 1
-#define DCT_SAMPLE 2
-#define DCT_INSTRUMENT 3
-
-#define DCA_CUT 0
-#define DCA_NOTEOFF 1
-#define DCA_NOTEFADE 2
-
-typedef struct MOULUS_INSTRUMENT {
- unsigned char Flag;
- char VolumeLoopNodeStart, VolumeLoopNodeEnd;
- char SustainLoopNodeStart, SustainLoopNodeEnd;
- char DuplicateCheckType;
- char DuplicateCheckAction;
- char NewNoteAction;
- int FadeOut;
-
- unsigned char PitchPanSeperation, //0->64, Bit7: Don't use
- PitchPanCenter; //Note, from C-0 to B-9
- unsigned char GlobalVolume, //0->128
- DefaultPan; //0->64, Bit7: Don't use
-
-
- unsigned char NoteSample[120];
- unsigned char NoteNote[120];
-
- MODULUS_ENVELOPE VolumeEnvelope, PanningEnvelope, PitchEnvelope;
-} MODULUS_INSTRUMENT;
-
-#define SAMPLE_HASSAMPLE 1
-#define SAMPLE_16BIT 2
-#define SAMPLE_STEREO 4
-#define SAMPLE_USELOOP 16
-#define SAMPLE_USESUSTAINLOOP 32
-#define SAMPLE_PINGPONGLOOP 64
-#define SAMPLE_PINGPONGSUSTAINLOOP 128
-
-#define VIBRATO_SINE 0
-#define VIBRATO_RAMPDOWN 1
-#define VIBRATO_SQUARE 2
-#define VIBRATO_RANDOM 3
-
-typedef struct MODULUS_SAMPLE {
- unsigned char GlobalVolume; //0->64
- unsigned char Flag;
- unsigned char Volume;
- int SampleLength; //in samples, not bytes !
- int LoopBegin, LoopEnd; //in samples
- int SustainLoopBegin, SustainLoopEnd;
- int C5Speed; //Number of bytes/sec for C-5
-
- SAMPLE *Sample;
-
- char VibratoSpeed; //0->64
- char VibratoDepth; //0->64
- char VibratoWaveForm;
- char VibratoRate; //0->64
-} MODULUS_SAMPLE;
-
-typedef struct MODULUS_NOTE {
- char Mask; //If Bit0: Note, Bit1: Instrument, Bit2: Volume, Bit3: Panning, Bit4: Command
- char Channel; //if -1, then end of row.
- unsigned char Note;
- char Instrument;
- unsigned char Volume, Panning;
- unsigned char Command, CommandValue;
-} MODULUS_NOTE;
-
-typedef struct MODULUS_PATTERN {
- int NumRows;
- int NumNotes;
- MODULUS_NOTE *Note;
-} MODULUS_PATTERN;
-
-typedef struct MODULUS_VCHANNEL {
- MODULUS_SAMPLE *Sample; //NULL is unused
- char voice;
- char ChannelVolume;
- char NoteOn;
- char NNA;
- short FadeOutCount, FadeOut;
- float MixVolume, MixPan;
- MODULUS_VENVELOPE *VVolumeEnvelope, *VPanningEnvelope, *VPitchEnvelope;
- MODULUS_VCHANNEL *next, *prev;
-} MODULUS_VCHANNEL;
-
-typedef struct MODULUS_CHANNEL {
- unsigned char Volume; //0->64
- unsigned char Pan; //0->32->64, 100 = surround, Bit7: Disable
- char LastNote, LastInstrument, LastSample;
- MODULUS_VCHANNEL *VChannel;
-} MODULUS_CHANNEL;
-
-#define FLAG_STEREO 1
-#define FLAG_USEINSTRUMENTS 4
-#define FLAG_LINEARSLIDES 8
-#define FLAG_OLDEFFECT 16
-
-typedef struct MODULUS {
- MODULUS_INSTRUMENT *Instrument;
- MODULUS_SAMPLE *Sample;
- MODULUS_PATTERN *Pattern;
-
- int NumOrders;
- int NumInstruments;
- int NumSamples;
- int NumPatterns;
- int Flags;
- short Version;
- char GlobalVolume;
- char MixVolume;
- unsigned char Speed, Tempo;
- char PanningSeperation;
-
- unsigned char *Order;
-
- MODULUS_CHANNEL Channel[64];
-
-} MODULUS;
-
-#define COMMAND_SET_SONG_SPEED 1
-#define COMMAND_JUMP_TO_ORDER 2
-#define COMMAND_PATTERN_BREAK_TO_ROW 3
-#define COMMAND_SET_CHANNEL_VOLUME 13
-#define COMMAND_SET_SONG_TEMPO 20
-#define COMMAND_SET_GLOBAL_VOLUME 22
-
-typedef struct MODULUS_PLAY {
- MODULUS *Music;
- int Loop, Tick;
- int CurOrder, CurPattern, CurPos;
- int Command, CommandVal0, CommandVal1, CommandVal2;
- int pos;
-} MODULUS_PLAY;
-extern MODULUS_PLAY *song;
-
-extern int IT_Play_Method;
-
-MODULUS *load_it(char*);
-int get_module_size(MODULUS *);
-
-int play_it(MODULUS *j, int loop);
-void install_modulus();
-void set_mix_volume(int i);
-
-void stop_it();
-int is_music_done();
-void destroy_it(MODULUS *j);
-
-//Should be internal:
-extern MODULUS_PLAY *song;
-extern int note_freq[120];
-
-extern void MOD_Interrupt(...);
-extern int MOD_Poller(void*);
-
-#define IT_TIMER 0
-#define IT_POLL 1
-
+
+#define MUSIC_IT AL_ID('I','M','P','M')
+
+typedef struct MODULUS_MUSIC_INFO {
+ char Name[29];
+ int Type;
+} MODULUS_MUSIC_INFO;
+
+#define ENVELOPE_ON 1
+#define ENVELOPE_LOOP_ON 2
+#define ENVELOPE_SUSTAINLOOP 4
+
+typedef struct MODULUS_ENVELOPE {
+ unsigned char Flag,
+ NumNodes,
+ LoopBegin, LoopEnd, SustainLoopBegin, SustainLoopEnd; //in nodes.
+ char NodeY[25];
+ short NodeTick[25];
+} MODULUS_ENVELOPE;
+
+typedef struct MODULUS_VENVELOPE {
+ char CurNode;
+ unsigned char CurTick;
+ char End;
+ //float CVolume;
+ MODULUS_ENVELOPE *Envelope;
+} MODULUS_VENVELOPE;
+
+#define NNA_NOTECUT 1
+#define NNA_NOTECONTINUE 2
+#define NNA_NOTEOFF 3
+#define NNA_NOTEFADE 4
+
+#define DCT_OFF 0
+#define DCT_NOTE 1
+#define DCT_SAMPLE 2
+#define DCT_INSTRUMENT 3
+
+#define DCA_CUT 0
+#define DCA_NOTEOFF 1
+#define DCA_NOTEFADE 2
+
+typedef struct MOULUS_INSTRUMENT {
+ unsigned char Flag;
+ char VolumeLoopNodeStart, VolumeLoopNodeEnd;
+ char SustainLoopNodeStart, SustainLoopNodeEnd;
+ char DuplicateCheckType;
+ char DuplicateCheckAction;
+ char NewNoteAction;
+ int FadeOut;
+
+ unsigned char PitchPanSeperation, //0->64, Bit7: Don't use
+ PitchPanCenter; //Note, from C-0 to B-9
+ unsigned char GlobalVolume, //0->128
+ DefaultPan; //0->64, Bit7: Don't use
+
+
+ unsigned char NoteSample[120];
+ unsigned char NoteNote[120];
+
+ MODULUS_ENVELOPE VolumeEnvelope, PanningEnvelope, PitchEnvelope;
+} MODULUS_INSTRUMENT;
+
+#define SAMPLE_HASSAMPLE 1
+#define SAMPLE_16BIT 2
+#define SAMPLE_STEREO 4
+#define SAMPLE_USELOOP 16
+#define SAMPLE_USESUSTAINLOOP 32
+#define SAMPLE_PINGPONGLOOP 64
+#define SAMPLE_PINGPONGSUSTAINLOOP 128
+
+#define VIBRATO_SINE 0
+#define VIBRATO_RAMPDOWN 1
+#define VIBRATO_SQUARE 2
+#define VIBRATO_RANDOM 3
+
+typedef struct MODULUS_SAMPLE {
+ unsigned char GlobalVolume; //0->64
+ unsigned char Flag;
+ unsigned char Volume;
+ int SampleLength; //in samples, not bytes !
+ int LoopBegin, LoopEnd; //in samples
+ int SustainLoopBegin, SustainLoopEnd;
+ int C5Speed; //Number of bytes/sec for C-5
+
+ SAMPLE *Sample;
+
+ char VibratoSpeed; //0->64
+ char VibratoDepth; //0->64
+ char VibratoWaveForm;
+ char VibratoRate; //0->64
+} MODULUS_SAMPLE;
+
+typedef struct MODULUS_NOTE {
+ char Mask; //If Bit0: Note, Bit1: Instrument, Bit2: Volume, Bit3: Panning, Bit4: Command
+ char Channel; //if -1, then end of row.
+ unsigned char Note;
+ char Instrument;
+ unsigned char Volume, Panning;
+ unsigned char Command, CommandValue;
+} MODULUS_NOTE;
+
+typedef struct MODULUS_PATTERN {
+ int NumRows;
+ int NumNotes;
+ MODULUS_NOTE *Note;
+} MODULUS_PATTERN;
+
+typedef struct MODULUS_VCHANNEL {
+ MODULUS_SAMPLE *Sample; //NULL is unused
+ char voice;
+ char ChannelVolume;
+ char NoteOn;
+ char NNA;
+ short FadeOutCount, FadeOut;
+ float MixVolume, MixPan;
+ MODULUS_VENVELOPE *VVolumeEnvelope, *VPanningEnvelope, *VPitchEnvelope;
+ MODULUS_VCHANNEL *next, *prev;
+} MODULUS_VCHANNEL;
+
+typedef struct MODULUS_CHANNEL {
+ unsigned char Volume; //0->64
+ unsigned char Pan; //0->32->64, 100 = surround, Bit7: Disable
+ char LastNote, LastInstrument, LastSample;
+ MODULUS_VCHANNEL *VChannel;
+} MODULUS_CHANNEL;
+
+#define FLAG_STEREO 1
+#define FLAG_USEINSTRUMENTS 4
+#define FLAG_LINEARSLIDES 8
+#define FLAG_OLDEFFECT 16
+
+typedef struct MODULUS {
+ MODULUS_INSTRUMENT *Instrument;
+ MODULUS_SAMPLE *Sample;
+ MODULUS_PATTERN *Pattern;
+
+ int NumOrders;
+ int NumInstruments;
+ int NumSamples;
+ int NumPatterns;
+ int Flags;
+ short Version;
+ char GlobalVolume;
+ char MixVolume;
+ unsigned char Speed, Tempo;
+ char PanningSeperation;
+
+ unsigned char *Order;
+
+ MODULUS_CHANNEL Channel[64];
+
+} MODULUS;
+
+#define COMMAND_SET_SONG_SPEED 1
+#define COMMAND_JUMP_TO_ORDER 2
+#define COMMAND_PATTERN_BREAK_TO_ROW 3
+#define COMMAND_SET_CHANNEL_VOLUME 13
+#define COMMAND_SET_SONG_TEMPO 20
+#define COMMAND_SET_GLOBAL_VOLUME 22
+
+typedef struct MODULUS_PLAY {
+ MODULUS *Music;
+ int Loop, Tick;
+ int CurOrder, CurPattern, CurPos;
+ int Command, CommandVal0, CommandVal1, CommandVal2;
+ int pos;
+} MODULUS_PLAY;
+extern MODULUS_PLAY *song;
+
+extern int IT_Play_Method;
+
+MODULUS *load_it(char*);
+int get_module_size(MODULUS *);
+
+int play_it(MODULUS *j, int loop);
+void install_modulus();
+void set_mix_volume(int i);
+
+void stop_it();
+int is_music_done();
+void destroy_it(MODULUS *j);
+
+//Should be internal:
+extern MODULUS_PLAY *song;
+extern int note_freq[120];
+
+extern void MOD_Interrupt(...);
+extern int MOD_Poller(void*);
+
+#define IT_TIMER 0
+#define IT_POLL 1
+
diff --git a/plugins/dumb/dumb-kode54/studio/include/dumbdesk.h b/plugins/dumb/dumb-kode54/studio/include/dumbdesk.h
index f8320f1c..b0e9cc59 100644
--- a/plugins/dumb/dumb-kode54/studio/include/dumbdesk.h
+++ b/plugins/dumb/dumb-kode54/studio/include/dumbdesk.h
@@ -1,44 +1,44 @@
-#ifndef INCLUDED_DUMBDESK_H
-#define INCLUDED_DUMBDESK_H
-
-
-#include "dumbgui.h"
-#include "dumbmenu.h"
-
-
-typedef struct DESKGUI
-{
- struct DESKGUI *next;
-
- GUI *gui;
-
- const char *name;
-}
-DESKGUI;
-
-
-typedef struct GUI_DESKTOP_PARAM
-{
- const char *title;
- GUI_MENU_PARAM *menu_bar;
-}
-GUI_DESKTOP_PARAM;
-
-
-#define DESKTOP_CHANGED_TITLE GUI_OTHER
-#define DESKTOP_CHANGED_REST (GUI_OTHER << 1)
-#define DESKTOP_CHANGED_ALL (DESKTOP_CHANGED_TITLE | DESKTOP_CHANGED_REST)
-
-typedef struct GUI_DESKTOP_DATA
-{
- const char *title;
- GUI_MENU_PARAM *menu_bar;
- DESKGUI *deskgui;
-}
-GUI_DESKTOP_DATA;
-
-
-extern GUI_COMMANDS gui_desktop_commands;
-
-
-#endif /* INCLUDED_DUMBDESK_H */
+#ifndef INCLUDED_DUMBDESK_H
+#define INCLUDED_DUMBDESK_H
+
+
+#include "dumbgui.h"
+#include "dumbmenu.h"
+
+
+typedef struct DESKGUI
+{
+ struct DESKGUI *next;
+
+ GUI *gui;
+
+ const char *name;
+}
+DESKGUI;
+
+
+typedef struct GUI_DESKTOP_PARAM
+{
+ const char *title;
+ GUI_MENU_PARAM *menu_bar;
+}
+GUI_DESKTOP_PARAM;
+
+
+#define DESKTOP_CHANGED_TITLE GUI_OTHER
+#define DESKTOP_CHANGED_REST (GUI_OTHER << 1)
+#define DESKTOP_CHANGED_ALL (DESKTOP_CHANGED_TITLE | DESKTOP_CHANGED_REST)
+
+typedef struct GUI_DESKTOP_DATA
+{
+ const char *title;
+ GUI_MENU_PARAM *menu_bar;
+ DESKGUI *deskgui;
+}
+GUI_DESKTOP_DATA;
+
+
+extern GUI_COMMANDS gui_desktop_commands;
+
+
+#endif /* INCLUDED_DUMBDESK_H */
diff --git a/plugins/dumb/dumb-kode54/studio/include/dumbgui.h b/plugins/dumb/dumb-kode54/studio/include/dumbgui.h
index f6cc2bc7..1b4cfb70 100644
--- a/plugins/dumb/dumb-kode54/studio/include/dumbgui.h
+++ b/plugins/dumb/dumb-kode54/studio/include/dumbgui.h
@@ -1,82 +1,82 @@
-#ifndef INCLUDED_DUMBGUI_H
-#define INCLUDED_DUMBGUI_H
-
-
-/* GUI_FINISHED_WITH: Set this in your update, key or mouse function when you
- * don't need the object any more. It will be destroyed
- * before redrawing or any subsequent updates take place.
- * GUI_OTHER: Any powers of two greater than or equal to this are
- * free for use by objects for specific purposes.
- */
-#define GUI_FINISHED_WITH 1
-#define GUI_OTHER 2
-
-
-typedef struct GUI GUI;
-
-
-/* GUI_CREATE: Create a GUI object.
- * GUI_DESTROY: Destroy the GUI object.
- * GUI_KEY: Respond to a key.
- * GUI_UPDATE: Process any real-time activity.
- * GUI_DRAW: Draw any parts of the GUI that have changed. This may be
- * called more than once with different clipping rectangles,
- * so don't clear any flags here.
- * GUI_DRAWN: Clear any redraw flags.
- * GUI_CHANGED_*: Set flags to redraw parts of the object as necessary for
- * the change that has occurred.
- */
-typedef void (*GUI_CREATE)(GUI *gui, void *param);
-typedef void (*GUI_DESTROY)(GUI *gui);
-typedef void (*GUI_KEY)(GUI *gui, int k);
-typedef void (*GUI_UPDATE)(GUI *gui);
-typedef void (*GUI_DRAW)(GUI *gui);
-typedef void (*GUI_DRAWN)(GUI *gui);
-typedef void (*GUI_CHANGED_ALL)(GUI *gui);
-typedef void (*GUI_CHANGED_ACTIVE)(GUI *gui);
-
-
-typedef struct GUI_COMMANDS
-{
- GUI_CREATE create;
- GUI_DESTROY destroy;
- GUI_KEY key;
- GUI_UPDATE update;
- GUI_DRAW draw;
- GUI_DRAWN drawn;
- GUI_CHANGED_ALL changed_all;
- GUI_CHANGED_ACTIVE changed_active;
-}
-GUI_COMMANDS;
-
-
-struct GUI
-{
- GUI_COMMANDS *com;
-
- GUI *parent;
-
- int x, y, w, h;
- int flags;
-
- void *data;
-};
-
-
-extern GUI *gui_active;
-
-void gui_set_active(GUI *gui);
-
-GUI *gui_create(GUI_COMMANDS *com, GUI *parent, int x, int y, int w, int h, void *param);
-void gui_destroy(GUI *gui);
-void gui_key(GUI *gui, int k);
-void gui_update(GUI *gui);
-void gui_draw(GUI *gui);
-void gui_draw_void(void *gui);
-void gui_drawn(GUI *gui);
-void gui_changed_all(GUI *gui);
-void gui_changed_active(GUI *gui);
-
-
-#endif /* INCLUDED_DUMBGUI_H */
-
+#ifndef INCLUDED_DUMBGUI_H
+#define INCLUDED_DUMBGUI_H
+
+
+/* GUI_FINISHED_WITH: Set this in your update, key or mouse function when you
+ * don't need the object any more. It will be destroyed
+ * before redrawing or any subsequent updates take place.
+ * GUI_OTHER: Any powers of two greater than or equal to this are
+ * free for use by objects for specific purposes.
+ */
+#define GUI_FINISHED_WITH 1
+#define GUI_OTHER 2
+
+
+typedef struct GUI GUI;
+
+
+/* GUI_CREATE: Create a GUI object.
+ * GUI_DESTROY: Destroy the GUI object.
+ * GUI_KEY: Respond to a key.
+ * GUI_UPDATE: Process any real-time activity.
+ * GUI_DRAW: Draw any parts of the GUI that have changed. This may be
+ * called more than once with different clipping rectangles,
+ * so don't clear any flags here.
+ * GUI_DRAWN: Clear any redraw flags.
+ * GUI_CHANGED_*: Set flags to redraw parts of the object as necessary for
+ * the change that has occurred.
+ */
+typedef void (*GUI_CREATE)(GUI *gui, void *param);
+typedef void (*GUI_DESTROY)(GUI *gui);
+typedef void (*GUI_KEY)(GUI *gui, int k);
+typedef void (*GUI_UPDATE)(GUI *gui);
+typedef void (*GUI_DRAW)(GUI *gui);
+typedef void (*GUI_DRAWN)(GUI *gui);
+typedef void (*GUI_CHANGED_ALL)(GUI *gui);
+typedef void (*GUI_CHANGED_ACTIVE)(GUI *gui);
+
+
+typedef struct GUI_COMMANDS
+{
+ GUI_CREATE create;
+ GUI_DESTROY destroy;
+ GUI_KEY key;
+ GUI_UPDATE update;
+ GUI_DRAW draw;
+ GUI_DRAWN drawn;
+ GUI_CHANGED_ALL changed_all;
+ GUI_CHANGED_ACTIVE changed_active;
+}
+GUI_COMMANDS;
+
+
+struct GUI
+{
+ GUI_COMMANDS *com;
+
+ GUI *parent;
+
+ int x, y, w, h;
+ int flags;
+
+ void *data;
+};
+
+
+extern GUI *gui_active;
+
+void gui_set_active(GUI *gui);
+
+GUI *gui_create(GUI_COMMANDS *com, GUI *parent, int x, int y, int w, int h, void *param);
+void gui_destroy(GUI *gui);
+void gui_key(GUI *gui, int k);
+void gui_update(GUI *gui);
+void gui_draw(GUI *gui);
+void gui_draw_void(void *gui);
+void gui_drawn(GUI *gui);
+void gui_changed_all(GUI *gui);
+void gui_changed_active(GUI *gui);
+
+
+#endif /* INCLUDED_DUMBGUI_H */
+
diff --git a/plugins/dumb/dumb-kode54/studio/include/dumbmenu.h b/plugins/dumb/dumb-kode54/studio/include/dumbmenu.h
index c28dcda1..ddf07327 100644
--- a/plugins/dumb/dumb-kode54/studio/include/dumbmenu.h
+++ b/plugins/dumb/dumb-kode54/studio/include/dumbmenu.h
@@ -1,44 +1,44 @@
-#ifndef INCLUDED_DUMBMENU_H
-#define INCLUDED_DUMBMENU_H
-
-
-#include "dumbgui.h"
-
-
-typedef void (*GUI_MENU_ACTIVATOR)(void *param);
-
-
-typedef struct GUI_MENU_ENTRY
-{
- char *text; /* If the first char is '\t', draw an arrow on the right. */
- GUI_MENU_ACTIVATOR activator;
- void *param;
-}
-GUI_MENU_ENTRY;
-
-
-typedef struct GUI_MENU_PARAM
-{
- int n_entries;
- GUI_MENU_ENTRY *entry;
-}
-GUI_MENU_PARAM;
-
-
-#define GUI_MENU_REDRAW_ALL GUI_OTHER
-
-typedef struct GUI_MENU_DATA
-{
- GUI_MENU_PARAM *menu;
- int sel;
- int lastsel; /* When this is different from 'sel', rows 'lastsel' and 'sel' need redrawing. */
-}
-GUI_MENU_DATA;
-
-
-extern GUI_COMMANDS gui_menu_commands;
-
-void gui_menu_get_size(GUI_MENU_PARAM *menu, int *w, int *h);
-
-
-#endif /* INCLUDED_DUMBMENU_H */
+#ifndef INCLUDED_DUMBMENU_H
+#define INCLUDED_DUMBMENU_H
+
+
+#include "dumbgui.h"
+
+
+typedef void (*GUI_MENU_ACTIVATOR)(void *param);
+
+
+typedef struct GUI_MENU_ENTRY
+{
+ char *text; /* If the first char is '\t', draw an arrow on the right. */
+ GUI_MENU_ACTIVATOR activator;
+ void *param;
+}
+GUI_MENU_ENTRY;
+
+
+typedef struct GUI_MENU_PARAM
+{
+ int n_entries;
+ GUI_MENU_ENTRY *entry;
+}
+GUI_MENU_PARAM;
+
+
+#define GUI_MENU_REDRAW_ALL GUI_OTHER
+
+typedef struct GUI_MENU_DATA
+{
+ GUI_MENU_PARAM *menu;
+ int sel;
+ int lastsel; /* When this is different from 'sel', rows 'lastsel' and 'sel' need redrawing. */
+}
+GUI_MENU_DATA;
+
+
+extern GUI_COMMANDS gui_menu_commands;
+
+void gui_menu_get_size(GUI_MENU_PARAM *menu, int *w, int *h);
+
+
+#endif /* INCLUDED_DUMBMENU_H */
diff --git a/plugins/dumb/dumb-kode54/studio/include/guiproc.h b/plugins/dumb/dumb-kode54/studio/include/guiproc.h
index ab3d8d71..2757384a 100644
--- a/plugins/dumb/dumb-kode54/studio/include/guiproc.h
+++ b/plugins/dumb/dumb-kode54/studio/include/guiproc.h
@@ -1,52 +1,52 @@
-#ifndef INCLUDED_GUIPROC_H
-#define INCLUDED_GUIPROC_H
-
-
-#define THE_SIZE 2
-
-
-#if THE_SIZE == 2
-
-#define BEVEL_SIZE 3
-#define BORDER_SIZE 3
-#define TITLE_HEIGHT 21
-
-#define THE_FONT FONT2
-
-#elif THE_SIZE == 1
-
-#define BEVEL_SIZE 2
-#define BORDER_SIZE 2
-#define TITLE_HEIGHT 13
-
-#define THE_FONT FONT1
-
-#else
-
-#define BEVEL_SIZE 1
-#define BORDER_SIZE 1
-#define TITLE_HEIGHT 7
-
-#define THE_FONT FONT0
-
-#endif
-
-
-#define HIGHLIGHT 15
-#define MIDTONE 7
-#define SHADOW 8
-#define TITLE_BG_FOCUS 9
-#define TITLE_FG_FOCUS 14
-#define TITLE_BG 8
-#define TITLE_FG 7
-#define MENU_BG_FOCUS 1
-#define MENU_FG_FOCUS 15
-#define MENU_BG MIDTONE
-#define MENU_FG 0
-#define DESKTOP 4
-
-
-void draw_bevel(int l, int t, int r, int b, int tl, int m, int br);
-
-
-#endif /* INCLUDED_GUIPROC_H */
+#ifndef INCLUDED_GUIPROC_H
+#define INCLUDED_GUIPROC_H
+
+
+#define THE_SIZE 2
+
+
+#if THE_SIZE == 2
+
+#define BEVEL_SIZE 3
+#define BORDER_SIZE 3
+#define TITLE_HEIGHT 21
+
+#define THE_FONT FONT2
+
+#elif THE_SIZE == 1
+
+#define BEVEL_SIZE 2
+#define BORDER_SIZE 2
+#define TITLE_HEIGHT 13
+
+#define THE_FONT FONT1
+
+#else
+
+#define BEVEL_SIZE 1
+#define BORDER_SIZE 1
+#define TITLE_HEIGHT 7
+
+#define THE_FONT FONT0
+
+#endif
+
+
+#define HIGHLIGHT 15
+#define MIDTONE 7
+#define SHADOW 8
+#define TITLE_BG_FOCUS 9
+#define TITLE_FG_FOCUS 14
+#define TITLE_BG 8
+#define TITLE_FG 7
+#define MENU_BG_FOCUS 1
+#define MENU_FG_FOCUS 15
+#define MENU_BG MIDTONE
+#define MENU_FG 0
+#define DESKTOP 4
+
+
+void draw_bevel(int l, int t, int r, int b, int tl, int m, int br);
+
+
+#endif /* INCLUDED_GUIPROC_H */
diff --git a/plugins/dumb/dumb-kode54/studio/include/guitop.h b/plugins/dumb/dumb-kode54/studio/include/guitop.h
index 25557122..ac7fa8ff 100644
--- a/plugins/dumb/dumb-kode54/studio/include/guitop.h
+++ b/plugins/dumb/dumb-kode54/studio/include/guitop.h
@@ -1,17 +1,17 @@
-#ifndef INCLUDED_GUITOP_H
-#define INCLUDED_GUITOP_H
-
-
-#include "dumbdesk.h"
-
-extern int the_time;
-
-extern volatile int true_time;
-
-
-void run_desktop(GUI_DESKTOP_PARAM *param);
-
-void initialise_guitop(void);
-
-
-#endif /* INCLUDED_GUITOP_H */
+#ifndef INCLUDED_GUITOP_H
+#define INCLUDED_GUITOP_H
+
+
+#include "dumbdesk.h"
+
+extern int the_time;
+
+extern volatile int true_time;
+
+
+void run_desktop(GUI_DESKTOP_PARAM *param);
+
+void initialise_guitop(void);
+
+
+#endif /* INCLUDED_GUITOP_H */
diff --git a/plugins/dumb/dumb-kode54/studio/include/main.h b/plugins/dumb/dumb-kode54/studio/include/main.h
index 968fe5d6..9b0a5468 100644
--- a/plugins/dumb/dumb-kode54/studio/include/main.h
+++ b/plugins/dumb/dumb-kode54/studio/include/main.h
@@ -1,10 +1,10 @@
-#ifndef INCLUDED_MAIN_H
-#define INCLUDED_MAIN_H
-
-
-extern DATAFILE *dat;
-
-#include "datafile.h"
-
-
-#endif /* INCLUDED_MAIN_H */
+#ifndef INCLUDED_MAIN_H
+#define INCLUDED_MAIN_H
+
+
+extern DATAFILE *dat;
+
+#include "datafile.h"
+
+
+#endif /* INCLUDED_MAIN_H */
diff --git a/plugins/dumb/dumb-kode54/studio/include/options.h b/plugins/dumb/dumb-kode54/studio/include/options.h
index a62d48c5..0042afe4 100644
--- a/plugins/dumb/dumb-kode54/studio/include/options.h
+++ b/plugins/dumb/dumb-kode54/studio/include/options.h
@@ -1,34 +1,34 @@
-#ifndef INCLUDED_OPTIONS_H
-#define INCLUDED_OPTIONS_H
-
-
-typedef struct OPTIONS
-{
- int gfx_w, gfx_h;
-}
-OPTIONS;
-
-
-OPTIONS opt;
-
-
-#ifdef ALLEGRO_DOS
-
-#define DEF_GFX_W 320
-#define DEF_GFX_H 200
-#define DEF_GFX_STR "320x200"
-
-#else
-
-#define DEF_GFX_W 640
-#define DEF_GFX_H 480
-#define DEF_GFX_STR "640x480"
-
-#endif
-
-
-void load_options(void);
-void save_options(void);
-
-
-#endif /* INCLUDED_OPTIONS_H */
+#ifndef INCLUDED_OPTIONS_H
+#define INCLUDED_OPTIONS_H
+
+
+typedef struct OPTIONS
+{
+ int gfx_w, gfx_h;
+}
+OPTIONS;
+
+
+OPTIONS opt;
+
+
+#ifdef ALLEGRO_DOS
+
+#define DEF_GFX_W 320
+#define DEF_GFX_H 200
+#define DEF_GFX_STR "320x200"
+
+#else
+
+#define DEF_GFX_W 640
+#define DEF_GFX_H 480
+#define DEF_GFX_STR "640x480"
+
+#endif
+
+
+void load_options(void);
+void save_options(void);
+
+
+#endif /* INCLUDED_OPTIONS_H */
diff --git a/plugins/dumb/dumb-kode54/studio/include/subclip.h b/plugins/dumb/dumb-kode54/studio/include/subclip.h
index 5a5f8210..a30dd340 100644
--- a/plugins/dumb/dumb-kode54/studio/include/subclip.h
+++ b/plugins/dumb/dumb-kode54/studio/include/subclip.h
@@ -1,8 +1,8 @@
-#ifndef INCLUDED_SUBCLIP_H
-#define INCLUDED_SUBCLIP_H
-
-
-void subclip(int l, int t, int r, int b, void (*proc)(void *data), void *data);
-
-
-#endif /* INCLUDED_SUBCLIP_H */
+#ifndef INCLUDED_SUBCLIP_H
+#define INCLUDED_SUBCLIP_H
+
+
+void subclip(int l, int t, int r, int b, void (*proc)(void *data), void *data);
+
+
+#endif /* INCLUDED_SUBCLIP_H */
diff --git a/plugins/dumb/dumb-kode54/studio/src/dumbdesk.c b/plugins/dumb/dumb-kode54/studio/src/dumbdesk.c
index 61a3cd0e..8915f66b 100644
--- a/plugins/dumb/dumb-kode54/studio/src/dumbdesk.c
+++ b/plugins/dumb/dumb-kode54/studio/src/dumbdesk.c
@@ -1,271 +1,271 @@
-#include <stdlib.h>
-#include <allegro.h>
-
-#include "main.h"
-#include "subclip.h"
-#include "dumbgui.h"
-#include "guiproc.h"
-#include "dumbdesk.h"
-#include "options.h"
-
-
-
-static void gui_desktop_create(GUI *gui, void *param)
-{
- GUI_DESKTOP_PARAM *desktop = param;
-
- GUI_DESKTOP_DATA *data = gui->data = malloc(sizeof(*data));
-
- if (!data)
- return;
-
- data->title = desktop->title;
- data->menu_bar = desktop->menu_bar;
- data->deskgui = NULL;
-}
-
-
-
-static void gui_desktop_destroy(GUI *gui)
-{
- GUI_DESKTOP_DATA *data = gui->data;
-
- DESKGUI *deskgui = data->deskgui;
-
- while (deskgui) {
- DESKGUI *next = deskgui->next;
- gui_destroy(deskgui->gui);
- free(deskgui);
- deskgui = next;
- }
-
- free(data);
-}
-
-
-
-static void gui_desktop_key(GUI *gui, int k)
-{
- switch (k >> 8) {
- case KEY_N:
- {
- GUI_DESKTOP_PARAM param2 = {"well.duh", NULL};
- GUI_DESKTOP_DATA *data = gui->data;
- DESKGUI *next = data->deskgui;
- data->deskgui = malloc(sizeof(*data->deskgui));
- if (!data->deskgui) break;
- data->deskgui->gui = gui_create(
- &gui_desktop_commands,
- gui,
- 10 + rand() % 50, 30 + rand() % 50, 50 + rand() % 600, 50 + rand() % 350,
- &param2
- );
- if (!data->deskgui->gui) {
- free(data->deskgui);
- break;
- }
- data->deskgui->name = param2.title;
- data->deskgui->next = next;
- gui_set_active(data->deskgui->gui);
- }
- }
-}
-
-
-
-static void gui_desktop_update(GUI *gui)
-{
- GUI_DESKTOP_DATA *data = gui->data;
-
- DESKGUI *deskgui = data->deskgui;
-
- while (deskgui) {
- gui_update(deskgui->gui);
- deskgui = deskgui->next;
- }
-}
-
-
-
-static void draw_desktop_itself(void *g)
-{
- GUI *gui = g;
- GUI_DESKTOP_DATA *data = gui->data;
-
- if (data->deskgui) {
-
- /* Unlink child GUI. */
- DESKGUI *deskgui = data->deskgui;
- GUI *subgui = deskgui->gui;
-
- data->deskgui = deskgui->next;
-
- /* Child GUI outer bevel */
- draw_bevel(
- subgui->x - BORDER_SIZE - BEVEL_SIZE,
- subgui->y - BORDER_SIZE - BEVEL_SIZE,
- subgui->x + subgui->w + BORDER_SIZE + BEVEL_SIZE - 1,
- subgui->y + subgui->h + BORDER_SIZE + BEVEL_SIZE - 1,
- HIGHLIGHT, MIDTONE, SHADOW
- );
-
- /* Child GUI border */
- rectfill(screen, subgui->x - BORDER_SIZE, subgui->y - BORDER_SIZE, subgui->x + subgui->w + BORDER_SIZE - 1, subgui->y - 1, MIDTONE);
- rectfill(screen, subgui->x - BORDER_SIZE, subgui->y, subgui->x - 1, subgui->y + subgui->h - 1, MIDTONE);
- rectfill(screen, subgui->x + subgui->w, subgui->y, subgui->x + subgui->w + BORDER_SIZE - 1, subgui->y + subgui->h - 1, MIDTONE);
- rectfill(screen, subgui->x - BORDER_SIZE, subgui->y + subgui->h, subgui->x + subgui->w + BORDER_SIZE - 1, subgui->y + subgui->h + BORDER_SIZE - 1, MIDTONE);
-
- /* Child GUI */
- subclip(subgui->x, subgui->y, subgui->x + subgui->w, subgui->y + subgui->h,
- &gui_draw_void, subgui);
-
- /* Draw self, and other child GUIs, around this child GUI. */
- subclip(0, 0, opt.gfx_w, subgui->y - BORDER_SIZE - BEVEL_SIZE, &draw_desktop_itself, gui);
- subclip(0, subgui->y - BORDER_SIZE - BEVEL_SIZE, subgui->x - BORDER_SIZE - BEVEL_SIZE, subgui->y + subgui->h + BORDER_SIZE + BEVEL_SIZE, &draw_desktop_itself, gui);
- subclip(subgui->x + subgui->w + BORDER_SIZE + BEVEL_SIZE, subgui->y - BORDER_SIZE - BEVEL_SIZE, opt.gfx_w, subgui->y + subgui->h + BORDER_SIZE + BEVEL_SIZE, &draw_desktop_itself, gui);
- subclip(0, subgui->y + subgui->h + BORDER_SIZE + BEVEL_SIZE, opt.gfx_w, opt.gfx_h, &draw_desktop_itself, gui);
-
- /* Link child GUI back in. */
- data->deskgui = deskgui;
-
- return;
- }
-
- if (gui->flags & DESKTOP_CHANGED_REST)
- /* Desktop area */
- clear_to_color(screen, DESKTOP);
-}
-
-
-
-static int desktop_x;
-static int desktop_y;
-static GUI *desktop_gui;
-
-
-
-static void draw_desktop_title_bar(void *t)
-{
- const char *title = t;
- clear_to_color(screen, desktop_gui == gui_active ? TITLE_BG_FOCUS : TITLE_BG);
- textout(screen, dat[THE_FONT].dat, title, desktop_x, desktop_y, desktop_gui == gui_active ? TITLE_FG_FOCUS : TITLE_FG);
-}
-
-
-
-static void draw_menu_bar(void *data)
-{
- GUI_MENU_PARAM *menu_bar = data;
-
- clear_to_color(screen, MENU_BG);
-
- if (menu_bar) {
- int i;
- GUI_MENU_ENTRY *entry = menu_bar->entry;
- for (i = 0; i < menu_bar->n_entries; i++) {
- // If the first char is '\t', draw an arrow on the right.
- textout(screen, dat[THE_FONT].dat, entry->text,
- desktop_x + BORDER_SIZE, desktop_y + BORDER_SIZE, MENU_FG);
- desktop_x += BORDER_SIZE + text_length(dat[THE_FONT].dat, entry->text) + BORDER_SIZE;
- entry++;
- }
- } // else hide the damn thing?
-}
-
-
-
-static void gui_desktop_draw(GUI *gui)
-{
- GUI_DESKTOP_DATA *data = gui->data;
-
- subclip(
- gui->x + BEVEL_SIZE,
- gui->y + TITLE_HEIGHT + TITLE_HEIGHT + BEVEL_SIZE,
- gui->x + gui->w - BEVEL_SIZE,
- gui->y + gui->h - BEVEL_SIZE,
- &draw_desktop_itself, gui
- );
-
- if (gui->flags & DESKTOP_CHANGED_TITLE) {
- /* Title bar */
- desktop_x = gui->x + BORDER_SIZE;
- desktop_y = gui->y + BORDER_SIZE;
- desktop_gui = gui;
-
- subclip(gui->x, gui->y, gui->x + gui->w, gui->y + TITLE_HEIGHT,
- &draw_desktop_title_bar, (void *)data->title);
- }
-
- if (gui->flags & DESKTOP_CHANGED_REST) {
- /* Separation between title bar and inner bevel */
- //rectfill(screen, gui->x, gui->y + TITLE_HEIGHT, gui->x + gui->w - 1, gui->y + TITLE_HEIGHT + BORDER_SIZE - 1, MIDTONE);
-
- /* Menu bar */
- desktop_x = gui->x;
- desktop_y = gui->y + TITLE_HEIGHT;
-
- subclip(
- gui->x, gui->y + TITLE_HEIGHT,
- gui->x + gui->w, gui->y + TITLE_HEIGHT + TITLE_HEIGHT,
- &draw_menu_bar, data->menu_bar
- );
-
- /* Inner bevel */
- draw_bevel(gui->x, gui->y + TITLE_HEIGHT + TITLE_HEIGHT, gui->x + gui->w - 1, gui->y + gui->h - 1, SHADOW, MIDTONE, HIGHLIGHT);
- }
-}
-
-
-
-static void gui_desktop_drawn(GUI *gui)
-{
- GUI_DESKTOP_DATA *data = gui->data;
-
- if (data->deskgui) {
- /* Mark child GUIs as drawn. */
- DESKGUI *deskgui = data->deskgui;
- while (deskgui) {
- gui_drawn(deskgui->gui);
- deskgui = deskgui->next;
- }
- }
-
- /* Mark self as drawn. */
- gui->flags &= ~DESKTOP_CHANGED_ALL;
-}
-
-
-
-static void gui_desktop_changed_all(GUI *gui)
-{
- gui->flags |= DESKTOP_CHANGED_ALL;
-
- {
- GUI_DESKTOP_DATA *data = gui->data;
- DESKGUI *deskgui = data->deskgui;
- while (deskgui) {
- gui_changed_all(deskgui->gui);
- deskgui = deskgui->next;
- }
- }
-}
-
-
-
-static void gui_desktop_changed_active(GUI *gui)
-{
- gui->flags |= DESKTOP_CHANGED_TITLE;
-}
-
-
-
-GUI_COMMANDS gui_desktop_commands = {
- &gui_desktop_create,
- &gui_desktop_destroy,
- &gui_desktop_key,
- &gui_desktop_update,
- &gui_desktop_draw,
- &gui_desktop_drawn,
- &gui_desktop_changed_all,
- &gui_desktop_changed_active
-};
+#include <stdlib.h>
+#include <allegro.h>
+
+#include "main.h"
+#include "subclip.h"
+#include "dumbgui.h"
+#include "guiproc.h"
+#include "dumbdesk.h"
+#include "options.h"
+
+
+
+static void gui_desktop_create(GUI *gui, void *param)
+{
+ GUI_DESKTOP_PARAM *desktop = param;
+
+ GUI_DESKTOP_DATA *data = gui->data = malloc(sizeof(*data));
+
+ if (!data)
+ return;
+
+ data->title = desktop->title;
+ data->menu_bar = desktop->menu_bar;
+ data->deskgui = NULL;
+}
+
+
+
+static void gui_desktop_destroy(GUI *gui)
+{
+ GUI_DESKTOP_DATA *data = gui->data;
+
+ DESKGUI *deskgui = data->deskgui;
+
+ while (deskgui) {
+ DESKGUI *next = deskgui->next;
+ gui_destroy(deskgui->gui);
+ free(deskgui);
+ deskgui = next;
+ }
+
+ free(data);
+}
+
+
+
+static void gui_desktop_key(GUI *gui, int k)
+{
+ switch (k >> 8) {
+ case KEY_N:
+ {
+ GUI_DESKTOP_PARAM param2 = {"well.duh", NULL};
+ GUI_DESKTOP_DATA *data = gui->data;
+ DESKGUI *next = data->deskgui;
+ data->deskgui = malloc(sizeof(*data->deskgui));
+ if (!data->deskgui) break;
+ data->deskgui->gui = gui_create(
+ &gui_desktop_commands,
+ gui,
+ 10 + rand() % 50, 30 + rand() % 50, 50 + rand() % 600, 50 + rand() % 350,
+ &param2
+ );
+ if (!data->deskgui->gui) {
+ free(data->deskgui);
+ break;
+ }
+ data->deskgui->name = param2.title;
+ data->deskgui->next = next;
+ gui_set_active(data->deskgui->gui);
+ }
+ }
+}
+
+
+
+static void gui_desktop_update(GUI *gui)
+{
+ GUI_DESKTOP_DATA *data = gui->data;
+
+ DESKGUI *deskgui = data->deskgui;
+
+ while (deskgui) {
+ gui_update(deskgui->gui);
+ deskgui = deskgui->next;
+ }
+}
+
+
+
+static void draw_desktop_itself(void *g)
+{
+ GUI *gui = g;
+ GUI_DESKTOP_DATA *data = gui->data;
+
+ if (data->deskgui) {
+
+ /* Unlink child GUI. */
+ DESKGUI *deskgui = data->deskgui;
+ GUI *subgui = deskgui->gui;
+
+ data->deskgui = deskgui->next;
+
+ /* Child GUI outer bevel */
+ draw_bevel(
+ subgui->x - BORDER_SIZE - BEVEL_SIZE,
+ subgui->y - BORDER_SIZE - BEVEL_SIZE,
+ subgui->x + subgui->w + BORDER_SIZE + BEVEL_SIZE - 1,
+ subgui->y + subgui->h + BORDER_SIZE + BEVEL_SIZE - 1,
+ HIGHLIGHT, MIDTONE, SHADOW
+ );
+
+ /* Child GUI border */
+ rectfill(screen, subgui->x - BORDER_SIZE, subgui->y - BORDER_SIZE, subgui->x + subgui->w + BORDER_SIZE - 1, subgui->y - 1, MIDTONE);
+ rectfill(screen, subgui->x - BORDER_SIZE, subgui->y, subgui->x - 1, subgui->y + subgui->h - 1, MIDTONE);
+ rectfill(screen, subgui->x + subgui->w, subgui->y, subgui->x + subgui->w + BORDER_SIZE - 1, subgui->y + subgui->h - 1, MIDTONE);
+ rectfill(screen, subgui->x - BORDER_SIZE, subgui->y + subgui->h, subgui->x + subgui->w + BORDER_SIZE - 1, subgui->y + subgui->h + BORDER_SIZE - 1, MIDTONE);
+
+ /* Child GUI */
+ subclip(subgui->x, subgui->y, subgui->x + subgui->w, subgui->y + subgui->h,
+ &gui_draw_void, subgui);
+
+ /* Draw self, and other child GUIs, around this child GUI. */
+ subclip(0, 0, opt.gfx_w, subgui->y - BORDER_SIZE - BEVEL_SIZE, &draw_desktop_itself, gui);
+ subclip(0, subgui->y - BORDER_SIZE - BEVEL_SIZE, subgui->x - BORDER_SIZE - BEVEL_SIZE, subgui->y + subgui->h + BORDER_SIZE + BEVEL_SIZE, &draw_desktop_itself, gui);
+ subclip(subgui->x + subgui->w + BORDER_SIZE + BEVEL_SIZE, subgui->y - BORDER_SIZE - BEVEL_SIZE, opt.gfx_w, subgui->y + subgui->h + BORDER_SIZE + BEVEL_SIZE, &draw_desktop_itself, gui);
+ subclip(0, subgui->y + subgui->h + BORDER_SIZE + BEVEL_SIZE, opt.gfx_w, opt.gfx_h, &draw_desktop_itself, gui);
+
+ /* Link child GUI back in. */
+ data->deskgui = deskgui;
+
+ return;
+ }
+
+ if (gui->flags & DESKTOP_CHANGED_REST)
+ /* Desktop area */
+ clear_to_color(screen, DESKTOP);
+}
+
+
+
+static int desktop_x;
+static int desktop_y;
+static GUI *desktop_gui;
+
+
+
+static void draw_desktop_title_bar(void *t)
+{
+ const char *title = t;
+ clear_to_color(screen, desktop_gui == gui_active ? TITLE_BG_FOCUS : TITLE_BG);
+ textout(screen, dat[THE_FONT].dat, title, desktop_x, desktop_y, desktop_gui == gui_active ? TITLE_FG_FOCUS : TITLE_FG);
+}
+
+
+
+static void draw_menu_bar(void *data)
+{
+ GUI_MENU_PARAM *menu_bar = data;
+
+ clear_to_color(screen, MENU_BG);
+
+ if (menu_bar) {
+ int i;
+ GUI_MENU_ENTRY *entry = menu_bar->entry;
+ for (i = 0; i < menu_bar->n_entries; i++) {
+ // If the first char is '\t', draw an arrow on the right.
+ textout(screen, dat[THE_FONT].dat, entry->text,
+ desktop_x + BORDER_SIZE, desktop_y + BORDER_SIZE, MENU_FG);
+ desktop_x += BORDER_SIZE + text_length(dat[THE_FONT].dat, entry->text) + BORDER_SIZE;
+ entry++;
+ }
+ } // else hide the damn thing?
+}
+
+
+
+static void gui_desktop_draw(GUI *gui)
+{
+ GUI_DESKTOP_DATA *data = gui->data;
+
+ subclip(
+ gui->x + BEVEL_SIZE,
+ gui->y + TITLE_HEIGHT + TITLE_HEIGHT + BEVEL_SIZE,
+ gui->x + gui->w - BEVEL_SIZE,
+ gui->y + gui->h - BEVEL_SIZE,
+ &draw_desktop_itself, gui
+ );
+
+ if (gui->flags & DESKTOP_CHANGED_TITLE) {
+ /* Title bar */
+ desktop_x = gui->x + BORDER_SIZE;
+ desktop_y = gui->y + BORDER_SIZE;
+ desktop_gui = gui;
+
+ subclip(gui->x, gui->y, gui->x + gui->w, gui->y + TITLE_HEIGHT,
+ &draw_desktop_title_bar, (void *)data->title);
+ }
+
+ if (gui->flags & DESKTOP_CHANGED_REST) {
+ /* Separation between title bar and inner bevel */
+ //rectfill(screen, gui->x, gui->y + TITLE_HEIGHT, gui->x + gui->w - 1, gui->y + TITLE_HEIGHT + BORDER_SIZE - 1, MIDTONE);
+
+ /* Menu bar */
+ desktop_x = gui->x;
+ desktop_y = gui->y + TITLE_HEIGHT;
+
+ subclip(
+ gui->x, gui->y + TITLE_HEIGHT,
+ gui->x + gui->w, gui->y + TITLE_HEIGHT + TITLE_HEIGHT,
+ &draw_menu_bar, data->menu_bar
+ );
+
+ /* Inner bevel */
+ draw_bevel(gui->x, gui->y + TITLE_HEIGHT + TITLE_HEIGHT, gui->x + gui->w - 1, gui->y + gui->h - 1, SHADOW, MIDTONE, HIGHLIGHT);
+ }
+}
+
+
+
+static void gui_desktop_drawn(GUI *gui)
+{
+ GUI_DESKTOP_DATA *data = gui->data;
+
+ if (data->deskgui) {
+ /* Mark child GUIs as drawn. */
+ DESKGUI *deskgui = data->deskgui;
+ while (deskgui) {
+ gui_drawn(deskgui->gui);
+ deskgui = deskgui->next;
+ }
+ }
+
+ /* Mark self as drawn. */
+ gui->flags &= ~DESKTOP_CHANGED_ALL;
+}
+
+
+
+static void gui_desktop_changed_all(GUI *gui)
+{
+ gui->flags |= DESKTOP_CHANGED_ALL;
+
+ {
+ GUI_DESKTOP_DATA *data = gui->data;
+ DESKGUI *deskgui = data->deskgui;
+ while (deskgui) {
+ gui_changed_all(deskgui->gui);
+ deskgui = deskgui->next;
+ }
+ }
+}
+
+
+
+static void gui_desktop_changed_active(GUI *gui)
+{
+ gui->flags |= DESKTOP_CHANGED_TITLE;
+}
+
+
+
+GUI_COMMANDS gui_desktop_commands = {
+ &gui_desktop_create,
+ &gui_desktop_destroy,
+ &gui_desktop_key,
+ &gui_desktop_update,
+ &gui_desktop_draw,
+ &gui_desktop_drawn,
+ &gui_desktop_changed_all,
+ &gui_desktop_changed_active
+};
diff --git a/plugins/dumb/dumb-kode54/studio/src/dumbgui.c b/plugins/dumb/dumb-kode54/studio/src/dumbgui.c
index 4927a09c..320f1af4 100644
--- a/plugins/dumb/dumb-kode54/studio/src/dumbgui.c
+++ b/plugins/dumb/dumb-kode54/studio/src/dumbgui.c
@@ -1,120 +1,120 @@
-#include <stdlib.h>
-
-#include "dumbgui.h"
-
-
-
-GUI *gui_active;
-
-
-
-void gui_set_active(GUI *gui)
-{
- gui_changed_active(gui_active);
- gui_active = gui;
- gui_changed_active(gui_active);
-}
-
-
-
-GUI *gui_create(GUI_COMMANDS *com, GUI *parent, int x, int y, int w, int h, void *param)
-{
- GUI *gui = malloc(sizeof(*gui));
-
- if (!gui)
- return NULL;
-
- gui->com = com;
-
- gui->parent = parent;
-
- gui->x = x;
- gui->y = y;
- gui->w = w;
- gui->h = h;
-
- gui->flags = 0;
-
- if (com->create) {
- (*com->create)(gui, param);
-
- if (!gui->data) {
- free(gui);
- return NULL;
- }
- } else
- gui->data = NULL;
-
- gui_changed_all(gui);
-
- return gui;
-}
-
-
-
-void gui_destroy(GUI *gui)
-{
- if (gui) {
- if (gui->com->destroy)
- (*gui->com->destroy)(gui);
-
- free(gui);
- }
-}
-
-
-
-void gui_key(GUI *gui, int k)
-{
- if (gui && gui->com->key)
- (*gui->com->key)(gui, k);
-}
-
-
-
-void gui_update(GUI *gui)
-{
- if (gui && gui->com->update)
- (*gui->com->update)(gui);
-}
-
-
-
-void gui_draw(GUI *gui)
-{
- if (gui && gui->com->draw)
- (*gui->com->draw)(gui);
-}
-
-
-
-/* For use with subclip(). */
-void gui_draw_void(void *gui)
-{
- gui_draw(gui);
-}
-
-
-
-void gui_drawn(GUI *gui)
-{
- if (gui && gui->com->drawn)
- (*gui->com->drawn)(gui);
-}
-
-
-
-void gui_changed_all(GUI *gui)
-{
- if (gui && gui->com->changed_all)
- (*gui->com->changed_all)(gui);
-}
-
-
-
-void gui_changed_active(GUI *gui)
-{
- if (gui && gui->com->changed_active)
- (*gui->com->changed_active)(gui);
-}
-
+#include <stdlib.h>
+
+#include "dumbgui.h"
+
+
+
+GUI *gui_active;
+
+
+
+void gui_set_active(GUI *gui)
+{
+ gui_changed_active(gui_active);
+ gui_active = gui;
+ gui_changed_active(gui_active);
+}
+
+
+
+GUI *gui_create(GUI_COMMANDS *com, GUI *parent, int x, int y, int w, int h, void *param)
+{
+ GUI *gui = malloc(sizeof(*gui));
+
+ if (!gui)
+ return NULL;
+
+ gui->com = com;
+
+ gui->parent = parent;
+
+ gui->x = x;
+ gui->y = y;
+ gui->w = w;
+ gui->h = h;
+
+ gui->flags = 0;
+
+ if (com->create) {
+ (*com->create)(gui, param);
+
+ if (!gui->data) {
+ free(gui);
+ return NULL;
+ }
+ } else
+ gui->data = NULL;
+
+ gui_changed_all(gui);
+
+ return gui;
+}
+
+
+
+void gui_destroy(GUI *gui)
+{
+ if (gui) {
+ if (gui->com->destroy)
+ (*gui->com->destroy)(gui);
+
+ free(gui);
+ }
+}
+
+
+
+void gui_key(GUI *gui, int k)
+{
+ if (gui && gui->com->key)
+ (*gui->com->key)(gui, k);
+}
+
+
+
+void gui_update(GUI *gui)
+{
+ if (gui && gui->com->update)
+ (*gui->com->update)(gui);
+}
+
+
+
+void gui_draw(GUI *gui)
+{
+ if (gui && gui->com->draw)
+ (*gui->com->draw)(gui);
+}
+
+
+
+/* For use with subclip(). */
+void gui_draw_void(void *gui)
+{
+ gui_draw(gui);
+}
+
+
+
+void gui_drawn(GUI *gui)
+{
+ if (gui && gui->com->drawn)
+ (*gui->com->drawn)(gui);
+}
+
+
+
+void gui_changed_all(GUI *gui)
+{
+ if (gui && gui->com->changed_all)
+ (*gui->com->changed_all)(gui);
+}
+
+
+
+void gui_changed_active(GUI *gui)
+{
+ if (gui && gui->com->changed_active)
+ (*gui->com->changed_active)(gui);
+}
+
diff --git a/plugins/dumb/dumb-kode54/studio/src/dumbmenu.c b/plugins/dumb/dumb-kode54/studio/src/dumbmenu.c
index 609c70e2..25f0dba8 100644
--- a/plugins/dumb/dumb-kode54/studio/src/dumbmenu.c
+++ b/plugins/dumb/dumb-kode54/studio/src/dumbmenu.c
@@ -1,191 +1,191 @@
-#include <stdlib.h>
-#include <allegro.h>
-
-#include "main.h"
-#include "dumbgui.h"
-#include "guiproc.h"
-#include "subclip.h"
-#include "dumbmenu.h"
-
-
-
-static void gui_menu_create(GUI *gui, void *param)
-{
- GUI_MENU_PARAM *menu = param;
-
- GUI_MENU_DATA *data = gui->data = malloc(sizeof(*data));
-
- if (!data)
- return;
-
- data->menu = menu;
- data->sel = -1;
- /* data->lastsel will be initialised by gui_menu_drawn(). */
-}
-
-
-
-static void gui_menu_destroy(GUI *gui)
-{
- free(gui->data);
-}
-
-
-
-static void gui_menu_key(GUI *gui, int k)
-{
- GUI_MENU_DATA *data = gui->data;
-
- switch (k >> 8) {
- case KEY_UP:
- case KEY_8_PAD:
- if (data->sel <= 0) data->sel = data->menu->n_entries;
- data->sel--;
- break;
- case KEY_DOWN:
- case KEY_2_PAD:
- data->sel++;
- if (data->sel >= data->menu->n_entries) data->sel = 0;
- break;
- case KEY_RIGHT:
- case KEY_6_PAD:
- case KEY_ENTER:
- if (data->sel >= 0) {
- GUI_MENU_ENTRY *entry = &data->menu->entry[data->sel];
- if (k >> 8 != KEY_RIGHT || entry->text[0] == '\t')
- (*entry->activator)(entry->param);
- }
- // To do: defer 'right' to parent menus, making sure it doesn't reopen the same submenu
- break;
- case KEY_ESC:
- gui->flags |= GUI_FINISHED_WITH;
- break;
- }
-}
-
-
-
-static void gui_menu_update(GUI *gui)
-{
- // Remove this function?
- (void)gui;
-}
-
-
-
-typedef struct GUI_MENU_DRAW_ENTRY_DATA
-{
- GUI *gui;
- GUI_MENU_DATA *data;
- int i, y;
-}
-GUI_MENU_DRAW_ENTRY_DATA;
-
-
-
-static void gui_menu_draw_entry_proc(void *data)
-{
- GUI_MENU_DRAW_ENTRY_DATA *d = data;
- char *text = d->data->menu->entry[d->i].text;
-
- clear_to_color(screen, d->i == d->data->sel ? MENU_BG_FOCUS : MENU_BG);
-
- if (text[0] == '\t') {
- text++;
- // Draw an arrow
- }
-
- textout(screen, dat[THE_FONT].dat, text, d->gui->x + BORDER_SIZE, d->y + BORDER_SIZE,
- d->i == d->data->sel ? MENU_FG_FOCUS : MENU_FG);
-}
-
-
-
-static void gui_menu_draw(GUI *gui)
-{
- GUI_MENU_DRAW_ENTRY_DATA d;
- d.gui = gui;
- d.data = gui->data;
-
- if (gui->flags & GUI_MENU_REDRAW_ALL) {
- // Redraw the whole menu
- d.y = gui->y;
- for (d.i = 0; d.i < d.data->menu->n_entries; d.i++) {
- subclip(gui->x, d.y, gui->x + gui->w, d.y + TITLE_HEIGHT, &gui_menu_draw_entry_proc, &d);
- d.y += TITLE_HEIGHT;
- }
- } else if (d.data->sel != d.data->lastsel) {
- if (d.data->lastsel >= 0) {
- // Redraw the 'lastsel' row
- d.i = d.data->lastsel;
- d.y = gui->y + d.i * TITLE_HEIGHT;
- subclip(gui->x, d.y, gui->x + gui->w, d.y + TITLE_HEIGHT, &gui_menu_draw_entry_proc, &d);
- }
- if (d.data->sel >= 0) { // Necessary?
- // Redraw the 'sel' row
- d.i = d.data->sel;
- d.y = gui->y + d.i * TITLE_HEIGHT;
- subclip(gui->x, d.y, gui->x + gui->w, d.y + TITLE_HEIGHT, &gui_menu_draw_entry_proc, &d);
- }
- }
-}
-
-
-
-static void gui_menu_drawn(GUI *gui)
-{
- GUI_MENU_DATA *data = gui->data;
-
- gui->flags &= ~GUI_MENU_REDRAW_ALL;
- data->lastsel = data->sel;
-}
-
-
-
-static void gui_menu_changed_all(GUI *gui)
-{
- gui->flags |= GUI_MENU_REDRAW_ALL;
-}
-
-
-
-static void gui_menu_changed_active(GUI *gui)
-{
- // Remove this function?
- (void)gui;
-}
-
-
-
-GUI_COMMANDS gui_menu_commands = {
- &gui_menu_create,
- &gui_menu_destroy,
- &gui_menu_key,
- &gui_menu_update,
- &gui_menu_draw,
- &gui_menu_drawn,
- &gui_menu_changed_all,
- &gui_menu_changed_active
-};
-
-
-
-void gui_menu_get_size(GUI_MENU_PARAM *menu, int *w, int *h)
-{
- int i;
-
- *w = 2*BORDER_SIZE + TITLE_HEIGHT; /* A reasonable minimum width */
- *h = 2*BORDER_SIZE;
-
- for (i = 0; i < menu->n_entries; i++) {
- char *text = menu->entry[i].text;
- int wi = 2*BORDER_SIZE;
- if (text[0] == '\t') {
- text++;
- wi += 10; // Fix this later
- }
- wi += text_length(dat[THE_FONT].dat, text);
- if (wi > *w) *w = wi;
- *h += TITLE_HEIGHT;
- }
-}
+#include <stdlib.h>
+#include <allegro.h>
+
+#include "main.h"
+#include "dumbgui.h"
+#include "guiproc.h"
+#include "subclip.h"
+#include "dumbmenu.h"
+
+
+
+static void gui_menu_create(GUI *gui, void *param)
+{
+ GUI_MENU_PARAM *menu = param;
+
+ GUI_MENU_DATA *data = gui->data = malloc(sizeof(*data));
+
+ if (!data)
+ return;
+
+ data->menu = menu;
+ data->sel = -1;
+ /* data->lastsel will be initialised by gui_menu_drawn(). */
+}
+
+
+
+static void gui_menu_destroy(GUI *gui)
+{
+ free(gui->data);
+}
+
+
+
+static void gui_menu_key(GUI *gui, int k)
+{
+ GUI_MENU_DATA *data = gui->data;
+
+ switch (k >> 8) {
+ case KEY_UP:
+ case KEY_8_PAD:
+ if (data->sel <= 0) data->sel = data->menu->n_entries;
+ data->sel--;
+ break;
+ case KEY_DOWN:
+ case KEY_2_PAD:
+ data->sel++;
+ if (data->sel >= data->menu->n_entries) data->sel = 0;
+ break;
+ case KEY_RIGHT:
+ case KEY_6_PAD:
+ case KEY_ENTER:
+ if (data->sel >= 0) {
+ GUI_MENU_ENTRY *entry = &data->menu->entry[data->sel];
+ if (k >> 8 != KEY_RIGHT || entry->text[0] == '\t')
+ (*entry->activator)(entry->param);
+ }
+ // To do: defer 'right' to parent menus, making sure it doesn't reopen the same submenu
+ break;
+ case KEY_ESC:
+ gui->flags |= GUI_FINISHED_WITH;
+ break;
+ }
+}
+
+
+
+static void gui_menu_update(GUI *gui)
+{
+ // Remove this function?
+ (void)gui;
+}
+
+
+
+typedef struct GUI_MENU_DRAW_ENTRY_DATA
+{
+ GUI *gui;
+ GUI_MENU_DATA *data;
+ int i, y;
+}
+GUI_MENU_DRAW_ENTRY_DATA;
+
+
+
+static void gui_menu_draw_entry_proc(void *data)
+{
+ GUI_MENU_DRAW_ENTRY_DATA *d = data;
+ char *text = d->data->menu->entry[d->i].text;
+
+ clear_to_color(screen, d->i == d->data->sel ? MENU_BG_FOCUS : MENU_BG);
+
+ if (text[0] == '\t') {
+ text++;
+ // Draw an arrow
+ }
+
+ textout(screen, dat[THE_FONT].dat, text, d->gui->x + BORDER_SIZE, d->y + BORDER_SIZE,
+ d->i == d->data->sel ? MENU_FG_FOCUS : MENU_FG);
+}
+
+
+
+static void gui_menu_draw(GUI *gui)
+{
+ GUI_MENU_DRAW_ENTRY_DATA d;
+ d.gui = gui;
+ d.data = gui->data;
+
+ if (gui->flags & GUI_MENU_REDRAW_ALL) {
+ // Redraw the whole menu
+ d.y = gui->y;
+ for (d.i = 0; d.i < d.data->menu->n_entries; d.i++) {
+ subclip(gui->x, d.y, gui->x + gui->w, d.y + TITLE_HEIGHT, &gui_menu_draw_entry_proc, &d);
+ d.y += TITLE_HEIGHT;
+ }
+ } else if (d.data->sel != d.data->lastsel) {
+ if (d.data->lastsel >= 0) {
+ // Redraw the 'lastsel' row
+ d.i = d.data->lastsel;
+ d.y = gui->y + d.i * TITLE_HEIGHT;
+ subclip(gui->x, d.y, gui->x + gui->w, d.y + TITLE_HEIGHT, &gui_menu_draw_entry_proc, &d);
+ }
+ if (d.data->sel >= 0) { // Necessary?
+ // Redraw the 'sel' row
+ d.i = d.data->sel;
+ d.y = gui->y + d.i * TITLE_HEIGHT;
+ subclip(gui->x, d.y, gui->x + gui->w, d.y + TITLE_HEIGHT, &gui_menu_draw_entry_proc, &d);
+ }
+ }
+}
+
+
+
+static void gui_menu_drawn(GUI *gui)
+{
+ GUI_MENU_DATA *data = gui->data;
+
+ gui->flags &= ~GUI_MENU_REDRAW_ALL;
+ data->lastsel = data->sel;
+}
+
+
+
+static void gui_menu_changed_all(GUI *gui)
+{
+ gui->flags |= GUI_MENU_REDRAW_ALL;
+}
+
+
+
+static void gui_menu_changed_active(GUI *gui)
+{
+ // Remove this function?
+ (void)gui;
+}
+
+
+
+GUI_COMMANDS gui_menu_commands = {
+ &gui_menu_create,
+ &gui_menu_destroy,
+ &gui_menu_key,
+ &gui_menu_update,
+ &gui_menu_draw,
+ &gui_menu_drawn,
+ &gui_menu_changed_all,
+ &gui_menu_changed_active
+};
+
+
+
+void gui_menu_get_size(GUI_MENU_PARAM *menu, int *w, int *h)
+{
+ int i;
+
+ *w = 2*BORDER_SIZE + TITLE_HEIGHT; /* A reasonable minimum width */
+ *h = 2*BORDER_SIZE;
+
+ for (i = 0; i < menu->n_entries; i++) {
+ char *text = menu->entry[i].text;
+ int wi = 2*BORDER_SIZE;
+ if (text[0] == '\t') {
+ text++;
+ wi += 10; // Fix this later
+ }
+ wi += text_length(dat[THE_FONT].dat, text);
+ if (wi > *w) *w = wi;
+ *h += TITLE_HEIGHT;
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/studio/src/guiproc.c b/plugins/dumb/dumb-kode54/studio/src/guiproc.c
index 6e53b323..88c766fa 100644
--- a/plugins/dumb/dumb-kode54/studio/src/guiproc.c
+++ b/plugins/dumb/dumb-kode54/studio/src/guiproc.c
@@ -1,16 +1,16 @@
-#include <allegro.h>
-#include "guiproc.h"
-
-
-void draw_bevel(int l, int t, int r, int b, int tl, int m, int br)
-{
- int n;
- for (n = 0; n < BEVEL_SIZE; n++) {
- hline(screen, l + n, t + n, r - 1 - n, tl);
- putpixel(screen, r - n, t + n, m);
- vline(screen, l + n, t + 1 + n, b - 1 - n, tl);
- vline(screen, r - n, t + 1 + n, b - 1 - n, br);
- putpixel(screen, l + n, b - n, m);
- hline(screen, l + 1 + n, b - n, r - n, br);
- }
-}
+#include <allegro.h>
+#include "guiproc.h"
+
+
+void draw_bevel(int l, int t, int r, int b, int tl, int m, int br)
+{
+ int n;
+ for (n = 0; n < BEVEL_SIZE; n++) {
+ hline(screen, l + n, t + n, r - 1 - n, tl);
+ putpixel(screen, r - n, t + n, m);
+ vline(screen, l + n, t + 1 + n, b - 1 - n, tl);
+ vline(screen, r - n, t + 1 + n, b - 1 - n, br);
+ putpixel(screen, l + n, b - n, m);
+ hline(screen, l + 1 + n, b - n, r - n, br);
+ }
+}
diff --git a/plugins/dumb/dumb-kode54/studio/src/guitop.c b/plugins/dumb/dumb-kode54/studio/src/guitop.c
index be5cddf9..715eb813 100644
--- a/plugins/dumb/dumb-kode54/studio/src/guitop.c
+++ b/plugins/dumb/dumb-kode54/studio/src/guitop.c
@@ -1,131 +1,131 @@
-#include <allegro.h>
-
-#include "options.h"
-#include "guitop.h"
-#include "guiproc.h"
-#include "dumbdesk.h"
-
-
-
-int the_time;
-
-volatile int true_time;
-static int max_time;
-
-
-
-static void timer_handler(void)
-{
- if (true_time < max_time)
- true_time++;
-}
-END_OF_STATIC_FUNCTION(timer_handler);
-
-
-
-#define MAX_SKIP 20
-
-
-
-/*
-Every GUI has a reference to its parent - except the top one.
-
-Main loop:
- Test keyboard.
- Esc makes parent GUI active.
- Other keys go to active GUI, which can do as it pleases.
- Test mouse.
- Mouse clicks go to the top GUI.
- The top GUI may pass them down recursively.
- A GUI may be marked as mouse-active, for dragging.
- Update top GUI.
- Update functions are called recursively.
- This can be used for animation for example.
- If there's time, draw top GUI.
- Draw functions only draw areas marked for redrawing.
- Marked areas are unmarked once they have been drawn.
- Draw functions are called recursively.
- If a child has moved:
- It will call its parent for the vacated areas.*
-
-The child will have been removed from the parent's list while
-it was drawn, so recursive cycles cannot occur.
-*/
-
-
-
-void run_desktop(GUI_DESKTOP_PARAM *param)
-{
- GUI *gui = gui_create(
- &gui_desktop_commands,
- NULL,
- 0, 0, opt.gfx_w, opt.gfx_h,
- param
- );
-
- if (!gui)
- return;
-
- gui_active = gui;
-
- true_time = the_time = 0;
- max_time = MAX_SKIP;
-
- install_int_ex(timer_handler, BPS_TO_TIMER(100));
-
- for (;;) {
- gui_draw(gui);
- gui_drawn(gui);
-
- while (the_time >= true_time)
- yield_timeslice();
-
- while (the_time < true_time) {
- the_time++;
-
- /*
- Test keyboard.
- Esc makes parent GUI active.
- Other keys go to active GUI, which can do as it pleases.
- */
- while (keypressed()) {
- int k = readkey();
- if (k >> 8 == KEY_ESC) {
- if (!gui_active->parent) {
- remove_int(timer_handler);
- return;
- }
- gui_set_active(gui_active->parent);
- } else
- gui_key(gui_active, k);
- }
-
- /*
- Test mouse.
- Mouse clicks go to the top GUI.
- The top GUI may pass them down recursively.
- A GUI may be marked as mouse-active, for dragging.
- */
-
- /*
- Update top GUI.
- Update functions are called recursively.
- This can be used for animation for example.
- */
- gui_update(gui);
- }
-
- max_time = the_time + MAX_SKIP;
- }
-
- gui_destroy(gui);
-}
-
-
-
-void initialise_guitop(void)
-{
- LOCK_FUNCTION(timer_handler);
- LOCK_VARIABLE(true_time);
- LOCK_VARIABLE(max_time);
-}
+#include <allegro.h>
+
+#include "options.h"
+#include "guitop.h"
+#include "guiproc.h"
+#include "dumbdesk.h"
+
+
+
+int the_time;
+
+volatile int true_time;
+static int max_time;
+
+
+
+static void timer_handler(void)
+{
+ if (true_time < max_time)
+ true_time++;
+}
+END_OF_STATIC_FUNCTION(timer_handler);
+
+
+
+#define MAX_SKIP 20
+
+
+
+/*
+Every GUI has a reference to its parent - except the top one.
+
+Main loop:
+ Test keyboard.
+ Esc makes parent GUI active.
+ Other keys go to active GUI, which can do as it pleases.
+ Test mouse.
+ Mouse clicks go to the top GUI.
+ The top GUI may pass them down recursively.
+ A GUI may be marked as mouse-active, for dragging.
+ Update top GUI.
+ Update functions are called recursively.
+ This can be used for animation for example.
+ If there's time, draw top GUI.
+ Draw functions only draw areas marked for redrawing.
+ Marked areas are unmarked once they have been drawn.
+ Draw functions are called recursively.
+ If a child has moved:
+ It will call its parent for the vacated areas.*
+
+The child will have been removed from the parent's list while
+it was drawn, so recursive cycles cannot occur.
+*/
+
+
+
+void run_desktop(GUI_DESKTOP_PARAM *param)
+{
+ GUI *gui = gui_create(
+ &gui_desktop_commands,
+ NULL,
+ 0, 0, opt.gfx_w, opt.gfx_h,
+ param
+ );
+
+ if (!gui)
+ return;
+
+ gui_active = gui;
+
+ true_time = the_time = 0;
+ max_time = MAX_SKIP;
+
+ install_int_ex(timer_handler, BPS_TO_TIMER(100));
+
+ for (;;) {
+ gui_draw(gui);
+ gui_drawn(gui);
+
+ while (the_time >= true_time)
+ yield_timeslice();
+
+ while (the_time < true_time) {
+ the_time++;
+
+ /*
+ Test keyboard.
+ Esc makes parent GUI active.
+ Other keys go to active GUI, which can do as it pleases.
+ */
+ while (keypressed()) {
+ int k = readkey();
+ if (k >> 8 == KEY_ESC) {
+ if (!gui_active->parent) {
+ remove_int(timer_handler);
+ return;
+ }
+ gui_set_active(gui_active->parent);
+ } else
+ gui_key(gui_active, k);
+ }
+
+ /*
+ Test mouse.
+ Mouse clicks go to the top GUI.
+ The top GUI may pass them down recursively.
+ A GUI may be marked as mouse-active, for dragging.
+ */
+
+ /*
+ Update top GUI.
+ Update functions are called recursively.
+ This can be used for animation for example.
+ */
+ gui_update(gui);
+ }
+
+ max_time = the_time + MAX_SKIP;
+ }
+
+ gui_destroy(gui);
+}
+
+
+
+void initialise_guitop(void)
+{
+ LOCK_FUNCTION(timer_handler);
+ LOCK_VARIABLE(true_time);
+ LOCK_VARIABLE(max_time);
+}
diff --git a/plugins/dumb/dumb-kode54/studio/src/main.c b/plugins/dumb/dumb-kode54/studio/src/main.c
index 577d40c6..a2064701 100644
--- a/plugins/dumb/dumb-kode54/studio/src/main.c
+++ b/plugins/dumb/dumb-kode54/studio/src/main.c
@@ -1,118 +1,118 @@
-#include <stdlib.h>
-#include <errno.h>
-#include <allegro.h>
-#include "dumb.h"
-
-#include "options.h"
-#include "guitop.h"
-#include "dumbdesk.h"
-
-
-
-DATAFILE *dat;
-
-
-
-static int load_studio_datafile(void)
-{
- char ef[256], df[256];
-
- get_executable_name(ef, 256);
- replace_filename(df, ef, "studio.dat", 256);
-
- dat = load_datafile(df);
-
- if (!dat)
- return 1;
-
- return 0;
-}
-
-
-
-static GUI_MENU_ENTRY main_menu_bar_entries[] = {
- {"File", NULL, NULL},
- {"Edit", NULL, NULL},
- {"View", NULL, NULL}
-};
-
-static GUI_MENU_PARAM main_menu_bar = {3, main_menu_bar_entries};
-
-static GUI_DESKTOP_PARAM desktop_param = {"DUMB Studio v0.001", &main_menu_bar};
-
-
-
-int main(void)//(int argc, char *argv[])
-{
- int old_gfx_w, old_gfx_h;
- char old_allegro_error[ALLEGRO_ERROR_SIZE];
-
- if (allegro_init())
- return 1;
-
- if (install_timer()) {
- allegro_message("Unable to initialise timer\n");
- return 1;
- }
-
- if (install_keyboard()) {
- allegro_message("Unable to initialise keyboard\n");
- return 1;
- }
-
- /*
- if (install_dumb(&errno, &atexit)) {
- allegro_message("Unable to initialise the DUMB library\n");
- return 1;
- }
-
- register_sigtype_sample();
- register_sigtype_combining();
- register_sigtype_stereopan();
- register_sigtype_sequence();
- */
-
- initialise_guitop();
-
- if (load_studio_datafile()) {
- allegro_message("Unable to load studio.dat\n");
- return 1;
- }
-
- load_options();
-
- old_gfx_w = opt.gfx_w;
- old_gfx_h = opt.gfx_h;
-
- while (set_gfx_mode(GFX_AUTODETECT, opt.gfx_w, opt.gfx_h, 0, 0)) {
- if (opt.gfx_w == DEF_GFX_W && opt.gfx_h == DEF_GFX_H) {
- if (opt.gfx_w == old_gfx_w && opt.gfx_h == old_gfx_h) {
- allegro_message(
- "Unable to set graphics mode "DEF_GFX_STR"\n%s\n",
- allegro_error
- );
- } else {
- allegro_message(
- "Unable to set graphics mode %dx%d\n%s\n"
- "Unable to revert to graphics mode "DEF_GFX_STR"\n%s\n",
- old_gfx_w, old_gfx_h,
- old_allegro_error,
- allegro_error
- );
- }
- return 1;
- }
-
- opt.gfx_w = DEF_GFX_W;
- opt.gfx_h = DEF_GFX_H;
- ustrncpy(old_allegro_error, allegro_error, ALLEGRO_ERROR_SIZE);
- }
-
- text_mode(-1);
-
- run_desktop(&desktop_param);
-
- return 0;
-}
-END_OF_MAIN();
-
+#include <stdlib.h>
+#include <errno.h>
+#include <allegro.h>
+#include "dumb.h"
+
+#include "options.h"
+#include "guitop.h"
+#include "dumbdesk.h"
+
+
+
+DATAFILE *dat;
+
+
+
+static int load_studio_datafile(void)
+{
+ char ef[256], df[256];
+
+ get_executable_name(ef, 256);
+ replace_filename(df, ef, "studio.dat", 256);
+
+ dat = load_datafile(df);
+
+ if (!dat)
+ return 1;
+
+ return 0;
+}
+
+
+
+static GUI_MENU_ENTRY main_menu_bar_entries[] = {
+ {"File", NULL, NULL},
+ {"Edit", NULL, NULL},
+ {"View", NULL, NULL}
+};
+
+static GUI_MENU_PARAM main_menu_bar = {3, main_menu_bar_entries};
+
+static GUI_DESKTOP_PARAM desktop_param = {"DUMB Studio v0.001", &main_menu_bar};
+
+
+
+int main(void)//(int argc, char *argv[])
+{
+ int old_gfx_w, old_gfx_h;
+ char old_allegro_error[ALLEGRO_ERROR_SIZE];
+
+ if (allegro_init())
+ return 1;
+
+ if (install_timer()) {
+ allegro_message("Unable to initialise timer\n");
+ return 1;
+ }
+
+ if (install_keyboard()) {
+ allegro_message("Unable to initialise keyboard\n");
+ return 1;
+ }
+
+ /*
+ if (install_dumb(&errno, &atexit)) {
+ allegro_message("Unable to initialise the DUMB library\n");
+ return 1;
+ }
+
+ register_sigtype_sample();
+ register_sigtype_combining();
+ register_sigtype_stereopan();
+ register_sigtype_sequence();
+ */
+
+ initialise_guitop();
+
+ if (load_studio_datafile()) {
+ allegro_message("Unable to load studio.dat\n");
+ return 1;
+ }
+
+ load_options();
+
+ old_gfx_w = opt.gfx_w;
+ old_gfx_h = opt.gfx_h;
+
+ while (set_gfx_mode(GFX_AUTODETECT, opt.gfx_w, opt.gfx_h, 0, 0)) {
+ if (opt.gfx_w == DEF_GFX_W && opt.gfx_h == DEF_GFX_H) {
+ if (opt.gfx_w == old_gfx_w && opt.gfx_h == old_gfx_h) {
+ allegro_message(
+ "Unable to set graphics mode "DEF_GFX_STR"\n%s\n",
+ allegro_error
+ );
+ } else {
+ allegro_message(
+ "Unable to set graphics mode %dx%d\n%s\n"
+ "Unable to revert to graphics mode "DEF_GFX_STR"\n%s\n",
+ old_gfx_w, old_gfx_h,
+ old_allegro_error,
+ allegro_error
+ );
+ }
+ return 1;
+ }
+
+ opt.gfx_w = DEF_GFX_W;
+ opt.gfx_h = DEF_GFX_H;
+ ustrncpy(old_allegro_error, allegro_error, ALLEGRO_ERROR_SIZE);
+ }
+
+ text_mode(-1);
+
+ run_desktop(&desktop_param);
+
+ return 0;
+}
+END_OF_MAIN();
+
diff --git a/plugins/dumb/dumb-kode54/studio/src/options.c b/plugins/dumb/dumb-kode54/studio/src/options.c
index e387db13..0e47de29 100644
--- a/plugins/dumb/dumb-kode54/studio/src/options.c
+++ b/plugins/dumb/dumb-kode54/studio/src/options.c
@@ -1,31 +1,31 @@
-#include <stdlib.h>
-#include <allegro.h>
-#include "options.h"
-
-
-
-void load_options(void)
-{
- {
- char ef[256], cf[256];
-
- get_executable_name(ef, 256);
- replace_filename(cf, ef, "studio.ini", 256);
-
- set_config_file(cf);
- }
-
- opt.gfx_w = get_config_int("options", "gfx_w", DEF_GFX_W);
- opt.gfx_h = get_config_int("options", "gfx_h", DEF_GFX_H);
-
- atexit(&save_options);
-}
-
-
-
-void save_options(void)
-{
- set_config_int("options", "gfx_w", opt.gfx_w);
- set_config_int("options", "gfx_h", opt.gfx_h);
-}
-
+#include <stdlib.h>
+#include <allegro.h>
+#include "options.h"
+
+
+
+void load_options(void)
+{
+ {
+ char ef[256], cf[256];
+
+ get_executable_name(ef, 256);
+ replace_filename(cf, ef, "studio.ini", 256);
+
+ set_config_file(cf);
+ }
+
+ opt.gfx_w = get_config_int("options", "gfx_w", DEF_GFX_W);
+ opt.gfx_h = get_config_int("options", "gfx_h", DEF_GFX_H);
+
+ atexit(&save_options);
+}
+
+
+
+void save_options(void)
+{
+ set_config_int("options", "gfx_w", opt.gfx_w);
+ set_config_int("options", "gfx_h", opt.gfx_h);
+}
+
diff --git a/plugins/dumb/dumb-kode54/studio/src/subclip.c b/plugins/dumb/dumb-kode54/studio/src/subclip.c
index ef1a9137..f68f5563 100644
--- a/plugins/dumb/dumb-kode54/studio/src/subclip.c
+++ b/plugins/dumb/dumb-kode54/studio/src/subclip.c
@@ -1,33 +1,33 @@
-#include <allegro.h>
-
-#include "subclip.h"
-
-
-
-void subclip(int l, int t, int r, int b, void (*proc)(void *data), void *data)
-{
- int cl = screen->cl;
- int ct = screen->ct;
- int cr = screen->cr;
- int cb = screen->cb;
-
- if (l < cl) l = cl;
- if (t < ct) t = ct;
- if (r > cr) r = cr;
- if (b > cb) b = cb;
-
- if (r > l && b > t) {
- screen->cl = l;
- screen->ct = t;
- screen->cr = r;
- screen->cb = b;
-
- (*proc)(data);
-
- screen->cl = cl;
- screen->ct = ct;
- screen->cr = cr;
- screen->cb = cb;
- }
-}
-
+#include <allegro.h>
+
+#include "subclip.h"
+
+
+
+void subclip(int l, int t, int r, int b, void (*proc)(void *data), void *data)
+{
+ int cl = screen->cl;
+ int ct = screen->ct;
+ int cr = screen->cr;
+ int cb = screen->cb;
+
+ if (l < cl) l = cl;
+ if (t < ct) t = ct;
+ if (r > cr) r = cr;
+ if (b > cb) b = cb;
+
+ if (r > l && b > t) {
+ screen->cl = l;
+ screen->ct = t;
+ screen->cr = r;
+ screen->cb = b;
+
+ (*proc)(data);
+
+ screen->cl = cl;
+ screen->ct = ct;
+ screen->cr = cr;
+ screen->cb = cb;
+ }
+}
+
diff --git a/plugins/dumb/dumb-kode54/tools/cit.c b/plugins/dumb/dumb-kode54/tools/cit.c
index 3bda6392..b2f3a41f 100644
--- a/plugins/dumb/dumb-kode54/tools/cit.c
+++ b/plugins/dumb/dumb-kode54/tools/cit.c
@@ -1,2968 +1,2968 @@
-/* These #defines are TEMPORARY. They are used to write alternative code to
- * handle ambiguities in the format specification. The correct code in each
- * case will be determined most likely by experimentation.
- */
-#define STEREO_SAMPLES_COUNT_AS_TWO
-#define INVALID_ORDERS_END_SONG
-#define SUSTAIN_LOOP_OVERRIDES_NORMAL_LOOP
-#define VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
-
-
-
-#include <stdio.h>//temporary
-
-
-
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * cit.c - IT Compiler / / \ \
- * | < / \_
- * Derived from an IT file loader by Bob. | \/ /\ /
- * \_ / > /
- * Written by entheh. Barely works. A complete | \ / /
- * mess. | ' /
- * \__/
- */
-
-#include <string.h>
-#include <math.h>
-#include "allegro.h"
-
-
-
-#define MUSIC_IT AL_ID('I','M','P','M')
-
-
-
-typedef struct MODULE_MUSIC_INFO {
- char Name[29];
- int Type;
-} MODULE_MUSIC_INFO;
-
-#define ENVELOPE_ON 1
-#define ENVELOPE_LOOP_ON 2
-#define ENVELOPE_SUSTAINLOOP 4
-#define ENVELOPE_PITCH_IS_FILTER 128
-
-typedef struct MODULE_ENVELOPE {
- unsigned char Flag,
- NumNodes,
- LoopBegin, LoopEnd, SustainLoopBegin, SustainLoopEnd; //in nodes.
- char NodeY[25];
- short NodeTick[25];
-} MODULE_ENVELOPE;
-
-typedef struct MODULE_VENVELOPE {
- unsigned char NextNode;
- unsigned short CurTick;
-} MODULE_VENVELOPE;
-
-#define NNA_NOTECUT 0
-#define NNA_NOTECONTINUE 1
-#define NNA_NOTEOFF 2
-#define NNA_NOTEFADE 3
-
-#define DCT_OFF 0
-#define DCT_NOTE 1
-#define DCT_SAMPLE 2
-#define DCT_INSTRUMENT 3
-
-#define DCA_CUT 0
-#define DCA_NOTEOFF 1
-#define DCA_NOTEFADE 2
-
-typedef struct MODULE_INSTRUMENT {
- //unsigned char Flag;
- char VolumeLoopNodeStart, VolumeLoopNodeEnd;
- char SustainLoopNodeStart, SustainLoopNodeEnd;
- char DuplicateCheckType;
- char DuplicateCheckAction;
- char NewNoteAction;
- int FadeOut;
-
- unsigned char PitchPanSeparation, //0->64, Bit7: Don't use
- PitchPanCenter; //Note, from C-0 to B-9
- unsigned char GlobalVolume, //0->128
- DefaultPan; //0->64, Bit7: Don't use
- unsigned char RandomVolume, RandomPanning;
-
- unsigned char FilterCutOff;
- unsigned char FilterResonance;
-
- unsigned char NoteSample[120];
- unsigned char NoteNote[120];
-
- MODULE_ENVELOPE VolumeEnvelope, PanningEnvelope, PitchEnvelope;
-} MODULE_INSTRUMENT;
-
-#define SAMPLE_HASSAMPLE 1
-#define SAMPLE_16BIT 2
-#define SAMPLE_STEREO 4
-#define SAMPLE_USELOOP 16
-#define SAMPLE_USESUSTAINLOOP 32
-#define SAMPLE_PINGPONGLOOP 64
-#define SAMPLE_PINGPONGSUSTAINLOOP 128
-
-#define VIBRATO_SINE 0
-#define VIBRATO_RAMPDOWN 1
-#define VIBRATO_SQUARE 2
-#define VIBRATO_RANDOM 3
-
-typedef struct MODULE_SAMPLE {
- unsigned char GlobalVolume; //0->64
- unsigned char Flag;
- unsigned char DefaultVolume;
- unsigned char DefaultPanning;
- int SampleLength; //in samples, not bytes !
- int LoopBegin, LoopEnd; //in samples
- int SustainLoopBegin, SustainLoopEnd;
- int C5Speed; //Number of bytes/sec for C-5
-
- SAMPLE *Sample;
-
- char VibratoSpeed; //0->64
- char VibratoDepth; //0->64
- char VibratoWaveForm;
- char VibratoRate; //0->64
-} MODULE_SAMPLE;
-
-#define NOTEMASK_NOTE 1
-#define NOTEMASK_INSTRUMENT 2
-#define NOTEMASK_VOLPAN 4
-#define NOTEMASK_COMMAND 8
-
-#define NOTE_OFF 255
-#define NOTE_CUT 254
-
-typedef struct MODULE_NOTE {
- char Mask;
- char Channel; //if -1, then end of row.
- unsigned char Note;
- char Instrument;
- unsigned char VolPan;
- unsigned char Command, CommandValue;
-} MODULE_NOTE;
-
-typedef struct MODULE_PATTERN {
- int NumRows;
- int NumNotes;
- MODULE_NOTE *Note;
-} MODULE_PATTERN;
-
-#define VCHANNEL_PLAYING 1
-#define VCHANNEL_BACKGROUND 2
-#define VCHANNEL_FADING 4
-#define VCHANNEL_RETRIG 8
-
-struct MODULE_CHANNEL;
-
-typedef struct MODULE_VCHANNEL {
- unsigned char Flag;
- unsigned char Instrument;
- unsigned char Note;
- unsigned int Volume;
- unsigned char Pan;
- signed char PanSep;
-
- MODULE_SAMPLE *sample;
-
- int pitch; /* 0 corresponds to C-5, 256 is one semitone. */
-
- MODULE_VENVELOPE VVolEnv;
- int fadeoutcount;
-
- /* WARNING: search for BLEARGH when adding to this struct. */
-/*
- MODULE_SAMPLE *Sample; //NULL is unused
- char voice;
- char ChannelVolume;
- char NoteOn;
- char NNA;
- short FadeOutCount, FadeOut;
- float MixVolume, MixPan;
- MODULE_VENVELOPE *VVolumeEnvelope, *VPanningEnvelope, *VPitchEnvelope;
- struct MODULE_VCHANNEL *next, *prev;
-*/
- unsigned char NNA;
-
- unsigned int DUHvol, DUHpan;
-
- struct MODULE_CHANNEL *channel;
-} MODULE_VCHANNEL;
-
-#define CHANNEL_RETRIG 1
-
-typedef struct MODULE_CHANNEL {
- unsigned int ID;
- unsigned char Flag;
- unsigned char Note;
- unsigned char Instrument;
- unsigned char Volume; //0->64
- unsigned char Pan; //0->32->64, 100 = surround, Bit7: Disable
- signed char PanSep;
-
- int pitch;
-
- unsigned char ChannelVolume;
-
- unsigned char lastvolslide;
- unsigned char lastDKL, lastN, lastW, lastEF, lastG, lastT;
- int portamento, toneporta;
- signed char volslide;
- signed char channelvolslide;
-
- MODULE_SAMPLE *sample;
-
- MODULE_VCHANNEL *VChannel;
-} MODULE_CHANNEL;
-
-#define FLAG_STEREO 1
-#define FLAG_USEINSTRUMENTS 4
-#define FLAG_LINEARSLIDES 8 /* If not set, use Amiga slides */
-#define FLAG_OLDEFFECT 16
-#define FLAG_COMPATIBLEGXX 32
-
-#define ORDER_END 255
-#define ORDER_SKIP 254
-
-typedef struct MODULE {
- MODULE_INSTRUMENT *Instrument;
- MODULE_SAMPLE *Sample;
- MODULE_PATTERN *Pattern;
-
- int NumOrders;
- int NumInstruments;
- int NumSamples;
- int NumPatterns;
- int Flags;
- short Version;
- unsigned char GlobalVolume;
- signed char globalvolslide;
- unsigned char MixVolume;
- unsigned char Speed, Tempo, tick;
- signed char temposlide;
- unsigned char PanningSeparation;
-
- unsigned char *Order;
-
- MODULE_CHANNEL Channel[64];
- MODULE_VCHANNEL VChannel[256];
-
- int processorder;
- int processrow;
- int breakrow;
- int rowcount;
-} MODULE;
-
-
-
-#define IT_SET_SPEED 1
-#define IT_JUMP_TO_ORDER 2
-#define IT_BREAK_TO_ROW 3
-#define IT_VOLUME_SLIDE 4
-#define IT_PORTAMENTO_DOWN 5
-#define IT_PORTAMENTO_UP 6
-#define IT_TONE_PORTAMENTO 7
-#define IT_VIBRATO 8
-#define IT_TREMOR 9
-#define IT_ARPEGGIO 10
-#define IT_VOLSLIDE_VIBRATO 11
-#define IT_VOLSLIDE_TONEPORTA 12
-#define IT_SET_CHANNEL_VOLUME 13
-#define IT_CHANNEL_VOLUME_SLIDE 14
-#define IT_SET_SAMPLE_OFFSET 15
-#define IT_PANNING_SLIDE 16
-#define IT_RETRIGGER_NOTE 17
-#define IT_TREMOLO 18
-#define IT_S 19
-#define IT_SET_SONG_TEMPO 20
-#define IT_FINE_VIBRATO 21
-#define IT_SET_GLOBAL_VOLUME 22
-#define IT_GLOBAL_VOLUME_SLIDE 23
-#define IT_SET_PANNING 24
-#define IT_PANBRELLO 25
-#define IT_MIDI_MACRO 26 //see MIDI.TXT
-
-
-
-/* These represent the top nibble of the command value. */
-#define IT_S_SET_FILTER 0 /* Greyed out in IT... */
-#define IT_S_SET_GLISSANDO_CONTROL 1 /* Greyed out in IT... */
-#define IT_S_FINETUNE 2 /* Greyed out in IT... */
-#define IT_S_SET_VIBRATO_WAVEFORM 3
-#define IT_S_SET_TREMOLO_WAVEFORM 4
-#define IT_S_SET_PANBRELLO_WAVEFORM 5
-#define IT_S_FINE_PATTERN_DELAY 6
-#define IT_S7 7
-#define IT_S_SET_PAN 8
-#define IT_S_SET_SURROUND_SOUND 9
-#define IT_S_SET_HIGH_OFFSET 10
-#define IT_S_PATTERN_LOOP 11
-#define IT_S_DELAYED_NOTE_CUT 12
-#define IT_S_NOTE_DELAY 13
-#define IT_S_PATTERN_DELAY 14
-#define IT_S_SET_MIDI_MACRO 15
-
-/*
-S0x Set filter
-S1x Set glissando control
-S2x Set finetune
-
-
-S3x Set vibrato waveform to type x
-S4x Set tremelo waveform to type x
-S5x Set panbrello waveform to type x
- Waveforms for commands S3x, S4x and S5x:
- 0: Sine wave
- 1: Ramp down
- 2: Square wave
- 3: Random wave
-S6x Pattern delay for x ticks
-S70 Past note cut
-S71 Past note off
-S72 Past note fade
-S73 Set NNA to note cut
-S74 Set NNA to continue
-S75 Set NNA to note off
-S76 Set NNA to note fade
-S77 Turn off volume envelope
-S78 Turn on volume envelope
-S79 Turn off panning envelope
-S7A Turn on panning envelope
-S7B Turn off pitch envelope
-S7C Turn on pitch envelope
-S8x Set panning position
-S91 Set surround sound
-SAy Set high value of sample offset yxx00h
-SB0 Set loopback point
-SBx Loop x times to loopback point
-SCx Note cut after x ticks
-SDx Note delay for x ticks
-SEx Pattern delay for x rows
-SFx Set parameterised MIDI Macro
-*/
-
-
-
-typedef struct MODULE_PLAY {
- MODULE *Music;
- int Loop, Tick;
- int CurOrder, CurPattern, CurPos;
- int Command, CommandVal0, CommandVal1, CommandVal2;
- int pos;
-} MODULE_PLAY;
-extern MODULE_PLAY *song;
-
-extern int IT_Play_Method;
-
-MODULE *load_it(char*);
-//int get_module_size(MODULE *);
-
-int play_it(MODULE *j, int loop);
-void install_module();
-void set_mix_volume(int i);
-
-void stop_it();
-int is_music_done();
-void destroy_it(MODULE *j);
-
-//Should be internal:
-extern MODULE_PLAY *song;
-extern int note_freq[120];
-
-//extern void MOD_Interrupt(...);
-extern int MOD_Poller(void*);
-
-#define IT_TIMER 0
-#define IT_POLL 1
-
-/* typedef.hpp */
-
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned int dword;
-
-/* load_it.cpp */
-
-/*
-int detect_it(char *f) {
- int sig;
- PACKFILE *fn = pack_fopen(f, F_READ);
-
- if (fn == NULL)
- return FALSE;
-
- sig = pack_mgetl(fn);
- if (sig != MUSIC_IT) {
- pack_fclose(fn);
- return FALSE;
- }
- pack_fclose(fn);
-
- return TRUE;
-}
-*/
-
-
-
-MODULE *create_it() {
- MODULE *m = (MODULE*)malloc(sizeof(MODULE));
- if (!m)
- return NULL;
- memset(m, 0, sizeof(MODULE));
- return m;
-}
-
-
-
-void destroy_it(MODULE *j) {
-
- int i;
-
- if (j) {
- /* Remove patterns. */
- if (j->Pattern) {
- for (i = 0; i < j->NumPatterns; i++)
- free(j->Pattern[i].Note);
- free(j->Pattern);
- }
-
- /* Remove instruments. */
- free(j->Instrument);
-
- /* Remove samples. */
- if (j->Sample) {
- for (i = 0; i < j->NumSamples; i++)
- destroy_sample(j->Sample[i].Sample);
- free(j->Sample);
- }
-
- /* Remove orders. */
- free(j->Order);
-
- free(j);
- }
-}
-
-
-
-//#define DEBUG_IT_SIZE
-
-/*
-int get_module_size(MODULE *j) {
- int a, b, c, d = 0, e;
- int i;
- a = sizeof(MODULE) + j->NumOrders;
- b = j->NumInstruments * sizeof(MODULE_INSTRUMENT);
- c = j->NumSamples * sizeof(MODULE_SAMPLE);
-
- for (i=0; i<j->NumSamples; i++)
- d += j->Sample[i].SampleLength * (j->Sample[i].Flag & 2 ? sizeof(short) : 1) * (j->Sample[i].Flag & 4 ? 2: 1);
-
- e = 4 + sizeof(MODULE_PATTERN) * j->NumPatterns;
-
- for (i=0; i<j->NumPatterns; i++)
- e += j->Pattern[i].NumNotes * sizeof(MODULE_NOTE);
- #ifdef DEBUG_IT_SIZE
- fprintf(stderr, "Base: %i, Instruments(%i): %i, Samples(%i): %i, Data: %i, Patterns(%i): %i\n", a, j->NumInstruments, b, j->NumSamples, c, d, j->NumPatterns, e);
- #endif
-
- return a+b+c+d+e;
-}
-*/
-
-
-
-#define MAX_IT_CHN 64
-
-//#define DEBUG_HEADER
-//#define DEBUG_INSTRUMENTS
-//#define DEBUG_SAMPLES
-//#define DEBUG_PATTERNS
-
-static dword *sourcebuf = NULL;
-static dword *sourcepos = NULL;
-static byte rembits = 0;
-
-int readblock(PACKFILE *f) {
- long size;
- int c = pack_igetw(f);
- if (c == -1)
- return 0;
- size = c;
-
- sourcebuf = (dword*)malloc(size+4);
- if (!sourcebuf)
- return 0;
-
- c = pack_fread(sourcebuf, size, f);
- if (c < 1) {
- free(sourcebuf);
- sourcebuf = NULL;
- return 0;
- }
- sourcepos = sourcebuf;
- rembits = 32;
- return 1;
-}
-
-void freeblock() {
- if (sourcebuf)
- free(sourcebuf);
- sourcebuf = NULL;
-}
-
-dword readbits(char b) {
- dword val;
- if (b <= rembits) {
- val = *sourcepos & ((1 << b) - 1);
- *sourcepos >>= b;
- rembits -= b;
- }
- else {
- dword nbits = b - rembits;
- val = *sourcepos;
- sourcepos++;
- val |= ((*sourcepos & ((1 << nbits) - 1)) << rembits);
- *sourcepos >>= nbits;
- rembits = 32 - nbits;
- }
- return val;
-}
-
-void decompress8(PACKFILE *f, void *data, int len, int tver) {
- char *destbuf = (char*)data;
- char *destpos = destbuf;
- int blocklen, blockpos;
- byte bitwidth;
- word val;
- char d1, d2;
-
- memset(destbuf, 0, len);
-
- while (len>0) {
- //Read a block of compressed data:
- if (!readblock(f))
- return;
- //Set up a few variables
- blocklen = (len < 0x8000) ? len : 0x8000; //Max block length is 0x8000 bytes
- blockpos = 0;
- bitwidth = 9;
- d1 = d2 = 0;
- //Start the decompression:
- while (blockpos < blocklen) {
- //Read a value:
- val = readbits(bitwidth);
- //Check for bit width change:
-
- if (bitwidth < 7) { //Method 1:
- if (val == (1 << (bitwidth - 1))) {
- val = readbits(3) + 1;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth < 9) { //Method 2
- byte border = (0xFF >> (9 - bitwidth)) - 4;
-
- if (val > border && val <= (border + 8)) {
- val -= border;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth == 9) { //Method 3
- if (val & 0x100) {
- bitwidth = (val + 1) & 0xFF;
- continue;
- }
- }
- else { //Illegal width, abort ?
- freeblock();
- return;
- }
-
- //Expand the value to signed byte:
- {
- char v; //The sample value:
- if (bitwidth < 8) {
- byte shift = 8 - bitwidth;
- v = (val << shift);
- v >>= shift;
- }
- else
- v = (char)val;
-
- //And integrate the sample value
- //(It always has to end with integration doesn't it ? ;-)
- d1 += v;
- d2 += d1;
- }
-
- //Store !
- *destpos = ((tver == 0x215) ? d2 : d1);
- destpos++;
- blockpos++;
- }
- freeblock();
- len -= blocklen;
- }
- return;
-}
-
-void decompress16(PACKFILE *f, void *data, int len, int tver) {
- //make the output buffer:
- short *destbuf = (short*)data;
- short *destpos = destbuf;
- int blocklen, blockpos;
- byte bitwidth;
- long val;
- short d1, d2;
-
- memset(destbuf, 0, len);
-
- while (len>0) {
- //Read a block of compressed data:
- if (!readblock(f))
- return;
- //Set up a few variables
- blocklen = (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes
- blockpos = 0;
- bitwidth = 17;
- d1 = d2 = 0;
- //Start the decompression:
- while (blockpos < blocklen) {
- val = readbits(bitwidth);
- //Check for bit width change:
-
- if (bitwidth < 7) { //Method 1:
- if (val == (1 << (bitwidth - 1))) {
- val = readbits(4) + 1;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth < 17) { //Method 2
- word border = (0xFFFF >> (17 - bitwidth)) - 8;
-
- if (val > border && val <= (border + 16)) {
- val -= border;
- bitwidth = val < bitwidth ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth == 17) { //Method 3
- if (val & 0x10000) {
- bitwidth = (val + 1) & 0xFF;
- continue;
- }
- }
- else { //Illegal width, abort ?
- freeblock();
- return;
- }
-
- //Expand the value to signed byte:
- {
- short v; //The sample value:
- if (bitwidth < 16) {
- byte shift = 16 - bitwidth;
- v = (val << shift);
- v >>= shift;
- }
- else
- v = (short)val;
-
- //And integrate the sample value
- //(It always has to end with integration doesn't it ? ;-)
- d1 += v;
- d2 += d1;
- }
-
- //Store !
- *destpos = ((tver == 0x215) ? d2 : d1);
- destpos++;
- blockpos++;
- }
- freeblock();
- len -= blocklen;
- }
- return;
-}
-
-
-
-void read_envelopes(PACKFILE *f, MODULE *j, int i)
-{
- int k;
-
- j->Instrument[i].VolumeEnvelope.Flag = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.NumNodes = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.LoopBegin = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.LoopEnd = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.SustainLoopBegin = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.SustainLoopEnd = pack_getc(f);
- for (k = 0; k < j->Instrument[i].VolumeEnvelope.NumNodes; k++) {
- j->Instrument[i].VolumeEnvelope.NodeY[k] = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.NodeTick[k] = pack_igetw(f);
- }
- pack_fseek(f, 75 - j->Instrument[i].VolumeEnvelope.NumNodes * 3);
-
- j->Instrument[i].PanningEnvelope.Flag = pack_getc(f);
- j->Instrument[i].PanningEnvelope.NumNodes = pack_getc(f);
- j->Instrument[i].PanningEnvelope.LoopBegin = pack_getc(f);
- j->Instrument[i].PanningEnvelope.LoopEnd = pack_getc(f);
- j->Instrument[i].PanningEnvelope.SustainLoopBegin = pack_getc(f);
- j->Instrument[i].PanningEnvelope.SustainLoopEnd = pack_getc(f);
- for (k = 0; k < j->Instrument[i].PanningEnvelope.NumNodes; k++) {
- j->Instrument[i].PanningEnvelope.NodeY[k] = pack_getc(f);
- j->Instrument[i].PanningEnvelope.NodeTick[k] = pack_igetw(f);
- }
- pack_fseek(f, 75 - j->Instrument[i].PanningEnvelope.NumNodes * 3);
-
- j->Instrument[i].PitchEnvelope.Flag = pack_getc(f);
- j->Instrument[i].PitchEnvelope.NumNodes = pack_getc(f);
- j->Instrument[i].PitchEnvelope.LoopBegin = pack_getc(f);
- j->Instrument[i].PitchEnvelope.LoopEnd = pack_getc(f);
- j->Instrument[i].PitchEnvelope.SustainLoopBegin = pack_getc(f);
- j->Instrument[i].PitchEnvelope.SustainLoopEnd = pack_getc(f);
- for (k = 0; k < j->Instrument[i].PitchEnvelope.NumNodes; k++) {
- j->Instrument[i].PitchEnvelope.NodeY[k] = pack_getc(f);
- j->Instrument[i].PitchEnvelope.NodeTick[k] = pack_igetw(f);
- }
-}
-
-
-
-MODULE *load_old_instrument(char *file, long offset, MODULE *j, int i)
-{
- int k;
- PACKFILE *f = pack_fopen(file, F_READ);
-
- if (!f) {
- #ifdef DEBUG_INSTRUMENTS
- fprintf(stderr, "Error reopening!\n");
- #endif
- destroy_it(j);
- return NULL;
- }
-
- pack_fseek(f, offset);
-
- if (pack_mgetl(f) != AL_ID('I','M','P','I')) {
- destroy_it(j);
- return NULL;
- }
-
- /* Skip DOS Filename */
- pack_fseek(f, 13);
-
- j->Instrument[i].VolumeEnvelope.Flag = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.LoopBegin = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.LoopEnd = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.SustainLoopBegin = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.SustainLoopEnd = pack_getc(f);
-
- /* Two unused bytes */
- pack_fseek(f, 2);
-
- /* OLD FadeOut: Ranges between 0 and 64, but the fadeout "Count" is 512.
- * NEW FadeOut: Ranges between 0 and 128, but the fadeout "Count" is 1024
- *
- * TODO: Find out what this means, and make adjustments accordingly.
- */
- j->Instrument[i].FadeOut = pack_igetw(f) << 1;
- j->Instrument[i].NewNoteAction = pack_getc(f);
- j->Instrument[i].DuplicateCheckType = pack_getc(f);
- j->Instrument[i].DuplicateCheckAction = DCA_CUT; /* This might be wrong! */
-
- /* Skip Tracker Version and Number of Samples. These are only used in
- * separate instrument files. Also skip unused bytes and Instrument Name.
- */
- pack_fseek(f, 36);
-
- j->Instrument[i].PitchPanSeparation = 0;
- j->Instrument[i].PitchPanCenter = 60;
- j->Instrument[i].GlobalVolume = 128; /* Should this be 64 or something? */
- j->Instrument[i].DefaultPan = 32; /* Should this be 128? */
- j->Instrument[i].RandomVolume = 0;
- j->Instrument[i].RandomPanning = 0;
-
- for (k = 0; k < 120; k++) {
- j->Instrument[i].NoteNote[k] = pack_getc(f);
- j->Instrument[i].NoteSample[k] = pack_getc(f);
- }
-
- /* Skip "Volume envelope (200 bytes)" - need to know better what this is
- * for though.
- */
- pack_fseek(f, 200);
-
- fprintf(stderr, "Inst %02d Env:", i);
-
- for (j->Instrument[i].VolumeEnvelope.NumNodes = 0;
- j->Instrument[i].VolumeEnvelope.NumNodes < 25;
- j->Instrument[i].VolumeEnvelope.NumNodes++)
- {
- j->Instrument[i].VolumeEnvelope.NodeTick[k] = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.NodeY[k] = pack_getc(f);
-
- fprintf(stderr, " %d,%d",
- j->Instrument[i].VolumeEnvelope.NodeTick[k],
- j->Instrument[i].VolumeEnvelope.NodeY[k]);
- }
- pack_fseek(f, 50 - j->Instrument[i].VolumeEnvelope.NumNodes * 2);
-
- fprintf(stderr, "\n");
-
- j->Instrument[i].FilterCutOff = 0; //Are these the right values
- j->Instrument[i].FilterResonance = 0; //to disable the filter?
-
- j->Instrument[i].PanningEnvelope.Flag = 0;
- j->Instrument[i].PanningEnvelope.NumNodes = 0;
- j->Instrument[i].PanningEnvelope.LoopBegin = 0;
- j->Instrument[i].PanningEnvelope.LoopEnd = 0;
- j->Instrument[i].PanningEnvelope.SustainLoopBegin = 0;
- j->Instrument[i].PanningEnvelope.SustainLoopEnd = 0;
-
- j->Instrument[i].PitchEnvelope.Flag = 0;
- j->Instrument[i].PitchEnvelope.NumNodes = 0;
- j->Instrument[i].PitchEnvelope.LoopBegin = 0;
- j->Instrument[i].PitchEnvelope.LoopEnd = 0;
- j->Instrument[i].PitchEnvelope.SustainLoopBegin = 0;
- j->Instrument[i].PitchEnvelope.SustainLoopEnd = 0;
-
- pack_fclose(f);
-
- if (errno) {
- destroy_it(j);
- return NULL;
- }
-
- return j;
-}
-
-
-
-MODULE *load_instrument(char *file, long offset, MODULE *j, int i)
-{
- int k;
- PACKFILE *f = pack_fopen(file, F_READ);
-
- if (!f) {
- #ifdef DEBUG_INSTRUMENTS
- fprintf(stderr, "Error reopening!\n");
- #endif
- destroy_it(j);
- return NULL;
- }
-
- pack_fseek(f, offset);
-
- if (pack_mgetl(f) != AL_ID('I','M','P','I')) {
- destroy_it(j);
- return NULL;
- }
-
- /* Skip DOS Filename */
- pack_fseek(f, 13);
-
- j->Instrument[i].NewNoteAction = pack_getc(f);
- j->Instrument[i].DuplicateCheckType = pack_getc(f);
- j->Instrument[i].DuplicateCheckAction = pack_getc(f);
- j->Instrument[i].FadeOut = pack_igetw(f);
- j->Instrument[i].PitchPanSeparation = pack_getc(f);
- j->Instrument[i].PitchPanCenter = pack_getc(f);
- j->Instrument[i].GlobalVolume = pack_getc(f);
- j->Instrument[i].DefaultPan = pack_getc(f);
- j->Instrument[i].RandomVolume = pack_getc(f);
- j->Instrument[i].RandomPanning = pack_getc(f);
-
- #ifdef DEBUG_INSTRUMENTS
- fprintf(stderr, "I%02i @ 0x%X, NNA %i, DCT %i, DCA %i, FO %i, "
- "PPS %i, PPC %i, GVol %i, DPan %i, RV %i, RP %i\n",
- i, insoffs[i],
- j->Instrument[i].NewNoteAction,
- j->Instrument[i].DuplicateCheckType,
- j->Instrument[i].DuplicateCheckAction,
- j->Instrument[i].FadeOut,
- j->Instrument[i].PitchPanSeparation,
- j->Instrument[i].PitchPanCenter,
- j->Instrument[i].GlobalVolume,
- j->Instrument[i].DefaultPan,
- j->Instrument[i].RandomVolume,
- j->Instrument[i].RandomPanning);
- #endif
-
- /* Skip Tracker Version and Number of Samples. These are only used in
- * separate instrument files. Also skip unused byte and Instrument Name.
- */
- pack_fseek(f, 30);
-
- j->Instrument[i].FilterCutOff = pack_getc(f);
- j->Instrument[i].FilterResonance = pack_getc(f);
-
- /* Skip MIDI Channel, Program and Bank */
- pack_fseek(f, 4);
-
- for (k = 0; k < 120; k++) {
- j->Instrument[i].NoteNote[k] = pack_getc(f);
- j->Instrument[i].NoteSample[k] = pack_getc(f);
- }
-
- read_envelopes(f, j, i);
-
- pack_fclose(f);
-
- if (errno) {
- destroy_it(j);
- return NULL;
- }
-
- return j;
-}
-
-
-
-MODULE *load_it_sample(char *file, long offset, MODULE *j, int i)
-{
- int sam_samptr, convert;
- int len;
- int k;
- SAMPLE *sam;
- void *dat;
-
- PACKFILE *f = pack_fopen(file, F_READ);
- if (!f) {
- #ifdef DEBUG_SAMPLES
- fprintf(stderr, "Error opening!\n");
- #endif
- destroy_it(j);
- return NULL;
- }
-
- pack_fseek(f, offset);
-
- if (pack_mgetl(f) != AL_ID('I','M','P','S')) {
- destroy_it(j);
- return NULL;
- }
-
- /* Skip DOS Filename. */
- pack_fseek(f, 13);
-
- j->Sample[i].GlobalVolume = pack_getc(f);
- j->Sample[i].Flag = pack_getc(f);
- j->Sample[i].DefaultVolume = pack_getc(f);
-
- #ifdef DEBUG_SAMPLES
- fprintf(stderr, "S%02i @ 0x%X, Vol: %i/%i, Flag: %i", i, samoffs[i], j->Sample[i].GlobalVolume, j->Sample[i].Volume, j->Sample[i].Flag);
- #endif
-
- /* Skip Sample Name. */
- pack_fseek(f, 26);
-
- convert = pack_getc(f);
- j->Sample[i].DefaultPanning = pack_getc(f);
- j->Sample[i].SampleLength = pack_igetl(f);
- j->Sample[i].LoopBegin = pack_igetl(f);
- j->Sample[i].LoopEnd = pack_igetl(f);
- j->Sample[i].C5Speed = pack_igetl(f);
- j->Sample[i].SustainLoopBegin = pack_igetl(f);
- j->Sample[i].SustainLoopEnd = pack_igetl(f);
-
- #ifdef DEBUG_SAMPLES
- fprintf(stderr, ", SLen: %i, LpB: %i, LpE: %i, C5S: %i\n", j->Sample[i].SampleLength, j->Sample[i].LoopBegin, j->Sample[i].LoopEnd, j->Sample[i].C5Speed);
- #endif
-
- sam_samptr = pack_igetl(f);
-
- j->Sample[i].VibratoSpeed = pack_getc(f);
- j->Sample[i].VibratoDepth = pack_getc(f);
- j->Sample[i].VibratoRate = pack_getc(f);
- j->Sample[i].VibratoWaveForm = pack_getc(f);
-
- #ifdef DEBUG_SAMPLES
- fprintf(stderr, "SusLpB: %i, SusLpE: %i, VibSp: %i, VibDep: %i, VibWav: %i, VibRat: %i\n", j->Sample[i].SustainLoopBegin, j->Sample[i].SustainLoopEnd, j->Sample[i].VibratoSpeed, j->Sample[i].VibratoDepth, j->Sample[i].VibratoWaveForm, j->Sample[i].VibratoRate);
- #endif
-
- pack_fclose(f);
-
- if (errno) {
- destroy_it(j);
- return NULL;
- }
-
- if (j->Sample[i].Flag & SAMPLE_HASSAMPLE) {
-
- f = pack_fopen(file, F_READ);
- pack_fseek(f, sam_samptr);
-
- len = j->Sample[i].SampleLength;
- if (j->Sample[i].Flag & SAMPLE_16BIT) len <<= 1;
-#ifndef STEREO_SAMPLES_COUNT_AS_TWO
- if (j->Sample[i].Flag & SAMPLE_STEREO) len <<= 1;
-#endif
-
- #ifdef DEBUG_SAMPLES
- fprintf(stderr, "Len: %i, Size: %i KB\n", j->Sample[i].SampleLength, len/1024);
- #endif
-
- sam = create_sample(j->Sample[i].Flag & SAMPLE_16BIT ? 16 : 8,
- j->Sample[i].Flag & SAMPLE_STEREO ? 1 : 0,
-#ifdef STEREO_SAMPLES_COUNT_AS_TWO
- j->Sample[i].C5Speed >> 1,
-#else
- j->Sample[i].C5Speed,
-#endif
- j->Sample[i].SampleLength);
-
- if (j->Sample[i].Flag & 8) { // If the sample is packed, then we must unpack it
-
- if (j->Sample[i].Flag & SAMPLE_16BIT)
- decompress16(f, sam->data, j->Sample[i].SampleLength, j->Version);
- else
- decompress8(f, sam->data, j->Sample[i].SampleLength, j->Version);
-
- } else if ((j->Sample[i].Flag & SAMPLE_16BIT)) {
- if (convert & 2)
- for (k = 0; k < len; k += 2)
- *(short *)((char *)sam->data + k) = pack_mgetw(f);
- else
- for (k = 0; k < len; k += 2)
- *(short *)((char *)sam->data + k) = pack_igetw(f);
- } else {
- pack_fread(sam->data, len, f);
- }
-
- if (j->Sample[i].Flag & SAMPLE_USELOOP) {
- sam->loop_start = j->Sample[i].LoopBegin;
- sam->loop_end = j->Sample[i].LoopEnd;
- }
-
- j->Sample[i].Sample = sam;
-
- dat = sam->data;
-
- if (convert & 1) {
- /* Convert to unsigned. */
- if (sam->bits == 8)
- for (k = 0; k < len; k++)
- ((char *)dat)[k] ^= 0x80;
- else
- for (k = 0; k < len; k += 2)
- *(short *)((char *)dat + k) ^= 0x8000;
- }
-
- /* NOT SUPPORTED:
- *
- * convert & 4 - Samples stored as delta values
- * convert & 8 - Samples stored as byte delta values
- * convert & 16 - Samples stored as TX-Wave 12-bit values
- * convert & 32 - Left/Right/All Stereo prompt
- */
-
- pack_fclose(f);
-
- if (errno) {
- destroy_it(j);
- return NULL;
- }
- }
-
- return j;
-}
-
-
-
-MODULE *load_pattern(char *file, long offset, MODULE *j, int i)
-{
- unsigned char *buf;
- unsigned char cmask[64],
- cnote[64],
- cinstrument[64],
- cvol[64],
- ccom[64],
- ccomval[64];
-
- int numnotes = 0, len, pos = 0, mask = 0, chn = 0;
-
- PACKFILE *f;
-
- if (offset == 0) {
- /* Empty 64-row pattern. */
-
- j->Pattern[i].NumRows = 64;
- j->Pattern[i].NumNotes = 0;
-
- return j;
- }
-
- f = pack_fopen(file, F_READ);
- if (!f) {
- destroy_it(j);
- return NULL;
- }
-
- buf = malloc(65536);
-
- memset(cmask, 0, 64);
- memset(cnote, 0, 64);
- memset(cinstrument, 0, 64);
- memset(cvol, 0, 64);
- memset(ccom, 0, 64);
- memset(ccomval, 0, 64);
-
- pack_fseek(f, offset);
-
- len = pack_igetw(f);
- j->Pattern[i].NumRows = pack_igetw(f);
-
- /* Skip four unused bytes. */
- pack_fseek(f, 4);
-
- pack_fread(buf, len, f);
-
- while (pos < len) {
-
- int b = buf[pos++];
-
- if (!b) {
- /* End of row. */
- numnotes++;
- continue;
- }
-
- chn = (b - 1) & 63;
-
- if (b & 128) {
- mask = buf[pos];
- pos++;
- cmask[chn] = mask;
- } else
- mask = cmask[chn];
-
- if (mask)
- numnotes++;
- if (mask & 1)
- pos++;
- if (mask & 2)
- pos++;
- if (mask & 4)
- pos++;
- if (mask & 8)
- pos += 2;
- }
-
- j->Pattern[i].NumNotes = numnotes;
- j->Pattern[i].Note = malloc(numnotes * sizeof(MODULE_NOTE));
- memset(j->Pattern[i].Note, 0, numnotes * sizeof(MODULE_NOTE));
-
- pos = 0;
- memset(cmask, 0, 64);
- mask = 0;
- numnotes = 0;
-
- while (pos < len) {
-
- int b = buf[pos];
- #ifdef DEBUG_PATTERNS
- fprintf(stderr, "NumNote: %i ", numnotes);
- #endif
- pos++;
-
- if (b == 0) { //If end of row:
- j->Pattern[i].Note[numnotes].Channel = -1;
- numnotes++;
- #ifdef DEBUG_PATTERNS
- fprintf(stderr, "Channel: -1\n");
- #endif
- continue;
- }
-
- chn = (b - 1) & 63;
-
- if (b & 128) {
- mask = buf[pos];
- pos++;
- cmask[chn] = mask;
- } else
- mask = cmask[chn];
-
- #ifdef DEBUG_PATTERNS
- fprintf(stderr, "Channel: %i Mask: %i ", chn, mask);
- #endif
-
- if (mask)
- j->Pattern[i].Note[numnotes].Channel = chn;
-
- if (mask & 1) {
- j->Pattern[i].Note[numnotes].Note = buf[pos];
- j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_NOTE;
- cnote[chn] = buf[pos];
- #ifdef DEBUG_PATTERNS
- fprintf(stderr, "Note: %i ", buf[pos]);
- #endif
- pos++;
- }
-
- if (mask & 2) {
- j->Pattern[i].Note[numnotes].Instrument = buf[pos];
- j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_INSTRUMENT;
- cinstrument[chn] = buf[pos];
- #ifdef DEBUG_PATTERNS
- fprintf(stderr, "Inst: %i ", buf[pos]);
- #endif
- pos++;
- }
-
- if (mask & 4) {
- j->Pattern[i].Note[numnotes].VolPan = buf[pos];
- j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_VOLPAN;
- cvol[chn] = buf[pos];
- #ifdef DEBUG_PATTERNS
- fprintf(stderr, "Vol: %i ", buf[pos]);
- #endif
- pos++;
- }
-
- if (mask & 8) {
- j->Pattern[i].Note[numnotes].Command = buf[pos];
- j->Pattern[i].Note[numnotes].CommandValue = buf[pos+1];
- j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_COMMAND;
- ccom[chn] = buf[pos];
- ccomval[chn] = buf[pos+1];
- #ifdef DEBUG_PATTERNS
- fprintf(stderr, "Com: %i CommArg: %i ", buf[pos], buf[pos+1]);
- #endif
- pos += 2;
- }
-
- if (mask & 16) {
- j->Pattern[i].Note[numnotes].Note = cnote[chn];
- j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_NOTE;
- #ifdef DEBUG_PATTERNS
- fprintf(stderr, "LNote: %i ", cnote[chn]);
- #endif
- }
-
- if (mask & 32) {
- j->Pattern[i].Note[numnotes].Instrument = cinstrument[chn];
- j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_INSTRUMENT;
- #ifdef DEBUG_PATTERNS
- fprintf(stderr, "LInst: %i ", cinstrument[chn]);
- #endif
- }
-
- if (mask & 64) {
- j->Pattern[i].Note[numnotes].VolPan = cvol[chn];
- j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_VOLPAN;
- #ifdef DEBUG_PATTERNS
- fprintf(stderr, "LVol: %i ", cvol[chn]);
- #endif
- }
-
- if (mask & 128) {
- j->Pattern[i].Note[numnotes].Command = ccom[chn];
- j->Pattern[i].Note[numnotes].CommandValue = ccomval[chn];
- j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_COMMAND;
- #ifdef DEBUG_PATTERNS
- fprintf(stderr, "LCom: %i LComArg: %i ", ccom[chn], ccomval[chn]);
- #endif
- }
-
- #ifdef DEBUG_PATTERNS
- fprintf(stderr, "\n");
- #endif
-
- if (mask)
- numnotes++;
-
- #ifdef DEBUG_PATTERNS
- rest(1000);
- #endif
- }
-
- free(buf);
-
- pack_fclose(f);
-
- if (errno) {
- destroy_it(j);
- return NULL;
- }
-
- return j;
-}
-
-
-
-MODULE *load_it(char *file) {
- PACKFILE *f;
- MODULE *j = create_it();
- int tver, tver2, flag;
- long *insoffs = NULL, *samoffs = NULL, *patoffs = NULL;
- int i;
-
- if (!j)
- return NULL;
-
- f = pack_fopen(file, F_READ);
-
- if (!f)
- return NULL;
-
- if (pack_mgetl(f) != MUSIC_IT) {
- pack_fclose(f);
- return NULL;
- }
-
- /* Skip song name and pattern row highlight info */
- pack_fseek(f, 28);
-
- j->NumOrders = pack_igetw(f);
- j->NumInstruments = pack_igetw(f);
- j->NumSamples = pack_igetw(f);
- j->NumPatterns = pack_igetw(f);
-
- #ifdef DEBUG_HEADER
- fprintf(stderr, "Loading IT: %i Orders, %i Instruments, %i Samples, %i Patterns\n", j->NumOrders, j->NumInstruments, j->NumSamples, j->NumPatterns);
- #endif
-
- tver = pack_igetw(f);
- j->Version = tver2 = pack_igetw(f);
-
- #ifdef DEBUG_HEADER
- fprintf(stderr, "Tracker ver: %X, %X\n", tver, tver2);
- #endif
-
- j->Flags = pack_igetw(f);
- flag = pack_igetw(f);
-
- j->GlobalVolume = pack_getc(f);
- j->MixVolume = pack_getc(f);
- j->Speed = pack_getc(f);
- j->Tempo = pack_getc(f);
- j->PanningSeparation = pack_getc(f);
-
- #ifdef DEBUG_HEADER
- fprintf(stderr, "Global Volume: %i, Mixing Volume: %i, Speed: %i, Tempo: %i, PanSep: %i\n", j->GlobalVolume, j->MixVolume, j->Speed, j->Tempo, j->PanningSeparation);
- #endif
-
- /* Skip Pitch Wheel Depth, Message Length, Message Offset and Reserved */
- pack_fseek(f, 11);
-
- #ifdef DEBUG_HEADER
- fprintf(stderr, "Channel Pan:");
- #endif
-
- for (i = 0; i < MAX_IT_CHN; i++) {
- j->Channel[i].Pan = pack_getc(f);
- #ifdef DEBUG_HEADER
- fprintf(stderr, " %i", j->Channel[i].Pan);
- #endif
- }
- #ifdef DEBUG_HEADER
- fprintf(stderr, "\nChannel Vol:");
- #endif
- for (i = 0; i < MAX_IT_CHN; i++) {
- j->Channel[i].ChannelVolume = pack_getc(f);
- #ifdef DEBUG_HEADER
- fprintf(stderr, " %i", j->Channel[i].ChannelVolume);
- #endif
- }
- #ifdef DEBUG_HEADER
- fprintf(stderr, "\n");
- #endif
-
- j->Order = malloc(j->NumOrders);
- if (!j->Order) {
- destroy_it(j);
- return NULL;
- }
- pack_fread(j->Order, j->NumOrders, f);
-
- /* Whoops, no error checking! Er, would it be better to use arrays? */
- if (j->NumInstruments)
- insoffs = malloc(j->NumInstruments * sizeof(*insoffs));
- if (j->NumSamples)
- samoffs = malloc(j->NumSamples * sizeof(*samoffs));
- if (j->NumPatterns)
- patoffs = malloc(j->NumPatterns * sizeof(*patoffs));
-
- for (i = 0; i < j->NumInstruments; i++) insoffs[i] = pack_igetl(f);
- for (i = 0; i < j->NumSamples; i++) samoffs[i] = pack_igetl(f);
- for (i = 0; i < j->NumPatterns; i++) patoffs[i] = pack_igetl(f);
-
-/* No skipping necessary - we can use the offsets.
-
- if (flag&1) { //Song message attached
- //Ignore.
- }
- if (flag & 4) { //skip something:
- short u;
- char dummy[8];
- int i;
- u = pack_igetw(f);
- for (i=0; i<u; u++)
- pack_fread(dummy, 8, f);
- }
- if (flag & 8) { //skip embedded MIDI configuration
- char dummy[33];
- int i;
- for (i=0; i<9+16+128; i++)
- pack_fread(dummy, 32, f);
-
- }
-*/
- pack_fclose(f);
-
- if (j->NumInstruments) {
- j->Instrument = malloc(j->NumInstruments * sizeof(MODULE_INSTRUMENT));
-
- if (!j->Instrument) {
- #ifdef DEBUG_INSTRUMENTS
- fprintf(stderr, "No Mem for Instruments!\n");
- #endif
- free(insoffs);
- free(samoffs);
- free(patoffs);
- destroy_it(j);
- return NULL;
- }
- memset(j->Instrument, 0, j->NumInstruments * sizeof(MODULE_INSTRUMENT));
-
- for (i = 0; i < j->NumInstruments; i++) {
-
- if (tver2 < 0x200)
- j = load_old_instrument(file, insoffs[i], j, i);
- else
- j = load_instrument(file, insoffs[i], j, i);
-
- if (!j) {
- free(insoffs);
- free(samoffs);
- free(patoffs);
- return NULL;
- }
- }
- }
-
- if (j->NumSamples) {
- j->Sample = malloc(j->NumSamples * sizeof(MODULE_SAMPLE));
-
- if (!j->Sample) {
- #ifdef DEBUG_SAMPLES
- fprintf(stderr, "No Mem for Samples!\n");
- #endif
- free(insoffs);
- free(samoffs);
- free(patoffs);
- destroy_it(j);
- return NULL;
- }
- memset(j->Sample, 0, j->NumSamples * sizeof(MODULE_SAMPLE));
-
- for (i=0; i<j->NumSamples; i++) {
-
- j = load_it_sample(file, samoffs[i], j, i);
-
- if (!j) {
- free(insoffs);
- free(samoffs);
- free(patoffs);
- return NULL;
- }
- }
- }
-
- if (j->NumPatterns) {
- j->Pattern = malloc(j->NumPatterns * sizeof(MODULE_PATTERN));
-
- if (!j->Pattern) {
- #ifdef DEBUG_PATTERNS
- fprintf(stderr, "No Mem for Patterns!\n");
- #endif
- free(insoffs);
- free(samoffs);
- free(patoffs);
- destroy_it(j);
- return NULL;
- }
- memset(j->Pattern, 0, j->NumPatterns * sizeof(MODULE_PATTERN));
-
- for (i = 0; i < j->NumPatterns; i++) {
-
- j = load_pattern(file, patoffs[i], j, i);
-
- if (!j) {
- free(insoffs);
- free(samoffs);
- free(patoffs);
- return NULL;
- }
- }
- }
-
- if (insoffs)
- free(insoffs);
- if (samoffs)
- free(samoffs);
- if (patoffs)
- free(patoffs);
-
- return j;
-}
-
-
-
-/* ----------------- */
-
-
-
-#define DUH_SIGNATURE AL_ID('D', 'U', 'H', '!')
-
-
-
-#define SIGTYPE_SAMPLE AL_ID('S', 'A', 'M', 'P')
-
-#define SAMPFLAG_16BIT 1 /* sample in file is 16 bit, rather than 8 bit */
-#define SAMPFLAG_LOOP 2 /* loop indefinitely */
-#define SAMPFLAG_XLOOP 4 /* loop x times; only relevant if LOOP not set */
-#define SAMPFLAG_PINGPONG 8 /* loop back and forth, if LOOP or XLOOP set */
-
-/* SAMPPARAM_N_LOOPS: add 'value' iterations to the loop. 'value' is assumed
- * to be positive.
- */
-#define SAMPPARAM_N_LOOPS 0
-
-
-
-#define SIGTYPE_COMBINING AL_ID('C', 'O', 'M', 'B')
-
-
-
-#define SIGTYPE_STEREOPAN AL_ID('S', 'P', 'A', 'N')
-
-#define SPANPARAM_PAN 0
-
-
-
-#define SIGTYPE_SEQUENCE AL_ID('S', 'E', 'Q', 'U')
-
-#define SEQUENCE_START_SIGNAL 0
-#define SEQUENCE_SET_VOLUME 1
-#define SEQUENCE_SET_PITCH 2
-#define SEQUENCE_SET_PARAMETER 3
-#define SEQUENCE_STOP_SIGNAL 4
-
-
-
-void write_sample(MODULE_SAMPLE *sample, PACKFILE *f, int channel)
-{
- long size = sample->SampleLength;
- long i;
- int flags = 0;
- long loop_start = 0, loop_end = 0;
-
- SAMPLE *smp = sample->Sample;
-
- pack_mputl(SIGTYPE_SAMPLE, f);
-
-#ifdef STEREO_SAMPLES_COUNT_AS_TWO
- if (sample->Flag & SAMPLE_STEREO) {
- ASSERT((size & 1) == 0);
- size >>= 1;
- }
-#endif
-
-#ifdef SUSTAIN_LOOP_OVERRIDES_NORMAL_LOOP
- if (sample->Flag & SAMPLE_USESUSTAINLOOP) {
- flags |= SAMPFLAG_XLOOP;
- if (sample->Flag & SAMPLE_PINGPONGSUSTAINLOOP)
- flags |= SAMPFLAG_PINGPONG;
- } else if (sample->Flag & SAMPLE_USELOOP) {
- flags |= SAMPFLAG_LOOP;
- if (sample->Flag & SAMPLE_PINGPONGLOOP)
- flags |= SAMPFLAG_PINGPONG;
- }
-#else
- if (sample->Flag & SAMPLE_USELOOP) {
- flags |= SAMPFLAG_LOOP;
- if (sample->Flag & SAMPLE_PINGPONGLOOP)
- flags |= SAMPFLAG_PINGPONG;
- } else if (sample->Flag & SAMPLE_USESUSTAINLOOP) {
- flags |= SAMPFLAG_XLOOP;
- if (sample->Flag & SAMPLE_PINGPONGSUSTAINLOOP)
- flags |= SAMPFLAG_PINGPONG;
- }
-#endif
-
- if (flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP)) {
- if (flags & SAMPFLAG_LOOP) {
- loop_start = sample->LoopBegin;
- loop_end = sample->LoopEnd;
- } else {
- loop_start = sample->SustainLoopBegin;
- loop_end = sample->SustainLoopEnd;
- }
-
-#ifdef STEREO_SAMPLES_COUNT_AS_TWO
- if (sample->Flag & SAMPLE_STEREO) {
- ASSERT(((loop_start | loop_end) & 1) == 0);
- loop_start >>= 1;
- loop_end >>= 1;
- }
-#endif
-
- if (loop_end > size)
- loop_end = size;
- else if (flags & SAMPFLAG_LOOP)
- size = loop_end;
- }
-
- pack_iputl(size, f);
-
- if (smp->bits == 16)
- flags |= SAMPFLAG_16BIT;
-
- pack_putc(flags, f);
-
- if (flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP)) {
- pack_iputl(loop_start, f);
- if (!(flags & SAMPFLAG_LOOP))
- pack_iputl(loop_end, f);
- }
-
- if (flags & SAMPFLAG_16BIT) {
-
- if (smp->stereo) {
- for (i = 0; i < size; i++)
- pack_iputw(((unsigned short *)smp->data)[(i << 1) + channel] ^ 0x8000, f);
- } else {
- for (i = 0; i < size; i++)
- pack_iputw(((unsigned short *)smp->data)[i] ^ 0x8000, f);
- }
-
- } else {
-
- if (smp->stereo) {
- /* TEMPORARY CHANNEL COMBINING */
- for (i = 0; i < size; i++)
- pack_putc(((unsigned char *)smp->data)[(i << 1) + channel] ^ 0x80, f);
- } else {
- for (i = 0; i < size; i++)
- pack_putc(((unsigned char *)smp->data)[i] ^ 0x80, f);
- }
-
- }
-}
-
-
-
-int sample_is_valid(MODULE_SAMPLE *sample)
-{
- if (!(sample->Flag & SAMPLE_HASSAMPLE))
- return 0;
-
- if (sample->SampleLength <= 0)
- return 0;
-
-#ifdef SUSTAIN_LOOP_OVERRIDES_NORMAL_LOOP
- if ((sample->Flag & (SAMPLE_USELOOP | SAMPLE_USESUSTAINLOOP)) == SAMPLE_USELOOP)
-#else
- if (sample->Flag & SAMPLE_USELOOP)
-#endif
- if (sample->LoopEnd <= 0)
- return 0;
-
- return 1;
-}
-
-
-
-#define first_sample 1
-
-
-
-void write_mono_sample(MODULE_SAMPLE *sample, int n_samples, PACKFILE *f)
-{
- pack_mputl(SIGTYPE_STEREOPAN, f);
-
- /* Refer to the next sample. */
- pack_iputl(first_sample + n_samples + 1, f);
-
- write_sample(sample, f, 0);
-}
-
-
-
-void write_stereo_sample(MODULE_SAMPLE *sample, int n_samples, PACKFILE *f)
-{
- pack_mputl(SIGTYPE_COMBINING, f);
-
- /* Two samples. */
- pack_putc(2, f);
-
- /* Refer to the next two samples. */
- pack_iputl(first_sample + n_samples + 1, f);
- pack_iputl(first_sample + n_samples + 2, f);
-
- write_sample(sample, f, 0);
- write_sample(sample, f, 1);
-}
-
-
-
-unsigned char *seqdata = NULL;
-int seqpos = 0;
-int max_seqdata = 0;
-
-int seqtime = 0;
-
-int songtime;
-
-
-
-void sequence_c(int v)
-{
- if (seqpos >= max_seqdata) {
- max_seqdata += 1024;
- seqdata = realloc(seqdata, max_seqdata);
- if (!seqdata) {
- errno = ENOMEM;
- return;
- }
- }
- seqdata[seqpos++] = v;
-}
-
-
-void sequence_w(int v)
-{
- sequence_c(v);
- sequence_c(v >> 8);
-}
-
-
-void sequence_l(long v)
-{
- sequence_c(v);
- sequence_c(v >> 8);
- sequence_c(v >> 16);
- sequence_c(v >> 24);
-}
-
-
-void sequence_cl(unsigned long v)
-{
- int byte_count = 0;
-
- while (byte_count < 4 && v >= 128) {
- sequence_c(v | 128);
- v >>= 7;
- byte_count++;
- }
-
- sequence_c(v & 127);
-}
-
-
-
-void write_seqtime() {
- sequence_cl(seqtime);
- seqtime = 0;
-}
-
-
-
-int *sample_signal = NULL;
-
-
-
-void calculate_pan(MODULE *module, MODULE_CHANNEL *channel)
-{
- int samp;
-
- if (module->Flags & FLAG_USEINSTRUMENTS && channel->Instrument >= 1 && channel->Instrument <= module->NumInstruments) {
- MODULE_INSTRUMENT *instrument = &module->Instrument[(int)channel->Instrument - 1];
- if (instrument) {
- unsigned char note = instrument->NoteNote[channel->Note];
- samp = instrument->NoteSample[channel->Note];
- if (instrument->DefaultPan <= 64)
- channel->Pan = instrument->DefaultPan;
- channel->PanSep = (note - instrument->PitchPanCenter) * instrument->PitchPanSeparation / 8;
- } else {
- samp = 0;
- channel->PanSep = 0;
- }
- } else {
- samp = channel->Instrument;
- channel->PanSep = 0;
- }
-
- if (samp >= 1 && samp <= module->NumSamples) {
- int pan = module->Sample[samp - 1].DefaultPanning;
- if (pan >= 128 && pan <= 192)
- channel->Pan = pan - 128;
- }
-}
-
-
-
-/* This function assumes note->Channel >= 0. */
-void process_note_data(MODULE *module, MODULE_NOTE *note)
-{
- MODULE_CHANNEL *channel = &module->Channel[(int)note->Channel];
-
- if (note->Mask & NOTEMASK_NOTE) {
- if (note->Note >= 120) {
- channel->Note = note->Note;
- } else if (channel->Note >= 120) {
- channel->Note = note->Note;
- channel->Flag |= CHANNEL_RETRIG;
- } else {
- channel->Note = note->Note;
- if ((note->Mask & NOTEMASK_VOLPAN) == 0 ||
- !(note->VolPan >= 193 && note->VolPan <= 202))
- {
- if ((note->Mask & NOTEMASK_COMMAND) == 0 ||
- (note->Command != IT_TONE_PORTAMENTO &&
- note->Command != IT_VOLSLIDE_TONEPORTA))
- {
- channel->Flag |= CHANNEL_RETRIG;
- }
- }
- }
- }
-
- if (note->Mask & NOTEMASK_INSTRUMENT) {
- if (note->Instrument != channel->Instrument) {
- channel->Flag |= CHANNEL_RETRIG;
- channel->Instrument = note->Instrument;
- if (!(module->Flags & FLAG_USEINSTRUMENTS)) {
- if (channel->Instrument >= 1 && channel->Instrument <= module->NumSamples)
- channel->sample = &module->Sample[channel->Instrument - 1];
- else
- channel->sample = NULL;
- }
- }
- }
-
- if (module->Flags & FLAG_USEINSTRUMENTS) {
- if (channel->Instrument >= 1 && channel->Instrument <= module->NumInstruments) {
- int samp = module->Instrument[(int)channel->Instrument - 1].NoteSample[channel->Note];
- if (samp >= 1 && samp <= module->NumSamples)
- channel->sample = &module->Sample[samp - 1];
- else
- channel->sample = NULL;
- } else
- channel->sample = NULL;
- }
-
- if (channel->Flag & CHANNEL_RETRIG)
- calculate_pan(module, channel);
-
- if (note->Mask & NOTEMASK_INSTRUMENT)
- if (channel->sample)
- channel->Volume = channel->sample->DefaultVolume;
-
- if (!channel->sample)
- channel->Flag &= ~CHANNEL_RETRIG;
-
- if (note->Mask & NOTEMASK_VOLPAN) {
- if (note->VolPan <= 64)
- channel->Volume = note->VolPan;
- else if (note->VolPan <= 74) {
- unsigned char v = note->VolPan - 65;
- if (v == 0)
- v = channel->lastvolslide;
- channel->lastvolslide = v;
- /* = effect DxF where x == note->VolPan - 65 */
- channel->Volume += v;
- if (channel->Volume > 64) channel->Volume = 64;
-
- } else if (note->VolPan <= 84) {
- unsigned char v = note->VolPan - 75;
- if (v == 0)
- v = channel->lastvolslide;
- channel->lastvolslide = v;
- /* = effect DFx where x == note->VolPan - 75 */
- channel->Volume -= v;
- if (channel->Volume > 64) channel->Volume = 0;
- } else if (note->VolPan <= 94) {
- unsigned char v = note->VolPan - 85;
- if (v == 0)
- v = channel->lastvolslide;
- channel->lastvolslide = v;
- /* = effect Dx0 where x == note->VolPan - 85 */
- channel->volslide = v;
- } else if (note->VolPan <= 104) {
- unsigned char v = note->VolPan - 95;
- if (v == 0)
- v = channel->lastvolslide;
- channel->lastvolslide = v;
- /* = effect D0x where x == note->VolPan - 95 */
- channel->volslide = -v;
- } else if (note->VolPan <= 114) {
- unsigned char v = (note->VolPan - 105) << 2;
- if (v == 0)
- v = channel->lastEF;
- channel->lastEF = v;
- channel->portamento -= v << 4;
- } else if (note->VolPan <= 124) {
- unsigned char v = (note->VolPan - 115) << 2;
- if (v == 0)
- v = channel->lastEF;
- channel->lastEF = v;
- channel->portamento += v << 4;
- } else if (note->VolPan < 128) { }
- else if (note->VolPan <= 192)
- channel->Pan = note->VolPan - 128;
- else if (note->VolPan <= 202) {
- //Tone Portamento
- /* Affects G's memory. Has the equivalent slide given by this
- * table:
- */
- static unsigned char SlideTable[] = {0, 1, 4, 8, 16, 32, 64, 96, 128, 255};
-
- unsigned char v = SlideTable[note->VolPan - 193];
- if (module->Flags & FLAG_COMPATIBLEGXX) {
- if (v == 0)
- v = channel->lastG;
- channel->lastG = v;
- } else {
- if (v == 0)
- v = channel->lastEF;
- channel->lastEF = v;
- }
- channel->toneporta += v << 4;
- } else if (note->VolPan <= 212)
- ;//Vibrato
- /* This uses the same 'memory' as Hxx/Uxx. */
- }
-
- if (note->Mask & NOTEMASK_COMMAND) {
- //Interpret effect
- //unsigned char note->Command, note->CommandValue
- switch (note->Command) {
-/*
-Notes about effects (as compared to other module formats)
-
-C This is now in *HEX*. (Used to be in decimal in ST3)
-E/F/G/H/U You need to check whether the song uses Amiga/Linear slides.
-H/U Vibrato in Impulse Tracker is two times finer than in
- any other tracker and is updated EVERY tick.
- If "Old Effects" is *ON*, then the vibrato is played in the
- normal manner (every non-row tick and normal depth)
-E/F/G These commands ALL share the same memory.
-Oxx Offsets to samples are to the 'xx00th' SAMPLE. (ie. for
- 16 bit samples, the offset is xx00h*2)
- Oxx past the sample end will be ignored, unless "Old Effects"
- is ON, in which case the Oxx will play from the end of the
- sample.
-Yxy This uses a table 4 times larger (hence 4 times slower) than
- vibrato or tremelo. If the waveform is set to random, then
- the 'speed' part of the command is interpreted as a delay.
-*/
- case IT_SET_SPEED: if (note->CommandValue) {module->tick = module->Speed = note->CommandValue;} break;
- //case IT_JUMP_TO_ORDER: module->processorder = note->CommandValue - 1; module->processrow = 0xFFFE; break;
- //IT_JUMP_TO_ORDER would most likely be used to jump back, so it must be handled specially.
- case IT_BREAK_TO_ROW: module->breakrow = note->CommandValue; module->processrow = 0xFFFE; break;
- case IT_VOLUME_SLIDE:
- {
- unsigned char v = note->CommandValue;
- if (v == 0)
- v = channel->lastDKL;
- channel->lastDKL = v;
- if ((v & 0x0F) == 0) { /* Dx0 */
- channel->volslide = v >> 4;
- if (channel->volslide == 15) {
- channel->Volume += 15;
- if (channel->Volume > 64) channel->Volume = 64;
- }
- } else if ((v & 0xF0) == 0) { /* D0x */
- channel->volslide = -v;
- if (channel->volslide == -15) {
- channel->Volume -= 15;
- if (channel->Volume > 64) channel->Volume = 0;
- }
- } else if ((v & 0x0F) == 0x0F) { /* DxF */
- channel->Volume += v >> 4;
- if (channel->Volume > 64) channel->Volume = 64;
- } else if ((v & 0xF0) == 0xF0) { /* DFx */
- channel->Volume -= v & 15;
- if (channel->Volume > 64) channel->Volume = 0;
- }
- }
- break;
- case IT_PORTAMENTO_DOWN:
- {
- unsigned char v = note->CommandValue;
- if (v == 0)
- v = channel->lastEF;
- channel->lastEF = v;
- channel->portamento -= v << 4;
- }
- break;
- case IT_PORTAMENTO_UP:
- {
- unsigned char v = note->CommandValue;
- if (v == 0)
- v = channel->lastEF;
- channel->lastEF = v;
- channel->portamento += v << 4;
- }
- break;
- case IT_TONE_PORTAMENTO:
- {
- unsigned char v = note->CommandValue;
- if (module->Flags & FLAG_COMPATIBLEGXX) {
- if (v == 0)
- v = channel->lastG;
- channel->lastG = v;
- } else {
- if (v == 0)
- v = channel->lastEF;
- channel->lastEF = v;
- }
- channel->toneporta += v << 4;
- }
- break;
- //case IT_VIBRATO:
- //case IT_TREMOR:
- //case IT_ARPEGGIO:
- //case IT_VOLSLIDE_VIBRATO:
- //case IT_VOLSLIDE_TONEPORTA:
- case IT_SET_CHANNEL_VOLUME:
- if (note->CommandValue <= 64)
- channel->ChannelVolume = note->CommandValue;
-#ifdef VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
- else
- channel->ChannelVolume = 64;
-#endif
- break;
- case IT_CHANNEL_VOLUME_SLIDE:
- {
- unsigned char v = note->CommandValue;
- if (v == 0)
- v = channel->lastN;
- channel->lastN = v;
- if ((v & 0x0F) == 0) { /* Nx0 */
- channel->channelvolslide = v >> 4;
- } else if ((v & 0xF0) == 0) { /* N0x */
- channel->channelvolslide = -v;
- } else if ((v & 0x0F) == 0x0F) { /* NxF */
- channel->ChannelVolume += v >> 4;
- if (channel->ChannelVolume > 64) channel->ChannelVolume = 64;
- } else if ((v & 0xF0) == 0xF0) { /* NFx */
- channel->ChannelVolume -= v & 15;
- if (channel->ChannelVolume > 64) channel->ChannelVolume = 0;
- }
- }
- break;
- //case IT_SET_SAMPLE_OFFSET:
- //case IT_PANNING_SLIDE:
- //case IT_RETRIGGER_NOTE:
- //case IT_TREMOLO:
- case IT_S:
- switch (note->CommandValue >> 4) {
- //case IT_S_SET_FILTER:
- //case IT_S_SET_GLISSANDO_CONTROL:
- //case IT_S_FINETUNE:
- //case IT_S_SET_VIBRATO_WAVEFORM:
- //case IT_S_SET_TREMOLO_WAVEFORM:
- //case IT_S_SET_PANBRELLO_WAVEFORM:
- /* Waveforms for commands S3x, S4x and S5x:
- * 0: Sine wave
- * 1: Ramp down
- * 2: Square wave
- * 3: Random wave
- */
- //case IT_S7:
- case IT_S_SET_PAN:
- channel->Pan = ((note->CommandValue & 15) << 2) | ((note->CommandValue & 15) >> 2);
- break;
- //case IT_S_SET_SURROUND_SOUND:
- /* S91 Set surround sound */
- //case IT_S_SET_HIGH_OFFSET:
- /* SAy Set high value of sample offset yxx00h */
- //case IT_S_PATTERN_LOOP:
- /* SB0 Set loopback point */
- //case IT_S_DELAYED_NOTE_CUT:
- //case IT_S_NOTE_DELAY:
- /* SEx Pattern delay for x rows */
- //case IT_S_SET_MIDI_MACRO:
- }
- break;
- case IT_SET_SONG_TEMPO:
- {
- unsigned char v = note->CommandValue;
- if (v == 0)
- v = channel->lastW;
- channel->lastW = v;
- if (v < 0x10)
- module->temposlide = -v;
- else if (v < 0x20)
- module->temposlide = v & 15;
- else
- module->Tempo = v;
- }
- break;
- //case IT_FINE_VIBRATO:
- case IT_SET_GLOBAL_VOLUME:
- if (note->CommandValue <= 128)
- module->GlobalVolume = note->CommandValue;
-#ifdef VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
- else
- module->GlobalVolume = 128;
-#endif
- break;
- case IT_GLOBAL_VOLUME_SLIDE:
- {
- unsigned char v = note->CommandValue;
- if (v == 0)
- v = channel->lastW;
- channel->lastW = v;
- if ((v & 0x0F) == 0) { /* Nx0 */
- module->globalvolslide = v >> 4;
- } else if ((v & 0xF0) == 0) { /* N0x */
- module->globalvolslide = -v;
- } else if ((v & 0x0F) == 0x0F) { /* NxF */
- module->GlobalVolume += v >> 4;
- if (module->GlobalVolume > 64) module->GlobalVolume = 64;
- } else if ((v & 0xF0) == 0xF0) { /* NFx */
- module->GlobalVolume -= v & 15;
- if (module->GlobalVolume > 64) module->GlobalVolume = 0;
- }
- }
- break;
- case IT_SET_PANNING:
- channel->Pan = (note->CommandValue + 2) >> 2;
- break;
- //case IT_PANBRELLO:
- //case IT_MIDI_MACRO://see MIDI.TXT
- }
- }
-}
-
-
-
-void update_effects(MODULE *module)
-{
- int i;
-
- module->GlobalVolume += module->globalvolslide;
- if (module->GlobalVolume > 128) {
- if (module->globalvolslide >= 0)
- module->GlobalVolume = 128;
- else
- module->GlobalVolume = 0;
- }
-
- module->Tempo += module->temposlide;
- if (module->Tempo < 32) {
- if (module->temposlide >= 0)
- module->Tempo = 255;
- else
- module->Tempo = 32;
- }
-
- for (i = 0; i < 64; i++) {
- MODULE_CHANNEL *channel = &module->Channel[i];
-
- channel->Volume += channel->volslide;
- if (channel->Volume > 64) {
- if (channel->volslide >= 0)
- channel->Volume = 64;
- else
- channel->Volume = 0;
- }
-
- channel->ChannelVolume += channel->channelvolslide;
- if (channel->ChannelVolume > 64) {
- if (channel->channelvolslide >= 0)
- channel->ChannelVolume = 64;
- else
- channel->ChannelVolume = 0;
- }
-
- channel->pitch += channel->portamento;
- //We do not enforce any limits here. IT surely does. Investigate.
-
- if (channel->toneporta && channel->sample) {
- int destpitch;
- if (module->Flags & FLAG_USEINSTRUMENTS)
- destpitch = module->Instrument[(int)channel->Instrument - 1].NoteNote[channel->Note];
- else
- destpitch = channel->Note;
- destpitch = (destpitch - 60) << 8;
- if (channel->pitch > destpitch) {
- channel->pitch -= channel->toneporta;
- if (channel->pitch < destpitch)
- channel->pitch = destpitch;
- } else if (channel->pitch < destpitch) {
- channel->pitch += channel->toneporta;
- if (channel->pitch > destpitch)
- channel->pitch = destpitch;
- }
- }
- }
-}
-
-
-
-void reset_effects(MODULE *module)
-{
- int i;
-
- module->globalvolslide = 0;
- module->temposlide = 0;
-
- for (i = 0; i < 64; i++) {
- module->Channel[i].volslide = 0;
- module->Channel[i].channelvolslide = 0;
- module->Channel[i].portamento = 0;
- module->Channel[i].toneporta = 0;
- }
-}
-
-
-
-/* This function assumes note->Channel >= 0... or it might later. */
-void update_pattern_variables(MODULE *module, MODULE_NOTE *note)
-{
- /* MODULE_CHANNEL *channel = &module->Channel[(int)note->Channel]; */
-
- if (note->Mask & NOTEMASK_COMMAND) {
- switch (note->Command) {
- case IT_S:
- switch (note->CommandValue >> 4) {
- case IT_S_FINE_PATTERN_DELAY: module->tick = module->Speed + (note->CommandValue & 15); break;
- //case IT_S7:
- //case IT_S_PATTERN_LOOP:
- /* SB0 Set loopback point */
- //case IT_S_DELAYED_NOTE_CUT:
- //case IT_S_NOTE_DELAY:
- case IT_S_PATTERN_DELAY: module->rowcount = 1 + (note->CommandValue & 15); break;
- }
- break;
- }
- }
-}
-
-
-
-unsigned char envelope_get_y(MODULE_ENVELOPE *envelope, MODULE_VENVELOPE *venvelope)
-{
- int ys, ye;
- int ts, te;
- int t;
-
- if (venvelope->NextNode <= 0)
- return envelope->NodeY[0];
-
- if (venvelope->NextNode >= envelope->NumNodes)
- return envelope->NodeY[envelope->NumNodes - 1];
-
- ys = envelope->NodeY[venvelope->NextNode - 1];
- ye = envelope->NodeY[venvelope->NextNode];
- ts = envelope->NodeTick[venvelope->NextNode - 1];
- te = envelope->NodeTick[venvelope->NextNode];
- t = venvelope->CurTick;
-
- if (ts == te)
- return ys;
-
- return ys + (ye - ys) * (t - ts) / (te - ts);
-}
-
-
-
-unsigned int calculate_volume(MODULE *module, MODULE_VCHANNEL *vchannel)
-{
- if (module->Flags & FLAG_USEINSTRUMENTS) {
- int vev = 64;
- if (module->Instrument[vchannel->Instrument - 1].VolumeEnvelope.Flag & ENVELOPE_ON)
- vev = envelope_get_y(&module->Instrument[vchannel->Instrument - 1].VolumeEnvelope, &vchannel->VVolEnv);
- return (((((((vchannel->Volume *
- vchannel->sample->GlobalVolume *
- module->Instrument[vchannel->Instrument - 1].GlobalVolume) >> 7) *
- module->GlobalVolume) >> 11) *
- vev *
- module->MixVolume) >> 10) *
- vchannel->fadeoutcount) >> 11;
- }
-
- return (((vchannel->Volume *
- vchannel->sample->GlobalVolume *
- module->GlobalVolume) >> 11) *
- module->MixVolume) >> 5;
-}
-
-
-
-void process_channels(MODULE *module)
-{
- int i;
-
- for (i = 0; i < 64; i++) {
- MODULE_CHANNEL *channel = &module->Channel[i];
- if (channel->Note < 120) {
- if (channel->Flag & CHANNEL_RETRIG) {
- channel->Flag &= ~CHANNEL_RETRIG;
- if (channel->VChannel) {
- if (!(module->Flags & FLAG_USEINSTRUMENTS) ||
- (channel->VChannel->NNA = module->Instrument[channel->VChannel->Instrument - 1].NewNoteAction)
- == NNA_NOTECUT)
- {
- if (channel->VChannel->Flag & VCHANNEL_PLAYING) {
- write_seqtime();
- sequence_c(SEQUENCE_STOP_SIGNAL);
- sequence_c(channel->VChannel - module->VChannel);
- }
- } else {
- if (channel->VChannel->NNA == NNA_NOTEOFF)
- if ((module->Instrument[channel->VChannel->Instrument - 1].VolumeEnvelope.Flag & (ENVELOPE_ON | ENVELOPE_LOOP_ON)) != ENVELOPE_ON)
- channel->VChannel->NNA = NNA_NOTEFADE;
- if (channel->VChannel->NNA == NNA_NOTEFADE)
- channel->VChannel->Flag |= VCHANNEL_FADING;
- channel->VChannel->Flag |= VCHANNEL_BACKGROUND;
- channel->VChannel->channel = NULL;
- channel->VChannel = NULL;
- }
- }
- if (!channel->VChannel) {
- int k;
- for (k = 0; k < 256; k++) {
- if (!(module->VChannel[k].Flag & VCHANNEL_PLAYING)) {
- channel->VChannel = &module->VChannel[k];
- break;
- }
- }
- if (!channel->VChannel) {
- for (k = 0; k < 256; k++) {
- if (module->VChannel[k].Flag & VCHANNEL_BACKGROUND) {
- write_seqtime();
- sequence_c(SEQUENCE_STOP_SIGNAL);
- sequence_c(k);
- channel->VChannel = &module->VChannel[k];
- break;
- }
- }
- }
- }
- if (channel->VChannel) {
- unsigned char note;
- channel->VChannel->Flag = VCHANNEL_PLAYING | VCHANNEL_RETRIG;
- channel->VChannel->channel = channel;
- channel->VChannel->Note = channel->Note;
- if (module->Flags & FLAG_USEINSTRUMENTS)
- note = module->Instrument[(int)channel->Instrument - 1].NoteNote[channel->Note];
- else
- note = channel->Note;
- channel->pitch = (note - 60) << 8;
- channel->VChannel->pitch = channel->pitch;
- channel->VChannel->Instrument = channel->Instrument;
- channel->VChannel->sample = channel->sample;
- channel->VChannel->VVolEnv.NextNode = 0;
- channel->VChannel->VVolEnv.CurTick = 0;
- channel->VChannel->fadeoutcount = 1024;
- channel->VChannel->NNA = NNA_NOTECONTINUE;
- channel->VChannel->Volume = channel->ChannelVolume * channel->Volume;
- channel->VChannel->Pan = channel->Pan;
- channel->VChannel->PanSep = channel->PanSep;
- /* Note: The DUH* fields are set when writing the start command to the DUH sequence. */
- //BLEARGH: Anything else to initialise?
- }
- }
- } else if (channel->VChannel) {
- if (channel->Note == NOTE_CUT) {
- if (channel->VChannel->Flag & VCHANNEL_PLAYING) {
- write_seqtime();
- sequence_c(SEQUENCE_STOP_SIGNAL);
- sequence_c(channel->VChannel - module->VChannel);
- channel->VChannel->Flag &= ~VCHANNEL_PLAYING;
- channel->VChannel->channel = NULL;
- channel->VChannel = NULL;
- }
- } else {
- channel->VChannel->Flag |= VCHANNEL_BACKGROUND;
-
- if (channel->Note == NOTE_OFF) {
- if ((module->Instrument[channel->VChannel->Instrument - 1].VolumeEnvelope.Flag & (ENVELOPE_ON | ENVELOPE_LOOP_ON)) != ENVELOPE_ON)
- channel->VChannel->NNA = NNA_NOTEFADE;
- else
- channel->VChannel->NNA = NNA_NOTEOFF;
- } else
- channel->VChannel->NNA = NNA_NOTEFADE;
-
- if (channel->VChannel->NNA == NNA_NOTEFADE)
- channel->VChannel->Flag |= VCHANNEL_FADING;
- /*
- channel->VChannel->channel = NULL;
- channel->VChannel = NULL;
- */
- }
- }
- }
-}
-
-
-
-/* This returns 1 if the envelope finishes. */
-int update_envelope(MODULE_VCHANNEL *vchannel, MODULE_ENVELOPE *envelope, MODULE_VENVELOPE *venvelope)
-{
- if (!(envelope->Flag & ENVELOPE_ON))
- return 0;
-
- if (venvelope->NextNode >= envelope->NumNodes)
- return 1;
-
- while (venvelope->CurTick >= envelope->NodeTick[venvelope->NextNode]) {
- if ((envelope->Flag & ENVELOPE_LOOP_ON) && venvelope->NextNode == envelope->LoopEnd) {
- venvelope->NextNode = envelope->LoopBegin;
- venvelope->CurTick = envelope->NodeTick[envelope->LoopBegin];
- return 0;
- }
- if ((envelope->Flag & ENVELOPE_SUSTAINLOOP) && !(vchannel->Flag & VCHANNEL_BACKGROUND) && venvelope->NextNode == envelope->SustainLoopEnd) {
- venvelope->NextNode = envelope->SustainLoopBegin;
- venvelope->CurTick = envelope->NodeTick[envelope->SustainLoopBegin];
- return 0;
- }
- if (venvelope->NextNode >= envelope->NumNodes)
- return 1;
-
- venvelope->NextNode++;
- }
-
- venvelope->CurTick++;
-
- return 0;
-}
-
-
-
-/* This assumes the module uses instruments. */
-void update_envelopes(MODULE *module, MODULE_VCHANNEL *vchannel)
-{
- if (vchannel->Flag & VCHANNEL_PLAYING) {
- MODULE_ENVELOPE *volenv = &module->Instrument[vchannel->Instrument - 1].VolumeEnvelope;
-
- if (update_envelope(vchannel, volenv, &vchannel->VVolEnv)) {
- if (volenv->NumNodes && volenv->NodeY[volenv->NumNodes - 1] == 0) {
- write_seqtime();
- sequence_c(SEQUENCE_STOP_SIGNAL);
- sequence_c(vchannel - module->VChannel);
- vchannel->Flag = 0;
- if (vchannel->channel)
- vchannel->channel->VChannel = NULL;
- vchannel->channel = NULL;
- } else
- vchannel->Flag |= VCHANNEL_FADING;
- }
- }
-}
-
-
-
-/* This assumes the module uses instruments. */
-void update_fadeout(MODULE *module, MODULE_VCHANNEL *vchannel)
-{
- if (vchannel->Flag & VCHANNEL_PLAYING) {
- if (vchannel->Flag & VCHANNEL_FADING) {
- vchannel->fadeoutcount -= module->Instrument[vchannel->Instrument - 1].FadeOut;
-
- if (vchannel->fadeoutcount <= 0) {
- write_seqtime();
- sequence_c(SEQUENCE_STOP_SIGNAL);
- sequence_c(vchannel - module->VChannel);
- vchannel->Flag = 0;
- if (vchannel->channel)
- vchannel->channel->VChannel = NULL;
- vchannel->channel = NULL;
- }
- }
- }
-}
-
-
-
-#define INCLUDE_RETRIG
-#define INCLUDE_PLAYING
-void process_vchannels(MODULE *module)
-{
- int i;
-
- for (i = 0; i < 256; i++) {
- MODULE_VCHANNEL *vchannel = &module->VChannel[i];
-
- if ((vchannel->Flag & VCHANNEL_PLAYING) && vchannel->channel) {
- vchannel->Volume = vchannel->channel->ChannelVolume * vchannel->channel->Volume;
- vchannel->Pan = vchannel->channel->Pan;
- vchannel->PanSep = vchannel->channel->PanSep;
- }
-
- if (module->Flags & FLAG_USEINSTRUMENTS) {
- //Update envelopes as required
- update_envelopes(module, vchannel);
- //Update fadeout as required
- update_fadeout(module, vchannel);
- //Calculate final volume if req
- //Calculate final pan if req
- //Process sample vibrato if req
- } else {
- //Calculate final volume if required
- //Calculate final pan if required
- //Process sample vibrato if required
- }
-
-#ifdef INCLUDE_RETRIG
- if (vchannel->Flag & VCHANNEL_RETRIG) {
- vchannel->Flag &= ~VCHANNEL_RETRIG;
-
- if (vchannel->sample) {
- int C5Speed = vchannel->sample->C5Speed;
- int adjust;
-
-#ifdef STEREO_SAMPLES_COUNT_AS_TWO
- if (vchannel->sample->Flag & SAMPLE_STEREO)
- C5Speed >>= 1;
-#endif
-
- write_seqtime();
- sequence_c(SEQUENCE_START_SIGNAL);
- sequence_c(vchannel - module->VChannel);
-
- sequence_cl(sample_signal[vchannel->sample - module->Sample]);
- sequence_cl(0); // sample position: 65536 is one second
-
- vchannel->DUHvol = calculate_volume(module, vchannel);
-
- sequence_w(vchannel->DUHvol - (vchannel->DUHvol >> 16));
-
- adjust = floor(12 * 256 *
- (log(C5Speed / 65536.0) / log(2.0)) + 0.5);
-
- /* pitch */
- sequence_w(adjust + vchannel->pitch);
-
- vchannel->DUHpan = 32;
-
- } else
- vchannel->Flag = 0;
- }
-#endif
-
-#ifdef INCLUDE_PLAYING
- if (vchannel->Flag & VCHANNEL_PLAYING) {
- //Update to vchannel->channel->stuff if different from vchannel->stuff.
- //stuff would be volume, panning, pitch, etc.
- {
- unsigned int volume = calculate_volume(module, vchannel);
- if (volume != vchannel->DUHvol) {
- vchannel->DUHvol = volume;
- write_seqtime();
- sequence_c(SEQUENCE_SET_VOLUME);
- sequence_c(vchannel - module->VChannel);
- sequence_w(volume - (volume >> 16));
- }
- }
- {
- int pan = vchannel->Pan + vchannel->PanSep;
- if (pan < 0)
- pan = 0;
- else if (pan > 64)
- pan = 64;
- if (pan != vchannel->DUHpan) {
- vchannel->DUHpan = pan;
- write_seqtime();
- sequence_c(SEQUENCE_SET_PARAMETER);
- sequence_c(vchannel - module->VChannel);
- sequence_c(SPANPARAM_PAN);
- sequence_l(((int)pan << 3) - 256);
- }
- }
- if (vchannel->channel) {
- if (vchannel->channel->pitch != vchannel->pitch) {
- int C5Speed = vchannel->sample->C5Speed;
- int adjust;
-
-#ifdef STEREO_SAMPLES_COUNT_AS_TWO
- if (vchannel->sample->Flag & SAMPLE_STEREO)
- C5Speed >>= 1;
-#endif
-
- vchannel->pitch = vchannel->channel->pitch;
-
- write_seqtime();
- sequence_c(SEQUENCE_SET_PITCH);
- sequence_c(vchannel - module->VChannel);
-
- adjust = floor(12 * 256 *
- (log(C5Speed / 65536.0) / log(2.0)) + 0.5);
-
- sequence_w(adjust + vchannel->pitch);
- }
- }
-
- if (vchannel->Flag & VCHANNEL_BACKGROUND) {
- //Process vchannel->NNA
- //If the note has ended then:
- /*
- {
- write_seqtime();
- sequence_c(SEQUENCE_STOP_SIGNAL);
- sequence_c(vchannel - module->VChannel);
- vchannel->Flag = 0;
- }
- */
- } else {
- //Process note
- }
- }
-#endif
- }
-}
-
-
-
-void generate_patterns(MODULE *module)
-{
- int patnum = module->Order[0];
- int row;
-
- MODULE_PATTERN *pattern;
- MODULE_NOTE *note, *note_end;
-
- module->processorder = 0;
- module->processrow = 0;
- module->breakrow = 0;
- module->rowcount = 1;
-
- module->tick = module->Speed;
-
- goto start_the_loop; /* This ungainly goto will be averted later. */
-
- for (;;) {
- // Set note vol/freq to vol/freq set for each channel
-
- module->tick--;
- if (module->tick == 0) {
- module->tick = module->Speed;
- module->rowcount--;
- if (module->rowcount == 0) {
- module->rowcount = 1;
- module->processrow++;
- if (module->processrow >= pattern->NumRows) {
- module->processrow = module->breakrow;
- module->breakrow = 0;
- module->processorder++;
-
- start_the_loop:
-
- for (; ; module->processorder++) {
- if (module->processorder >= module->NumOrders)
- return;
-
- patnum = module->Order[module->processorder];
-
- if (patnum < module->NumPatterns)
- break;
-
-#ifdef INVALID_ORDERS_END_SONG
- if (patnum != ORDER_SKIP)
- return;
-#else
- if (patnum == ORDER_END)
- return;
-#endif
- }
-
- printf(" Order %i, Pattern %i\n", module->processorder, patnum);
-
- pattern = &module->Pattern[patnum];
-
- note = pattern->Note;
- note_end = note + pattern->NumNotes;
- }
-
- row = module->processrow;
-
- {
- MODULE_NOTE *note_start = note;
-
- while (note < note_end && note->Channel >= 0)
- update_pattern_variables(module, note++);
-
- note = note_start;
- }
-
- reset_effects(module);
-
- //Should this code go before updating the pattern variables?
- while (note < note_end) {
- if (note->Channel < 0) {
- note++;
- break;
- }
- process_note_data(module, note++);
- }
-
- } else
- update_effects(module);
- } else
- update_effects(module);
-
- process_channels(module);
-
- /* Output sound!!! */
- process_vchannels(module);
-
- /* Increment time by one tick. */
- {
- int inc = ((65536.0 * 60.0) / (4.0 * 6.0)) / module->Tempo;
- seqtime += inc;
- songtime += inc;
- }
- }
-}
-
-
-
-void stop_notes(MODULE *module)
-{
- int c;
- for (c = 0; c < 256; c++) {
- if (module->VChannel[c].Flag & VCHANNEL_PLAYING) {
- write_seqtime();
- sequence_c(SEQUENCE_STOP_SIGNAL);
- sequence_c(c);
- }
- }
-}
-
-
-
-void generate_sequence(MODULE *module)
-{
- int i;
-
- for (i = 0; i < 64; i++) {
- module->Channel[i].Note = 255;
- module->Channel[i].Instrument = 0;
- module->Channel[i].sample = NULL;
- module->Channel[i].VChannel = NULL;
- module->Channel[i].lastvolslide = 0;
- module->Channel[i].lastDKL = 0;
- module->Channel[i].lastN = 0;
- module->Channel[i].lastW = 0;
- module->Channel[i].lastEF = 0;
- module->Channel[i].lastG = 0;
- module->Channel[i].lastT = 0;
- }
-
- for (i = 0; i < 256; i++)
- module->VChannel[i].Flag = 0;
-
- songtime = 0;
-
- generate_patterns(module);
-/*
- for (i = 0; i < module->NumOrders; i++) {
-
- if (module->Order[i] < module->NumPatterns)
- write_pattern(module, &module->Pattern[module->Order[i]]);
- else {
-#ifdef INVALID_ORDERS_END_SONG
- if (module->Order[i] != ORDER_SKIP)
- break;
-#else
- if (module->Order[i] == ORDER_END)
- break;
-#endif
- }
- }
-*/
- stop_notes(module);
-
- /* Negative time to indicate the end of the sequence. */
- sequence_cl(-1);
-
- if (errno)
- return;
-}
-
-
-
-void write_sequence(PACKFILE *f)
-{
- pack_mputl(SIGTYPE_SEQUENCE, f);
-
- pack_iputl(seqpos, f);
- pack_fwrite(seqdata, seqpos, f);
-}
-
-
-
-void free_sequence()
-{
- free(seqdata);
- seqdata = NULL;
- seqpos = 0;
- max_seqdata = 0;
- seqtime = 0;
-}
-
-
-
-int save_it_to_duh(MODULE *module, const char *filename)
-{
- int i;
- int n_samples = 0;
-
- PACKFILE *f = pack_fopen(filename, F_WRITE_PACKED);
- if (!f) return 1;
-
- /* Write signature. */
- pack_mputl(DUH_SIGNATURE, f);
-
- /* Create array of true samples. */
- sample_signal = malloc(module->NumSamples * sizeof(*sample_signal));
-
- for (i = 0; i < module->NumSamples; i++) {
- if (sample_is_valid(&module->Sample[i])) {
- sample_signal[i] = first_sample + n_samples;
- if (module->Sample[i].Flag & SAMPLE_STEREO)
- n_samples += 3; /* COMB,SAMP,SAMP */
- else
- n_samples += 2; /* SPAN,SAMP */
- } else
- sample_signal[i] = -1;
- }
-
- printf("Generating sequence\n");
- generate_sequence(module);
-
- /* Write length of song. */
- pack_iputl(songtime, f);
-
- /* Write number of signals - one for the sequence, one for each sample. */
- pack_iputl(1 + n_samples, f);
-
- if (errno) {pack_fclose(f); free(sample_signal); return 1;}
-
- printf("Writing sequence\n");
- write_sequence(f);
- free_sequence();
-
- if (errno) {pack_fclose(f); free(sample_signal); return 1;}
-
- printf("Writing samples");
- n_samples = 0;
- for (i = 0; i < module->NumSamples; i++) {
- if ((i & 7) == 0)
- printf("\n ");
- printf("%4d", i + 1);
-
- if (sample_is_valid(&module->Sample[i])) {
-
- if (module->Sample[i].Flag & SAMPLE_STEREO) {
- write_stereo_sample(&module->Sample[i], n_samples, f);
- n_samples += 3;
- } else {
- write_mono_sample(&module->Sample[i], n_samples, f);
- n_samples += 2;
- }
-
- if (errno) {pack_fclose(f); free(sample_signal); return 1;}
- }
- }
- printf("\n");
-
- free(sample_signal);
- sample_signal = NULL;
-
- pack_fclose(f);
-
- if (errno) {pack_fclose(f); return 1;}
-
- return 0;
-}
-
-
-
-#undef first_sample
-
-
-
-void usage()
-{
- allegro_message(
- "Usage: cit.exe filename.it [filename.duh]\n"
- "Converts an Impulse Tracker file into a Dynamic Universal Harmony.\n"
- );
-
- exit(1);
-}
-
-
-
-int main(int argc, char *argv[])
-{
- MODULE *module;
- int rv;
- char *outmod;
-
- if (argc < 2 || argc > 3)
- usage();
-
- allegro_init();
-
- /* Make the output file name if it wasn't specified */
- if (argc == 2) {
- int size = sizeof(char) * (ustrsizez(argv[1]) + 32);
- outmod = malloc(size);
- if (!outmod) {
- allegro_message("Ran out of memory while trying to allocate %i bytes. (%s:(%i))\n", size, __FILE__, __LINE__);
- return -1;
- }
- ustrzcpy(outmod, size, argv[1]);
- replace_extension(outmod, argv[1], "duh", size);
- }
- else
- outmod = argv[2];
-
- module = load_it(argv[1]);
-
- if (!module) {
- allegro_exit();
- allegro_message("Unable to load %s!\n", argv[1]);
- return 1;
- }
-
- rv = save_it_to_duh(module, outmod);
-
- destroy_it(module);
-
- if (rv) {
- delete_file(outmod);
- allegro_exit();
- allegro_message("Unable to save %s!\n", outmod);
- return 1;
- }
-
- if (argc == 2 && outmod)
- free(outmod);
-
- return 0;
-}
-END_OF_MAIN();
+/* These #defines are TEMPORARY. They are used to write alternative code to
+ * handle ambiguities in the format specification. The correct code in each
+ * case will be determined most likely by experimentation.
+ */
+#define STEREO_SAMPLES_COUNT_AS_TWO
+#define INVALID_ORDERS_END_SONG
+#define SUSTAIN_LOOP_OVERRIDES_NORMAL_LOOP
+#define VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
+
+
+
+#include <stdio.h>//temporary
+
+
+
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * cit.c - IT Compiler / / \ \
+ * | < / \_
+ * Derived from an IT file loader by Bob. | \/ /\ /
+ * \_ / > /
+ * Written by entheh. Barely works. A complete | \ / /
+ * mess. | ' /
+ * \__/
+ */
+
+#include <string.h>
+#include <math.h>
+#include "allegro.h"
+
+
+
+#define MUSIC_IT AL_ID('I','M','P','M')
+
+
+
+typedef struct MODULE_MUSIC_INFO {
+ char Name[29];
+ int Type;
+} MODULE_MUSIC_INFO;
+
+#define ENVELOPE_ON 1
+#define ENVELOPE_LOOP_ON 2
+#define ENVELOPE_SUSTAINLOOP 4
+#define ENVELOPE_PITCH_IS_FILTER 128
+
+typedef struct MODULE_ENVELOPE {
+ unsigned char Flag,
+ NumNodes,
+ LoopBegin, LoopEnd, SustainLoopBegin, SustainLoopEnd; //in nodes.
+ char NodeY[25];
+ short NodeTick[25];
+} MODULE_ENVELOPE;
+
+typedef struct MODULE_VENVELOPE {
+ unsigned char NextNode;
+ unsigned short CurTick;
+} MODULE_VENVELOPE;
+
+#define NNA_NOTECUT 0
+#define NNA_NOTECONTINUE 1
+#define NNA_NOTEOFF 2
+#define NNA_NOTEFADE 3
+
+#define DCT_OFF 0
+#define DCT_NOTE 1
+#define DCT_SAMPLE 2
+#define DCT_INSTRUMENT 3
+
+#define DCA_CUT 0
+#define DCA_NOTEOFF 1
+#define DCA_NOTEFADE 2
+
+typedef struct MODULE_INSTRUMENT {
+ //unsigned char Flag;
+ char VolumeLoopNodeStart, VolumeLoopNodeEnd;
+ char SustainLoopNodeStart, SustainLoopNodeEnd;
+ char DuplicateCheckType;
+ char DuplicateCheckAction;
+ char NewNoteAction;
+ int FadeOut;
+
+ unsigned char PitchPanSeparation, //0->64, Bit7: Don't use
+ PitchPanCenter; //Note, from C-0 to B-9
+ unsigned char GlobalVolume, //0->128
+ DefaultPan; //0->64, Bit7: Don't use
+ unsigned char RandomVolume, RandomPanning;
+
+ unsigned char FilterCutOff;
+ unsigned char FilterResonance;
+
+ unsigned char NoteSample[120];
+ unsigned char NoteNote[120];
+
+ MODULE_ENVELOPE VolumeEnvelope, PanningEnvelope, PitchEnvelope;
+} MODULE_INSTRUMENT;
+
+#define SAMPLE_HASSAMPLE 1
+#define SAMPLE_16BIT 2
+#define SAMPLE_STEREO 4
+#define SAMPLE_USELOOP 16
+#define SAMPLE_USESUSTAINLOOP 32
+#define SAMPLE_PINGPONGLOOP 64
+#define SAMPLE_PINGPONGSUSTAINLOOP 128
+
+#define VIBRATO_SINE 0
+#define VIBRATO_RAMPDOWN 1
+#define VIBRATO_SQUARE 2
+#define VIBRATO_RANDOM 3
+
+typedef struct MODULE_SAMPLE {
+ unsigned char GlobalVolume; //0->64
+ unsigned char Flag;
+ unsigned char DefaultVolume;
+ unsigned char DefaultPanning;
+ int SampleLength; //in samples, not bytes !
+ int LoopBegin, LoopEnd; //in samples
+ int SustainLoopBegin, SustainLoopEnd;
+ int C5Speed; //Number of bytes/sec for C-5
+
+ SAMPLE *Sample;
+
+ char VibratoSpeed; //0->64
+ char VibratoDepth; //0->64
+ char VibratoWaveForm;
+ char VibratoRate; //0->64
+} MODULE_SAMPLE;
+
+#define NOTEMASK_NOTE 1
+#define NOTEMASK_INSTRUMENT 2
+#define NOTEMASK_VOLPAN 4
+#define NOTEMASK_COMMAND 8
+
+#define NOTE_OFF 255
+#define NOTE_CUT 254
+
+typedef struct MODULE_NOTE {
+ char Mask;
+ char Channel; //if -1, then end of row.
+ unsigned char Note;
+ char Instrument;
+ unsigned char VolPan;
+ unsigned char Command, CommandValue;
+} MODULE_NOTE;
+
+typedef struct MODULE_PATTERN {
+ int NumRows;
+ int NumNotes;
+ MODULE_NOTE *Note;
+} MODULE_PATTERN;
+
+#define VCHANNEL_PLAYING 1
+#define VCHANNEL_BACKGROUND 2
+#define VCHANNEL_FADING 4
+#define VCHANNEL_RETRIG 8
+
+struct MODULE_CHANNEL;
+
+typedef struct MODULE_VCHANNEL {
+ unsigned char Flag;
+ unsigned char Instrument;
+ unsigned char Note;
+ unsigned int Volume;
+ unsigned char Pan;
+ signed char PanSep;
+
+ MODULE_SAMPLE *sample;
+
+ int pitch; /* 0 corresponds to C-5, 256 is one semitone. */
+
+ MODULE_VENVELOPE VVolEnv;
+ int fadeoutcount;
+
+ /* WARNING: search for BLEARGH when adding to this struct. */
+/*
+ MODULE_SAMPLE *Sample; //NULL is unused
+ char voice;
+ char ChannelVolume;
+ char NoteOn;
+ char NNA;
+ short FadeOutCount, FadeOut;
+ float MixVolume, MixPan;
+ MODULE_VENVELOPE *VVolumeEnvelope, *VPanningEnvelope, *VPitchEnvelope;
+ struct MODULE_VCHANNEL *next, *prev;
+*/
+ unsigned char NNA;
+
+ unsigned int DUHvol, DUHpan;
+
+ struct MODULE_CHANNEL *channel;
+} MODULE_VCHANNEL;
+
+#define CHANNEL_RETRIG 1
+
+typedef struct MODULE_CHANNEL {
+ unsigned int ID;
+ unsigned char Flag;
+ unsigned char Note;
+ unsigned char Instrument;
+ unsigned char Volume; //0->64
+ unsigned char Pan; //0->32->64, 100 = surround, Bit7: Disable
+ signed char PanSep;
+
+ int pitch;
+
+ unsigned char ChannelVolume;
+
+ unsigned char lastvolslide;
+ unsigned char lastDKL, lastN, lastW, lastEF, lastG, lastT;
+ int portamento, toneporta;
+ signed char volslide;
+ signed char channelvolslide;
+
+ MODULE_SAMPLE *sample;
+
+ MODULE_VCHANNEL *VChannel;
+} MODULE_CHANNEL;
+
+#define FLAG_STEREO 1
+#define FLAG_USEINSTRUMENTS 4
+#define FLAG_LINEARSLIDES 8 /* If not set, use Amiga slides */
+#define FLAG_OLDEFFECT 16
+#define FLAG_COMPATIBLEGXX 32
+
+#define ORDER_END 255
+#define ORDER_SKIP 254
+
+typedef struct MODULE {
+ MODULE_INSTRUMENT *Instrument;
+ MODULE_SAMPLE *Sample;
+ MODULE_PATTERN *Pattern;
+
+ int NumOrders;
+ int NumInstruments;
+ int NumSamples;
+ int NumPatterns;
+ int Flags;
+ short Version;
+ unsigned char GlobalVolume;
+ signed char globalvolslide;
+ unsigned char MixVolume;
+ unsigned char Speed, Tempo, tick;
+ signed char temposlide;
+ unsigned char PanningSeparation;
+
+ unsigned char *Order;
+
+ MODULE_CHANNEL Channel[64];
+ MODULE_VCHANNEL VChannel[256];
+
+ int processorder;
+ int processrow;
+ int breakrow;
+ int rowcount;
+} MODULE;
+
+
+
+#define IT_SET_SPEED 1
+#define IT_JUMP_TO_ORDER 2
+#define IT_BREAK_TO_ROW 3
+#define IT_VOLUME_SLIDE 4
+#define IT_PORTAMENTO_DOWN 5
+#define IT_PORTAMENTO_UP 6
+#define IT_TONE_PORTAMENTO 7
+#define IT_VIBRATO 8
+#define IT_TREMOR 9
+#define IT_ARPEGGIO 10
+#define IT_VOLSLIDE_VIBRATO 11
+#define IT_VOLSLIDE_TONEPORTA 12
+#define IT_SET_CHANNEL_VOLUME 13
+#define IT_CHANNEL_VOLUME_SLIDE 14
+#define IT_SET_SAMPLE_OFFSET 15
+#define IT_PANNING_SLIDE 16
+#define IT_RETRIGGER_NOTE 17
+#define IT_TREMOLO 18
+#define IT_S 19
+#define IT_SET_SONG_TEMPO 20
+#define IT_FINE_VIBRATO 21
+#define IT_SET_GLOBAL_VOLUME 22
+#define IT_GLOBAL_VOLUME_SLIDE 23
+#define IT_SET_PANNING 24
+#define IT_PANBRELLO 25
+#define IT_MIDI_MACRO 26 //see MIDI.TXT
+
+
+
+/* These represent the top nibble of the command value. */
+#define IT_S_SET_FILTER 0 /* Greyed out in IT... */
+#define IT_S_SET_GLISSANDO_CONTROL 1 /* Greyed out in IT... */
+#define IT_S_FINETUNE 2 /* Greyed out in IT... */
+#define IT_S_SET_VIBRATO_WAVEFORM 3
+#define IT_S_SET_TREMOLO_WAVEFORM 4
+#define IT_S_SET_PANBRELLO_WAVEFORM 5
+#define IT_S_FINE_PATTERN_DELAY 6
+#define IT_S7 7
+#define IT_S_SET_PAN 8
+#define IT_S_SET_SURROUND_SOUND 9
+#define IT_S_SET_HIGH_OFFSET 10
+#define IT_S_PATTERN_LOOP 11
+#define IT_S_DELAYED_NOTE_CUT 12
+#define IT_S_NOTE_DELAY 13
+#define IT_S_PATTERN_DELAY 14
+#define IT_S_SET_MIDI_MACRO 15
+
+/*
+S0x Set filter
+S1x Set glissando control
+S2x Set finetune
+
+
+S3x Set vibrato waveform to type x
+S4x Set tremelo waveform to type x
+S5x Set panbrello waveform to type x
+ Waveforms for commands S3x, S4x and S5x:
+ 0: Sine wave
+ 1: Ramp down
+ 2: Square wave
+ 3: Random wave
+S6x Pattern delay for x ticks
+S70 Past note cut
+S71 Past note off
+S72 Past note fade
+S73 Set NNA to note cut
+S74 Set NNA to continue
+S75 Set NNA to note off
+S76 Set NNA to note fade
+S77 Turn off volume envelope
+S78 Turn on volume envelope
+S79 Turn off panning envelope
+S7A Turn on panning envelope
+S7B Turn off pitch envelope
+S7C Turn on pitch envelope
+S8x Set panning position
+S91 Set surround sound
+SAy Set high value of sample offset yxx00h
+SB0 Set loopback point
+SBx Loop x times to loopback point
+SCx Note cut after x ticks
+SDx Note delay for x ticks
+SEx Pattern delay for x rows
+SFx Set parameterised MIDI Macro
+*/
+
+
+
+typedef struct MODULE_PLAY {
+ MODULE *Music;
+ int Loop, Tick;
+ int CurOrder, CurPattern, CurPos;
+ int Command, CommandVal0, CommandVal1, CommandVal2;
+ int pos;
+} MODULE_PLAY;
+extern MODULE_PLAY *song;
+
+extern int IT_Play_Method;
+
+MODULE *load_it(char*);
+//int get_module_size(MODULE *);
+
+int play_it(MODULE *j, int loop);
+void install_module();
+void set_mix_volume(int i);
+
+void stop_it();
+int is_music_done();
+void destroy_it(MODULE *j);
+
+//Should be internal:
+extern MODULE_PLAY *song;
+extern int note_freq[120];
+
+//extern void MOD_Interrupt(...);
+extern int MOD_Poller(void*);
+
+#define IT_TIMER 0
+#define IT_POLL 1
+
+/* typedef.hpp */
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned int dword;
+
+/* load_it.cpp */
+
+/*
+int detect_it(char *f) {
+ int sig;
+ PACKFILE *fn = pack_fopen(f, F_READ);
+
+ if (fn == NULL)
+ return FALSE;
+
+ sig = pack_mgetl(fn);
+ if (sig != MUSIC_IT) {
+ pack_fclose(fn);
+ return FALSE;
+ }
+ pack_fclose(fn);
+
+ return TRUE;
+}
+*/
+
+
+
+MODULE *create_it() {
+ MODULE *m = (MODULE*)malloc(sizeof(MODULE));
+ if (!m)
+ return NULL;
+ memset(m, 0, sizeof(MODULE));
+ return m;
+}
+
+
+
+void destroy_it(MODULE *j) {
+
+ int i;
+
+ if (j) {
+ /* Remove patterns. */
+ if (j->Pattern) {
+ for (i = 0; i < j->NumPatterns; i++)
+ free(j->Pattern[i].Note);
+ free(j->Pattern);
+ }
+
+ /* Remove instruments. */
+ free(j->Instrument);
+
+ /* Remove samples. */
+ if (j->Sample) {
+ for (i = 0; i < j->NumSamples; i++)
+ destroy_sample(j->Sample[i].Sample);
+ free(j->Sample);
+ }
+
+ /* Remove orders. */
+ free(j->Order);
+
+ free(j);
+ }
+}
+
+
+
+//#define DEBUG_IT_SIZE
+
+/*
+int get_module_size(MODULE *j) {
+ int a, b, c, d = 0, e;
+ int i;
+ a = sizeof(MODULE) + j->NumOrders;
+ b = j->NumInstruments * sizeof(MODULE_INSTRUMENT);
+ c = j->NumSamples * sizeof(MODULE_SAMPLE);
+
+ for (i=0; i<j->NumSamples; i++)
+ d += j->Sample[i].SampleLength * (j->Sample[i].Flag & 2 ? sizeof(short) : 1) * (j->Sample[i].Flag & 4 ? 2: 1);
+
+ e = 4 + sizeof(MODULE_PATTERN) * j->NumPatterns;
+
+ for (i=0; i<j->NumPatterns; i++)
+ e += j->Pattern[i].NumNotes * sizeof(MODULE_NOTE);
+ #ifdef DEBUG_IT_SIZE
+ fprintf(stderr, "Base: %i, Instruments(%i): %i, Samples(%i): %i, Data: %i, Patterns(%i): %i\n", a, j->NumInstruments, b, j->NumSamples, c, d, j->NumPatterns, e);
+ #endif
+
+ return a+b+c+d+e;
+}
+*/
+
+
+
+#define MAX_IT_CHN 64
+
+//#define DEBUG_HEADER
+//#define DEBUG_INSTRUMENTS
+//#define DEBUG_SAMPLES
+//#define DEBUG_PATTERNS
+
+static dword *sourcebuf = NULL;
+static dword *sourcepos = NULL;
+static byte rembits = 0;
+
+int readblock(PACKFILE *f) {
+ long size;
+ int c = pack_igetw(f);
+ if (c == -1)
+ return 0;
+ size = c;
+
+ sourcebuf = (dword*)malloc(size+4);
+ if (!sourcebuf)
+ return 0;
+
+ c = pack_fread(sourcebuf, size, f);
+ if (c < 1) {
+ free(sourcebuf);
+ sourcebuf = NULL;
+ return 0;
+ }
+ sourcepos = sourcebuf;
+ rembits = 32;
+ return 1;
+}
+
+void freeblock() {
+ if (sourcebuf)
+ free(sourcebuf);
+ sourcebuf = NULL;
+}
+
+dword readbits(char b) {
+ dword val;
+ if (b <= rembits) {
+ val = *sourcepos & ((1 << b) - 1);
+ *sourcepos >>= b;
+ rembits -= b;
+ }
+ else {
+ dword nbits = b - rembits;
+ val = *sourcepos;
+ sourcepos++;
+ val |= ((*sourcepos & ((1 << nbits) - 1)) << rembits);
+ *sourcepos >>= nbits;
+ rembits = 32 - nbits;
+ }
+ return val;
+}
+
+void decompress8(PACKFILE *f, void *data, int len, int tver) {
+ char *destbuf = (char*)data;
+ char *destpos = destbuf;
+ int blocklen, blockpos;
+ byte bitwidth;
+ word val;
+ char d1, d2;
+
+ memset(destbuf, 0, len);
+
+ while (len>0) {
+ //Read a block of compressed data:
+ if (!readblock(f))
+ return;
+ //Set up a few variables
+ blocklen = (len < 0x8000) ? len : 0x8000; //Max block length is 0x8000 bytes
+ blockpos = 0;
+ bitwidth = 9;
+ d1 = d2 = 0;
+ //Start the decompression:
+ while (blockpos < blocklen) {
+ //Read a value:
+ val = readbits(bitwidth);
+ //Check for bit width change:
+
+ if (bitwidth < 7) { //Method 1:
+ if (val == (1 << (bitwidth - 1))) {
+ val = readbits(3) + 1;
+ bitwidth = (val < bitwidth) ? val : val + 1;
+ continue;
+ }
+ }
+ else if (bitwidth < 9) { //Method 2
+ byte border = (0xFF >> (9 - bitwidth)) - 4;
+
+ if (val > border && val <= (border + 8)) {
+ val -= border;
+ bitwidth = (val < bitwidth) ? val : val + 1;
+ continue;
+ }
+ }
+ else if (bitwidth == 9) { //Method 3
+ if (val & 0x100) {
+ bitwidth = (val + 1) & 0xFF;
+ continue;
+ }
+ }
+ else { //Illegal width, abort ?
+ freeblock();
+ return;
+ }
+
+ //Expand the value to signed byte:
+ {
+ char v; //The sample value:
+ if (bitwidth < 8) {
+ byte shift = 8 - bitwidth;
+ v = (val << shift);
+ v >>= shift;
+ }
+ else
+ v = (char)val;
+
+ //And integrate the sample value
+ //(It always has to end with integration doesn't it ? ;-)
+ d1 += v;
+ d2 += d1;
+ }
+
+ //Store !
+ *destpos = ((tver == 0x215) ? d2 : d1);
+ destpos++;
+ blockpos++;
+ }
+ freeblock();
+ len -= blocklen;
+ }
+ return;
+}
+
+void decompress16(PACKFILE *f, void *data, int len, int tver) {
+ //make the output buffer:
+ short *destbuf = (short*)data;
+ short *destpos = destbuf;
+ int blocklen, blockpos;
+ byte bitwidth;
+ long val;
+ short d1, d2;
+
+ memset(destbuf, 0, len);
+
+ while (len>0) {
+ //Read a block of compressed data:
+ if (!readblock(f))
+ return;
+ //Set up a few variables
+ blocklen = (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes
+ blockpos = 0;
+ bitwidth = 17;
+ d1 = d2 = 0;
+ //Start the decompression:
+ while (blockpos < blocklen) {
+ val = readbits(bitwidth);
+ //Check for bit width change:
+
+ if (bitwidth < 7) { //Method 1:
+ if (val == (1 << (bitwidth - 1))) {
+ val = readbits(4) + 1;
+ bitwidth = (val < bitwidth) ? val : val + 1;
+ continue;
+ }
+ }
+ else if (bitwidth < 17) { //Method 2
+ word border = (0xFFFF >> (17 - bitwidth)) - 8;
+
+ if (val > border && val <= (border + 16)) {
+ val -= border;
+ bitwidth = val < bitwidth ? val : val + 1;
+ continue;
+ }
+ }
+ else if (bitwidth == 17) { //Method 3
+ if (val & 0x10000) {
+ bitwidth = (val + 1) & 0xFF;
+ continue;
+ }
+ }
+ else { //Illegal width, abort ?
+ freeblock();
+ return;
+ }
+
+ //Expand the value to signed byte:
+ {
+ short v; //The sample value:
+ if (bitwidth < 16) {
+ byte shift = 16 - bitwidth;
+ v = (val << shift);
+ v >>= shift;
+ }
+ else
+ v = (short)val;
+
+ //And integrate the sample value
+ //(It always has to end with integration doesn't it ? ;-)
+ d1 += v;
+ d2 += d1;
+ }
+
+ //Store !
+ *destpos = ((tver == 0x215) ? d2 : d1);
+ destpos++;
+ blockpos++;
+ }
+ freeblock();
+ len -= blocklen;
+ }
+ return;
+}
+
+
+
+void read_envelopes(PACKFILE *f, MODULE *j, int i)
+{
+ int k;
+
+ j->Instrument[i].VolumeEnvelope.Flag = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.NumNodes = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.LoopBegin = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.LoopEnd = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.SustainLoopBegin = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.SustainLoopEnd = pack_getc(f);
+ for (k = 0; k < j->Instrument[i].VolumeEnvelope.NumNodes; k++) {
+ j->Instrument[i].VolumeEnvelope.NodeY[k] = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.NodeTick[k] = pack_igetw(f);
+ }
+ pack_fseek(f, 75 - j->Instrument[i].VolumeEnvelope.NumNodes * 3);
+
+ j->Instrument[i].PanningEnvelope.Flag = pack_getc(f);
+ j->Instrument[i].PanningEnvelope.NumNodes = pack_getc(f);
+ j->Instrument[i].PanningEnvelope.LoopBegin = pack_getc(f);
+ j->Instrument[i].PanningEnvelope.LoopEnd = pack_getc(f);
+ j->Instrument[i].PanningEnvelope.SustainLoopBegin = pack_getc(f);
+ j->Instrument[i].PanningEnvelope.SustainLoopEnd = pack_getc(f);
+ for (k = 0; k < j->Instrument[i].PanningEnvelope.NumNodes; k++) {
+ j->Instrument[i].PanningEnvelope.NodeY[k] = pack_getc(f);
+ j->Instrument[i].PanningEnvelope.NodeTick[k] = pack_igetw(f);
+ }
+ pack_fseek(f, 75 - j->Instrument[i].PanningEnvelope.NumNodes * 3);
+
+ j->Instrument[i].PitchEnvelope.Flag = pack_getc(f);
+ j->Instrument[i].PitchEnvelope.NumNodes = pack_getc(f);
+ j->Instrument[i].PitchEnvelope.LoopBegin = pack_getc(f);
+ j->Instrument[i].PitchEnvelope.LoopEnd = pack_getc(f);
+ j->Instrument[i].PitchEnvelope.SustainLoopBegin = pack_getc(f);
+ j->Instrument[i].PitchEnvelope.SustainLoopEnd = pack_getc(f);
+ for (k = 0; k < j->Instrument[i].PitchEnvelope.NumNodes; k++) {
+ j->Instrument[i].PitchEnvelope.NodeY[k] = pack_getc(f);
+ j->Instrument[i].PitchEnvelope.NodeTick[k] = pack_igetw(f);
+ }
+}
+
+
+
+MODULE *load_old_instrument(char *file, long offset, MODULE *j, int i)
+{
+ int k;
+ PACKFILE *f = pack_fopen(file, F_READ);
+
+ if (!f) {
+ #ifdef DEBUG_INSTRUMENTS
+ fprintf(stderr, "Error reopening!\n");
+ #endif
+ destroy_it(j);
+ return NULL;
+ }
+
+ pack_fseek(f, offset);
+
+ if (pack_mgetl(f) != AL_ID('I','M','P','I')) {
+ destroy_it(j);
+ return NULL;
+ }
+
+ /* Skip DOS Filename */
+ pack_fseek(f, 13);
+
+ j->Instrument[i].VolumeEnvelope.Flag = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.LoopBegin = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.LoopEnd = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.SustainLoopBegin = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.SustainLoopEnd = pack_getc(f);
+
+ /* Two unused bytes */
+ pack_fseek(f, 2);
+
+ /* OLD FadeOut: Ranges between 0 and 64, but the fadeout "Count" is 512.
+ * NEW FadeOut: Ranges between 0 and 128, but the fadeout "Count" is 1024
+ *
+ * TODO: Find out what this means, and make adjustments accordingly.
+ */
+ j->Instrument[i].FadeOut = pack_igetw(f) << 1;
+ j->Instrument[i].NewNoteAction = pack_getc(f);
+ j->Instrument[i].DuplicateCheckType = pack_getc(f);
+ j->Instrument[i].DuplicateCheckAction = DCA_CUT; /* This might be wrong! */
+
+ /* Skip Tracker Version and Number of Samples. These are only used in
+ * separate instrument files. Also skip unused bytes and Instrument Name.
+ */
+ pack_fseek(f, 36);
+
+ j->Instrument[i].PitchPanSeparation = 0;
+ j->Instrument[i].PitchPanCenter = 60;
+ j->Instrument[i].GlobalVolume = 128; /* Should this be 64 or something? */
+ j->Instrument[i].DefaultPan = 32; /* Should this be 128? */
+ j->Instrument[i].RandomVolume = 0;
+ j->Instrument[i].RandomPanning = 0;
+
+ for (k = 0; k < 120; k++) {
+ j->Instrument[i].NoteNote[k] = pack_getc(f);
+ j->Instrument[i].NoteSample[k] = pack_getc(f);
+ }
+
+ /* Skip "Volume envelope (200 bytes)" - need to know better what this is
+ * for though.
+ */
+ pack_fseek(f, 200);
+
+ fprintf(stderr, "Inst %02d Env:", i);
+
+ for (j->Instrument[i].VolumeEnvelope.NumNodes = 0;
+ j->Instrument[i].VolumeEnvelope.NumNodes < 25;
+ j->Instrument[i].VolumeEnvelope.NumNodes++)
+ {
+ j->Instrument[i].VolumeEnvelope.NodeTick[k] = pack_getc(f);
+ j->Instrument[i].VolumeEnvelope.NodeY[k] = pack_getc(f);
+
+ fprintf(stderr, " %d,%d",
+ j->Instrument[i].VolumeEnvelope.NodeTick[k],
+ j->Instrument[i].VolumeEnvelope.NodeY[k]);
+ }
+ pack_fseek(f, 50 - j->Instrument[i].VolumeEnvelope.NumNodes * 2);
+
+ fprintf(stderr, "\n");
+
+ j->Instrument[i].FilterCutOff = 0; //Are these the right values
+ j->Instrument[i].FilterResonance = 0; //to disable the filter?
+
+ j->Instrument[i].PanningEnvelope.Flag = 0;
+ j->Instrument[i].PanningEnvelope.NumNodes = 0;
+ j->Instrument[i].PanningEnvelope.LoopBegin = 0;
+ j->Instrument[i].PanningEnvelope.LoopEnd = 0;
+ j->Instrument[i].PanningEnvelope.SustainLoopBegin = 0;
+ j->Instrument[i].PanningEnvelope.SustainLoopEnd = 0;
+
+ j->Instrument[i].PitchEnvelope.Flag = 0;
+ j->Instrument[i].PitchEnvelope.NumNodes = 0;
+ j->Instrument[i].PitchEnvelope.LoopBegin = 0;
+ j->Instrument[i].PitchEnvelope.LoopEnd = 0;
+ j->Instrument[i].PitchEnvelope.SustainLoopBegin = 0;
+ j->Instrument[i].PitchEnvelope.SustainLoopEnd = 0;
+
+ pack_fclose(f);
+
+ if (errno) {
+ destroy_it(j);
+ return NULL;
+ }
+
+ return j;
+}
+
+
+
+MODULE *load_instrument(char *file, long offset, MODULE *j, int i)
+{
+ int k;
+ PACKFILE *f = pack_fopen(file, F_READ);
+
+ if (!f) {
+ #ifdef DEBUG_INSTRUMENTS
+ fprintf(stderr, "Error reopening!\n");
+ #endif
+ destroy_it(j);
+ return NULL;
+ }
+
+ pack_fseek(f, offset);
+
+ if (pack_mgetl(f) != AL_ID('I','M','P','I')) {
+ destroy_it(j);
+ return NULL;
+ }
+
+ /* Skip DOS Filename */
+ pack_fseek(f, 13);
+
+ j->Instrument[i].NewNoteAction = pack_getc(f);
+ j->Instrument[i].DuplicateCheckType = pack_getc(f);
+ j->Instrument[i].DuplicateCheckAction = pack_getc(f);
+ j->Instrument[i].FadeOut = pack_igetw(f);
+ j->Instrument[i].PitchPanSeparation = pack_getc(f);
+ j->Instrument[i].PitchPanCenter = pack_getc(f);
+ j->Instrument[i].GlobalVolume = pack_getc(f);
+ j->Instrument[i].DefaultPan = pack_getc(f);
+ j->Instrument[i].RandomVolume = pack_getc(f);
+ j->Instrument[i].RandomPanning = pack_getc(f);
+
+ #ifdef DEBUG_INSTRUMENTS
+ fprintf(stderr, "I%02i @ 0x%X, NNA %i, DCT %i, DCA %i, FO %i, "
+ "PPS %i, PPC %i, GVol %i, DPan %i, RV %i, RP %i\n",
+ i, insoffs[i],
+ j->Instrument[i].NewNoteAction,
+ j->Instrument[i].DuplicateCheckType,
+ j->Instrument[i].DuplicateCheckAction,
+ j->Instrument[i].FadeOut,
+ j->Instrument[i].PitchPanSeparation,
+ j->Instrument[i].PitchPanCenter,
+ j->Instrument[i].GlobalVolume,
+ j->Instrument[i].DefaultPan,
+ j->Instrument[i].RandomVolume,
+ j->Instrument[i].RandomPanning);
+ #endif
+
+ /* Skip Tracker Version and Number of Samples. These are only used in
+ * separate instrument files. Also skip unused byte and Instrument Name.
+ */
+ pack_fseek(f, 30);
+
+ j->Instrument[i].FilterCutOff = pack_getc(f);
+ j->Instrument[i].FilterResonance = pack_getc(f);
+
+ /* Skip MIDI Channel, Program and Bank */
+ pack_fseek(f, 4);
+
+ for (k = 0; k < 120; k++) {
+ j->Instrument[i].NoteNote[k] = pack_getc(f);
+ j->Instrument[i].NoteSample[k] = pack_getc(f);
+ }
+
+ read_envelopes(f, j, i);
+
+ pack_fclose(f);
+
+ if (errno) {
+ destroy_it(j);
+ return NULL;
+ }
+
+ return j;
+}
+
+
+
+MODULE *load_it_sample(char *file, long offset, MODULE *j, int i)
+{
+ int sam_samptr, convert;
+ int len;
+ int k;
+ SAMPLE *sam;
+ void *dat;
+
+ PACKFILE *f = pack_fopen(file, F_READ);
+ if (!f) {
+ #ifdef DEBUG_SAMPLES
+ fprintf(stderr, "Error opening!\n");
+ #endif
+ destroy_it(j);
+ return NULL;
+ }
+
+ pack_fseek(f, offset);
+
+ if (pack_mgetl(f) != AL_ID('I','M','P','S')) {
+ destroy_it(j);
+ return NULL;
+ }
+
+ /* Skip DOS Filename. */
+ pack_fseek(f, 13);
+
+ j->Sample[i].GlobalVolume = pack_getc(f);
+ j->Sample[i].Flag = pack_getc(f);
+ j->Sample[i].DefaultVolume = pack_getc(f);
+
+ #ifdef DEBUG_SAMPLES
+ fprintf(stderr, "S%02i @ 0x%X, Vol: %i/%i, Flag: %i", i, samoffs[i], j->Sample[i].GlobalVolume, j->Sample[i].Volume, j->Sample[i].Flag);
+ #endif
+
+ /* Skip Sample Name. */
+ pack_fseek(f, 26);
+
+ convert = pack_getc(f);
+ j->Sample[i].DefaultPanning = pack_getc(f);
+ j->Sample[i].SampleLength = pack_igetl(f);
+ j->Sample[i].LoopBegin = pack_igetl(f);
+ j->Sample[i].LoopEnd = pack_igetl(f);
+ j->Sample[i].C5Speed = pack_igetl(f);
+ j->Sample[i].SustainLoopBegin = pack_igetl(f);
+ j->Sample[i].SustainLoopEnd = pack_igetl(f);
+
+ #ifdef DEBUG_SAMPLES
+ fprintf(stderr, ", SLen: %i, LpB: %i, LpE: %i, C5S: %i\n", j->Sample[i].SampleLength, j->Sample[i].LoopBegin, j->Sample[i].LoopEnd, j->Sample[i].C5Speed);
+ #endif
+
+ sam_samptr = pack_igetl(f);
+
+ j->Sample[i].VibratoSpeed = pack_getc(f);
+ j->Sample[i].VibratoDepth = pack_getc(f);
+ j->Sample[i].VibratoRate = pack_getc(f);
+ j->Sample[i].VibratoWaveForm = pack_getc(f);
+
+ #ifdef DEBUG_SAMPLES
+ fprintf(stderr, "SusLpB: %i, SusLpE: %i, VibSp: %i, VibDep: %i, VibWav: %i, VibRat: %i\n", j->Sample[i].SustainLoopBegin, j->Sample[i].SustainLoopEnd, j->Sample[i].VibratoSpeed, j->Sample[i].VibratoDepth, j->Sample[i].VibratoWaveForm, j->Sample[i].VibratoRate);
+ #endif
+
+ pack_fclose(f);
+
+ if (errno) {
+ destroy_it(j);
+ return NULL;
+ }
+
+ if (j->Sample[i].Flag & SAMPLE_HASSAMPLE) {
+
+ f = pack_fopen(file, F_READ);
+ pack_fseek(f, sam_samptr);
+
+ len = j->Sample[i].SampleLength;
+ if (j->Sample[i].Flag & SAMPLE_16BIT) len <<= 1;
+#ifndef STEREO_SAMPLES_COUNT_AS_TWO
+ if (j->Sample[i].Flag & SAMPLE_STEREO) len <<= 1;
+#endif
+
+ #ifdef DEBUG_SAMPLES
+ fprintf(stderr, "Len: %i, Size: %i KB\n", j->Sample[i].SampleLength, len/1024);
+ #endif
+
+ sam = create_sample(j->Sample[i].Flag & SAMPLE_16BIT ? 16 : 8,
+ j->Sample[i].Flag & SAMPLE_STEREO ? 1 : 0,
+#ifdef STEREO_SAMPLES_COUNT_AS_TWO
+ j->Sample[i].C5Speed >> 1,
+#else
+ j->Sample[i].C5Speed,
+#endif
+ j->Sample[i].SampleLength);
+
+ if (j->Sample[i].Flag & 8) { // If the sample is packed, then we must unpack it
+
+ if (j->Sample[i].Flag & SAMPLE_16BIT)
+ decompress16(f, sam->data, j->Sample[i].SampleLength, j->Version);
+ else
+ decompress8(f, sam->data, j->Sample[i].SampleLength, j->Version);
+
+ } else if ((j->Sample[i].Flag & SAMPLE_16BIT)) {
+ if (convert & 2)
+ for (k = 0; k < len; k += 2)
+ *(short *)((char *)sam->data + k) = pack_mgetw(f);
+ else
+ for (k = 0; k < len; k += 2)
+ *(short *)((char *)sam->data + k) = pack_igetw(f);
+ } else {
+ pack_fread(sam->data, len, f);
+ }
+
+ if (j->Sample[i].Flag & SAMPLE_USELOOP) {
+ sam->loop_start = j->Sample[i].LoopBegin;
+ sam->loop_end = j->Sample[i].LoopEnd;
+ }
+
+ j->Sample[i].Sample = sam;
+
+ dat = sam->data;
+
+ if (convert & 1) {
+ /* Convert to unsigned. */
+ if (sam->bits == 8)
+ for (k = 0; k < len; k++)
+ ((char *)dat)[k] ^= 0x80;
+ else
+ for (k = 0; k < len; k += 2)
+ *(short *)((char *)dat + k) ^= 0x8000;
+ }
+
+ /* NOT SUPPORTED:
+ *
+ * convert & 4 - Samples stored as delta values
+ * convert & 8 - Samples stored as byte delta values
+ * convert & 16 - Samples stored as TX-Wave 12-bit values
+ * convert & 32 - Left/Right/All Stereo prompt
+ */
+
+ pack_fclose(f);
+
+ if (errno) {
+ destroy_it(j);
+ return NULL;
+ }
+ }
+
+ return j;
+}
+
+
+
+MODULE *load_pattern(char *file, long offset, MODULE *j, int i)
+{
+ unsigned char *buf;
+ unsigned char cmask[64],
+ cnote[64],
+ cinstrument[64],
+ cvol[64],
+ ccom[64],
+ ccomval[64];
+
+ int numnotes = 0, len, pos = 0, mask = 0, chn = 0;
+
+ PACKFILE *f;
+
+ if (offset == 0) {
+ /* Empty 64-row pattern. */
+
+ j->Pattern[i].NumRows = 64;
+ j->Pattern[i].NumNotes = 0;
+
+ return j;
+ }
+
+ f = pack_fopen(file, F_READ);
+ if (!f) {
+ destroy_it(j);
+ return NULL;
+ }
+
+ buf = malloc(65536);
+
+ memset(cmask, 0, 64);
+ memset(cnote, 0, 64);
+ memset(cinstrument, 0, 64);
+ memset(cvol, 0, 64);
+ memset(ccom, 0, 64);
+ memset(ccomval, 0, 64);
+
+ pack_fseek(f, offset);
+
+ len = pack_igetw(f);
+ j->Pattern[i].NumRows = pack_igetw(f);
+
+ /* Skip four unused bytes. */
+ pack_fseek(f, 4);
+
+ pack_fread(buf, len, f);
+
+ while (pos < len) {
+
+ int b = buf[pos++];
+
+ if (!b) {
+ /* End of row. */
+ numnotes++;
+ continue;
+ }
+
+ chn = (b - 1) & 63;
+
+ if (b & 128) {
+ mask = buf[pos];
+ pos++;
+ cmask[chn] = mask;
+ } else
+ mask = cmask[chn];
+
+ if (mask)
+ numnotes++;
+ if (mask & 1)
+ pos++;
+ if (mask & 2)
+ pos++;
+ if (mask & 4)
+ pos++;
+ if (mask & 8)
+ pos += 2;
+ }
+
+ j->Pattern[i].NumNotes = numnotes;
+ j->Pattern[i].Note = malloc(numnotes * sizeof(MODULE_NOTE));
+ memset(j->Pattern[i].Note, 0, numnotes * sizeof(MODULE_NOTE));
+
+ pos = 0;
+ memset(cmask, 0, 64);
+ mask = 0;
+ numnotes = 0;
+
+ while (pos < len) {
+
+ int b = buf[pos];
+ #ifdef DEBUG_PATTERNS
+ fprintf(stderr, "NumNote: %i ", numnotes);
+ #endif
+ pos++;
+
+ if (b == 0) { //If end of row:
+ j->Pattern[i].Note[numnotes].Channel = -1;
+ numnotes++;
+ #ifdef DEBUG_PATTERNS
+ fprintf(stderr, "Channel: -1\n");
+ #endif
+ continue;
+ }
+
+ chn = (b - 1) & 63;
+
+ if (b & 128) {
+ mask = buf[pos];
+ pos++;
+ cmask[chn] = mask;
+ } else
+ mask = cmask[chn];
+
+ #ifdef DEBUG_PATTERNS
+ fprintf(stderr, "Channel: %i Mask: %i ", chn, mask);
+ #endif
+
+ if (mask)
+ j->Pattern[i].Note[numnotes].Channel = chn;
+
+ if (mask & 1) {
+ j->Pattern[i].Note[numnotes].Note = buf[pos];
+ j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_NOTE;
+ cnote[chn] = buf[pos];
+ #ifdef DEBUG_PATTERNS
+ fprintf(stderr, "Note: %i ", buf[pos]);
+ #endif
+ pos++;
+ }
+
+ if (mask & 2) {
+ j->Pattern[i].Note[numnotes].Instrument = buf[pos];
+ j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_INSTRUMENT;
+ cinstrument[chn] = buf[pos];
+ #ifdef DEBUG_PATTERNS
+ fprintf(stderr, "Inst: %i ", buf[pos]);
+ #endif
+ pos++;
+ }
+
+ if (mask & 4) {
+ j->Pattern[i].Note[numnotes].VolPan = buf[pos];
+ j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_VOLPAN;
+ cvol[chn] = buf[pos];
+ #ifdef DEBUG_PATTERNS
+ fprintf(stderr, "Vol: %i ", buf[pos]);
+ #endif
+ pos++;
+ }
+
+ if (mask & 8) {
+ j->Pattern[i].Note[numnotes].Command = buf[pos];
+ j->Pattern[i].Note[numnotes].CommandValue = buf[pos+1];
+ j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_COMMAND;
+ ccom[chn] = buf[pos];
+ ccomval[chn] = buf[pos+1];
+ #ifdef DEBUG_PATTERNS
+ fprintf(stderr, "Com: %i CommArg: %i ", buf[pos], buf[pos+1]);
+ #endif
+ pos += 2;
+ }
+
+ if (mask & 16) {
+ j->Pattern[i].Note[numnotes].Note = cnote[chn];
+ j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_NOTE;
+ #ifdef DEBUG_PATTERNS
+ fprintf(stderr, "LNote: %i ", cnote[chn]);
+ #endif
+ }
+
+ if (mask & 32) {
+ j->Pattern[i].Note[numnotes].Instrument = cinstrument[chn];
+ j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_INSTRUMENT;
+ #ifdef DEBUG_PATTERNS
+ fprintf(stderr, "LInst: %i ", cinstrument[chn]);
+ #endif
+ }
+
+ if (mask & 64) {
+ j->Pattern[i].Note[numnotes].VolPan = cvol[chn];
+ j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_VOLPAN;
+ #ifdef DEBUG_PATTERNS
+ fprintf(stderr, "LVol: %i ", cvol[chn]);
+ #endif
+ }
+
+ if (mask & 128) {
+ j->Pattern[i].Note[numnotes].Command = ccom[chn];
+ j->Pattern[i].Note[numnotes].CommandValue = ccomval[chn];
+ j->Pattern[i].Note[numnotes].Mask |= NOTEMASK_COMMAND;
+ #ifdef DEBUG_PATTERNS
+ fprintf(stderr, "LCom: %i LComArg: %i ", ccom[chn], ccomval[chn]);
+ #endif
+ }
+
+ #ifdef DEBUG_PATTERNS
+ fprintf(stderr, "\n");
+ #endif
+
+ if (mask)
+ numnotes++;
+
+ #ifdef DEBUG_PATTERNS
+ rest(1000);
+ #endif
+ }
+
+ free(buf);
+
+ pack_fclose(f);
+
+ if (errno) {
+ destroy_it(j);
+ return NULL;
+ }
+
+ return j;
+}
+
+
+
+MODULE *load_it(char *file) {
+ PACKFILE *f;
+ MODULE *j = create_it();
+ int tver, tver2, flag;
+ long *insoffs = NULL, *samoffs = NULL, *patoffs = NULL;
+ int i;
+
+ if (!j)
+ return NULL;
+
+ f = pack_fopen(file, F_READ);
+
+ if (!f)
+ return NULL;
+
+ if (pack_mgetl(f) != MUSIC_IT) {
+ pack_fclose(f);
+ return NULL;
+ }
+
+ /* Skip song name and pattern row highlight info */
+ pack_fseek(f, 28);
+
+ j->NumOrders = pack_igetw(f);
+ j->NumInstruments = pack_igetw(f);
+ j->NumSamples = pack_igetw(f);
+ j->NumPatterns = pack_igetw(f);
+
+ #ifdef DEBUG_HEADER
+ fprintf(stderr, "Loading IT: %i Orders, %i Instruments, %i Samples, %i Patterns\n", j->NumOrders, j->NumInstruments, j->NumSamples, j->NumPatterns);
+ #endif
+
+ tver = pack_igetw(f);
+ j->Version = tver2 = pack_igetw(f);
+
+ #ifdef DEBUG_HEADER
+ fprintf(stderr, "Tracker ver: %X, %X\n", tver, tver2);
+ #endif
+
+ j->Flags = pack_igetw(f);
+ flag = pack_igetw(f);
+
+ j->GlobalVolume = pack_getc(f);
+ j->MixVolume = pack_getc(f);
+ j->Speed = pack_getc(f);
+ j->Tempo = pack_getc(f);
+ j->PanningSeparation = pack_getc(f);
+
+ #ifdef DEBUG_HEADER
+ fprintf(stderr, "Global Volume: %i, Mixing Volume: %i, Speed: %i, Tempo: %i, PanSep: %i\n", j->GlobalVolume, j->MixVolume, j->Speed, j->Tempo, j->PanningSeparation);
+ #endif
+
+ /* Skip Pitch Wheel Depth, Message Length, Message Offset and Reserved */
+ pack_fseek(f, 11);
+
+ #ifdef DEBUG_HEADER
+ fprintf(stderr, "Channel Pan:");
+ #endif
+
+ for (i = 0; i < MAX_IT_CHN; i++) {
+ j->Channel[i].Pan = pack_getc(f);
+ #ifdef DEBUG_HEADER
+ fprintf(stderr, " %i", j->Channel[i].Pan);
+ #endif
+ }
+ #ifdef DEBUG_HEADER
+ fprintf(stderr, "\nChannel Vol:");
+ #endif
+ for (i = 0; i < MAX_IT_CHN; i++) {
+ j->Channel[i].ChannelVolume = pack_getc(f);
+ #ifdef DEBUG_HEADER
+ fprintf(stderr, " %i", j->Channel[i].ChannelVolume);
+ #endif
+ }
+ #ifdef DEBUG_HEADER
+ fprintf(stderr, "\n");
+ #endif
+
+ j->Order = malloc(j->NumOrders);
+ if (!j->Order) {
+ destroy_it(j);
+ return NULL;
+ }
+ pack_fread(j->Order, j->NumOrders, f);
+
+ /* Whoops, no error checking! Er, would it be better to use arrays? */
+ if (j->NumInstruments)
+ insoffs = malloc(j->NumInstruments * sizeof(*insoffs));
+ if (j->NumSamples)
+ samoffs = malloc(j->NumSamples * sizeof(*samoffs));
+ if (j->NumPatterns)
+ patoffs = malloc(j->NumPatterns * sizeof(*patoffs));
+
+ for (i = 0; i < j->NumInstruments; i++) insoffs[i] = pack_igetl(f);
+ for (i = 0; i < j->NumSamples; i++) samoffs[i] = pack_igetl(f);
+ for (i = 0; i < j->NumPatterns; i++) patoffs[i] = pack_igetl(f);
+
+/* No skipping necessary - we can use the offsets.
+
+ if (flag&1) { //Song message attached
+ //Ignore.
+ }
+ if (flag & 4) { //skip something:
+ short u;
+ char dummy[8];
+ int i;
+ u = pack_igetw(f);
+ for (i=0; i<u; u++)
+ pack_fread(dummy, 8, f);
+ }
+ if (flag & 8) { //skip embedded MIDI configuration
+ char dummy[33];
+ int i;
+ for (i=0; i<9+16+128; i++)
+ pack_fread(dummy, 32, f);
+
+ }
+*/
+ pack_fclose(f);
+
+ if (j->NumInstruments) {
+ j->Instrument = malloc(j->NumInstruments * sizeof(MODULE_INSTRUMENT));
+
+ if (!j->Instrument) {
+ #ifdef DEBUG_INSTRUMENTS
+ fprintf(stderr, "No Mem for Instruments!\n");
+ #endif
+ free(insoffs);
+ free(samoffs);
+ free(patoffs);
+ destroy_it(j);
+ return NULL;
+ }
+ memset(j->Instrument, 0, j->NumInstruments * sizeof(MODULE_INSTRUMENT));
+
+ for (i = 0; i < j->NumInstruments; i++) {
+
+ if (tver2 < 0x200)
+ j = load_old_instrument(file, insoffs[i], j, i);
+ else
+ j = load_instrument(file, insoffs[i], j, i);
+
+ if (!j) {
+ free(insoffs);
+ free(samoffs);
+ free(patoffs);
+ return NULL;
+ }
+ }
+ }
+
+ if (j->NumSamples) {
+ j->Sample = malloc(j->NumSamples * sizeof(MODULE_SAMPLE));
+
+ if (!j->Sample) {
+ #ifdef DEBUG_SAMPLES
+ fprintf(stderr, "No Mem for Samples!\n");
+ #endif
+ free(insoffs);
+ free(samoffs);
+ free(patoffs);
+ destroy_it(j);
+ return NULL;
+ }
+ memset(j->Sample, 0, j->NumSamples * sizeof(MODULE_SAMPLE));
+
+ for (i=0; i<j->NumSamples; i++) {
+
+ j = load_it_sample(file, samoffs[i], j, i);
+
+ if (!j) {
+ free(insoffs);
+ free(samoffs);
+ free(patoffs);
+ return NULL;
+ }
+ }
+ }
+
+ if (j->NumPatterns) {
+ j->Pattern = malloc(j->NumPatterns * sizeof(MODULE_PATTERN));
+
+ if (!j->Pattern) {
+ #ifdef DEBUG_PATTERNS
+ fprintf(stderr, "No Mem for Patterns!\n");
+ #endif
+ free(insoffs);
+ free(samoffs);
+ free(patoffs);
+ destroy_it(j);
+ return NULL;
+ }
+ memset(j->Pattern, 0, j->NumPatterns * sizeof(MODULE_PATTERN));
+
+ for (i = 0; i < j->NumPatterns; i++) {
+
+ j = load_pattern(file, patoffs[i], j, i);
+
+ if (!j) {
+ free(insoffs);
+ free(samoffs);
+ free(patoffs);
+ return NULL;
+ }
+ }
+ }
+
+ if (insoffs)
+ free(insoffs);
+ if (samoffs)
+ free(samoffs);
+ if (patoffs)
+ free(patoffs);
+
+ return j;
+}
+
+
+
+/* ----------------- */
+
+
+
+#define DUH_SIGNATURE AL_ID('D', 'U', 'H', '!')
+
+
+
+#define SIGTYPE_SAMPLE AL_ID('S', 'A', 'M', 'P')
+
+#define SAMPFLAG_16BIT 1 /* sample in file is 16 bit, rather than 8 bit */
+#define SAMPFLAG_LOOP 2 /* loop indefinitely */
+#define SAMPFLAG_XLOOP 4 /* loop x times; only relevant if LOOP not set */
+#define SAMPFLAG_PINGPONG 8 /* loop back and forth, if LOOP or XLOOP set */
+
+/* SAMPPARAM_N_LOOPS: add 'value' iterations to the loop. 'value' is assumed
+ * to be positive.
+ */
+#define SAMPPARAM_N_LOOPS 0
+
+
+
+#define SIGTYPE_COMBINING AL_ID('C', 'O', 'M', 'B')
+
+
+
+#define SIGTYPE_STEREOPAN AL_ID('S', 'P', 'A', 'N')
+
+#define SPANPARAM_PAN 0
+
+
+
+#define SIGTYPE_SEQUENCE AL_ID('S', 'E', 'Q', 'U')
+
+#define SEQUENCE_START_SIGNAL 0
+#define SEQUENCE_SET_VOLUME 1
+#define SEQUENCE_SET_PITCH 2
+#define SEQUENCE_SET_PARAMETER 3
+#define SEQUENCE_STOP_SIGNAL 4
+
+
+
+void write_sample(MODULE_SAMPLE *sample, PACKFILE *f, int channel)
+{
+ long size = sample->SampleLength;
+ long i;
+ int flags = 0;
+ long loop_start = 0, loop_end = 0;
+
+ SAMPLE *smp = sample->Sample;
+
+ pack_mputl(SIGTYPE_SAMPLE, f);
+
+#ifdef STEREO_SAMPLES_COUNT_AS_TWO
+ if (sample->Flag & SAMPLE_STEREO) {
+ ASSERT((size & 1) == 0);
+ size >>= 1;
+ }
+#endif
+
+#ifdef SUSTAIN_LOOP_OVERRIDES_NORMAL_LOOP
+ if (sample->Flag & SAMPLE_USESUSTAINLOOP) {
+ flags |= SAMPFLAG_XLOOP;
+ if (sample->Flag & SAMPLE_PINGPONGSUSTAINLOOP)
+ flags |= SAMPFLAG_PINGPONG;
+ } else if (sample->Flag & SAMPLE_USELOOP) {
+ flags |= SAMPFLAG_LOOP;
+ if (sample->Flag & SAMPLE_PINGPONGLOOP)
+ flags |= SAMPFLAG_PINGPONG;
+ }
+#else
+ if (sample->Flag & SAMPLE_USELOOP) {
+ flags |= SAMPFLAG_LOOP;
+ if (sample->Flag & SAMPLE_PINGPONGLOOP)
+ flags |= SAMPFLAG_PINGPONG;
+ } else if (sample->Flag & SAMPLE_USESUSTAINLOOP) {
+ flags |= SAMPFLAG_XLOOP;
+ if (sample->Flag & SAMPLE_PINGPONGSUSTAINLOOP)
+ flags |= SAMPFLAG_PINGPONG;
+ }
+#endif
+
+ if (flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP)) {
+ if (flags & SAMPFLAG_LOOP) {
+ loop_start = sample->LoopBegin;
+ loop_end = sample->LoopEnd;
+ } else {
+ loop_start = sample->SustainLoopBegin;
+ loop_end = sample->SustainLoopEnd;
+ }
+
+#ifdef STEREO_SAMPLES_COUNT_AS_TWO
+ if (sample->Flag & SAMPLE_STEREO) {
+ ASSERT(((loop_start | loop_end) & 1) == 0);
+ loop_start >>= 1;
+ loop_end >>= 1;
+ }
+#endif
+
+ if (loop_end > size)
+ loop_end = size;
+ else if (flags & SAMPFLAG_LOOP)
+ size = loop_end;
+ }
+
+ pack_iputl(size, f);
+
+ if (smp->bits == 16)
+ flags |= SAMPFLAG_16BIT;
+
+ pack_putc(flags, f);
+
+ if (flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP)) {
+ pack_iputl(loop_start, f);
+ if (!(flags & SAMPFLAG_LOOP))
+ pack_iputl(loop_end, f);
+ }
+
+ if (flags & SAMPFLAG_16BIT) {
+
+ if (smp->stereo) {
+ for (i = 0; i < size; i++)
+ pack_iputw(((unsigned short *)smp->data)[(i << 1) + channel] ^ 0x8000, f);
+ } else {
+ for (i = 0; i < size; i++)
+ pack_iputw(((unsigned short *)smp->data)[i] ^ 0x8000, f);
+ }
+
+ } else {
+
+ if (smp->stereo) {
+ /* TEMPORARY CHANNEL COMBINING */
+ for (i = 0; i < size; i++)
+ pack_putc(((unsigned char *)smp->data)[(i << 1) + channel] ^ 0x80, f);
+ } else {
+ for (i = 0; i < size; i++)
+ pack_putc(((unsigned char *)smp->data)[i] ^ 0x80, f);
+ }
+
+ }
+}
+
+
+
+int sample_is_valid(MODULE_SAMPLE *sample)
+{
+ if (!(sample->Flag & SAMPLE_HASSAMPLE))
+ return 0;
+
+ if (sample->SampleLength <= 0)
+ return 0;
+
+#ifdef SUSTAIN_LOOP_OVERRIDES_NORMAL_LOOP
+ if ((sample->Flag & (SAMPLE_USELOOP | SAMPLE_USESUSTAINLOOP)) == SAMPLE_USELOOP)
+#else
+ if (sample->Flag & SAMPLE_USELOOP)
+#endif
+ if (sample->LoopEnd <= 0)
+ return 0;
+
+ return 1;
+}
+
+
+
+#define first_sample 1
+
+
+
+void write_mono_sample(MODULE_SAMPLE *sample, int n_samples, PACKFILE *f)
+{
+ pack_mputl(SIGTYPE_STEREOPAN, f);
+
+ /* Refer to the next sample. */
+ pack_iputl(first_sample + n_samples + 1, f);
+
+ write_sample(sample, f, 0);
+}
+
+
+
+void write_stereo_sample(MODULE_SAMPLE *sample, int n_samples, PACKFILE *f)
+{
+ pack_mputl(SIGTYPE_COMBINING, f);
+
+ /* Two samples. */
+ pack_putc(2, f);
+
+ /* Refer to the next two samples. */
+ pack_iputl(first_sample + n_samples + 1, f);
+ pack_iputl(first_sample + n_samples + 2, f);
+
+ write_sample(sample, f, 0);
+ write_sample(sample, f, 1);
+}
+
+
+
+unsigned char *seqdata = NULL;
+int seqpos = 0;
+int max_seqdata = 0;
+
+int seqtime = 0;
+
+int songtime;
+
+
+
+void sequence_c(int v)
+{
+ if (seqpos >= max_seqdata) {
+ max_seqdata += 1024;
+ seqdata = realloc(seqdata, max_seqdata);
+ if (!seqdata) {
+ errno = ENOMEM;
+ return;
+ }
+ }
+ seqdata[seqpos++] = v;
+}
+
+
+void sequence_w(int v)
+{
+ sequence_c(v);
+ sequence_c(v >> 8);
+}
+
+
+void sequence_l(long v)
+{
+ sequence_c(v);
+ sequence_c(v >> 8);
+ sequence_c(v >> 16);
+ sequence_c(v >> 24);
+}
+
+
+void sequence_cl(unsigned long v)
+{
+ int byte_count = 0;
+
+ while (byte_count < 4 && v >= 128) {
+ sequence_c(v | 128);
+ v >>= 7;
+ byte_count++;
+ }
+
+ sequence_c(v & 127);
+}
+
+
+
+void write_seqtime() {
+ sequence_cl(seqtime);
+ seqtime = 0;
+}
+
+
+
+int *sample_signal = NULL;
+
+
+
+void calculate_pan(MODULE *module, MODULE_CHANNEL *channel)
+{
+ int samp;
+
+ if (module->Flags & FLAG_USEINSTRUMENTS && channel->Instrument >= 1 && channel->Instrument <= module->NumInstruments) {
+ MODULE_INSTRUMENT *instrument = &module->Instrument[(int)channel->Instrument - 1];
+ if (instrument) {
+ unsigned char note = instrument->NoteNote[channel->Note];
+ samp = instrument->NoteSample[channel->Note];
+ if (instrument->DefaultPan <= 64)
+ channel->Pan = instrument->DefaultPan;
+ channel->PanSep = (note - instrument->PitchPanCenter) * instrument->PitchPanSeparation / 8;
+ } else {
+ samp = 0;
+ channel->PanSep = 0;
+ }
+ } else {
+ samp = channel->Instrument;
+ channel->PanSep = 0;
+ }
+
+ if (samp >= 1 && samp <= module->NumSamples) {
+ int pan = module->Sample[samp - 1].DefaultPanning;
+ if (pan >= 128 && pan <= 192)
+ channel->Pan = pan - 128;
+ }
+}
+
+
+
+/* This function assumes note->Channel >= 0. */
+void process_note_data(MODULE *module, MODULE_NOTE *note)
+{
+ MODULE_CHANNEL *channel = &module->Channel[(int)note->Channel];
+
+ if (note->Mask & NOTEMASK_NOTE) {
+ if (note->Note >= 120) {
+ channel->Note = note->Note;
+ } else if (channel->Note >= 120) {
+ channel->Note = note->Note;
+ channel->Flag |= CHANNEL_RETRIG;
+ } else {
+ channel->Note = note->Note;
+ if ((note->Mask & NOTEMASK_VOLPAN) == 0 ||
+ !(note->VolPan >= 193 && note->VolPan <= 202))
+ {
+ if ((note->Mask & NOTEMASK_COMMAND) == 0 ||
+ (note->Command != IT_TONE_PORTAMENTO &&
+ note->Command != IT_VOLSLIDE_TONEPORTA))
+ {
+ channel->Flag |= CHANNEL_RETRIG;
+ }
+ }
+ }
+ }
+
+ if (note->Mask & NOTEMASK_INSTRUMENT) {
+ if (note->Instrument != channel->Instrument) {
+ channel->Flag |= CHANNEL_RETRIG;
+ channel->Instrument = note->Instrument;
+ if (!(module->Flags & FLAG_USEINSTRUMENTS)) {
+ if (channel->Instrument >= 1 && channel->Instrument <= module->NumSamples)
+ channel->sample = &module->Sample[channel->Instrument - 1];
+ else
+ channel->sample = NULL;
+ }
+ }
+ }
+
+ if (module->Flags & FLAG_USEINSTRUMENTS) {
+ if (channel->Instrument >= 1 && channel->Instrument <= module->NumInstruments) {
+ int samp = module->Instrument[(int)channel->Instrument - 1].NoteSample[channel->Note];
+ if (samp >= 1 && samp <= module->NumSamples)
+ channel->sample = &module->Sample[samp - 1];
+ else
+ channel->sample = NULL;
+ } else
+ channel->sample = NULL;
+ }
+
+ if (channel->Flag & CHANNEL_RETRIG)
+ calculate_pan(module, channel);
+
+ if (note->Mask & NOTEMASK_INSTRUMENT)
+ if (channel->sample)
+ channel->Volume = channel->sample->DefaultVolume;
+
+ if (!channel->sample)
+ channel->Flag &= ~CHANNEL_RETRIG;
+
+ if (note->Mask & NOTEMASK_VOLPAN) {
+ if (note->VolPan <= 64)
+ channel->Volume = note->VolPan;
+ else if (note->VolPan <= 74) {
+ unsigned char v = note->VolPan - 65;
+ if (v == 0)
+ v = channel->lastvolslide;
+ channel->lastvolslide = v;
+ /* = effect DxF where x == note->VolPan - 65 */
+ channel->Volume += v;
+ if (channel->Volume > 64) channel->Volume = 64;
+
+ } else if (note->VolPan <= 84) {
+ unsigned char v = note->VolPan - 75;
+ if (v == 0)
+ v = channel->lastvolslide;
+ channel->lastvolslide = v;
+ /* = effect DFx where x == note->VolPan - 75 */
+ channel->Volume -= v;
+ if (channel->Volume > 64) channel->Volume = 0;
+ } else if (note->VolPan <= 94) {
+ unsigned char v = note->VolPan - 85;
+ if (v == 0)
+ v = channel->lastvolslide;
+ channel->lastvolslide = v;
+ /* = effect Dx0 where x == note->VolPan - 85 */
+ channel->volslide = v;
+ } else if (note->VolPan <= 104) {
+ unsigned char v = note->VolPan - 95;
+ if (v == 0)
+ v = channel->lastvolslide;
+ channel->lastvolslide = v;
+ /* = effect D0x where x == note->VolPan - 95 */
+ channel->volslide = -v;
+ } else if (note->VolPan <= 114) {
+ unsigned char v = (note->VolPan - 105) << 2;
+ if (v == 0)
+ v = channel->lastEF;
+ channel->lastEF = v;
+ channel->portamento -= v << 4;
+ } else if (note->VolPan <= 124) {
+ unsigned char v = (note->VolPan - 115) << 2;
+ if (v == 0)
+ v = channel->lastEF;
+ channel->lastEF = v;
+ channel->portamento += v << 4;
+ } else if (note->VolPan < 128) { }
+ else if (note->VolPan <= 192)
+ channel->Pan = note->VolPan - 128;
+ else if (note->VolPan <= 202) {
+ //Tone Portamento
+ /* Affects G's memory. Has the equivalent slide given by this
+ * table:
+ */
+ static unsigned char SlideTable[] = {0, 1, 4, 8, 16, 32, 64, 96, 128, 255};
+
+ unsigned char v = SlideTable[note->VolPan - 193];
+ if (module->Flags & FLAG_COMPATIBLEGXX) {
+ if (v == 0)
+ v = channel->lastG;
+ channel->lastG = v;
+ } else {
+ if (v == 0)
+ v = channel->lastEF;
+ channel->lastEF = v;
+ }
+ channel->toneporta += v << 4;
+ } else if (note->VolPan <= 212)
+ ;//Vibrato
+ /* This uses the same 'memory' as Hxx/Uxx. */
+ }
+
+ if (note->Mask & NOTEMASK_COMMAND) {
+ //Interpret effect
+ //unsigned char note->Command, note->CommandValue
+ switch (note->Command) {
+/*
+Notes about effects (as compared to other module formats)
+
+C This is now in *HEX*. (Used to be in decimal in ST3)
+E/F/G/H/U You need to check whether the song uses Amiga/Linear slides.
+H/U Vibrato in Impulse Tracker is two times finer than in
+ any other tracker and is updated EVERY tick.
+ If "Old Effects" is *ON*, then the vibrato is played in the
+ normal manner (every non-row tick and normal depth)
+E/F/G These commands ALL share the same memory.
+Oxx Offsets to samples are to the 'xx00th' SAMPLE. (ie. for
+ 16 bit samples, the offset is xx00h*2)
+ Oxx past the sample end will be ignored, unless "Old Effects"
+ is ON, in which case the Oxx will play from the end of the
+ sample.
+Yxy This uses a table 4 times larger (hence 4 times slower) than
+ vibrato or tremelo. If the waveform is set to random, then
+ the 'speed' part of the command is interpreted as a delay.
+*/
+ case IT_SET_SPEED: if (note->CommandValue) {module->tick = module->Speed = note->CommandValue;} break;
+ //case IT_JUMP_TO_ORDER: module->processorder = note->CommandValue - 1; module->processrow = 0xFFFE; break;
+ //IT_JUMP_TO_ORDER would most likely be used to jump back, so it must be handled specially.
+ case IT_BREAK_TO_ROW: module->breakrow = note->CommandValue; module->processrow = 0xFFFE; break;
+ case IT_VOLUME_SLIDE:
+ {
+ unsigned char v = note->CommandValue;
+ if (v == 0)
+ v = channel->lastDKL;
+ channel->lastDKL = v;
+ if ((v & 0x0F) == 0) { /* Dx0 */
+ channel->volslide = v >> 4;
+ if (channel->volslide == 15) {
+ channel->Volume += 15;
+ if (channel->Volume > 64) channel->Volume = 64;
+ }
+ } else if ((v & 0xF0) == 0) { /* D0x */
+ channel->volslide = -v;
+ if (channel->volslide == -15) {
+ channel->Volume -= 15;
+ if (channel->Volume > 64) channel->Volume = 0;
+ }
+ } else if ((v & 0x0F) == 0x0F) { /* DxF */
+ channel->Volume += v >> 4;
+ if (channel->Volume > 64) channel->Volume = 64;
+ } else if ((v & 0xF0) == 0xF0) { /* DFx */
+ channel->Volume -= v & 15;
+ if (channel->Volume > 64) channel->Volume = 0;
+ }
+ }
+ break;
+ case IT_PORTAMENTO_DOWN:
+ {
+ unsigned char v = note->CommandValue;
+ if (v == 0)
+ v = channel->lastEF;
+ channel->lastEF = v;
+ channel->portamento -= v << 4;
+ }
+ break;
+ case IT_PORTAMENTO_UP:
+ {
+ unsigned char v = note->CommandValue;
+ if (v == 0)
+ v = channel->lastEF;
+ channel->lastEF = v;
+ channel->portamento += v << 4;
+ }
+ break;
+ case IT_TONE_PORTAMENTO:
+ {
+ unsigned char v = note->CommandValue;
+ if (module->Flags & FLAG_COMPATIBLEGXX) {
+ if (v == 0)
+ v = channel->lastG;
+ channel->lastG = v;
+ } else {
+ if (v == 0)
+ v = channel->lastEF;
+ channel->lastEF = v;
+ }
+ channel->toneporta += v << 4;
+ }
+ break;
+ //case IT_VIBRATO:
+ //case IT_TREMOR:
+ //case IT_ARPEGGIO:
+ //case IT_VOLSLIDE_VIBRATO:
+ //case IT_VOLSLIDE_TONEPORTA:
+ case IT_SET_CHANNEL_VOLUME:
+ if (note->CommandValue <= 64)
+ channel->ChannelVolume = note->CommandValue;
+#ifdef VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
+ else
+ channel->ChannelVolume = 64;
+#endif
+ break;
+ case IT_CHANNEL_VOLUME_SLIDE:
+ {
+ unsigned char v = note->CommandValue;
+ if (v == 0)
+ v = channel->lastN;
+ channel->lastN = v;
+ if ((v & 0x0F) == 0) { /* Nx0 */
+ channel->channelvolslide = v >> 4;
+ } else if ((v & 0xF0) == 0) { /* N0x */
+ channel->channelvolslide = -v;
+ } else if ((v & 0x0F) == 0x0F) { /* NxF */
+ channel->ChannelVolume += v >> 4;
+ if (channel->ChannelVolume > 64) channel->ChannelVolume = 64;
+ } else if ((v & 0xF0) == 0xF0) { /* NFx */
+ channel->ChannelVolume -= v & 15;
+ if (channel->ChannelVolume > 64) channel->ChannelVolume = 0;
+ }
+ }
+ break;
+ //case IT_SET_SAMPLE_OFFSET:
+ //case IT_PANNING_SLIDE:
+ //case IT_RETRIGGER_NOTE:
+ //case IT_TREMOLO:
+ case IT_S:
+ switch (note->CommandValue >> 4) {
+ //case IT_S_SET_FILTER:
+ //case IT_S_SET_GLISSANDO_CONTROL:
+ //case IT_S_FINETUNE:
+ //case IT_S_SET_VIBRATO_WAVEFORM:
+ //case IT_S_SET_TREMOLO_WAVEFORM:
+ //case IT_S_SET_PANBRELLO_WAVEFORM:
+ /* Waveforms for commands S3x, S4x and S5x:
+ * 0: Sine wave
+ * 1: Ramp down
+ * 2: Square wave
+ * 3: Random wave
+ */
+ //case IT_S7:
+ case IT_S_SET_PAN:
+ channel->Pan = ((note->CommandValue & 15) << 2) | ((note->CommandValue & 15) >> 2);
+ break;
+ //case IT_S_SET_SURROUND_SOUND:
+ /* S91 Set surround sound */
+ //case IT_S_SET_HIGH_OFFSET:
+ /* SAy Set high value of sample offset yxx00h */
+ //case IT_S_PATTERN_LOOP:
+ /* SB0 Set loopback point */
+ //case IT_S_DELAYED_NOTE_CUT:
+ //case IT_S_NOTE_DELAY:
+ /* SEx Pattern delay for x rows */
+ //case IT_S_SET_MIDI_MACRO:
+ }
+ break;
+ case IT_SET_SONG_TEMPO:
+ {
+ unsigned char v = note->CommandValue;
+ if (v == 0)
+ v = channel->lastW;
+ channel->lastW = v;
+ if (v < 0x10)
+ module->temposlide = -v;
+ else if (v < 0x20)
+ module->temposlide = v & 15;
+ else
+ module->Tempo = v;
+ }
+ break;
+ //case IT_FINE_VIBRATO:
+ case IT_SET_GLOBAL_VOLUME:
+ if (note->CommandValue <= 128)
+ module->GlobalVolume = note->CommandValue;
+#ifdef VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
+ else
+ module->GlobalVolume = 128;
+#endif
+ break;
+ case IT_GLOBAL_VOLUME_SLIDE:
+ {
+ unsigned char v = note->CommandValue;
+ if (v == 0)
+ v = channel->lastW;
+ channel->lastW = v;
+ if ((v & 0x0F) == 0) { /* Nx0 */
+ module->globalvolslide = v >> 4;
+ } else if ((v & 0xF0) == 0) { /* N0x */
+ module->globalvolslide = -v;
+ } else if ((v & 0x0F) == 0x0F) { /* NxF */
+ module->GlobalVolume += v >> 4;
+ if (module->GlobalVolume > 64) module->GlobalVolume = 64;
+ } else if ((v & 0xF0) == 0xF0) { /* NFx */
+ module->GlobalVolume -= v & 15;
+ if (module->GlobalVolume > 64) module->GlobalVolume = 0;
+ }
+ }
+ break;
+ case IT_SET_PANNING:
+ channel->Pan = (note->CommandValue + 2) >> 2;
+ break;
+ //case IT_PANBRELLO:
+ //case IT_MIDI_MACRO://see MIDI.TXT
+ }
+ }
+}
+
+
+
+void update_effects(MODULE *module)
+{
+ int i;
+
+ module->GlobalVolume += module->globalvolslide;
+ if (module->GlobalVolume > 128) {
+ if (module->globalvolslide >= 0)
+ module->GlobalVolume = 128;
+ else
+ module->GlobalVolume = 0;
+ }
+
+ module->Tempo += module->temposlide;
+ if (module->Tempo < 32) {
+ if (module->temposlide >= 0)
+ module->Tempo = 255;
+ else
+ module->Tempo = 32;
+ }
+
+ for (i = 0; i < 64; i++) {
+ MODULE_CHANNEL *channel = &module->Channel[i];
+
+ channel->Volume += channel->volslide;
+ if (channel->Volume > 64) {
+ if (channel->volslide >= 0)
+ channel->Volume = 64;
+ else
+ channel->Volume = 0;
+ }
+
+ channel->ChannelVolume += channel->channelvolslide;
+ if (channel->ChannelVolume > 64) {
+ if (channel->channelvolslide >= 0)
+ channel->ChannelVolume = 64;
+ else
+ channel->ChannelVolume = 0;
+ }
+
+ channel->pitch += channel->portamento;
+ //We do not enforce any limits here. IT surely does. Investigate.
+
+ if (channel->toneporta && channel->sample) {
+ int destpitch;
+ if (module->Flags & FLAG_USEINSTRUMENTS)
+ destpitch = module->Instrument[(int)channel->Instrument - 1].NoteNote[channel->Note];
+ else
+ destpitch = channel->Note;
+ destpitch = (destpitch - 60) << 8;
+ if (channel->pitch > destpitch) {
+ channel->pitch -= channel->toneporta;
+ if (channel->pitch < destpitch)
+ channel->pitch = destpitch;
+ } else if (channel->pitch < destpitch) {
+ channel->pitch += channel->toneporta;
+ if (channel->pitch > destpitch)
+ channel->pitch = destpitch;
+ }
+ }
+ }
+}
+
+
+
+void reset_effects(MODULE *module)
+{
+ int i;
+
+ module->globalvolslide = 0;
+ module->temposlide = 0;
+
+ for (i = 0; i < 64; i++) {
+ module->Channel[i].volslide = 0;
+ module->Channel[i].channelvolslide = 0;
+ module->Channel[i].portamento = 0;
+ module->Channel[i].toneporta = 0;
+ }
+}
+
+
+
+/* This function assumes note->Channel >= 0... or it might later. */
+void update_pattern_variables(MODULE *module, MODULE_NOTE *note)
+{
+ /* MODULE_CHANNEL *channel = &module->Channel[(int)note->Channel]; */
+
+ if (note->Mask & NOTEMASK_COMMAND) {
+ switch (note->Command) {
+ case IT_S:
+ switch (note->CommandValue >> 4) {
+ case IT_S_FINE_PATTERN_DELAY: module->tick = module->Speed + (note->CommandValue & 15); break;
+ //case IT_S7:
+ //case IT_S_PATTERN_LOOP:
+ /* SB0 Set loopback point */
+ //case IT_S_DELAYED_NOTE_CUT:
+ //case IT_S_NOTE_DELAY:
+ case IT_S_PATTERN_DELAY: module->rowcount = 1 + (note->CommandValue & 15); break;
+ }
+ break;
+ }
+ }
+}
+
+
+
+unsigned char envelope_get_y(MODULE_ENVELOPE *envelope, MODULE_VENVELOPE *venvelope)
+{
+ int ys, ye;
+ int ts, te;
+ int t;
+
+ if (venvelope->NextNode <= 0)
+ return envelope->NodeY[0];
+
+ if (venvelope->NextNode >= envelope->NumNodes)
+ return envelope->NodeY[envelope->NumNodes - 1];
+
+ ys = envelope->NodeY[venvelope->NextNode - 1];
+ ye = envelope->NodeY[venvelope->NextNode];
+ ts = envelope->NodeTick[venvelope->NextNode - 1];
+ te = envelope->NodeTick[venvelope->NextNode];
+ t = venvelope->CurTick;
+
+ if (ts == te)
+ return ys;
+
+ return ys + (ye - ys) * (t - ts) / (te - ts);
+}
+
+
+
+unsigned int calculate_volume(MODULE *module, MODULE_VCHANNEL *vchannel)
+{
+ if (module->Flags & FLAG_USEINSTRUMENTS) {
+ int vev = 64;
+ if (module->Instrument[vchannel->Instrument - 1].VolumeEnvelope.Flag & ENVELOPE_ON)
+ vev = envelope_get_y(&module->Instrument[vchannel->Instrument - 1].VolumeEnvelope, &vchannel->VVolEnv);
+ return (((((((vchannel->Volume *
+ vchannel->sample->GlobalVolume *
+ module->Instrument[vchannel->Instrument - 1].GlobalVolume) >> 7) *
+ module->GlobalVolume) >> 11) *
+ vev *
+ module->MixVolume) >> 10) *
+ vchannel->fadeoutcount) >> 11;
+ }
+
+ return (((vchannel->Volume *
+ vchannel->sample->GlobalVolume *
+ module->GlobalVolume) >> 11) *
+ module->MixVolume) >> 5;
+}
+
+
+
+void process_channels(MODULE *module)
+{
+ int i;
+
+ for (i = 0; i < 64; i++) {
+ MODULE_CHANNEL *channel = &module->Channel[i];
+ if (channel->Note < 120) {
+ if (channel->Flag & CHANNEL_RETRIG) {
+ channel->Flag &= ~CHANNEL_RETRIG;
+ if (channel->VChannel) {
+ if (!(module->Flags & FLAG_USEINSTRUMENTS) ||
+ (channel->VChannel->NNA = module->Instrument[channel->VChannel->Instrument - 1].NewNoteAction)
+ == NNA_NOTECUT)
+ {
+ if (channel->VChannel->Flag & VCHANNEL_PLAYING) {
+ write_seqtime();
+ sequence_c(SEQUENCE_STOP_SIGNAL);
+ sequence_c(channel->VChannel - module->VChannel);
+ }
+ } else {
+ if (channel->VChannel->NNA == NNA_NOTEOFF)
+ if ((module->Instrument[channel->VChannel->Instrument - 1].VolumeEnvelope.Flag & (ENVELOPE_ON | ENVELOPE_LOOP_ON)) != ENVELOPE_ON)
+ channel->VChannel->NNA = NNA_NOTEFADE;
+ if (channel->VChannel->NNA == NNA_NOTEFADE)
+ channel->VChannel->Flag |= VCHANNEL_FADING;
+ channel->VChannel->Flag |= VCHANNEL_BACKGROUND;
+ channel->VChannel->channel = NULL;
+ channel->VChannel = NULL;
+ }
+ }
+ if (!channel->VChannel) {
+ int k;
+ for (k = 0; k < 256; k++) {
+ if (!(module->VChannel[k].Flag & VCHANNEL_PLAYING)) {
+ channel->VChannel = &module->VChannel[k];
+ break;
+ }
+ }
+ if (!channel->VChannel) {
+ for (k = 0; k < 256; k++) {
+ if (module->VChannel[k].Flag & VCHANNEL_BACKGROUND) {
+ write_seqtime();
+ sequence_c(SEQUENCE_STOP_SIGNAL);
+ sequence_c(k);
+ channel->VChannel = &module->VChannel[k];
+ break;
+ }
+ }
+ }
+ }
+ if (channel->VChannel) {
+ unsigned char note;
+ channel->VChannel->Flag = VCHANNEL_PLAYING | VCHANNEL_RETRIG;
+ channel->VChannel->channel = channel;
+ channel->VChannel->Note = channel->Note;
+ if (module->Flags & FLAG_USEINSTRUMENTS)
+ note = module->Instrument[(int)channel->Instrument - 1].NoteNote[channel->Note];
+ else
+ note = channel->Note;
+ channel->pitch = (note - 60) << 8;
+ channel->VChannel->pitch = channel->pitch;
+ channel->VChannel->Instrument = channel->Instrument;
+ channel->VChannel->sample = channel->sample;
+ channel->VChannel->VVolEnv.NextNode = 0;
+ channel->VChannel->VVolEnv.CurTick = 0;
+ channel->VChannel->fadeoutcount = 1024;
+ channel->VChannel->NNA = NNA_NOTECONTINUE;
+ channel->VChannel->Volume = channel->ChannelVolume * channel->Volume;
+ channel->VChannel->Pan = channel->Pan;
+ channel->VChannel->PanSep = channel->PanSep;
+ /* Note: The DUH* fields are set when writing the start command to the DUH sequence. */
+ //BLEARGH: Anything else to initialise?
+ }
+ }
+ } else if (channel->VChannel) {
+ if (channel->Note == NOTE_CUT) {
+ if (channel->VChannel->Flag & VCHANNEL_PLAYING) {
+ write_seqtime();
+ sequence_c(SEQUENCE_STOP_SIGNAL);
+ sequence_c(channel->VChannel - module->VChannel);
+ channel->VChannel->Flag &= ~VCHANNEL_PLAYING;
+ channel->VChannel->channel = NULL;
+ channel->VChannel = NULL;
+ }
+ } else {
+ channel->VChannel->Flag |= VCHANNEL_BACKGROUND;
+
+ if (channel->Note == NOTE_OFF) {
+ if ((module->Instrument[channel->VChannel->Instrument - 1].VolumeEnvelope.Flag & (ENVELOPE_ON | ENVELOPE_LOOP_ON)) != ENVELOPE_ON)
+ channel->VChannel->NNA = NNA_NOTEFADE;
+ else
+ channel->VChannel->NNA = NNA_NOTEOFF;
+ } else
+ channel->VChannel->NNA = NNA_NOTEFADE;
+
+ if (channel->VChannel->NNA == NNA_NOTEFADE)
+ channel->VChannel->Flag |= VCHANNEL_FADING;
+ /*
+ channel->VChannel->channel = NULL;
+ channel->VChannel = NULL;
+ */
+ }
+ }
+ }
+}
+
+
+
+/* This returns 1 if the envelope finishes. */
+int update_envelope(MODULE_VCHANNEL *vchannel, MODULE_ENVELOPE *envelope, MODULE_VENVELOPE *venvelope)
+{
+ if (!(envelope->Flag & ENVELOPE_ON))
+ return 0;
+
+ if (venvelope->NextNode >= envelope->NumNodes)
+ return 1;
+
+ while (venvelope->CurTick >= envelope->NodeTick[venvelope->NextNode]) {
+ if ((envelope->Flag & ENVELOPE_LOOP_ON) && venvelope->NextNode == envelope->LoopEnd) {
+ venvelope->NextNode = envelope->LoopBegin;
+ venvelope->CurTick = envelope->NodeTick[envelope->LoopBegin];
+ return 0;
+ }
+ if ((envelope->Flag & ENVELOPE_SUSTAINLOOP) && !(vchannel->Flag & VCHANNEL_BACKGROUND) && venvelope->NextNode == envelope->SustainLoopEnd) {
+ venvelope->NextNode = envelope->SustainLoopBegin;
+ venvelope->CurTick = envelope->NodeTick[envelope->SustainLoopBegin];
+ return 0;
+ }
+ if (venvelope->NextNode >= envelope->NumNodes)
+ return 1;
+
+ venvelope->NextNode++;
+ }
+
+ venvelope->CurTick++;
+
+ return 0;
+}
+
+
+
+/* This assumes the module uses instruments. */
+void update_envelopes(MODULE *module, MODULE_VCHANNEL *vchannel)
+{
+ if (vchannel->Flag & VCHANNEL_PLAYING) {
+ MODULE_ENVELOPE *volenv = &module->Instrument[vchannel->Instrument - 1].VolumeEnvelope;
+
+ if (update_envelope(vchannel, volenv, &vchannel->VVolEnv)) {
+ if (volenv->NumNodes && volenv->NodeY[volenv->NumNodes - 1] == 0) {
+ write_seqtime();
+ sequence_c(SEQUENCE_STOP_SIGNAL);
+ sequence_c(vchannel - module->VChannel);
+ vchannel->Flag = 0;
+ if (vchannel->channel)
+ vchannel->channel->VChannel = NULL;
+ vchannel->channel = NULL;
+ } else
+ vchannel->Flag |= VCHANNEL_FADING;
+ }
+ }
+}
+
+
+
+/* This assumes the module uses instruments. */
+void update_fadeout(MODULE *module, MODULE_VCHANNEL *vchannel)
+{
+ if (vchannel->Flag & VCHANNEL_PLAYING) {
+ if (vchannel->Flag & VCHANNEL_FADING) {
+ vchannel->fadeoutcount -= module->Instrument[vchannel->Instrument - 1].FadeOut;
+
+ if (vchannel->fadeoutcount <= 0) {
+ write_seqtime();
+ sequence_c(SEQUENCE_STOP_SIGNAL);
+ sequence_c(vchannel - module->VChannel);
+ vchannel->Flag = 0;
+ if (vchannel->channel)
+ vchannel->channel->VChannel = NULL;
+ vchannel->channel = NULL;
+ }
+ }
+ }
+}
+
+
+
+#define INCLUDE_RETRIG
+#define INCLUDE_PLAYING
+void process_vchannels(MODULE *module)
+{
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ MODULE_VCHANNEL *vchannel = &module->VChannel[i];
+
+ if ((vchannel->Flag & VCHANNEL_PLAYING) && vchannel->channel) {
+ vchannel->Volume = vchannel->channel->ChannelVolume * vchannel->channel->Volume;
+ vchannel->Pan = vchannel->channel->Pan;
+ vchannel->PanSep = vchannel->channel->PanSep;
+ }
+
+ if (module->Flags & FLAG_USEINSTRUMENTS) {
+ //Update envelopes as required
+ update_envelopes(module, vchannel);
+ //Update fadeout as required
+ update_fadeout(module, vchannel);
+ //Calculate final volume if req
+ //Calculate final pan if req
+ //Process sample vibrato if req
+ } else {
+ //Calculate final volume if required
+ //Calculate final pan if required
+ //Process sample vibrato if required
+ }
+
+#ifdef INCLUDE_RETRIG
+ if (vchannel->Flag & VCHANNEL_RETRIG) {
+ vchannel->Flag &= ~VCHANNEL_RETRIG;
+
+ if (vchannel->sample) {
+ int C5Speed = vchannel->sample->C5Speed;
+ int adjust;
+
+#ifdef STEREO_SAMPLES_COUNT_AS_TWO
+ if (vchannel->sample->Flag & SAMPLE_STEREO)
+ C5Speed >>= 1;
+#endif
+
+ write_seqtime();
+ sequence_c(SEQUENCE_START_SIGNAL);
+ sequence_c(vchannel - module->VChannel);
+
+ sequence_cl(sample_signal[vchannel->sample - module->Sample]);
+ sequence_cl(0); // sample position: 65536 is one second
+
+ vchannel->DUHvol = calculate_volume(module, vchannel);
+
+ sequence_w(vchannel->DUHvol - (vchannel->DUHvol >> 16));
+
+ adjust = floor(12 * 256 *
+ (log(C5Speed / 65536.0) / log(2.0)) + 0.5);
+
+ /* pitch */
+ sequence_w(adjust + vchannel->pitch);
+
+ vchannel->DUHpan = 32;
+
+ } else
+ vchannel->Flag = 0;
+ }
+#endif
+
+#ifdef INCLUDE_PLAYING
+ if (vchannel->Flag & VCHANNEL_PLAYING) {
+ //Update to vchannel->channel->stuff if different from vchannel->stuff.
+ //stuff would be volume, panning, pitch, etc.
+ {
+ unsigned int volume = calculate_volume(module, vchannel);
+ if (volume != vchannel->DUHvol) {
+ vchannel->DUHvol = volume;
+ write_seqtime();
+ sequence_c(SEQUENCE_SET_VOLUME);
+ sequence_c(vchannel - module->VChannel);
+ sequence_w(volume - (volume >> 16));
+ }
+ }
+ {
+ int pan = vchannel->Pan + vchannel->PanSep;
+ if (pan < 0)
+ pan = 0;
+ else if (pan > 64)
+ pan = 64;
+ if (pan != vchannel->DUHpan) {
+ vchannel->DUHpan = pan;
+ write_seqtime();
+ sequence_c(SEQUENCE_SET_PARAMETER);
+ sequence_c(vchannel - module->VChannel);
+ sequence_c(SPANPARAM_PAN);
+ sequence_l(((int)pan << 3) - 256);
+ }
+ }
+ if (vchannel->channel) {
+ if (vchannel->channel->pitch != vchannel->pitch) {
+ int C5Speed = vchannel->sample->C5Speed;
+ int adjust;
+
+#ifdef STEREO_SAMPLES_COUNT_AS_TWO
+ if (vchannel->sample->Flag & SAMPLE_STEREO)
+ C5Speed >>= 1;
+#endif
+
+ vchannel->pitch = vchannel->channel->pitch;
+
+ write_seqtime();
+ sequence_c(SEQUENCE_SET_PITCH);
+ sequence_c(vchannel - module->VChannel);
+
+ adjust = floor(12 * 256 *
+ (log(C5Speed / 65536.0) / log(2.0)) + 0.5);
+
+ sequence_w(adjust + vchannel->pitch);
+ }
+ }
+
+ if (vchannel->Flag & VCHANNEL_BACKGROUND) {
+ //Process vchannel->NNA
+ //If the note has ended then:
+ /*
+ {
+ write_seqtime();
+ sequence_c(SEQUENCE_STOP_SIGNAL);
+ sequence_c(vchannel - module->VChannel);
+ vchannel->Flag = 0;
+ }
+ */
+ } else {
+ //Process note
+ }
+ }
+#endif
+ }
+}
+
+
+
+void generate_patterns(MODULE *module)
+{
+ int patnum = module->Order[0];
+ int row;
+
+ MODULE_PATTERN *pattern;
+ MODULE_NOTE *note, *note_end;
+
+ module->processorder = 0;
+ module->processrow = 0;
+ module->breakrow = 0;
+ module->rowcount = 1;
+
+ module->tick = module->Speed;
+
+ goto start_the_loop; /* This ungainly goto will be averted later. */
+
+ for (;;) {
+ // Set note vol/freq to vol/freq set for each channel
+
+ module->tick--;
+ if (module->tick == 0) {
+ module->tick = module->Speed;
+ module->rowcount--;
+ if (module->rowcount == 0) {
+ module->rowcount = 1;
+ module->processrow++;
+ if (module->processrow >= pattern->NumRows) {
+ module->processrow = module->breakrow;
+ module->breakrow = 0;
+ module->processorder++;
+
+ start_the_loop:
+
+ for (; ; module->processorder++) {
+ if (module->processorder >= module->NumOrders)
+ return;
+
+ patnum = module->Order[module->processorder];
+
+ if (patnum < module->NumPatterns)
+ break;
+
+#ifdef INVALID_ORDERS_END_SONG
+ if (patnum != ORDER_SKIP)
+ return;
+#else
+ if (patnum == ORDER_END)
+ return;
+#endif
+ }
+
+ printf(" Order %i, Pattern %i\n", module->processorder, patnum);
+
+ pattern = &module->Pattern[patnum];
+
+ note = pattern->Note;
+ note_end = note + pattern->NumNotes;
+ }
+
+ row = module->processrow;
+
+ {
+ MODULE_NOTE *note_start = note;
+
+ while (note < note_end && note->Channel >= 0)
+ update_pattern_variables(module, note++);
+
+ note = note_start;
+ }
+
+ reset_effects(module);
+
+ //Should this code go before updating the pattern variables?
+ while (note < note_end) {
+ if (note->Channel < 0) {
+ note++;
+ break;
+ }
+ process_note_data(module, note++);
+ }
+
+ } else
+ update_effects(module);
+ } else
+ update_effects(module);
+
+ process_channels(module);
+
+ /* Output sound!!! */
+ process_vchannels(module);
+
+ /* Increment time by one tick. */
+ {
+ int inc = ((65536.0 * 60.0) / (4.0 * 6.0)) / module->Tempo;
+ seqtime += inc;
+ songtime += inc;
+ }
+ }
+}
+
+
+
+void stop_notes(MODULE *module)
+{
+ int c;
+ for (c = 0; c < 256; c++) {
+ if (module->VChannel[c].Flag & VCHANNEL_PLAYING) {
+ write_seqtime();
+ sequence_c(SEQUENCE_STOP_SIGNAL);
+ sequence_c(c);
+ }
+ }
+}
+
+
+
+void generate_sequence(MODULE *module)
+{
+ int i;
+
+ for (i = 0; i < 64; i++) {
+ module->Channel[i].Note = 255;
+ module->Channel[i].Instrument = 0;
+ module->Channel[i].sample = NULL;
+ module->Channel[i].VChannel = NULL;
+ module->Channel[i].lastvolslide = 0;
+ module->Channel[i].lastDKL = 0;
+ module->Channel[i].lastN = 0;
+ module->Channel[i].lastW = 0;
+ module->Channel[i].lastEF = 0;
+ module->Channel[i].lastG = 0;
+ module->Channel[i].lastT = 0;
+ }
+
+ for (i = 0; i < 256; i++)
+ module->VChannel[i].Flag = 0;
+
+ songtime = 0;
+
+ generate_patterns(module);
+/*
+ for (i = 0; i < module->NumOrders; i++) {
+
+ if (module->Order[i] < module->NumPatterns)
+ write_pattern(module, &module->Pattern[module->Order[i]]);
+ else {
+#ifdef INVALID_ORDERS_END_SONG
+ if (module->Order[i] != ORDER_SKIP)
+ break;
+#else
+ if (module->Order[i] == ORDER_END)
+ break;
+#endif
+ }
+ }
+*/
+ stop_notes(module);
+
+ /* Negative time to indicate the end of the sequence. */
+ sequence_cl(-1);
+
+ if (errno)
+ return;
+}
+
+
+
+void write_sequence(PACKFILE *f)
+{
+ pack_mputl(SIGTYPE_SEQUENCE, f);
+
+ pack_iputl(seqpos, f);
+ pack_fwrite(seqdata, seqpos, f);
+}
+
+
+
+void free_sequence()
+{
+ free(seqdata);
+ seqdata = NULL;
+ seqpos = 0;
+ max_seqdata = 0;
+ seqtime = 0;
+}
+
+
+
+int save_it_to_duh(MODULE *module, const char *filename)
+{
+ int i;
+ int n_samples = 0;
+
+ PACKFILE *f = pack_fopen(filename, F_WRITE_PACKED);
+ if (!f) return 1;
+
+ /* Write signature. */
+ pack_mputl(DUH_SIGNATURE, f);
+
+ /* Create array of true samples. */
+ sample_signal = malloc(module->NumSamples * sizeof(*sample_signal));
+
+ for (i = 0; i < module->NumSamples; i++) {
+ if (sample_is_valid(&module->Sample[i])) {
+ sample_signal[i] = first_sample + n_samples;
+ if (module->Sample[i].Flag & SAMPLE_STEREO)
+ n_samples += 3; /* COMB,SAMP,SAMP */
+ else
+ n_samples += 2; /* SPAN,SAMP */
+ } else
+ sample_signal[i] = -1;
+ }
+
+ printf("Generating sequence\n");
+ generate_sequence(module);
+
+ /* Write length of song. */
+ pack_iputl(songtime, f);
+
+ /* Write number of signals - one for the sequence, one for each sample. */
+ pack_iputl(1 + n_samples, f);
+
+ if (errno) {pack_fclose(f); free(sample_signal); return 1;}
+
+ printf("Writing sequence\n");
+ write_sequence(f);
+ free_sequence();
+
+ if (errno) {pack_fclose(f); free(sample_signal); return 1;}
+
+ printf("Writing samples");
+ n_samples = 0;
+ for (i = 0; i < module->NumSamples; i++) {
+ if ((i & 7) == 0)
+ printf("\n ");
+ printf("%4d", i + 1);
+
+ if (sample_is_valid(&module->Sample[i])) {
+
+ if (module->Sample[i].Flag & SAMPLE_STEREO) {
+ write_stereo_sample(&module->Sample[i], n_samples, f);
+ n_samples += 3;
+ } else {
+ write_mono_sample(&module->Sample[i], n_samples, f);
+ n_samples += 2;
+ }
+
+ if (errno) {pack_fclose(f); free(sample_signal); return 1;}
+ }
+ }
+ printf("\n");
+
+ free(sample_signal);
+ sample_signal = NULL;
+
+ pack_fclose(f);
+
+ if (errno) {pack_fclose(f); return 1;}
+
+ return 0;
+}
+
+
+
+#undef first_sample
+
+
+
+void usage()
+{
+ allegro_message(
+ "Usage: cit.exe filename.it [filename.duh]\n"
+ "Converts an Impulse Tracker file into a Dynamic Universal Harmony.\n"
+ );
+
+ exit(1);
+}
+
+
+
+int main(int argc, char *argv[])
+{
+ MODULE *module;
+ int rv;
+ char *outmod;
+
+ if (argc < 2 || argc > 3)
+ usage();
+
+ allegro_init();
+
+ /* Make the output file name if it wasn't specified */
+ if (argc == 2) {
+ int size = sizeof(char) * (ustrsizez(argv[1]) + 32);
+ outmod = malloc(size);
+ if (!outmod) {
+ allegro_message("Ran out of memory while trying to allocate %i bytes. (%s:(%i))\n", size, __FILE__, __LINE__);
+ return -1;
+ }
+ ustrzcpy(outmod, size, argv[1]);
+ replace_extension(outmod, argv[1], "duh", size);
+ }
+ else
+ outmod = argv[2];
+
+ module = load_it(argv[1]);
+
+ if (!module) {
+ allegro_exit();
+ allegro_message("Unable to load %s!\n", argv[1]);
+ return 1;
+ }
+
+ rv = save_it_to_duh(module, outmod);
+
+ destroy_it(module);
+
+ if (rv) {
+ delete_file(outmod);
+ allegro_exit();
+ allegro_message("Unable to save %s!\n", outmod);
+ return 1;
+ }
+
+ if (argc == 2 && outmod)
+ free(outmod);
+
+ return 0;
+}
+END_OF_MAIN();
diff --git a/plugins/dumb/dumb-kode54/winamp/gui.c b/plugins/dumb/dumb-kode54/winamp/gui.c
index 45ac978b..af38a1fc 100644
--- a/plugins/dumb/dumb-kode54/winamp/gui.c
+++ b/plugins/dumb/dumb-kode54/winamp/gui.c
@@ -1,331 +1,331 @@
-
-#include <stdio.h>
-#include <windows.h>
-//#include <mmreg.h>
-//#include <msacm.h>
-#include <math.h>
-#include <commctrl.h>
-
-#include "in_duh.h"
-#include "resource.h"
-
-#include "gui.h"
-
-
-/* Registry settings */
-#define REGISTRY_KEY "Software\\Winamp\\DUH Plug-in"
-static HKEY registry = INVALID_HANDLE_VALUE;
-
-/* Some default values for config */
-int config_bits_per_sample = 16;
-int config_frequency = 44100;
-int config_stereo = CHANNEL_STEREO;
-int config_resampling = RESAMPLING_CUBIC;
-int config_buffer_size = 8192;
-int config_thread_priority = PRIORITY_HIGH;
-
-
-/*************************
- * Registry manipulation */
-
-static int read_registry(char const *name, unsigned long type, void *ptr, unsigned long size)
-{
- unsigned long reg_type;
-
- if (registry == INVALID_HANDLE_VALUE ||
- RegQueryValueEx(registry, name, 0, &reg_type, ptr, &size) != ERROR_SUCCESS
- || reg_type != type)
-
- return -1;
-
- return 0;
-}
-
-
-static int write_registry(char const *name, unsigned long type, void *ptr, unsigned long size)
-{
- if (registry == INVALID_HANDLE_VALUE
- || RegSetValueEx(registry, name, 0, type, ptr, size) != ERROR_SUCCESS)
-
- return -1;
-
- return 0;
-}
-
-
-# define LOAD_REG_INT(name, var, defaultv) (read_registry(name, REG_DWORD, \
- &(var), sizeof(var)) == -1 ? ((var) = (defaultv)) : (var))
-
-# define LOAD_REG_STRING(name, var, defaultv) (read_registry(name, REG_SZ, \
- (var), sizeof(var)) == -1 ? strcpy(var, (defaultv)) : (var))
-
-# define SAVE_REG_INT(name, var) (write_registry(name, REG_DWORD, &(var), sizeof(var)))
-# define SAVE_REG_STRING(name, var) (write_registry(name, REG_SZ, (var), sizeof(var)))
-
-
-/*********************
- * Range check */
-
-#define CHECK_RANGE(x, a, b) x = ((x < (a)) ? (a) : ((x > (b)) ? (b) : x))
-
-
-/*********************
- * Config Dialog Box */
-
-
-static INT_PTR CALLBACK config_dialog(HWND dialog, UINT message,
- WPARAM wparam, LPARAM lparam)
-{
- int which;
- int temp;
- static int old_slider1 = 0;
- char str[64];
-
- (void)lparam;
-
- switch (message) {
- case WM_INITDIALOG:
-
- /* Ok, now we need to set up the dialog's controls
- * to match the current config
- */
-
- /* Channels */
- CheckDlgButton(dialog, IDC_STEREO, config_stereo == CHANNEL_STEREO ? BST_CHECKED : BST_UNCHECKED);
-
- /* Bits per sample */
- switch (config_bits_per_sample) {
- case 8: which = IDC_8BPS; break;
- case 16: which = IDC_16BPS; break;
- default:
- which = 0;
- }
- if (which)
- CheckRadioButton(dialog, IDC_8BPS, IDC_16BPS, which);
-
- /* Resampling method */
- switch (config_resampling) {
- case RESAMPLING_ALIASING: which = IDC_ALIASING; break;
- case RESAMPLING_LINEAR: which = IDC_LINEAR; break;
- case RESAMPLING_LINEAR2: which = IDC_LINEAR_LOW_PASS; break;
- case RESAMPLING_QUADRATIC: which = IDC_QUADRATIC; break;
- case RESAMPLING_CUBIC: which = IDC_CUBIC; break;
- default:
- which = 0;
- }
- if (which)
- CheckRadioButton(dialog, IDC_ALIASING, IDC_CUBIC, which);
-
- /* Frequency */
- switch (config_frequency) {
- case 11025: which = IDC_11KHZ; break;
- case 22050: which = IDC_22KHZ; break;
- case 44100: which = IDC_44KHZ; break;
- case 48000: which = IDC_48KHZ; break;
- default:
- which = 0;
- }
- if (which)
- CheckRadioButton(dialog, IDC_11KHZ, IDC_48KHZ, which);
-
- /* Buffer size - 1 KB -> 32 KB slider */
- old_slider1 = (int)(log(config_buffer_size) / log(2)) - 10;
- SendDlgItemMessage(dialog, IDC_BUFFERSIZE, TBM_SETRANGE, FALSE, MAKELONG(0, 5));
- SendDlgItemMessage(dialog, IDC_BUFFERSIZE, TBM_SETPOS, TRUE, old_slider1);
- sprintf(str, "%i KS", config_buffer_size / 1024);
- SetDlgItemText(dialog, IDC_BUFFERSIZE2, str);
-
- /* Thread Priority */
- SendDlgItemMessage(dialog, IDC_THREAD_PRI, TBM_SETRANGE, FALSE, MAKELONG(0, 2));
- SendDlgItemMessage(dialog, IDC_THREAD_PRI, TBM_SETPOS, TRUE, config_thread_priority);
-
- return TRUE;
-
- case WM_COMMAND:
- switch (LOWORD(wparam)) {
-
- case IDC_DEFAULT:
- /* Load default settings */
-
- /* Channels */
- CheckDlgButton(dialog, IDC_STEREO, BST_CHECKED);
-
- /* Bits per sample */
- CheckRadioButton(dialog, IDC_8BPS, IDC_16BPS, IDC_16BPS);
-
- /* Resampling method */
- CheckRadioButton(dialog, IDC_ALIASING, IDC_CUBIC, IDC_LINEAR_LOW_PASS);
-
- /* Frequency */
- CheckRadioButton(dialog, IDC_11KHZ, IDC_48KHZ, IDC_44KHZ);
-
- /* Buffer size - 1 KB -> 32 KB slider */
- SendDlgItemMessage(dialog, IDC_BUFFERSIZE, TBM_SETPOS, TRUE, 3);
- sprintf(str, "%i KS", 8192 / 1024);
- SetDlgItemText(dialog, IDC_BUFFERSIZE2, str);
-
- /* Thread Priority */
- SendDlgItemMessage(dialog, IDC_THREAD_PRI, TBM_SETPOS, TRUE, PRIORITY_HIGH);
-
- return TRUE;
-
- case IDC_NICEST:
- /* Load nicest settings */
-
- /* Channels */
- CheckDlgButton(dialog, IDC_STEREO, BST_CHECKED);
-
- /* Bits per sample */
- CheckRadioButton(dialog, IDC_8BPS, IDC_16BPS, IDC_16BPS);
-
- /* Resampling method */
- CheckRadioButton(dialog, IDC_ALIASING, IDC_CUBIC, IDC_CUBIC);
-
- /* Frequency */
- CheckRadioButton(dialog, IDC_11KHZ, IDC_48KHZ, IDC_48KHZ);
-
- /* Buffer size - 1 KB -> 32 KB slider */
- SendDlgItemMessage(dialog, IDC_BUFFERSIZE, TBM_SETPOS, TRUE, 3);
- sprintf(str, "%i KS", 8192 / 1024);
- SetDlgItemText(dialog, IDC_BUFFERSIZE2, str);
-
- /* Thread Priority */
- SendDlgItemMessage(dialog, IDC_THREAD_PRI, TBM_SETPOS, TRUE, PRIORITY_HIGH);
-
- return TRUE;
-
- case IDC_FASTEST:
- /* Load fastest settings */
-
- /* Channels */
- CheckDlgButton(dialog, IDC_STEREO, BST_UNCHECKED);
-
- /* Bits per sample */
- CheckRadioButton(dialog, IDC_8BPS, IDC_16BPS, IDC_8BPS);
-
- /* Resampling method */
- CheckRadioButton(dialog, IDC_ALIASING, IDC_CUBIC, IDC_ALIASING);
-
- /* Frequency */
- CheckRadioButton(dialog, IDC_11KHZ, IDC_48KHZ, IDC_11KHZ);
-
- /* Buffer size - 1 KB -> 32 KB slider */
- SendDlgItemMessage(dialog, IDC_BUFFERSIZE, TBM_SETPOS, TRUE, 3);
- sprintf(str, "%i KS", 8192 / 1024);
- SetDlgItemText(dialog, IDC_BUFFERSIZE2, str);
-
- /* Thread Priority */
- SendDlgItemMessage(dialog, IDC_THREAD_PRI, TBM_SETPOS, TRUE, PRIORITY_HIGH);
-
- return TRUE;
-
- case IDC_OK:
- /* Read back configuration */
- config_stereo = (IsDlgButtonChecked(dialog, IDC_STEREO) == BST_CHECKED) ? CHANNEL_STEREO : CHANNEL_MONO;
- config_bits_per_sample = (IsDlgButtonChecked(dialog, IDC_8BPS) == BST_CHECKED) ? 8 : 16;
- config_resampling = (IsDlgButtonChecked(dialog, IDC_ALIASING) == BST_CHECKED) ? RESAMPLING_ALIASING
- : (IsDlgButtonChecked(dialog, IDC_LINEAR) == BST_CHECKED) ? RESAMPLING_LINEAR
- : (IsDlgButtonChecked(dialog, IDC_LINEAR_LOW_PASS) == BST_CHECKED) ? RESAMPLING_LINEAR2
- : (IsDlgButtonChecked(dialog, IDC_QUADRATIC) == BST_CHECKED) ? RESAMPLING_QUADRATIC
- : RESAMPLING_CUBIC;
- config_frequency = (IsDlgButtonChecked(dialog, IDC_11KHZ) == BST_CHECKED) ? 11025
- : (IsDlgButtonChecked(dialog, IDC_22KHZ) == BST_CHECKED) ? 22050
- : (IsDlgButtonChecked(dialog, IDC_44KHZ) == BST_CHECKED) ? 44100
- : 48000;
- config_buffer_size = 1 << (SendDlgItemMessage(dialog, IDC_BUFFERSIZE, TBM_GETPOS, 0, 0) + 10);
-
- config_thread_priority = SendDlgItemMessage(dialog, IDC_THREAD_PRI, TBM_GETPOS, 0, 0);
-
- case IDCANCEL:
- case IDC_CANCEL:
- case IDCLOSE:
- EndDialog(dialog, wparam);
- return TRUE;
- }
- break;
- default:
- temp = 1 << (SendDlgItemMessage(dialog, IDC_BUFFERSIZE, TBM_GETPOS, 0, 0) + 10);
- if (temp != old_slider1) {
- old_slider1 = temp;
- sprintf(str, "%i KS", temp / 1024);
- SetDlgItemText(dialog, IDC_BUFFERSIZE2, str);
- return TRUE;
- }
- break;
- }
- return FALSE;
-}
-
-
-
-/* DUH Config dialog */
-void config(HWND hwndParent) {
-
- if (DialogBox(mod.hDllInstance, MAKEINTRESOURCE(IDD_CONFIG),
- hwndParent, config_dialog) == IDC_OK) {
-
- SAVE_REG_INT("Stereo", config_stereo);
- SAVE_REG_INT("Frequency", config_frequency);
- SAVE_REG_INT("Resampling", config_resampling);
- SAVE_REG_INT("BitsPerSample", config_bits_per_sample);
- SAVE_REG_INT("BufferSize", config_buffer_size);
- SAVE_REG_INT("ThreadPriority", config_thread_priority);
- }
-}
-
-
-void config_init(void) {
-
- /* Load config from registry */
-
- if (RegCreateKeyEx(HKEY_CURRENT_USER, REGISTRY_KEY, 0, "",
- REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, 0,
- &registry, 0) != ERROR_SUCCESS)
-
- registry = INVALID_HANDLE_VALUE;
-
- LOAD_REG_INT("Stereo", config_stereo, CHANNEL_STEREO);
- LOAD_REG_INT("Frequency", config_frequency, 44100);
- LOAD_REG_INT("Resampling", config_resampling, RESAMPLING_CUBIC);
- LOAD_REG_INT("BitsPerSample", config_bits_per_sample, 16);
- LOAD_REG_INT("BufferSize", config_buffer_size, 8192);
- LOAD_REG_INT("ThreadPriority", config_thread_priority, PRIORITY_HIGH);
-
- CHECK_RANGE(config_stereo, CHANNEL_MONO, CHANNEL_STEREO);
- if ( config_frequency != 11025
- && config_frequency != 22050
- && config_frequency != 44100
- && config_frequency != 48000)
- config_frequency = 44100;
- CHECK_RANGE(config_resampling, RESAMPLING_ALIASING, RESAMPLING_CUBIC);
- if ( config_bits_per_sample != 8
- && config_bits_per_sample != 16)
- config_bits_per_sample = 16;
- CHECK_RANGE(config_buffer_size, 1024, 32768);
- CHECK_RANGE(config_thread_priority, PRIORITY_NORMAL, PRIORITY_HIGHEST);
-
-
- return;
-}
-
-
-
-void config_quit(void) {
-
- /* Close registry key */
- if (registry != INVALID_HANDLE_VALUE) {
- RegCloseKey(registry);
- registry = INVALID_HANDLE_VALUE;
- }
-
- return;
-}
-
-
-
-/* About box, yay! */
-void about(HWND hwndParent) {
- MessageBox(hwndParent, "DUH! Winamp Plugin\n Version " VERSION " (x86)\n",
- "About:", MB_OK | MB_ICONINFORMATION);
-}
-
+
+#include <stdio.h>
+#include <windows.h>
+//#include <mmreg.h>
+//#include <msacm.h>
+#include <math.h>
+#include <commctrl.h>
+
+#include "in_duh.h"
+#include "resource.h"
+
+#include "gui.h"
+
+
+/* Registry settings */
+#define REGISTRY_KEY "Software\\Winamp\\DUH Plug-in"
+static HKEY registry = INVALID_HANDLE_VALUE;
+
+/* Some default values for config */
+int config_bits_per_sample = 16;
+int config_frequency = 44100;
+int config_stereo = CHANNEL_STEREO;
+int config_resampling = RESAMPLING_CUBIC;
+int config_buffer_size = 8192;
+int config_thread_priority = PRIORITY_HIGH;
+
+
+/*************************
+ * Registry manipulation */
+
+static int read_registry(char const *name, unsigned long type, void *ptr, unsigned long size)
+{
+ unsigned long reg_type;
+
+ if (registry == INVALID_HANDLE_VALUE ||
+ RegQueryValueEx(registry, name, 0, &reg_type, ptr, &size) != ERROR_SUCCESS
+ || reg_type != type)
+
+ return -1;
+
+ return 0;
+}
+
+
+static int write_registry(char const *name, unsigned long type, void *ptr, unsigned long size)
+{
+ if (registry == INVALID_HANDLE_VALUE
+ || RegSetValueEx(registry, name, 0, type, ptr, size) != ERROR_SUCCESS)
+
+ return -1;
+
+ return 0;
+}
+
+
+# define LOAD_REG_INT(name, var, defaultv) (read_registry(name, REG_DWORD, \
+ &(var), sizeof(var)) == -1 ? ((var) = (defaultv)) : (var))
+
+# define LOAD_REG_STRING(name, var, defaultv) (read_registry(name, REG_SZ, \
+ (var), sizeof(var)) == -1 ? strcpy(var, (defaultv)) : (var))
+
+# define SAVE_REG_INT(name, var) (write_registry(name, REG_DWORD, &(var), sizeof(var)))
+# define SAVE_REG_STRING(name, var) (write_registry(name, REG_SZ, (var), sizeof(var)))
+
+
+/*********************
+ * Range check */
+
+#define CHECK_RANGE(x, a, b) x = ((x < (a)) ? (a) : ((x > (b)) ? (b) : x))
+
+
+/*********************
+ * Config Dialog Box */
+
+
+static INT_PTR CALLBACK config_dialog(HWND dialog, UINT message,
+ WPARAM wparam, LPARAM lparam)
+{
+ int which;
+ int temp;
+ static int old_slider1 = 0;
+ char str[64];
+
+ (void)lparam;
+
+ switch (message) {
+ case WM_INITDIALOG:
+
+ /* Ok, now we need to set up the dialog's controls
+ * to match the current config
+ */
+
+ /* Channels */
+ CheckDlgButton(dialog, IDC_STEREO, config_stereo == CHANNEL_STEREO ? BST_CHECKED : BST_UNCHECKED);
+
+ /* Bits per sample */
+ switch (config_bits_per_sample) {
+ case 8: which = IDC_8BPS; break;
+ case 16: which = IDC_16BPS; break;
+ default:
+ which = 0;
+ }
+ if (which)
+ CheckRadioButton(dialog, IDC_8BPS, IDC_16BPS, which);
+
+ /* Resampling method */
+ switch (config_resampling) {
+ case RESAMPLING_ALIASING: which = IDC_ALIASING; break;
+ case RESAMPLING_LINEAR: which = IDC_LINEAR; break;
+ case RESAMPLING_LINEAR2: which = IDC_LINEAR_LOW_PASS; break;
+ case RESAMPLING_QUADRATIC: which = IDC_QUADRATIC; break;
+ case RESAMPLING_CUBIC: which = IDC_CUBIC; break;
+ default:
+ which = 0;
+ }
+ if (which)
+ CheckRadioButton(dialog, IDC_ALIASING, IDC_CUBIC, which);
+
+ /* Frequency */
+ switch (config_frequency) {
+ case 11025: which = IDC_11KHZ; break;
+ case 22050: which = IDC_22KHZ; break;
+ case 44100: which = IDC_44KHZ; break;
+ case 48000: which = IDC_48KHZ; break;
+ default:
+ which = 0;
+ }
+ if (which)
+ CheckRadioButton(dialog, IDC_11KHZ, IDC_48KHZ, which);
+
+ /* Buffer size - 1 KB -> 32 KB slider */
+ old_slider1 = (int)(log(config_buffer_size) / log(2)) - 10;
+ SendDlgItemMessage(dialog, IDC_BUFFERSIZE, TBM_SETRANGE, FALSE, MAKELONG(0, 5));
+ SendDlgItemMessage(dialog, IDC_BUFFERSIZE, TBM_SETPOS, TRUE, old_slider1);
+ sprintf(str, "%i KS", config_buffer_size / 1024);
+ SetDlgItemText(dialog, IDC_BUFFERSIZE2, str);
+
+ /* Thread Priority */
+ SendDlgItemMessage(dialog, IDC_THREAD_PRI, TBM_SETRANGE, FALSE, MAKELONG(0, 2));
+ SendDlgItemMessage(dialog, IDC_THREAD_PRI, TBM_SETPOS, TRUE, config_thread_priority);
+
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wparam)) {
+
+ case IDC_DEFAULT:
+ /* Load default settings */
+
+ /* Channels */
+ CheckDlgButton(dialog, IDC_STEREO, BST_CHECKED);
+
+ /* Bits per sample */
+ CheckRadioButton(dialog, IDC_8BPS, IDC_16BPS, IDC_16BPS);
+
+ /* Resampling method */
+ CheckRadioButton(dialog, IDC_ALIASING, IDC_CUBIC, IDC_LINEAR_LOW_PASS);
+
+ /* Frequency */
+ CheckRadioButton(dialog, IDC_11KHZ, IDC_48KHZ, IDC_44KHZ);
+
+ /* Buffer size - 1 KB -> 32 KB slider */
+ SendDlgItemMessage(dialog, IDC_BUFFERSIZE, TBM_SETPOS, TRUE, 3);
+ sprintf(str, "%i KS", 8192 / 1024);
+ SetDlgItemText(dialog, IDC_BUFFERSIZE2, str);
+
+ /* Thread Priority */
+ SendDlgItemMessage(dialog, IDC_THREAD_PRI, TBM_SETPOS, TRUE, PRIORITY_HIGH);
+
+ return TRUE;
+
+ case IDC_NICEST:
+ /* Load nicest settings */
+
+ /* Channels */
+ CheckDlgButton(dialog, IDC_STEREO, BST_CHECKED);
+
+ /* Bits per sample */
+ CheckRadioButton(dialog, IDC_8BPS, IDC_16BPS, IDC_16BPS);
+
+ /* Resampling method */
+ CheckRadioButton(dialog, IDC_ALIASING, IDC_CUBIC, IDC_CUBIC);
+
+ /* Frequency */
+ CheckRadioButton(dialog, IDC_11KHZ, IDC_48KHZ, IDC_48KHZ);
+
+ /* Buffer size - 1 KB -> 32 KB slider */
+ SendDlgItemMessage(dialog, IDC_BUFFERSIZE, TBM_SETPOS, TRUE, 3);
+ sprintf(str, "%i KS", 8192 / 1024);
+ SetDlgItemText(dialog, IDC_BUFFERSIZE2, str);
+
+ /* Thread Priority */
+ SendDlgItemMessage(dialog, IDC_THREAD_PRI, TBM_SETPOS, TRUE, PRIORITY_HIGH);
+
+ return TRUE;
+
+ case IDC_FASTEST:
+ /* Load fastest settings */
+
+ /* Channels */
+ CheckDlgButton(dialog, IDC_STEREO, BST_UNCHECKED);
+
+ /* Bits per sample */
+ CheckRadioButton(dialog, IDC_8BPS, IDC_16BPS, IDC_8BPS);
+
+ /* Resampling method */
+ CheckRadioButton(dialog, IDC_ALIASING, IDC_CUBIC, IDC_ALIASING);
+
+ /* Frequency */
+ CheckRadioButton(dialog, IDC_11KHZ, IDC_48KHZ, IDC_11KHZ);
+
+ /* Buffer size - 1 KB -> 32 KB slider */
+ SendDlgItemMessage(dialog, IDC_BUFFERSIZE, TBM_SETPOS, TRUE, 3);
+ sprintf(str, "%i KS", 8192 / 1024);
+ SetDlgItemText(dialog, IDC_BUFFERSIZE2, str);
+
+ /* Thread Priority */
+ SendDlgItemMessage(dialog, IDC_THREAD_PRI, TBM_SETPOS, TRUE, PRIORITY_HIGH);
+
+ return TRUE;
+
+ case IDC_OK:
+ /* Read back configuration */
+ config_stereo = (IsDlgButtonChecked(dialog, IDC_STEREO) == BST_CHECKED) ? CHANNEL_STEREO : CHANNEL_MONO;
+ config_bits_per_sample = (IsDlgButtonChecked(dialog, IDC_8BPS) == BST_CHECKED) ? 8 : 16;
+ config_resampling = (IsDlgButtonChecked(dialog, IDC_ALIASING) == BST_CHECKED) ? RESAMPLING_ALIASING
+ : (IsDlgButtonChecked(dialog, IDC_LINEAR) == BST_CHECKED) ? RESAMPLING_LINEAR
+ : (IsDlgButtonChecked(dialog, IDC_LINEAR_LOW_PASS) == BST_CHECKED) ? RESAMPLING_LINEAR2
+ : (IsDlgButtonChecked(dialog, IDC_QUADRATIC) == BST_CHECKED) ? RESAMPLING_QUADRATIC
+ : RESAMPLING_CUBIC;
+ config_frequency = (IsDlgButtonChecked(dialog, IDC_11KHZ) == BST_CHECKED) ? 11025
+ : (IsDlgButtonChecked(dialog, IDC_22KHZ) == BST_CHECKED) ? 22050
+ : (IsDlgButtonChecked(dialog, IDC_44KHZ) == BST_CHECKED) ? 44100
+ : 48000;
+ config_buffer_size = 1 << (SendDlgItemMessage(dialog, IDC_BUFFERSIZE, TBM_GETPOS, 0, 0) + 10);
+
+ config_thread_priority = SendDlgItemMessage(dialog, IDC_THREAD_PRI, TBM_GETPOS, 0, 0);
+
+ case IDCANCEL:
+ case IDC_CANCEL:
+ case IDCLOSE:
+ EndDialog(dialog, wparam);
+ return TRUE;
+ }
+ break;
+ default:
+ temp = 1 << (SendDlgItemMessage(dialog, IDC_BUFFERSIZE, TBM_GETPOS, 0, 0) + 10);
+ if (temp != old_slider1) {
+ old_slider1 = temp;
+ sprintf(str, "%i KS", temp / 1024);
+ SetDlgItemText(dialog, IDC_BUFFERSIZE2, str);
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
+
+/* DUH Config dialog */
+void config(HWND hwndParent) {
+
+ if (DialogBox(mod.hDllInstance, MAKEINTRESOURCE(IDD_CONFIG),
+ hwndParent, config_dialog) == IDC_OK) {
+
+ SAVE_REG_INT("Stereo", config_stereo);
+ SAVE_REG_INT("Frequency", config_frequency);
+ SAVE_REG_INT("Resampling", config_resampling);
+ SAVE_REG_INT("BitsPerSample", config_bits_per_sample);
+ SAVE_REG_INT("BufferSize", config_buffer_size);
+ SAVE_REG_INT("ThreadPriority", config_thread_priority);
+ }
+}
+
+
+void config_init(void) {
+
+ /* Load config from registry */
+
+ if (RegCreateKeyEx(HKEY_CURRENT_USER, REGISTRY_KEY, 0, "",
+ REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, 0,
+ &registry, 0) != ERROR_SUCCESS)
+
+ registry = INVALID_HANDLE_VALUE;
+
+ LOAD_REG_INT("Stereo", config_stereo, CHANNEL_STEREO);
+ LOAD_REG_INT("Frequency", config_frequency, 44100);
+ LOAD_REG_INT("Resampling", config_resampling, RESAMPLING_CUBIC);
+ LOAD_REG_INT("BitsPerSample", config_bits_per_sample, 16);
+ LOAD_REG_INT("BufferSize", config_buffer_size, 8192);
+ LOAD_REG_INT("ThreadPriority", config_thread_priority, PRIORITY_HIGH);
+
+ CHECK_RANGE(config_stereo, CHANNEL_MONO, CHANNEL_STEREO);
+ if ( config_frequency != 11025
+ && config_frequency != 22050
+ && config_frequency != 44100
+ && config_frequency != 48000)
+ config_frequency = 44100;
+ CHECK_RANGE(config_resampling, RESAMPLING_ALIASING, RESAMPLING_CUBIC);
+ if ( config_bits_per_sample != 8
+ && config_bits_per_sample != 16)
+ config_bits_per_sample = 16;
+ CHECK_RANGE(config_buffer_size, 1024, 32768);
+ CHECK_RANGE(config_thread_priority, PRIORITY_NORMAL, PRIORITY_HIGHEST);
+
+
+ return;
+}
+
+
+
+void config_quit(void) {
+
+ /* Close registry key */
+ if (registry != INVALID_HANDLE_VALUE) {
+ RegCloseKey(registry);
+ registry = INVALID_HANDLE_VALUE;
+ }
+
+ return;
+}
+
+
+
+/* About box, yay! */
+void about(HWND hwndParent) {
+ MessageBox(hwndParent, "DUH! Winamp Plugin\n Version " VERSION " (x86)\n",
+ "About:", MB_OK | MB_ICONINFORMATION);
+}
+
diff --git a/plugins/dumb/dumb-kode54/winamp/gui.h b/plugins/dumb/dumb-kode54/winamp/gui.h
index 7924b247..79229e9f 100644
--- a/plugins/dumb/dumb-kode54/winamp/gui.h
+++ b/plugins/dumb/dumb-kode54/winamp/gui.h
@@ -1,26 +1,26 @@
-#define CHANNEL_MONO 1
-#define CHANNEL_STEREO 2
-
-#define RESAMPLING_ALIASING 0
-#define RESAMPLING_LINEAR 1
-#define RESAMPLING_LINEAR2 2
-#define RESAMPLING_QUADRATIC 3
-#define RESAMPLING_CUBIC 4
-
-#define PRIORITY_NORMAL 0
-#define PRIORITY_HIGH 1
-#define PRIORITY_HIGHEST 2
-
-
-extern void config(HWND hwndParent);
-extern void about(HWND hwndParent);
-
-extern void config_init(void);
-extern void config_quit(void);
-
-extern int config_bits_per_sample;
-extern int config_frequency;
-extern int config_stereo;
-extern int config_resampling;
-extern int config_buffer_size;
-extern int config_thread_priority;
+#define CHANNEL_MONO 1
+#define CHANNEL_STEREO 2
+
+#define RESAMPLING_ALIASING 0
+#define RESAMPLING_LINEAR 1
+#define RESAMPLING_LINEAR2 2
+#define RESAMPLING_QUADRATIC 3
+#define RESAMPLING_CUBIC 4
+
+#define PRIORITY_NORMAL 0
+#define PRIORITY_HIGH 1
+#define PRIORITY_HIGHEST 2
+
+
+extern void config(HWND hwndParent);
+extern void about(HWND hwndParent);
+
+extern void config_init(void);
+extern void config_quit(void);
+
+extern int config_bits_per_sample;
+extern int config_frequency;
+extern int config_stereo;
+extern int config_resampling;
+extern int config_buffer_size;
+extern int config_thread_priority;
diff --git a/plugins/dumb/dumb-kode54/winamp/in2.h b/plugins/dumb/dumb-kode54/winamp/in2.h
index d156c34b..0efff478 100644
--- a/plugins/dumb/dumb-kode54/winamp/in2.h
+++ b/plugins/dumb/dumb-kode54/winamp/in2.h
@@ -1,123 +1,123 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * in2.h - Winamp plug-in header file / / \ \
- * | < / \_
- * By Bob. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-
-#include "out.h"
-
-// note: exported symbol is now winampGetInModule2.
-
-#define IN_VER 0x100
-
-typedef struct
-{
- int version; // module type (IN_VER)
- char *description; // description of module, with version string
-
- HWND hMainWindow; // winamp's main window (filled in by winamp)
- HINSTANCE hDllInstance; // DLL instance handle (Also filled in by winamp)
-
- char *FileExtensions; // "mp3\0Layer 3 MPEG\0mp2\0Layer 2 MPEG\0mpg\0Layer 1 MPEG\0"
- // May be altered from Config, so the user can select what they want
-
- int is_seekable; // is this stream seekable?
- int UsesOutputPlug; // does this plug-in use the output plug-ins? (musn't ever change, ever :)
-
- void (*Config)(HWND hwndParent); // configuration dialog
- void (*About)(HWND hwndParent); // about dialog
-
- void (*Init)(); // called at program init
- void (*Quit)(); // called at program quit
-
- void (*GetFileInfo)(char *file, char *title, int *length_in_ms); // if file == NULL, current playing is used
- int (*InfoBox)(char *file, HWND hwndParent);
-
- int (*IsOurFile)(char *fn); // called before extension checks, to allow detection of mms://, etc
- // playback stuff
- int (*Play)(char *fn); // return zero on success, -1 on file-not-found, some other value on other (stopping winamp) error
- void (*Pause)(); // pause stream
- void (*UnPause)(); // unpause stream
- int (*IsPaused)(); // ispaused? return 1 if paused, 0 if not
- void (*Stop)(); // stop (unload) stream
-
- // time stuff
- int (*GetLength)(); // get length in ms
- int (*GetOutputTime)(); // returns current output time in ms. (usually returns outMod->GetOutputTime()
- void (*SetOutputTime)(int time_in_ms); // seeks to point in stream (in ms). Usually you signal yoru thread to seek, which seeks and calls outMod->Flush()..
-
- // volume stuff
- void (*SetVolume)(int volume); // from 0 to 255.. usually just call outMod->SetVolume
- void (*SetPan)(int pan); // from -127 to 127.. usually just call outMod->SetPan
-
- // in-window builtin vis stuff
-
- void (*SAVSAInit)(int maxlatency_in_ms, int srate); // call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open()
- // call after opening audio device with max latency in ms and samplerate
- void (*SAVSADeInit)(); // call in Stop()
-
-
- // simple vis supplying mode
- void (*SAAddPCMData)(void *PCMData, int nch, int bps, int timestamp);
- // sets the spec data directly from PCM data
- // quick and easy way to get vis working :)
- // needs at least 576 samples :)
-
- // advanced vis supplying mode, only use if you're cool. Use SAAddPCMData for most stuff.
- int (*SAGetMode)(); // gets csa (the current type (4=ws,2=osc,1=spec))
- // use when calling SAAdd()
- void (*SAAdd)(void *data, int timestamp, int csa); // sets the spec data, filled in by winamp
-
-
- // vis stuff (plug-in)
- // simple vis supplying mode
- void (*VSAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data
- // quick and easy way to get vis working :)
- // needs at least 576 samples :)
-
- // advanced vis supplying mode, only use if you're cool. Use VSAAddPCMData for most stuff.
- int (*VSAGetMode)(int *specNch, int *waveNch); // use to figure out what to give to VSAAdd
- void (*VSAAdd)(void *data, int timestamp); // filled in by winamp, called by plug-in
-
-
- // call this in Play() to tell the vis plug-ins the current output params.
- void (*VSASetInfo)(int nch, int srate);
-
-
- // dsp plug-in processing:
- // (filled in by winamp, called by input plug)
-
- // returns 1 if active (which means that the number of samples returned by dsp_dosamples
- // could be greater than went in.. Use it to estimate if you'll have enough room in the
- // output buffer
- int (*dsp_isactive)();
-
- // returns number of samples to output. This can be as much as twice numsamples.
- // be sure to allocate enough buffer for samples, then.
- int (*dsp_dosamples)(short int *samples, int numsamples, int bps, int nch, int srate);
-
-
- // eq stuff
- void (*EQSet)(int on, char data[10], int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore.
-
- // info setting (filled in by winamp)
- void (*SetInfo)(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :)
-
- Out_Module *outMod; // filled in by winamp, optionally used :)
-} In_Module;
-
-
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * in2.h - Winamp plug-in header file / / \ \
+ * | < / \_
+ * By Bob. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+
+#include "out.h"
+
+// note: exported symbol is now winampGetInModule2.
+
+#define IN_VER 0x100
+
+typedef struct
+{
+ int version; // module type (IN_VER)
+ char *description; // description of module, with version string
+
+ HWND hMainWindow; // winamp's main window (filled in by winamp)
+ HINSTANCE hDllInstance; // DLL instance handle (Also filled in by winamp)
+
+ char *FileExtensions; // "mp3\0Layer 3 MPEG\0mp2\0Layer 2 MPEG\0mpg\0Layer 1 MPEG\0"
+ // May be altered from Config, so the user can select what they want
+
+ int is_seekable; // is this stream seekable?
+ int UsesOutputPlug; // does this plug-in use the output plug-ins? (musn't ever change, ever :)
+
+ void (*Config)(HWND hwndParent); // configuration dialog
+ void (*About)(HWND hwndParent); // about dialog
+
+ void (*Init)(); // called at program init
+ void (*Quit)(); // called at program quit
+
+ void (*GetFileInfo)(char *file, char *title, int *length_in_ms); // if file == NULL, current playing is used
+ int (*InfoBox)(char *file, HWND hwndParent);
+
+ int (*IsOurFile)(char *fn); // called before extension checks, to allow detection of mms://, etc
+ // playback stuff
+ int (*Play)(char *fn); // return zero on success, -1 on file-not-found, some other value on other (stopping winamp) error
+ void (*Pause)(); // pause stream
+ void (*UnPause)(); // unpause stream
+ int (*IsPaused)(); // ispaused? return 1 if paused, 0 if not
+ void (*Stop)(); // stop (unload) stream
+
+ // time stuff
+ int (*GetLength)(); // get length in ms
+ int (*GetOutputTime)(); // returns current output time in ms. (usually returns outMod->GetOutputTime()
+ void (*SetOutputTime)(int time_in_ms); // seeks to point in stream (in ms). Usually you signal yoru thread to seek, which seeks and calls outMod->Flush()..
+
+ // volume stuff
+ void (*SetVolume)(int volume); // from 0 to 255.. usually just call outMod->SetVolume
+ void (*SetPan)(int pan); // from -127 to 127.. usually just call outMod->SetPan
+
+ // in-window builtin vis stuff
+
+ void (*SAVSAInit)(int maxlatency_in_ms, int srate); // call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open()
+ // call after opening audio device with max latency in ms and samplerate
+ void (*SAVSADeInit)(); // call in Stop()
+
+
+ // simple vis supplying mode
+ void (*SAAddPCMData)(void *PCMData, int nch, int bps, int timestamp);
+ // sets the spec data directly from PCM data
+ // quick and easy way to get vis working :)
+ // needs at least 576 samples :)
+
+ // advanced vis supplying mode, only use if you're cool. Use SAAddPCMData for most stuff.
+ int (*SAGetMode)(); // gets csa (the current type (4=ws,2=osc,1=spec))
+ // use when calling SAAdd()
+ void (*SAAdd)(void *data, int timestamp, int csa); // sets the spec data, filled in by winamp
+
+
+ // vis stuff (plug-in)
+ // simple vis supplying mode
+ void (*VSAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data
+ // quick and easy way to get vis working :)
+ // needs at least 576 samples :)
+
+ // advanced vis supplying mode, only use if you're cool. Use VSAAddPCMData for most stuff.
+ int (*VSAGetMode)(int *specNch, int *waveNch); // use to figure out what to give to VSAAdd
+ void (*VSAAdd)(void *data, int timestamp); // filled in by winamp, called by plug-in
+
+
+ // call this in Play() to tell the vis plug-ins the current output params.
+ void (*VSASetInfo)(int nch, int srate);
+
+
+ // dsp plug-in processing:
+ // (filled in by winamp, called by input plug)
+
+ // returns 1 if active (which means that the number of samples returned by dsp_dosamples
+ // could be greater than went in.. Use it to estimate if you'll have enough room in the
+ // output buffer
+ int (*dsp_isactive)();
+
+ // returns number of samples to output. This can be as much as twice numsamples.
+ // be sure to allocate enough buffer for samples, then.
+ int (*dsp_dosamples)(short int *samples, int numsamples, int bps, int nch, int srate);
+
+
+ // eq stuff
+ void (*EQSet)(int on, char data[10], int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore.
+
+ // info setting (filled in by winamp)
+ void (*SetInfo)(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :)
+
+ Out_Module *outMod; // filled in by winamp, optionally used :)
+} In_Module;
+
+
diff --git a/plugins/dumb/dumb-kode54/winamp/in_duh.c b/plugins/dumb/dumb-kode54/winamp/in_duh.c
index e97c07af..2d113e64 100644
--- a/plugins/dumb/dumb-kode54/winamp/in_duh.c
+++ b/plugins/dumb/dumb-kode54/winamp/in_duh.c
@@ -1,655 +1,655 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * in_duh.c - Winamp plug-in for DUMB. / / \ \
- * | < / \_
- * By Bob. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-
-//#define SOFTVOLUME
-
-#include "in_duh.h"
-#include "resource.h"
-#include "gui.h"
-
-
-typedef struct DUH_PLAYER
-{
- int n_channels;
- DUH_SIGRENDERER *dr;
- float volume;
-}
-DUH_PLAYER;
-
-
-/* Winamp Output module; we write to this to tell Winamp what to play */
-In_Module mod;
-
-/* Currently playing file */
-DUH *duh;
-DUH_PLAYER *duh_player;
-int init_duh = TRUE;
-char *duh_filename = NULL;
-#ifdef SOFTVOLUME
-int thevolume = 255;
-#endif
-
-
-
-/******************
- * Configuration */
-static int bits_per_sample;
-static int frequency;
-static int stereo;
-static int resampling;
-static int buffer_size;
-static int thread_priority;
-
-
-
-/****************
- * Winamp Stuff */
-
-HANDLE input_file = INVALID_HANDLE_VALUE; /* input file handle */
-
-int killDecodeThread = 0; /* the kill switch for the decode thread */
-HANDLE thread_handle = INVALID_HANDLE_VALUE; /* the handle to the decode thread */
-
-DWORD WINAPI __stdcall DecodeThread(void *b); /* the decode thread procedure */
-
-/* Avoid CRT. Evil. Big. Bloated. */
-BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
-{
- (void)hInst;
- (void)ul_reason_for_call;
- (void)lpReserved;
- return TRUE;
-}
-
-
-/* Post this to the main window at end of file (after playback as stopped) */
-#define WM_WA_MPEG_EOF (WM_USER+2)
-
-
-
-/* Stuff for interfacing with Winamp */
-int decode_pos_ms;
-int paused;
-int seek_needed; /* if != -1, it is the point that the decode thread should seek to, in ms. */
-//char *sample_buffer = NULL;
-
-//int buffer_pos = 0;
-
-
-
-/* Init DUH */
-void init()
-{
- config_init();
- dumb_register_stdfiles();
-}
-
-
-
-/* De-Init */
-void quit()
-{
- config_quit();
-
- if (duh_player)
- free(duh_player);
- if (duh)
- unload_duh(duh);
-
- if (duh_filename)
- free(duh_filename);
-
- //if (sample_buffer)
- //free(sample_buffer);
-
- dumb_exit();
-}
-
-
-
-/* WA SDK: used for detecting URL streams.. unused here. strncmp(fn,"http://",7) to detect HTTP streams, etc */
-/* I -think- we need to tell Winamp that the file should use our plug-in */
-int isourfile(char *fn) { (void)fn; return 0; }
-
-void stop_duh(DUH_PLAYER *dp)
-{
- if (dp) {
- duh_end_sigrenderer(dp->dr);
- free(dp);
- }
-}
-
-
-int play(char *fn)
-{
- static int priority_table[] = {
- THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST
- };
- int maxlatency;
- unsigned long thread_id;
-
- /* Get rid of an old DUH */
- if (duh_player) {
- stop_duh(duh_player);
- duh_player = NULL;
- }
-
- if (duh)
- unload_duh(duh);
-
- /* Load file */
- duh = load_duh(fn);
- if (!duh) {
- duh = dumb_load_it(fn);
- if (!duh) {
- duh = dumb_load_xm(fn);
- if (!duh) {
- duh = dumb_load_s3m(fn);
- if (!duh) {
- duh = dumb_load_mod(fn);
- if (!duh)
- return 1;
- }
- }
- }
- }
-
- init_duh = TRUE;
-
- /* Set up some things for Winamp */
- paused = 0;
- decode_pos_ms = 0;
- seek_needed = -1;
-
- bits_per_sample = config_bits_per_sample;
- frequency = config_frequency;
- stereo = config_stereo;
- resampling = config_resampling;
- buffer_size = config_buffer_size;
- thread_priority = priority_table[config_thread_priority];
-
- /* Create the sample buffer */
- //if (sample_buffer)
- //free(sample_buffer);
-
- //sample_buffer = malloc(((bits_per_sample + 7) / 8) * stereo * buffer_size);
-
- //if (!sample_buffer)
- //return 1;
-
- //buffer_pos = 0;
-
- /* Note: I -really- don't know what this does. Winamp's SDK doesn't mention this function... */
- maxlatency = mod.outMod->Open(frequency, stereo, bits_per_sample, -1, -1);
- if (maxlatency < 0) { /* error opening device */
- unload_duh(duh);
- duh = NULL;
- return 1;
- }
-
- /* Store the file name */
- if (duh_filename)
- free(duh_filename);
- duh_filename = strdup(fn);
-
- /* Note2: Dunno what does too; damn those Winamp docs */
- /* dividing by 1000 for the first parameter of setinfo makes it */
- /* display 'H'... for hundred.. i.e. 14H Kbps. */
- mod.SetInfo((frequency * bits_per_sample * stereo) / 1000,
- frequency / 1000, stereo, 1);
-
- /* Ditto */
- /* initialize vis stuff */
- mod.SAVSAInit(maxlatency, frequency);
- mod.VSASetInfo(frequency, stereo);
-
- /* Ditthree */
-#ifdef SOFTVOLUME
- mod.outMod->SetVolume(255);
-#else
- mod.outMod->SetVolume(-666); /* set the output plug-ins default volume */
-#endif
-
- /* Ok, now we set up the decoding thread */
- killDecodeThread = 0;
- thread_handle = (HANDLE) CreateThread(NULL,0,DecodeThread,&killDecodeThread,0,&thread_id);
- SetThreadPriority(thread_handle, thread_priority);
-
- return 0;
-}
-
-
-
-/* Standard Winamp stuff */
-void pause() { paused = 1; mod.outMod->Pause(1); }
-void unpause() { paused = 0; mod.outMod->Pause(0); }
-int ispaused() { return paused; }
-
-
-
-/* Stop playing the file */
-void stop()
-{
- if (thread_handle != INVALID_HANDLE_VALUE)
- {
- killDecodeThread=1;
- if (WaitForSingleObject(thread_handle,INFINITE) == WAIT_TIMEOUT)
- {
- MessageBox(mod.hMainWindow,"Error asking thread to die!\n","Error killing decode thread",0);
- TerminateThread(thread_handle,0);
- }
- CloseHandle(thread_handle);
- thread_handle = INVALID_HANDLE_VALUE;
- }
- if (duh_player) {
- stop_duh(duh_player);
- duh_player = NULL;
- }
-
- if (duh) {
- unload_duh(duh);
- duh = NULL;
- }
-
- /* Should I unload the file? It takes time to reload... */
-
- mod.outMod->Close();
-
- mod.SAVSADeInit();
-}
-
-
-
-int getlength()
-{
- return (int) ((LONG_LONG)duh_get_length(duh) * 1000 >> 16);
-}
-
-
-
-int getoutputtime()
-{
- return decode_pos_ms + (mod.outMod->GetOutputTime() - mod.outMod->GetWrittenTime());
-}
-
-
-
-void setoutputtime(int time_in_ms)
-{
- seek_needed = time_in_ms;
-}
-
-
-
-void setvolume(int volume)
-{
-#ifdef SOFTVOLUME
- thevolume = volume;
- if (duh_player) duh_player->volume = volume / 255.0f;
-#else
- mod.outMod->SetVolume(volume);
-#endif
-}
-
-
-
-void setpan(int pan) { mod.outMod->SetPan(pan); }
-
-
-
-int infoDlg(char *fn, HWND hwnd)
-{
- (void)fn;
- (void)hwnd;
- // TODO: implement info dialog.
- return 0;
-}
-
-
-
-static const char *fn_basename(const char *filename)
-{
- for (;;) {
- const char *p = strpbrk(filename, "/\\");
- if (!p) return filename;
- filename = p + 1;
- }
-}
-
-
-
-void getfileinfo(char *filename, char *title, int *length_in_ms)
-{
- if (!filename || !*filename) { /* currently playing file */
-
- if (length_in_ms)
- *length_in_ms = getlength();
-
- if (title) {
- const char *mod_title = duh_get_tag(duh, "TITLE");
- if (mod_title && mod_title[0])
- sprintf(title, "%s - %s", fn_basename(filename), mod_title);
- else
- strcpy(title, fn_basename(filename));
- }
- }
- else { /* some other file */
-#if 1 // needs fixing better than this! more to add to DUMB's API?
- if (length_in_ms || title) {
- DUH *duh = load_duh(filename);
- if (!duh) {
- duh = dumb_load_it(filename);
- if (!duh) {
- duh = dumb_load_xm(filename);
- if (!duh) {
- duh = dumb_load_s3m(filename);
- if (!duh) {
- duh = dumb_load_mod(filename);
- if (!duh)
- return;
- }
- }
- }
- }
-
- if (length_in_ms)
- *length_in_ms = (int)((LONG_LONG)duh_get_length(duh) * 1000 >> 16);
-
- if (title) {
- const char *mod_title = duh_get_tag(duh, "TITLE");
- if (mod_title && mod_title[0])
- sprintf(title, "%s - %s", fn_basename(duh_filename), mod_title);
- else
- strcpy(title, fn_basename(duh_filename));
- }
-
- unload_duh(duh);
- }
-#elif 0
- /* This code only works (worked?) for DUH files. */
- DUMBFILE *d = dumbfile_open(filename);
-
- if (!d)
- return;
-
- if (dumbfile_mgetl(d) != DUH_SIGNATURE)
- return;
-
- *length_in_ms = (unsigned int)((LONG_LONG)dumbfile_igetl(d) * 1000 >> 16);
-
- if (title)
- strcpy(title, filename);
-
- dumbfile_close(d);
-#else
- *length_in_ms = 1000 * 60 * 10;
-
- if (title)
- strcpy(title, filename);
-#endif
- }
-}
-
-
-
-void eq_set(int on, char data[10], int preamp)
-{
- (void)on;
- (void)data;
- (void)preamp;
- /* No equalizer support, sorry */
-}
-
-
-
-DUH_PLAYER *start_duh(DUH *duh, int n_channels, long pos, float volume)
-{
- DUH_PLAYER *dp;
-
- // This restriction is imposed by Allegro. <-- um...?
- ASSERT(n_channels > 0);
- ASSERT(n_channels <= 2);
-
- if (!duh)
- return NULL;
-
- dp = malloc(sizeof(*dp));
- if (!dp)
- return NULL;
-
- dp->n_channels = n_channels;
-
- dp->dr = duh_start_sigrenderer(duh, 0, n_channels, pos);
-
- if (!dp->dr) {
- free(dp);
- return NULL;
- }
-
- {
- DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(dp->dr);
- dumb_it_set_loop_callback(itsr, &dumb_it_callback_terminate, NULL);
- dumb_it_set_xm_speed_zero_callback(itsr, &dumb_it_callback_terminate, NULL);
- }
-
- dp->volume = volume;
-
- return dp;
-}
-
-
-
-
-void pause_duh(DUH_PLAYER *dp)
-{
- (void)dp;
- pause();
-}
-
-
-
-void resume_duh(DUH_PLAYER *dp)
-{
- (void)dp;
- unpause();
-}
-
-
-
-void set_duh_volume(DUH_PLAYER *dp, float volume)
-{
- (void)dp;
- setvolume((int)(volume * 255.0f));
-}
-
-
-
-
-/* Generate 576 samples of data from the DUH_PLAYER */
-int get_576_samples(DUH_PLAYER *dp, char *buf)
-{
-#if 1
- if (!dp) return 0;
-
- long n = duh_render(dp->dr, bits_per_sample, bits_per_sample == 8 ? 1 : 0,
- dp->volume, 65536.0f / frequency, 576, buf);
-
- return n * (bits_per_sample >> 3) * stereo;
-#else
- long n;
- int bps = ((bits_per_sample + 7) / 8) * stereo;
-
- if (!dp)
- return 0;
-
- if (buffer_pos == 0 || buffer_pos + 576 >= buffer_size) {
-
- if (buffer_pos) {
- memmove(sample_buffer, sample_buffer + bps * buffer_pos, (buffer_size - buffer_pos) * bps);
- buffer_pos = buffer_size - buffer_pos;
- }
-
- n = duh_render(dp->dr, bits_per_sample, bits_per_sample == 8 ? 1 : 0,
- dp->volume, 65536.0f / frequency, buffer_size - buffer_pos,
- sample_buffer + buffer_pos * bps);
-
- if (n > 576) n = 576;
-
- n *= bps;
- buffer_pos = 0;
- }
-
- memcpy(buf, sample_buffer + buffer_pos * bps, 576 * bps);
-
- buffer_pos += 576;
-
- return 576 * bps;
-#endif
-}
-
-
-DWORD WINAPI __stdcall DecodeThread(void *b)
-{
- static char buf[576 * 4];
- int done = 0;
- int length = 0;
-
- if (init_duh) {
- dumb_resampling_quality = resampling;
-#ifdef SOFTVOLUME
- duh_player = start_duh(duh, stereo, 0, thevolume / 255.0f);
-#else
- duh_player = start_duh(duh, stereo, 0, 1.0f);
-#endif
- init_duh = FALSE;
- }
- length = getlength();
-
-
- while (! *((int *)b) )
- {
- if (seek_needed != -1) {
-
- decode_pos_ms = seek_needed-(seek_needed%1000);
- seek_needed = -1;
- done = 0;
-
- mod.outMod->Flush(decode_pos_ms);
-
- /* Position the playback pointer */
- stop_duh(duh_player);
- duh_player = start_duh(duh, stereo, (unsigned int)(decode_pos_ms * 65536.0 / 1000.0), 1.0);
- }
- if (done) {
- mod.outMod->CanWrite();
-
- if (!mod.outMod->IsPlaying()) {
- PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0);
- return 0;
- }
- Sleep(10);
- }
- else if (mod.outMod->CanWrite() >= ((576 * stereo * ((bits_per_sample + 7) / 8)))) {
-
- int l = get_576_samples(duh_player, buf);
-
- if (!l || decode_pos_ms >= length) {
- done = 1;
- }
- else {
- /* Vis plug-ins interface */
- mod.SAAddPCMData((char *)buf, stereo, bits_per_sample, decode_pos_ms);
- mod.VSAAddPCMData((char *)buf, stereo, bits_per_sample, decode_pos_ms);
-
- /* Add PCM to output buffer */
- decode_pos_ms += (576 * 1000) / frequency;
-
- if (mod.dsp_isactive())
- l = mod.dsp_dosamples((short *)buf, l / stereo / ((bits_per_sample + 7) / 8), bits_per_sample,
- stereo, frequency) * (stereo * ((bits_per_sample + 7) / 8));
-
- mod.outMod->Write(buf, l);
- }
- }
- else /* Nothing to do this pass */
- Sleep(config_frequency / 1000);
- }
- return 0;
-}
-
-
-
-In_Module mod =
-{
- IN_VER,
- "DUH! Player v" VERSION
-#ifdef __alpha
- " (AXP)"
-#else
- " (x86)"
-#endif
- ,
- 0, /* hMainWindow */
- 0, /* hDllInstance */
- "DUH\0Dynamic Universal Harmony File (*.DUH)\0"
- "IT\0Impulse Tracker Module (*.IT)\0"
- "XM\0Fast Tracker 2 Module (*.XM)\0"
- "S3M\0Scream Tracker 3 Module (*.S3M)\0"
- "MOD\0Amiga Module (*.MOD)\0"
- ,
- 1, /* is_seekable */
- 1, /* uses output */
- config,
- about,
- init,
- quit,
- getfileinfo,
- infoDlg,
- isourfile,
- play,
- pause,
- unpause,
- ispaused,
- stop,
-
- getlength,
- getoutputtime,
- setoutputtime,
-
- setvolume,
- setpan,
-
- 0,0,0,0,0,0,0,0,0, /* vis stuff */
-
-
- 0,0, /* dsp */
-
- eq_set,
-
- NULL, /* setinfo */
-
- 0 /* out_mod */
-
-};
-
-__declspec( dllexport ) In_Module * winampGetInModule2()
-{
- return &mod;
-}
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * in_duh.c - Winamp plug-in for DUMB. / / \ \
+ * | < / \_
+ * By Bob. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+
+//#define SOFTVOLUME
+
+#include "in_duh.h"
+#include "resource.h"
+#include "gui.h"
+
+
+typedef struct DUH_PLAYER
+{
+ int n_channels;
+ DUH_SIGRENDERER *dr;
+ float volume;
+}
+DUH_PLAYER;
+
+
+/* Winamp Output module; we write to this to tell Winamp what to play */
+In_Module mod;
+
+/* Currently playing file */
+DUH *duh;
+DUH_PLAYER *duh_player;
+int init_duh = TRUE;
+char *duh_filename = NULL;
+#ifdef SOFTVOLUME
+int thevolume = 255;
+#endif
+
+
+
+/******************
+ * Configuration */
+static int bits_per_sample;
+static int frequency;
+static int stereo;
+static int resampling;
+static int buffer_size;
+static int thread_priority;
+
+
+
+/****************
+ * Winamp Stuff */
+
+HANDLE input_file = INVALID_HANDLE_VALUE; /* input file handle */
+
+int killDecodeThread = 0; /* the kill switch for the decode thread */
+HANDLE thread_handle = INVALID_HANDLE_VALUE; /* the handle to the decode thread */
+
+DWORD WINAPI __stdcall DecodeThread(void *b); /* the decode thread procedure */
+
+/* Avoid CRT. Evil. Big. Bloated. */
+BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
+{
+ (void)hInst;
+ (void)ul_reason_for_call;
+ (void)lpReserved;
+ return TRUE;
+}
+
+
+/* Post this to the main window at end of file (after playback as stopped) */
+#define WM_WA_MPEG_EOF (WM_USER+2)
+
+
+
+/* Stuff for interfacing with Winamp */
+int decode_pos_ms;
+int paused;
+int seek_needed; /* if != -1, it is the point that the decode thread should seek to, in ms. */
+//char *sample_buffer = NULL;
+
+//int buffer_pos = 0;
+
+
+
+/* Init DUH */
+void init()
+{
+ config_init();
+ dumb_register_stdfiles();
+}
+
+
+
+/* De-Init */
+void quit()
+{
+ config_quit();
+
+ if (duh_player)
+ free(duh_player);
+ if (duh)
+ unload_duh(duh);
+
+ if (duh_filename)
+ free(duh_filename);
+
+ //if (sample_buffer)
+ //free(sample_buffer);
+
+ dumb_exit();
+}
+
+
+
+/* WA SDK: used for detecting URL streams.. unused here. strncmp(fn,"http://",7) to detect HTTP streams, etc */
+/* I -think- we need to tell Winamp that the file should use our plug-in */
+int isourfile(char *fn) { (void)fn; return 0; }
+
+void stop_duh(DUH_PLAYER *dp)
+{
+ if (dp) {
+ duh_end_sigrenderer(dp->dr);
+ free(dp);
+ }
+}
+
+
+int play(char *fn)
+{
+ static int priority_table[] = {
+ THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST
+ };
+ int maxlatency;
+ unsigned long thread_id;
+
+ /* Get rid of an old DUH */
+ if (duh_player) {
+ stop_duh(duh_player);
+ duh_player = NULL;
+ }
+
+ if (duh)
+ unload_duh(duh);
+
+ /* Load file */
+ duh = load_duh(fn);
+ if (!duh) {
+ duh = dumb_load_it(fn);
+ if (!duh) {
+ duh = dumb_load_xm(fn);
+ if (!duh) {
+ duh = dumb_load_s3m(fn);
+ if (!duh) {
+ duh = dumb_load_mod(fn);
+ if (!duh)
+ return 1;
+ }
+ }
+ }
+ }
+
+ init_duh = TRUE;
+
+ /* Set up some things for Winamp */
+ paused = 0;
+ decode_pos_ms = 0;
+ seek_needed = -1;
+
+ bits_per_sample = config_bits_per_sample;
+ frequency = config_frequency;
+ stereo = config_stereo;
+ resampling = config_resampling;
+ buffer_size = config_buffer_size;
+ thread_priority = priority_table[config_thread_priority];
+
+ /* Create the sample buffer */
+ //if (sample_buffer)
+ //free(sample_buffer);
+
+ //sample_buffer = malloc(((bits_per_sample + 7) / 8) * stereo * buffer_size);
+
+ //if (!sample_buffer)
+ //return 1;
+
+ //buffer_pos = 0;
+
+ /* Note: I -really- don't know what this does. Winamp's SDK doesn't mention this function... */
+ maxlatency = mod.outMod->Open(frequency, stereo, bits_per_sample, -1, -1);
+ if (maxlatency < 0) { /* error opening device */
+ unload_duh(duh);
+ duh = NULL;
+ return 1;
+ }
+
+ /* Store the file name */
+ if (duh_filename)
+ free(duh_filename);
+ duh_filename = strdup(fn);
+
+ /* Note2: Dunno what does too; damn those Winamp docs */
+ /* dividing by 1000 for the first parameter of setinfo makes it */
+ /* display 'H'... for hundred.. i.e. 14H Kbps. */
+ mod.SetInfo((frequency * bits_per_sample * stereo) / 1000,
+ frequency / 1000, stereo, 1);
+
+ /* Ditto */
+ /* initialize vis stuff */
+ mod.SAVSAInit(maxlatency, frequency);
+ mod.VSASetInfo(frequency, stereo);
+
+ /* Ditthree */
+#ifdef SOFTVOLUME
+ mod.outMod->SetVolume(255);
+#else
+ mod.outMod->SetVolume(-666); /* set the output plug-ins default volume */
+#endif
+
+ /* Ok, now we set up the decoding thread */
+ killDecodeThread = 0;
+ thread_handle = (HANDLE) CreateThread(NULL,0,DecodeThread,&killDecodeThread,0,&thread_id);
+ SetThreadPriority(thread_handle, thread_priority);
+
+ return 0;
+}
+
+
+
+/* Standard Winamp stuff */
+void pause() { paused = 1; mod.outMod->Pause(1); }
+void unpause() { paused = 0; mod.outMod->Pause(0); }
+int ispaused() { return paused; }
+
+
+
+/* Stop playing the file */
+void stop()
+{
+ if (thread_handle != INVALID_HANDLE_VALUE)
+ {
+ killDecodeThread=1;
+ if (WaitForSingleObject(thread_handle,INFINITE) == WAIT_TIMEOUT)
+ {
+ MessageBox(mod.hMainWindow,"Error asking thread to die!\n","Error killing decode thread",0);
+ TerminateThread(thread_handle,0);
+ }
+ CloseHandle(thread_handle);
+ thread_handle = INVALID_HANDLE_VALUE;
+ }
+ if (duh_player) {
+ stop_duh(duh_player);
+ duh_player = NULL;
+ }
+
+ if (duh) {
+ unload_duh(duh);
+ duh = NULL;
+ }
+
+ /* Should I unload the file? It takes time to reload... */
+
+ mod.outMod->Close();
+
+ mod.SAVSADeInit();
+}
+
+
+
+int getlength()
+{
+ return (int) ((LONG_LONG)duh_get_length(duh) * 1000 >> 16);
+}
+
+
+
+int getoutputtime()
+{
+ return decode_pos_ms + (mod.outMod->GetOutputTime() - mod.outMod->GetWrittenTime());
+}
+
+
+
+void setoutputtime(int time_in_ms)
+{
+ seek_needed = time_in_ms;
+}
+
+
+
+void setvolume(int volume)
+{
+#ifdef SOFTVOLUME
+ thevolume = volume;
+ if (duh_player) duh_player->volume = volume / 255.0f;
+#else
+ mod.outMod->SetVolume(volume);
+#endif
+}
+
+
+
+void setpan(int pan) { mod.outMod->SetPan(pan); }
+
+
+
+int infoDlg(char *fn, HWND hwnd)
+{
+ (void)fn;
+ (void)hwnd;
+ // TODO: implement info dialog.
+ return 0;
+}
+
+
+
+static const char *fn_basename(const char *filename)
+{
+ for (;;) {
+ const char *p = strpbrk(filename, "/\\");
+ if (!p) return filename;
+ filename = p + 1;
+ }
+}
+
+
+
+void getfileinfo(char *filename, char *title, int *length_in_ms)
+{
+ if (!filename || !*filename) { /* currently playing file */
+
+ if (length_in_ms)
+ *length_in_ms = getlength();
+
+ if (title) {
+ const char *mod_title = duh_get_tag(duh, "TITLE");
+ if (mod_title && mod_title[0])
+ sprintf(title, "%s - %s", fn_basename(filename), mod_title);
+ else
+ strcpy(title, fn_basename(filename));
+ }
+ }
+ else { /* some other file */
+#if 1 // needs fixing better than this! more to add to DUMB's API?
+ if (length_in_ms || title) {
+ DUH *duh = load_duh(filename);
+ if (!duh) {
+ duh = dumb_load_it(filename);
+ if (!duh) {
+ duh = dumb_load_xm(filename);
+ if (!duh) {
+ duh = dumb_load_s3m(filename);
+ if (!duh) {
+ duh = dumb_load_mod(filename);
+ if (!duh)
+ return;
+ }
+ }
+ }
+ }
+
+ if (length_in_ms)
+ *length_in_ms = (int)((LONG_LONG)duh_get_length(duh) * 1000 >> 16);
+
+ if (title) {
+ const char *mod_title = duh_get_tag(duh, "TITLE");
+ if (mod_title && mod_title[0])
+ sprintf(title, "%s - %s", fn_basename(duh_filename), mod_title);
+ else
+ strcpy(title, fn_basename(duh_filename));
+ }
+
+ unload_duh(duh);
+ }
+#elif 0
+ /* This code only works (worked?) for DUH files. */
+ DUMBFILE *d = dumbfile_open(filename);
+
+ if (!d)
+ return;
+
+ if (dumbfile_mgetl(d) != DUH_SIGNATURE)
+ return;
+
+ *length_in_ms = (unsigned int)((LONG_LONG)dumbfile_igetl(d) * 1000 >> 16);
+
+ if (title)
+ strcpy(title, filename);
+
+ dumbfile_close(d);
+#else
+ *length_in_ms = 1000 * 60 * 10;
+
+ if (title)
+ strcpy(title, filename);
+#endif
+ }
+}
+
+
+
+void eq_set(int on, char data[10], int preamp)
+{
+ (void)on;
+ (void)data;
+ (void)preamp;
+ /* No equalizer support, sorry */
+}
+
+
+
+DUH_PLAYER *start_duh(DUH *duh, int n_channels, long pos, float volume)
+{
+ DUH_PLAYER *dp;
+
+ // This restriction is imposed by Allegro. <-- um...?
+ ASSERT(n_channels > 0);
+ ASSERT(n_channels <= 2);
+
+ if (!duh)
+ return NULL;
+
+ dp = malloc(sizeof(*dp));
+ if (!dp)
+ return NULL;
+
+ dp->n_channels = n_channels;
+
+ dp->dr = duh_start_sigrenderer(duh, 0, n_channels, pos);
+
+ if (!dp->dr) {
+ free(dp);
+ return NULL;
+ }
+
+ {
+ DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(dp->dr);
+ dumb_it_set_loop_callback(itsr, &dumb_it_callback_terminate, NULL);
+ dumb_it_set_xm_speed_zero_callback(itsr, &dumb_it_callback_terminate, NULL);
+ }
+
+ dp->volume = volume;
+
+ return dp;
+}
+
+
+
+
+void pause_duh(DUH_PLAYER *dp)
+{
+ (void)dp;
+ pause();
+}
+
+
+
+void resume_duh(DUH_PLAYER *dp)
+{
+ (void)dp;
+ unpause();
+}
+
+
+
+void set_duh_volume(DUH_PLAYER *dp, float volume)
+{
+ (void)dp;
+ setvolume((int)(volume * 255.0f));
+}
+
+
+
+
+/* Generate 576 samples of data from the DUH_PLAYER */
+int get_576_samples(DUH_PLAYER *dp, char *buf)
+{
+#if 1
+ if (!dp) return 0;
+
+ long n = duh_render(dp->dr, bits_per_sample, bits_per_sample == 8 ? 1 : 0,
+ dp->volume, 65536.0f / frequency, 576, buf);
+
+ return n * (bits_per_sample >> 3) * stereo;
+#else
+ long n;
+ int bps = ((bits_per_sample + 7) / 8) * stereo;
+
+ if (!dp)
+ return 0;
+
+ if (buffer_pos == 0 || buffer_pos + 576 >= buffer_size) {
+
+ if (buffer_pos) {
+ memmove(sample_buffer, sample_buffer + bps * buffer_pos, (buffer_size - buffer_pos) * bps);
+ buffer_pos = buffer_size - buffer_pos;
+ }
+
+ n = duh_render(dp->dr, bits_per_sample, bits_per_sample == 8 ? 1 : 0,
+ dp->volume, 65536.0f / frequency, buffer_size - buffer_pos,
+ sample_buffer + buffer_pos * bps);
+
+ if (n > 576) n = 576;
+
+ n *= bps;
+ buffer_pos = 0;
+ }
+
+ memcpy(buf, sample_buffer + buffer_pos * bps, 576 * bps);
+
+ buffer_pos += 576;
+
+ return 576 * bps;
+#endif
+}
+
+
+DWORD WINAPI __stdcall DecodeThread(void *b)
+{
+ static char buf[576 * 4];
+ int done = 0;
+ int length = 0;
+
+ if (init_duh) {
+ dumb_resampling_quality = resampling;
+#ifdef SOFTVOLUME
+ duh_player = start_duh(duh, stereo, 0, thevolume / 255.0f);
+#else
+ duh_player = start_duh(duh, stereo, 0, 1.0f);
+#endif
+ init_duh = FALSE;
+ }
+ length = getlength();
+
+
+ while (! *((int *)b) )
+ {
+ if (seek_needed != -1) {
+
+ decode_pos_ms = seek_needed-(seek_needed%1000);
+ seek_needed = -1;
+ done = 0;
+
+ mod.outMod->Flush(decode_pos_ms);
+
+ /* Position the playback pointer */
+ stop_duh(duh_player);
+ duh_player = start_duh(duh, stereo, (unsigned int)(decode_pos_ms * 65536.0 / 1000.0), 1.0);
+ }
+ if (done) {
+ mod.outMod->CanWrite();
+
+ if (!mod.outMod->IsPlaying()) {
+ PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0);
+ return 0;
+ }
+ Sleep(10);
+ }
+ else if (mod.outMod->CanWrite() >= ((576 * stereo * ((bits_per_sample + 7) / 8)))) {
+
+ int l = get_576_samples(duh_player, buf);
+
+ if (!l || decode_pos_ms >= length) {
+ done = 1;
+ }
+ else {
+ /* Vis plug-ins interface */
+ mod.SAAddPCMData((char *)buf, stereo, bits_per_sample, decode_pos_ms);
+ mod.VSAAddPCMData((char *)buf, stereo, bits_per_sample, decode_pos_ms);
+
+ /* Add PCM to output buffer */
+ decode_pos_ms += (576 * 1000) / frequency;
+
+ if (mod.dsp_isactive())
+ l = mod.dsp_dosamples((short *)buf, l / stereo / ((bits_per_sample + 7) / 8), bits_per_sample,
+ stereo, frequency) * (stereo * ((bits_per_sample + 7) / 8));
+
+ mod.outMod->Write(buf, l);
+ }
+ }
+ else /* Nothing to do this pass */
+ Sleep(config_frequency / 1000);
+ }
+ return 0;
+}
+
+
+
+In_Module mod =
+{
+ IN_VER,
+ "DUH! Player v" VERSION
+#ifdef __alpha
+ " (AXP)"
+#else
+ " (x86)"
+#endif
+ ,
+ 0, /* hMainWindow */
+ 0, /* hDllInstance */
+ "DUH\0Dynamic Universal Harmony File (*.DUH)\0"
+ "IT\0Impulse Tracker Module (*.IT)\0"
+ "XM\0Fast Tracker 2 Module (*.XM)\0"
+ "S3M\0Scream Tracker 3 Module (*.S3M)\0"
+ "MOD\0Amiga Module (*.MOD)\0"
+ ,
+ 1, /* is_seekable */
+ 1, /* uses output */
+ config,
+ about,
+ init,
+ quit,
+ getfileinfo,
+ infoDlg,
+ isourfile,
+ play,
+ pause,
+ unpause,
+ ispaused,
+ stop,
+
+ getlength,
+ getoutputtime,
+ setoutputtime,
+
+ setvolume,
+ setpan,
+
+ 0,0,0,0,0,0,0,0,0, /* vis stuff */
+
+
+ 0,0, /* dsp */
+
+ eq_set,
+
+ NULL, /* setinfo */
+
+ 0 /* out_mod */
+
+};
+
+__declspec( dllexport ) In_Module * winampGetInModule2()
+{
+ return &mod;
+}
diff --git a/plugins/dumb/dumb-kode54/winamp/in_duh.h b/plugins/dumb/dumb-kode54/winamp/in_duh.h
index 38dfe182..cdcf58f1 100644
--- a/plugins/dumb/dumb-kode54/winamp/in_duh.h
+++ b/plugins/dumb/dumb-kode54/winamp/in_duh.h
@@ -1,40 +1,40 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * in_duh.h - Winamp plug-in header file. / / \ \
- * | < / \_
- * By Bob. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <windows.h>
-//#include <mmreg.h>
-//#include <msacm.h>
-#include <math.h>
-
-#include "in2.h"
-
-#include "../include/dumb.h"
-
-
-/******************
- * Plug in config */
-
-#define VERSION "0.1"
-
-
-#define STREAM_SIZE 576
-#define STREAM_FREQ 44100
-
-
-extern In_Module mod;
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * in_duh.h - Winamp plug-in header file. / / \ \
+ * | < / \_
+ * By Bob. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <windows.h>
+//#include <mmreg.h>
+//#include <msacm.h>
+#include <math.h>
+
+#include "in2.h"
+
+#include "../include/dumb.h"
+
+
+/******************
+ * Plug in config */
+
+#define VERSION "0.1"
+
+
+#define STREAM_SIZE 576
+#define STREAM_FREQ 44100
+
+
+extern In_Module mod;
diff --git a/plugins/dumb/dumb-kode54/winamp/minalleg.c b/plugins/dumb/dumb-kode54/winamp/minalleg.c
index af645339..2fead6a0 100644
--- a/plugins/dumb/dumb-kode54/winamp/minalleg.c
+++ b/plugins/dumb/dumb-kode54/winamp/minalleg.c
@@ -1,2179 +1,2179 @@
-/* Mini Allegro - File and compression routines */
-/* Ripped from Allegro WIP */
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <limits.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <io.h>
-#include "minalleg.h"
-
-
-#ifndef _USE_LFN
-#define _USE_LFN 0
-#endif
-
-
-#if (!defined S_IRUSR) && (!defined SCAN_DEPEND)
- #define S_IRUSR S_IREAD
- #define S_IWUSR S_IWRITE
-#endif
-
-
-
-#define N 4096 /* 4k buffers for LZ compression */
-#define F 18 /* upper limit for LZ match length */
-#define THRESHOLD 2 /* LZ encode string into pos and length
- if match size is greater than this */
-
-
-typedef struct PACK_DATA /* stuff for doing LZ compression */
-{
- int state; /* where have we got to in the pack? */
- int i, c, len, r, s;
- int last_match_length, code_buf_ptr;
- unsigned char mask;
- char code_buf[17];
- int match_position;
- int match_length;
- int lson[N+1]; /* left children, */
- int rson[N+257]; /* right children, */
- int dad[N+1]; /* and parents, = binary search trees */
- unsigned char text_buf[N+F-1]; /* ring buffer, with F-1 extra bytes
- for string comparison */
-} PACK_DATA;
-
-
-typedef struct UNPACK_DATA /* for reading LZ files */
-{
- int state; /* where have we got to? */
- int i, j, k, r, c;
- int flags;
- unsigned char text_buf[N+F-1]; /* ring buffer, with F-1 extra bytes
- for string comparison */
-} UNPACK_DATA;
-
-
-static int refill_buffer(PACKFILE *f);
-static int flush_buffer(PACKFILE *f, int last);
-static void pack_inittree(PACK_DATA *dat);
-static void pack_insertnode(int r, PACK_DATA *dat);
-static void pack_deletenode(int p, PACK_DATA *dat);
-static int pack_write(PACKFILE *file, PACK_DATA *dat, int size, unsigned char *buf, int last);
-static int pack_read(PACKFILE *file, UNPACK_DATA *dat, int s, unsigned char *buf);
-
-static char the_password[256] = "";
-
-int _packfile_filesize = 0;
-int _packfile_datasize = 0;
-
-int _packfile_type = 0;
-
-
-#define FA_DAT_FLAGS (FA_RDONLY | FA_ARCH)
-
-
-int pack_getc(PACKFILE *f)
-{
- f->buf_size--;
- if (f->buf_size > 0)
- return *(f->buf_pos++);
- else
- return _sort_out_getc(f);
-}
-
-
-int pack_putc(int c, PACKFILE *f)
-{
- f->buf_size++;
- if (f->buf_size >= F_BUF_SIZE)
- return _sort_out_putc(c, f);
- else
- return (*(f->buf_pos++) = c);
-}
-
-
-/* fix_filename_case:
- * Converts filename to upper case.
- */
-char *fix_filename_case(char *filename)
-{
- return filename;
-}
-
-
-
-/* fix_filename_slashes:
- * Converts '/' or '\' to system specific path separator.
- */
-char *fix_filename_slashes(char *filename)
-{
- int pos, c;
-
- for (pos=0; c = filename[pos]; pos++) {
- if ((c == '/') || (c == '\\'))
- filename[pos] = OTHER_PATH_SEPARATOR;
- }
-
- return filename;
-}
-
-
-
-/* fix_filename_path:
- * Canonicalizes path.
- */
-char *fix_filename_path(char *dest, char *path, int size)
-{
- int saved_errno = errno;
- char buf[512], buf2[512];
- char *p;
- int pos = 0;
- int drive = -1;
- int c1, i;
-
- memset(buf, 0, sizeof(buf));
-
- #if (DEVICE_SEPARATOR != 0) && (DEVICE_SEPARATOR != '\0')
-
- /* check whether we have a drive letter */
- c1 = tolower(path[0]);
- if ((c1 >= 'a') && (c1 <= 'z')) {
- int c2 = path[1];
- if (c2 == DEVICE_SEPARATOR) {
- drive = c1 - 'a';
- path += 2;
- }
- }
-
- /* if not, use the current drive */
- if (drive < 0)
- drive = _al_getdrive();
-
- buf[pos] = drive + 'a'; pos++;
- buf[pos] = DEVICE_SEPARATOR; pos++;
- #endif
-
- /* if the path is relative, make it absolute */
- if ((path[0] != '/') && (path[0] != OTHER_PATH_SEPARATOR) && (path[0] != '#')) {
- _al_getdcwd(drive, buf2, sizeof(buf2) - 1);
- put_backslash(buf2);
-
- p = buf2;
- if ((tolower(p[0]) >= 'a') && (tolower(p[0]) <= 'z') && (p[1] == DEVICE_SEPARATOR))
- p += 2;
-
- memcpy(buf + pos, p, sizeof(buf) - pos);
- pos = strlen(buf);
- }
-
- /* add our path, and clean it up a bit */
- memcpy(buf + pos, path, sizeof(buf) - pos);
-
- fix_filename_case(buf);
- fix_filename_slashes(buf);
-
- /* remove duplicate slashes */
- buf2[0] = OTHER_PATH_SEPARATOR;
- buf2[1] = OTHER_PATH_SEPARATOR;
- buf2[2] = 0;
- pos = 2;
-
- while ((p = strstr(buf, buf2)) != NULL)
- memmove(p, p + 1, strlen(p));
-
- /* remove /./ patterns */
- buf2[0] = OTHER_PATH_SEPARATOR;
- buf2[1] = '.';
- buf2[2] = OTHER_PATH_SEPARATOR;
- buf2[3] = 0;
- pos = 3;
-
- while ((p = strstr(buf, buf2)) != NULL) {
- memmove(p, p + 1, strlen(p));
- memmove(p, p + 1, strlen(p));
- }
-
- /* collapse /../ patterns */
- buf2[0] = OTHER_PATH_SEPARATOR;
- buf2[1] = '.';
- buf2[2] = '.';
- buf2[3] = OTHER_PATH_SEPARATOR;
- buf2[4] = 0;
- pos = 4;
-
- while ((p = strstr(buf, buf2)) != NULL) {
- for (i = 0; buf + i < p; i++)
- ;
-
- while (--i > 0) {
- c1 = buf[i];
-
- if (c1 == OTHER_PATH_SEPARATOR)
- break;
-
- if (c1 == DEVICE_SEPARATOR) {
- i++;
- break;
- }
- }
-
- if (i < 0)
- i = 0;
-
- p += strlen(buf2);
- memmove(buf+i+1, p, strlen(p) + 1);
- }
-
- /* all done! */
- memcpy(dest, buf, MIN(size, (int)strlen(buf)));
-
- errno = saved_errno;
-
- return dest;
-}
-
-
-
-/* replace_filename:
- * Replaces filename in path with different one.
- * It does not append '/' to the path.
- */
-char *replace_filename(char *dest, char *path, char *filename, int size)
-{
- char tmp[512];
- int pos, c;
-
- pos = strlen(path);
-
- while (pos>0) {
- c = path[pos - 1];
- if ((c == '/') || (c == OTHER_PATH_SEPARATOR) || (c == DEVICE_SEPARATOR) || (c == '#'))
- break;
- pos--;
- }
- memset(tmp, 0, sizeof(tmp));
- memcpy(tmp, path, MIN(sizeof(tmp), pos));
- memcpy(tmp + MIN(sizeof(tmp), pos), filename, MIN(strlen(filename), sizeof(tmp) - pos));
-
- memcpy(dest, tmp, MIN((int)strlen(tmp), size));
-
- return dest;
-}
-
-
-
-/* replace_extension:
- * Replaces extension in filename with different one.
- * It appends '.' if it is not present in the filename.
- */
-char *replace_extension(char *dest, char *filename, char *ext, int size)
-{
- char tmp[512];
- int pos, end, c;
-
- pos = end = strlen(filename);
-
- while (pos>0) {
- c = filename[pos - 1];
- if ((c == '.') || (c == '/') || (c == OTHER_PATH_SEPARATOR) || (c == DEVICE_SEPARATOR) || (c == '#'))
- break;
- pos--;
- }
-
- if (filename[pos - 1] == '.')
- end = pos - 1;
-
- memcpy(tmp, filename, MIN((int)sizeof(tmp), strlen(filename)));
- if (strlen(tmp) < sizeof(tmp)-1) {
- tmp[strlen(tmp)+1] = 0;
- tmp[strlen(tmp)] = '.';
- }
- memcpy(tmp + strlen(tmp), ext, MIN(sizeof(tmp) - (int)strlen(tmp), (int)strlen(ext)));
- memcpy(dest, tmp, MIN(size, sizeof(tmp)));
-
- return dest;
-}
-
-
-
-/* append_filename:
- * Append filename to path, adding separator if necessary.
- */
-char *append_filename(char *dest, char *path, char *filename, int size)
-{
- char tmp[512];
- int pos, c;
-
- memcpy(tmp, path, MIN(sizeof(tmp) - 1, strlen(path)));
- tmp[511] = 0;
- pos = strlen(tmp);
-
- if ((pos > 0) && (tmp[pos] < ((int)sizeof(tmp) - 2))) {
- c = tmp[pos - 1];
-
- if ((c != '/') && (c != OTHER_PATH_SEPARATOR) && (c != DEVICE_SEPARATOR) && (c != '#')) {
- tmp[pos] = OTHER_PATH_SEPARATOR;
- pos++;
- tmp[pos] = 0;
- }
- }
-
- memcpy(tmp + strlen(tmp), filename, MIN(sizeof(tmp) - (int)strlen(tmp), (int)strlen(filename)));
- memcpy(dest, tmp, MIN(sizeof(tmp), (int)strlen(tmp)));
-
- return dest;
-}
-
-
-
-/* get_filename:
- * When passed a completely specified file path, this returns a pointer
- * to the filename portion. Both '\' and '/' are recognized as directory
- * separators.
- */
-char *get_filename(char *path)
-{
- int pos, c;
-
- pos = strlen(path);
-
- while (pos>0) {
- c = path[pos - 1];
- if ((c == '/') || (c == OTHER_PATH_SEPARATOR) || (c == DEVICE_SEPARATOR) || (c == '#'))
- break;
- pos--;
- }
-
- return (char *)path + pos;
-}
-
-
-
-/* get_extension:
- * When passed a complete filename (with or without path information)
- * this returns a pointer to the file extension.
- */
-char *get_extension(char *filename)
-{
- int pos, c;
-
- pos = strlen(filename);
-
- while (pos>0) {
- c = filename[pos - 1];
- if ((c == '.') || (c == '/') || (c == OTHER_PATH_SEPARATOR) || (c == DEVICE_SEPARATOR) || (c == '#'))
- break;
- pos--;
- }
-
- if ((pos>0) && (filename[pos-1] == '.'))
- return (char *)filename + pos;
-
- return (char *)filename + strlen(filename);
-}
-
-
-
-/* put_backslash:
- * If the last character of the filename is not a \, /, or #, this routine
- * will concatenate a \ on to it.
- */
-void put_backslash(char *filename)
-{
- int c;
-
- if (*filename) {
- c = filename[strlen(filename)-1];
-
- if ((c == '/') || (c == OTHER_PATH_SEPARATOR) || (c == DEVICE_SEPARATOR) || (c == '#'))
- return;
- }
-
- filename += strlen(filename);
- filename[0] = OTHER_PATH_SEPARATOR;
- filename[1] = 0;
-}
-
-
-
-/* file_exists:
- * Checks whether a file matching the given name and attributes exists,
- * returning non zero if it does. The file attribute may contain any of
- * the FA_* constants from dir.h. If aret is not null, it will be set
- * to the attributes of the matching file. If an error occurs the system
- * error code will be stored in errno.
- */
-int file_exists(char *filename, int attrib, int *aret)
-{
- int a;
-
- if (!_al_file_isok(filename))
- return 0;
-
- if (!_al_file_exists(filename, attrib, &a))
- return FALSE;
-
- if (aret)
- *aret = a;
-
- return TRUE;
-}
-
-
-
-/* exists:
- * Shortcut version of file_exists().
- */
-int exists(char *filename)
-{
- return file_exists(filename, FA_ARCH | FA_RDONLY, NULL);
-}
-
-
-
-/* file_size:
- * Returns the size of a file, in bytes.
- * If the file does not exist or an error occurs, it will return zero
- * and store the system error code in errno.
- */
-long file_size(char *filename)
-{
-
- if (!_al_file_isok(filename))
- return 0;
-
- return _al_file_size(filename);
-}
-
-
-
-/* file_time:
- * Returns a file time-stamp.
- * If the file does not exist or an error occurs, it will return zero
- * and store the system error code in errno.
- */
-time_t file_time(char *filename)
-{
- if (!_al_file_isok(filename))
- return 0;
-
- return _al_file_time(filename);
-}
-
-
-
-/* delete_file:
- * Removes a file from the disk.
- */
-int delete_file(char *filename)
-{
- errno = 0;
-
- if (!_al_file_isok(filename))
- return errno;
-
- unlink(filename);
-
- return errno;
-}
-
-
-
-/* for_each_file:
- * Finds all the files on the disk which match the given wildcard
- * specification and file attributes, and executes callback() once for
- * each. callback() will be passed three arguments, the first a string
- * which contains the completed filename, the second being the attributes
- * of the file, and the third an int which is simply a copy of param (you
- * can use this for whatever you like). If an error occurs an error code
- * will be stored in errno, and callback() can cause for_each_file() to
- * abort by setting errno itself. Returns the number of successful calls
- * made to callback(). The file attribute may contain any of the FA_*
- * flags from dir.h.
- */
-int for_each_file(char *name, int attrib, void (*callback)(char *filename, int attrib, int param), int param)
-{
- char dta_name[512], buf[512];
- void *dta;
- int dta_attrib;
- int c = 0;
-
- if (!_al_file_isok(name))
- return 0;
-
- dta = _al_findfirst(name, attrib, dta_name, &dta_attrib);
-
- if (!dta)
- return 0;
-
- do {
- replace_filename(buf, name, dta_name, sizeof(buf));
- (*callback)(buf, dta_attrib, param);
- if (errno != 0)
- break;
- c++;
- } while (_al_findnext(dta, dta_name, &dta_attrib) == 0);
-
- _al_findclose(dta);
-
- errno = 0;
- return c;
-}
-
-
-
-/* packfile_password:
- * Sets the password to be used by all future read/write operations.
- */
-void packfile_password(char *password)
-{
- int i = 0;
- int c;
-
- if (password) {
- while ((c = *password) != 0) {
- password++;
- the_password[i++] = c;
- if (i >= (int)sizeof(the_password)-1)
- break;
- }
- }
-
- the_password[i] = 0;
-}
-
-
-
-/* encrypt_id:
- * Helper for encrypting magic numbers, using the current password.
- */
-static long encrypt_id(long x, int new_format)
-{
- long mask = 0;
- int i, pos;
-
- if (the_password[0]) {
- for (i=0; the_password[i]; i++)
- mask ^= ((long)the_password[i] << ((i&3) * 8));
-
- for (i=0, pos=0; i<4; i++) {
- mask ^= (long)the_password[pos++] << (24-i*8);
- if (!the_password[pos])
- pos = 0;
- }
-
- if (new_format)
- mask ^= 42;
- }
-
- return x ^ mask;
-}
-
-
-
-/* clone_password:
- * Sets up a local password string for use by this packfile.
- */
-static int clone_password(PACKFILE *f)
-{
- if (the_password[0]) {
- if ((f->passdata = malloc(strlen(the_password)+1)) == NULL) {
- errno = ENOMEM;
- return FALSE;
- }
- strcpy(f->passdata, the_password);
- }
- else
- f->passdata = NULL;
-
- f->passpos = f->passdata;
-
- return TRUE;
-}
-
-
-
-/* pack_fopen:
- * Opens a file according to mode, which may contain any of the flags:
- * 'r': open file for reading.
- * 'w': open file for writing, overwriting any existing data.
- * 'p': open file in 'packed' mode. Data will be compressed as it is
- * written to the file, and automatically uncompressed during read
- * operations. Files created in this mode will produce garbage if
- * they are read without this flag being set.
- * '!': open file for writing in normal, unpacked mode, but add the value
- * F_NOPACK_MAGIC to the start of the file, so that it can be opened
- * in packed mode and Allegro will automatically detect that the
- * data does not need to be decompressed.
- *
- * Instead of these flags, one of the constants F_READ, F_WRITE,
- * F_READ_PACKED, F_WRITE_PACKED or F_WRITE_NOPACK may be used as the second
- * argument to fopen().
- *
- * On success, fopen() returns a pointer to a file structure, and on error
- * it returns NULL and stores an error code in errno. An attempt to read a
- * normal file in packed mode will cause errno to be set to EDOM.
- */
-PACKFILE *pack_fopen(const char *filename, char *mode)
-{
- PACKFILE *f, *f2;
- long header = FALSE;
- int c;
-
- _packfile_type = 0;
-
- if (!_al_file_isok(filename))
- return NULL;
-
- errno = 0;
-
- if ((f = malloc(sizeof(PACKFILE))) == NULL) {
- errno = ENOMEM;
- return NULL;
- }
-
- f->buf_pos = f->buf;
- f->flags = 0;
- f->buf_size = 0;
- f->filename = NULL;
- f->passdata = NULL;
- f->passpos = NULL;
-
- while ((c = *(mode++)) != 0) {
- switch (c) {
- case 'r': case 'R': f->flags &= ~PACKFILE_FLAG_WRITE; break;
- case 'w': case 'W': f->flags |= PACKFILE_FLAG_WRITE; break;
- case 'p': case 'P': f->flags |= PACKFILE_FLAG_PACK; break;
- case '!': f->flags &= ~PACKFILE_FLAG_PACK; header = TRUE; break;
- }
- }
-
- if (f->flags & PACKFILE_FLAG_WRITE) {
- if (f->flags & PACKFILE_FLAG_PACK) {
- /* write a packed file */
- PACK_DATA *dat = malloc(sizeof(PACK_DATA));
-
- if (!dat) {
- errno = ENOMEM;
- free(f);
- return NULL;
- }
-
- if ((f->parent = pack_fopen(filename, F_WRITE)) == NULL) {
- free(dat);
- free(f);
- return NULL;
- }
-
- pack_mputl(encrypt_id(F_PACK_MAGIC, TRUE), f->parent);
-
- f->todo = 4;
-
- for (c=0; c < N - F; c++)
- dat->text_buf[c] = 0;
-
- dat->state = 0;
-
- f->pack_data = dat;
- }
- else {
- /* write a 'real' file */
- f->parent = NULL;
- f->pack_data = NULL;
-
- if (!clone_password(f)) {
- free(f);
- return NULL;
- }
-#ifndef ALLEGRO_MPW
- f->hndl = open(filename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
-#else
- f->hndl = _al_open(uconvert_toascii(filename, NULL), O_WRONLY | O_BINARY | O_CREAT | O_TRUNC);
-#endif
- if (f->hndl < 0) {
- if (f->passdata)
- free(f->passdata);
- free(f);
- return NULL;
- }
-
- errno = 0;
- f->todo = 0;
-
- if (header)
- pack_mputl(encrypt_id(F_NOPACK_MAGIC, TRUE), f);
- }
- }
- else {
- if (f->flags & PACKFILE_FLAG_PACK) {
- /* read a packed file */
- UNPACK_DATA *dat = malloc(sizeof(UNPACK_DATA));
-
- if (!dat) {
- errno = ENOMEM;
- free(f);
- return NULL;
- }
-
- if ((f->parent = pack_fopen(filename, F_READ)) == NULL) {
- free(dat);
- free(f);
- return NULL;
- }
-
- header = pack_mgetl(f->parent);
-
- if ((f->parent->passpos) &&
- ((header == encrypt_id(F_PACK_MAGIC, FALSE)) ||
- (header == encrypt_id(F_NOPACK_MAGIC, FALSE)))) {
-
- /* backward compatibility mode */
- pack_fclose(f->parent);
-
- if (!clone_password(f)) {
- free(dat);
- free(f);
- return NULL;
- }
-
- if ((f->parent = pack_fopen(filename, F_READ)) == NULL) {
- free(dat);
- free(f);
- return NULL;
- }
-
- f->parent->flags |= PACKFILE_FLAG_OLD_CRYPT;
- f->flags |= PACKFILE_FLAG_OLD_CRYPT;
-
- pack_mgetl(f->parent);
-
- if (header == encrypt_id(F_PACK_MAGIC, FALSE))
- header = encrypt_id(F_PACK_MAGIC, TRUE);
- else
- header = encrypt_id(F_NOPACK_MAGIC, TRUE);
- }
-
- if (header == encrypt_id(F_PACK_MAGIC, TRUE)) {
- for (c=0; c < N - F; c++)
- dat->text_buf[c] = 0;
- dat->state = 0;
- f->todo = LONG_MAX;
- f->pack_data = (char *)dat;
- }
- else if (header == encrypt_id(F_NOPACK_MAGIC, TRUE)) {
- f2 = f->parent;
- free(dat);
- free(f);
- return f2;
- }
- else {
- pack_fclose(f->parent);
- free(dat);
- free(f);
- if (errno == 0)
- errno = EDOM;
- return NULL;
- }
- }
- else {
- /* read a 'real' file */
- f->parent = NULL;
- f->pack_data = NULL;
-
- f->todo = _al_file_size(filename);
-
- if (errno) {
- free(f);
- return NULL;
- }
-
- if (!clone_password(f)) {
- free(f);
- return NULL;
- }
-
-#ifndef ALLEGRO_MPW
- f->hndl = open(filename, O_RDONLY | O_BINARY, S_IRUSR | S_IWUSR);
-#else
- f->hndl = _al_open(uconvert_toascii(filename, NULL), O_RDONLY | O_BINARY);
-#endif
-
- if (f->hndl < 0) {
- if (f->passdata)
- free(f->passdata);
- free(f);
- return NULL;
- }
- }
- }
-
- return f;
-}
-
-
-
-/* pack_fclose:
- * Closes a file after it has been read or written.
- * Returns zero on success. On error it returns an error code which is
- * also stored in errno. This function can fail only when writing to
- * files: if the file was opened in read mode it will always succeed.
- */
-int pack_fclose(PACKFILE *f)
-{
- if (f) {
- if (f->flags & PACKFILE_FLAG_WRITE) {
- if (f->flags & PACKFILE_FLAG_CHUNK)
- return pack_fclose(pack_fclose_chunk(f));
-
- flush_buffer(f, TRUE);
- }
-
- if (f->passdata)
- free(f->passdata);
-
- if (f->pack_data)
- free(f->pack_data);
-
- if (f->parent)
- pack_fclose(f->parent);
- else
- close(f->hndl);
-
- free(f);
- return errno;
- }
-
- return 0;
-}
-
-
-
-/* pack_fopen_chunk:
- * Opens a sub-chunk of the specified file, for reading or writing depending
- * on the type of the file. The returned file pointer describes the sub
- * chunk, and replaces the original file, which will no longer be valid.
- * When writing to a chunk file, data is sent to the original file, but
- * is prefixed with two length counts (32 bit, big-endian). For uncompressed
- * chunks these will both be set to the length of the data in the chunk.
- * For compressed chunks, created by setting the pack flag, the first will
- * contain the raw size of the chunk, and the second will be the negative
- * size of the uncompressed data. When reading chunks, the pack flag is
- * ignored, and the compression type is detected from the sign of the
- * second size value. The file structure used to read chunks checks the
- * chunk size, and will return EOF if you try to read past the end of
- * the chunk. If you don't read all of the chunk data, when you call
- * pack_fclose_chunk(), the parent file will advance past the unused data.
- * When you have finished reading or writing a chunk, you should call
- * pack_fclose_chunk() to return to your original file.
- */
-PACKFILE *pack_fopen_chunk(PACKFILE *f, int pack)
-{
- PACKFILE *chunk;
- char *name;
- int c;
-
- if (f->flags & PACKFILE_FLAG_WRITE) {
-
- /* write a sub-chunk */
- name = tmpnam(NULL);
- chunk = pack_fopen(name, (pack ? F_WRITE_PACKED : F_WRITE_NOPACK));
-
- if (chunk) {
- chunk->filename = strdup(name);
-
- if (pack)
- chunk->parent->parent = f;
- else
- chunk->parent = f;
-
- chunk->flags |= PACKFILE_FLAG_CHUNK;
- }
- }
- else {
- /* read a sub-chunk */
- _packfile_filesize = pack_mgetl(f);
- _packfile_datasize = pack_mgetl(f);
-
- if ((chunk = malloc(sizeof(PACKFILE))) == NULL) {
- errno = ENOMEM;
- return NULL;
- }
-
- chunk->buf_pos = chunk->buf;
- chunk->flags = PACKFILE_FLAG_CHUNK;
- chunk->buf_size = 0;
- chunk->filename = NULL;
- chunk->passdata = NULL;
- chunk->passpos = NULL;
- chunk->parent = f;
-
- if (f->flags & PACKFILE_FLAG_OLD_CRYPT) {
- /* backward compatibility mode */
- if (f->passdata) {
- if ((chunk->passdata = malloc(strlen(f->passdata)+1)) == NULL) {
- errno = ENOMEM;
- free(chunk);
- return NULL;
- }
- strcpy(chunk->passdata, f->passdata);
- chunk->passpos = chunk->passdata + (long)f->passpos - (long)f->passdata;
- f->passpos = f->passdata;
- }
- chunk->flags |= PACKFILE_FLAG_OLD_CRYPT;
- }
-
- if (_packfile_datasize < 0) {
- /* read a packed chunk */
- UNPACK_DATA *dat = malloc(sizeof(UNPACK_DATA));
-
- if (!dat) {
- errno = ENOMEM;
- if (chunk->passdata) free(chunk->passdata);
- free(chunk);
- return NULL;
- }
-
- for (c=0; c < N - F; c++)
- dat->text_buf[c] = 0;
-
- dat->state = 0;
- _packfile_datasize = -_packfile_datasize;
- chunk->todo = _packfile_datasize;
- chunk->pack_data = (char *)dat;
- chunk->flags |= PACKFILE_FLAG_PACK;
- }
- else {
- /* read an uncompressed chunk */
- chunk->todo = _packfile_datasize;
- chunk->pack_data = NULL;
- }
- }
-
- return chunk;
-}
-
-
-
-/* pack_fclose_chunk:
- * Call after reading or writing a sub-chunk. This closes the chunk file,
- * and returns a pointer to the original file structure (the one you
- * passed to pack_fopen_chunk()), to allow you to read or write data
- * after the chunk.
- */
-PACKFILE *pack_fclose_chunk(PACKFILE *f)
-{
- PACKFILE *parent = f->parent;
- PACKFILE *tmp;
- char *name = f->filename;
- int header;
-
- if (f->flags & PACKFILE_FLAG_WRITE) {
- /* finish writing a chunk */
- _packfile_datasize = f->todo + f->buf_size - 4;
-
- if (f->flags & PACKFILE_FLAG_PACK) {
- parent = parent->parent;
- f->parent->parent = NULL;
- }
- else
- f->parent = NULL;
-
- f->flags &= ~PACKFILE_FLAG_CHUNK;
- pack_fclose(f);
-
- tmp = pack_fopen(name, F_READ);
- _packfile_filesize = tmp->todo - 4;
-
- header = pack_mgetl(tmp);
-
- pack_mputl(_packfile_filesize, parent);
-
- if (header == encrypt_id(F_PACK_MAGIC, TRUE))
- pack_mputl(-_packfile_datasize, parent);
- else
- pack_mputl(_packfile_datasize, parent);
-
- while (!pack_feof(tmp))
- pack_putc(pack_getc(tmp), parent);
-
- pack_fclose(tmp);
-
- delete_file(name);
- free(name);
- }
- else {
- /* finish reading a chunk */
- while (f->todo > 0)
- pack_getc(f);
-
- if ((f->passpos) && (f->flags & PACKFILE_FLAG_OLD_CRYPT))
- parent->passpos = parent->passdata + (long)f->passpos - (long)f->passdata;
-
- if (f->passdata)
- free(f->passdata);
-
- if (f->pack_data)
- free(f->pack_data);
-
- free(f);
- }
-
- return parent;
-}
-
-
-
-/* pack_fseek:
- * Like the stdio fseek() function, but only supports forward seeks
- * relative to the current file position.
- */
-int pack_fseek(PACKFILE *f, int offset)
-{
- int i;
-
- if (f->flags & PACKFILE_FLAG_WRITE)
- return -1;
-
- errno = 0;
-
- /* skip forward through the buffer */
- if (f->buf_size > 0) {
- i = MIN(offset, f->buf_size);
- f->buf_size -= i;
- f->buf_pos += i;
- offset -= i;
- if ((f->buf_size <= 0) && (f->todo <= 0))
- f->flags |= PACKFILE_FLAG_EOF;
- }
-
- /* need to seek some more? */
- if (offset > 0) {
- i = MIN(offset, f->todo);
-
- if ((f->flags & PACKFILE_FLAG_PACK) || (f->passpos)) {
- /* for compressed files, we just have to read through the data */
- while (i > 0) {
- pack_getc(f);
- i--;
- }
- }
- else {
- if (f->parent) {
- /* pass the seek request on to the parent file */
- pack_fseek(f->parent, i);
- }
- else {
- /* do a real seek */
- lseek(f->hndl, i, SEEK_CUR);
- }
- f->todo -= i;
- if (f->todo <= 0)
- f->flags |= PACKFILE_FLAG_EOF;
- }
- }
-
- return errno;
-}
-
-
-
-/* pack_igetw:
- * Reads a 16 bit word from a file, using intel byte ordering.
- */
-int pack_igetw(PACKFILE *f)
-{
- int b1, b2;
-
- if ((b1 = pack_getc(f)) != EOF)
- if ((b2 = pack_getc(f)) != EOF)
- return ((b2 << 8) | b1);
-
- return EOF;
-}
-
-
-
-/* pack_igetl:
- * Reads a 32 bit long from a file, using intel byte ordering.
- */
-long pack_igetl(PACKFILE *f)
-{
- int b1, b2, b3, b4;
-
- if ((b1 = pack_getc(f)) != EOF)
- if ((b2 = pack_getc(f)) != EOF)
- if ((b3 = pack_getc(f)) != EOF)
- if ((b4 = pack_getc(f)) != EOF)
- return (((long)b4 << 24) | ((long)b3 << 16) |
- ((long)b2 << 8) | (long)b1);
-
- return EOF;
-}
-
-
-
-/* pack_iputw:
- * Writes a 16 bit int to a file, using intel byte ordering.
- */
-int pack_iputw(int w, PACKFILE *f)
-{
- int b1, b2;
-
- b1 = (w & 0xFF00) >> 8;
- b2 = w & 0x00FF;
-
- if (pack_putc(b2,f)==b2)
- if (pack_putc(b1,f)==b1)
- return w;
-
- return EOF;
-}
-
-
-
-/* pack_iputw:
- * Writes a 32 bit long to a file, using intel byte ordering.
- */
-long pack_iputl(long l, PACKFILE *f)
-{
- int b1, b2, b3, b4;
-
- b1 = (int)((l & 0xFF000000L) >> 24);
- b2 = (int)((l & 0x00FF0000L) >> 16);
- b3 = (int)((l & 0x0000FF00L) >> 8);
- b4 = (int)l & 0x00FF;
-
- if (pack_putc(b4,f)==b4)
- if (pack_putc(b3,f)==b3)
- if (pack_putc(b2,f)==b2)
- if (pack_putc(b1,f)==b1)
- return l;
-
- return EOF;
-}
-
-
-
-/* pack_mgetw:
- * Reads a 16 bit int from a file, using motorola byte-ordering.
- */
-int pack_mgetw(PACKFILE *f)
-{
- int b1, b2;
-
- if ((b1 = pack_getc(f)) != EOF)
- if ((b2 = pack_getc(f)) != EOF)
- return ((b1 << 8) | b2);
-
- return EOF;
-}
-
-
-
-/* pack_mgetl:
- * Reads a 32 bit long from a file, using motorola byte-ordering.
- */
-long pack_mgetl(PACKFILE *f)
-{
- int b1, b2, b3, b4;
-
- if ((b1 = pack_getc(f)) != EOF)
- if ((b2 = pack_getc(f)) != EOF)
- if ((b3 = pack_getc(f)) != EOF)
- if ((b4 = pack_getc(f)) != EOF)
- return (((long)b1 << 24) | ((long)b2 << 16) |
- ((long)b3 << 8) | (long)b4);
-
- return EOF;
-}
-
-
-
-/* pack_mputw:
- * Writes a 16 bit int to a file, using motorola byte-ordering.
- */
-int pack_mputw(int w, PACKFILE *f)
-{
- int b1, b2;
-
- b1 = (w & 0xFF00) >> 8;
- b2 = w & 0x00FF;
-
- if (pack_putc(b1,f)==b1)
- if (pack_putc(b2,f)==b2)
- return w;
-
- return EOF;
-}
-
-
-
-/* pack_mputl:
- * Writes a 32 bit long to a file, using motorola byte-ordering.
- */
-long pack_mputl(long l, PACKFILE *f)
-{
- int b1, b2, b3, b4;
-
- b1 = (int)((l & 0xFF000000L) >> 24);
- b2 = (int)((l & 0x00FF0000L) >> 16);
- b3 = (int)((l & 0x0000FF00L) >> 8);
- b4 = (int)l & 0x00FF;
-
- if (pack_putc(b1,f)==b1)
- if (pack_putc(b2,f)==b2)
- if (pack_putc(b3,f)==b3)
- if (pack_putc(b4,f)==b4)
- return l;
-
- return EOF;
-}
-
-
-
-/* pack_fread:
- * Reads n bytes from f and stores them at memory location p. Returns the
- * number of items read, which will be less than n if EOF is reached or an
- * error occurs. Error codes are stored in errno.
- */
-long pack_fread(void *p, long n, PACKFILE *f)
-{
- unsigned char *cp = (unsigned char *)p;
- long c;
- int i;
-
- for (c=0; c<n; c++) {
- if (--(f->buf_size) > 0)
- *(cp++) = *(f->buf_pos++);
- else {
- i = _sort_out_getc(f);
- if (i == EOF)
- return c;
- else
- *(cp++) = i;
- }
- }
-
- return n;
-}
-
-
-
-/* pack_fwrite:
- * Writes n bytes to the file f from memory location p. Returns the number
- * of items written, which will be less than n if an error occurs. Error
- * codes are stored in errno.
- */
-long pack_fwrite(void *p, long n, PACKFILE *f)
-{
- unsigned char *cp = (unsigned char *)p;
- long c;
-
- for (c=0; c<n; c++) {
- if (++(f->buf_size) >= F_BUF_SIZE) {
- if (_sort_out_putc(*cp,f) != *cp)
- return c;
- cp++;
- }
- else
- *(f->buf_pos++)=*(cp++);
- }
-
- return n;
-}
-
-
-
-/* pack_ungetc:
- * Puts a character back in the file's input buffer. Added by gfoot for
- * use in the fgets function; maybe it should be in the API. It only works
- * for characters just fetched by pack_getc.
- */
-static void pack_ungetc (int ch, PACKFILE *f)
-{
- *(--f->buf_pos) = (unsigned char) ch;
- f->buf_size++;
- f->flags &= ~PACKFILE_FLAG_EOF;
-}
-
-
-
-/* pack_fgets:
- * Reads a line from a text file, storing it at location p. Stops when a
- * linefeed is encountered, or max characters have been read. Returns a
- * pointer to where it stored the text, or NULL on error. The end of line
- * is handled by detecting optional '\r' characters optionally followed
- * by '\n' characters. This supports CR-LF (DOS/Windows), LF (Unix), and
- * CR (Mac) formats.
- */
-char *pack_fgets(char *p, int max, PACKFILE *f)
-{
- char *pmax;
- int c;
-
- errno = 0;
-
- pmax = p+max - 1;
-
- if (pack_feof(f)) {
- if (1 < max) *p = 0;
- return NULL;
- }
-
- while ((c = pack_getc (f)) != EOF) {
-
- if (c == '\r' || c == '\n') {
- /* Technically we should check there's space in the buffer, and if so,
- * add a \n. But pack_fgets has never done this. */
- if (c == '\r') {
- /* eat the following \n, if any */
- if ((c = pack_getc (f)) != '\n') pack_ungetc (c, f);
- }
- break;
- }
-
- /* is there room in the buffer? */
- if (1 > pmax - p) {
- pack_ungetc (c, f);
- c = '\0';
- break;
- }
-
- /* write the character */
- *p = c;
- p++;
- }
-
- /* terminate the string */
- *p = 0;
-
- if (c == '\0' || errno)
- return NULL;
-
- return p;
-}
-
-
-
-/* pack_fputs:
- * Writes a string to a text file, returning zero on success, -1 on error.
- */
-int pack_fputs(char *p, PACKFILE *f)
-{
- char *s;
-
- errno = 0;
-
- s = p;
-
- while (*s) {
- if (*s == '\n')
- pack_putc('\r', f);
-
- pack_putc(*s, f);
- s++;
- }
-
- if (errno)
- return -1;
- else
- return 0;
-}
-
-
-
-/* _sort_out_getc:
- * Helper function for the pack_getc() macro.
- */
-int _sort_out_getc(PACKFILE *f)
-{
- if (f->buf_size == 0) {
- if (f->todo <= 0)
- f->flags |= PACKFILE_FLAG_EOF;
- return *(f->buf_pos++);
- }
- return refill_buffer(f);
-}
-
-
-
-/* refill_buffer:
- * Refills the read buffer. The file must have been opened in read mode,
- * and the buffer must be empty.
- */
-static int refill_buffer(PACKFILE *f)
-{
- int i, sz, done, offset;
-
- if ((f->flags & PACKFILE_FLAG_EOF) || (f->todo <= 0)) {
- f->flags |= PACKFILE_FLAG_EOF;
- return EOF;
- }
-
- if (f->parent) {
- if (f->flags & PACKFILE_FLAG_PACK) {
- f->buf_size = pack_read(f->parent, (UNPACK_DATA *)f->pack_data, MIN(F_BUF_SIZE, f->todo), f->buf);
- }
- else {
- f->buf_size = pack_fread(f->buf, MIN(F_BUF_SIZE, f->todo), f->parent);
- }
- if (f->parent->flags & PACKFILE_FLAG_EOF)
- f->todo = 0;
- if (f->parent->flags & PACKFILE_FLAG_ERROR)
- goto err;
- }
- else {
- f->buf_size = MIN(F_BUF_SIZE, f->todo);
-
- offset = lseek(f->hndl, 0, SEEK_CUR);
- done = 0;
-
- errno = 0;
- sz = read(f->hndl, f->buf, f->buf_size);
-
- while (sz+done < f->buf_size) {
- if ((sz < 0) && ((errno != EINTR) && (errno != EAGAIN)))
- goto err;
-
- if (sz > 0)
- done += sz;
-
- lseek(f->hndl, offset+done, SEEK_SET);
- errno = 0;
- sz = read(f->hndl, f->buf+done, f->buf_size-done);
- }
- errno = 0;
-
- if (errno == EINTR)
- errno = 0;
-
- if ((f->passpos) && (!(f->flags & PACKFILE_FLAG_OLD_CRYPT))) {
- for (i=0; i<f->buf_size; i++) {
- f->buf[i] ^= *(f->passpos++);
- if (!*f->passpos)
- f->passpos = f->passdata;
- }
- }
- }
-
- f->todo -= f->buf_size;
- f->buf_pos = f->buf;
- f->buf_size--;
- if (f->buf_size <= 0)
- if (f->todo <= 0)
- f->flags |= PACKFILE_FLAG_EOF;
-
- return *(f->buf_pos++);
-
- err:
- errno = EFAULT;
- f->flags |= PACKFILE_FLAG_ERROR;
- return EOF;
-}
-
-
-
-/* _sort_out_putc:
- * Helper function for the pack_putc() macro.
- */
-int _sort_out_putc(int c, PACKFILE *f)
-{
- f->buf_size--;
-
- if (flush_buffer(f, FALSE))
- return EOF;
-
- f->buf_size++;
- return (*(f->buf_pos++)=c);
-}
-
-
-
-/* flush_buffer:
- * flushes a file buffer to the disk. The file must be open in write mode.
- */
-static int flush_buffer(PACKFILE *f, int last)
-{
- int i, sz, done, offset;
-
- if (f->buf_size > 0) {
- if (f->flags & PACKFILE_FLAG_PACK) {
- if (pack_write(f->parent, (PACK_DATA *)f->pack_data, f->buf_size, f->buf, last))
- goto err;
- }
- else {
- if ((f->passpos) && (!(f->flags & PACKFILE_FLAG_OLD_CRYPT))) {
- for (i=0; i<f->buf_size; i++) {
- f->buf[i] ^= *(f->passpos++);
- if (!*f->passpos)
- f->passpos = f->passdata;
- }
- }
-
- offset = lseek(f->hndl, 0, SEEK_CUR);
- done = 0;
-
- errno = 0;
- sz = write(f->hndl, f->buf, f->buf_size);
-
- while (sz+done < f->buf_size) {
- if ((sz < 0) && ((errno != EINTR) && (errno != EAGAIN)))
- goto err;
-
- if (sz > 0)
- done += sz;
-
- lseek(f->hndl, offset+done, SEEK_SET);
- errno = 0;
- sz = write(f->hndl, f->buf+done, f->buf_size-done);
- }
- errno = 0;
- }
- f->todo += f->buf_size;
- }
- f->buf_pos = f->buf;
- f->buf_size = 0;
- return 0;
-
- err:
- errno = EFAULT;
- f->flags |= PACKFILE_FLAG_ERROR;
- return EOF;
-}
-
-
-
-/***************************************************
- ************ LZSS compression routines ************
- ***************************************************
-
- This compression algorithm is based on the ideas of Lempel and Ziv,
- with the modifications suggested by Storer and Szymanski. The algorithm
- is based on the use of a ring buffer, which initially contains zeros.
- We read several characters from the file into the buffer, and then
- search the buffer for the longest string that matches the characters
- just read, and output the length and position of the match in the buffer.
-
- With a buffer size of 4096 bytes, the position can be encoded in 12
- bits. If we represent the match length in four bits, the <position,
- length> pair is two bytes long. If the longest match is no more than
- two characters, then we send just one character without encoding, and
- restart the process with the next letter. We must send one extra bit
- each time to tell the decoder whether we are sending a <position,
- length> pair or an unencoded character, and these flags are stored as
- an eight bit mask every eight items.
-
- This implementation uses binary trees to speed up the search for the
- longest match.
-
- Original code by Haruhiko Okumura, 4/6/1989.
- 12-2-404 Green Heights, 580 Nagasawa, Yokosuka 239, Japan.
-
- Modified for use in the Allegro filesystem by Shawn Hargreaves.
-
- Use, distribute, and modify this code freely.
-*/
-
-
-
-/* pack_inittree:
- * For i = 0 to N-1, rson[i] and lson[i] will be the right and left
- * children of node i. These nodes need not be initialized. Also, dad[i]
- * is the parent of node i. These are initialized to N, which stands for
- * 'not used.' For i = 0 to 255, rson[N+i+1] is the root of the tree for
- * strings that begin with character i. These are initialized to N. Note
- * there are 256 trees.
- */
-static void pack_inittree(PACK_DATA *dat)
-{
- int i;
-
- for (i=N+1; i<=N+256; i++)
- dat->rson[i] = N;
-
- for (i=0; i<N; i++)
- dat->dad[i] = N;
-}
-
-
-
-/* pack_insertnode:
- * Inserts a string of length F, text_buf[r..r+F-1], into one of the trees
- * (text_buf[r]'th tree) and returns the longest-match position and length
- * via match_position and match_length. If match_length = F, then removes
- * the old node in favor of the new one, because the old one will be
- * deleted sooner. Note r plays double role, as tree node and position in
- * the buffer.
- */
-static void pack_insertnode(int r, PACK_DATA *dat)
-{
- int i, p, cmp;
- unsigned char *key;
- unsigned char *text_buf = dat->text_buf;
-
- cmp = 1;
- key = &text_buf[r];
- p = N + 1 + key[0];
- dat->rson[r] = dat->lson[r] = N;
- dat->match_length = 0;
-
- for (;;) {
-
- if (cmp >= 0) {
- if (dat->rson[p] != N)
- p = dat->rson[p];
- else {
- dat->rson[p] = r;
- dat->dad[r] = p;
- return;
- }
- }
- else {
- if (dat->lson[p] != N)
- p = dat->lson[p];
- else {
- dat->lson[p] = r;
- dat->dad[r] = p;
- return;
- }
- }
-
- for (i = 1; i < F; i++)
- if ((cmp = key[i] - text_buf[p + i]) != 0)
- break;
-
- if (i > dat->match_length) {
- dat->match_position = p;
- if ((dat->match_length = i) >= F)
- break;
- }
- }
-
- dat->dad[r] = dat->dad[p];
- dat->lson[r] = dat->lson[p];
- dat->rson[r] = dat->rson[p];
- dat->dad[dat->lson[p]] = r;
- dat->dad[dat->rson[p]] = r;
- if (dat->rson[dat->dad[p]] == p)
- dat->rson[dat->dad[p]] = r;
- else
- dat->lson[dat->dad[p]] = r;
- dat->dad[p] = N; /* remove p */
-}
-
-
-
-/* pack_deletenode:
- * Removes a node from a tree.
- */
-static void pack_deletenode(int p, PACK_DATA *dat)
-{
- int q;
-
- if (dat->dad[p] == N)
- return; /* not in tree */
-
- if (dat->rson[p] == N)
- q = dat->lson[p];
- else
- if (dat->lson[p] == N)
- q = dat->rson[p];
- else {
- q = dat->lson[p];
- if (dat->rson[q] != N) {
- do {
- q = dat->rson[q];
- } while (dat->rson[q] != N);
- dat->rson[dat->dad[q]] = dat->lson[q];
- dat->dad[dat->lson[q]] = dat->dad[q];
- dat->lson[q] = dat->lson[p];
- dat->dad[dat->lson[p]] = q;
- }
- dat->rson[q] = dat->rson[p];
- dat->dad[dat->rson[p]] = q;
- }
-
- dat->dad[q] = dat->dad[p];
- if (dat->rson[dat->dad[p]] == p)
- dat->rson[dat->dad[p]] = q;
- else
- dat->lson[dat->dad[p]] = q;
-
- dat->dad[p] = N;
-}
-
-
-
-/* pack_write:
- * Called by flush_buffer(). Packs size bytes from buf, using the pack
- * information contained in dat. Returns 0 on success.
- */
-static int pack_write(PACKFILE *file, PACK_DATA *dat, int size, unsigned char *buf, int last)
-{
- int i = dat->i;
- int c = dat->c;
- int len = dat->len;
- int r = dat->r;
- int s = dat->s;
- int last_match_length = dat->last_match_length;
- int code_buf_ptr = dat->code_buf_ptr;
- unsigned char mask = dat->mask;
- int ret = 0;
-
- if (dat->state==2)
- goto pos2;
- else
- if (dat->state==1)
- goto pos1;
-
- dat->code_buf[0] = 0;
- /* code_buf[1..16] saves eight units of code, and code_buf[0] works
- as eight flags, "1" representing that the unit is an unencoded
- letter (1 byte), "0" a position-and-length pair (2 bytes).
- Thus, eight units require at most 16 bytes of code. */
-
- code_buf_ptr = mask = 1;
-
- s = 0;
- r = N - F;
- pack_inittree(dat);
-
- for (len=0; (len < F) && (size > 0); len++) {
- dat->text_buf[r+len] = *(buf++);
- if (--size == 0) {
- if (!last) {
- dat->state = 1;
- goto getout;
- }
- }
- pos1:
- ;
- }
-
- if (len == 0)
- goto getout;
-
- for (i=1; i <= F; i++)
- pack_insertnode(r-i,dat);
- /* Insert the F strings, each of which begins with one or
- more 'space' characters. Note the order in which these
- strings are inserted. This way, degenerate trees will be
- less likely to occur. */
-
- pack_insertnode(r,dat);
- /* Finally, insert the whole string just read. match_length
- and match_position are set. */
-
- do {
- if (dat->match_length > len)
- dat->match_length = len; /* match_length may be long near the end */
-
- if (dat->match_length <= THRESHOLD) {
- dat->match_length = 1; /* not long enough match: send one byte */
- dat->code_buf[0] |= mask; /* 'send one byte' flag */
- dat->code_buf[code_buf_ptr++] = dat->text_buf[r]; /* send uncoded */
- }
- else {
- /* send position and length pair. Note match_length > THRESHOLD */
- dat->code_buf[code_buf_ptr++] = (unsigned char) dat->match_position;
- dat->code_buf[code_buf_ptr++] = (unsigned char)
- (((dat->match_position >> 4) & 0xF0) |
- (dat->match_length - (THRESHOLD + 1)));
- }
-
- if ((mask <<= 1) == 0) { /* shift mask left one bit */
- if ((file->passpos) && (file->flags & PACKFILE_FLAG_OLD_CRYPT)) {
- dat->code_buf[0] ^= *file->passpos;
- file->passpos++;
- if (!*file->passpos)
- file->passpos = file->passdata;
- };
-
- for (i=0; i<code_buf_ptr; i++) /* send at most 8 units of */
- pack_putc(dat->code_buf[i], file); /* code together */
-
- if (pack_ferror(file)) {
- ret = EOF;
- goto getout;
- }
- dat->code_buf[0] = 0;
- code_buf_ptr = mask = 1;
- }
-
- last_match_length = dat->match_length;
-
- for (i=0; (i < last_match_length) && (size > 0); i++) {
- c = *(buf++);
- if (--size == 0) {
- if (!last) {
- dat->state = 2;
- goto getout;
- }
- }
- pos2:
- pack_deletenode(s,dat); /* delete old strings and */
- dat->text_buf[s] = c; /* read new bytes */
- if (s < F-1)
- dat->text_buf[s+N] = c; /* if the position is near the end of
- buffer, extend the buffer to make
- string comparison easier */
- s = (s+1) & (N-1);
- r = (r+1) & (N-1); /* since this is a ring buffer,
- increment the position modulo N */
-
- pack_insertnode(r,dat); /* register the string in
- text_buf[r..r+F-1] */
- }
-
- while (i++ < last_match_length) { /* after the end of text, */
- pack_deletenode(s,dat); /* no need to read, but */
- s = (s+1) & (N-1); /* buffer may not be empty */
- r = (r+1) & (N-1);
- if (--len)
- pack_insertnode(r,dat);
- }
-
- } while (len > 0); /* until length of string to be processed is zero */
-
- if (code_buf_ptr > 1) { /* send remaining code */
- if ((file->passpos) && (file->flags & PACKFILE_FLAG_OLD_CRYPT)) {
- dat->code_buf[0] ^= *file->passpos;
- file->passpos++;
- if (!*file->passpos)
- file->passpos = file->passdata;
- };
-
- for (i=0; i<code_buf_ptr; i++) {
- pack_putc(dat->code_buf[i], file);
- if (pack_ferror(file)) {
- ret = EOF;
- goto getout;
- }
- }
- }
-
- dat->state = 0;
-
- getout:
-
- dat->i = i;
- dat->c = c;
- dat->len = len;
- dat->r = r;
- dat->s = s;
- dat->last_match_length = last_match_length;
- dat->code_buf_ptr = code_buf_ptr;
- dat->mask = mask;
-
- return ret;
-}
-
-
-
-/* pack_read:
- * Called by refill_buffer(). Unpacks from dat into buf, until either
- * EOF is reached or s bytes have been extracted. Returns the number of
- * bytes added to the buffer
- */
-static int pack_read(PACKFILE *file, UNPACK_DATA *dat, int s, unsigned char *buf)
-{
- int i = dat->i;
- int j = dat->j;
- int k = dat->k;
- int r = dat->r;
- int c = dat->c;
- unsigned int flags = dat->flags;
- int size = 0;
-
- if (dat->state==2)
- goto pos2;
- else
- if (dat->state==1)
- goto pos1;
-
- r = N-F;
- flags = 0;
-
- for (;;) {
- if (((flags >>= 1) & 256) == 0) {
- if ((c = pack_getc(file)) == EOF)
- break;
-
- if ((file->passpos) && (file->flags & PACKFILE_FLAG_OLD_CRYPT)) {
- c ^= *file->passpos;
- file->passpos++;
- if (!*file->passpos)
- file->passpos = file->passdata;
- };
-
- flags = c | 0xFF00; /* uses higher byte to count eight */
- }
-
- if (flags & 1) {
- if ((c = pack_getc(file)) == EOF)
- break;
- dat->text_buf[r++] = c;
- r &= (N - 1);
- *(buf++) = c;
- if (++size >= s) {
- dat->state = 1;
- goto getout;
- }
- pos1:
- ;
- }
- else {
- if ((i = pack_getc(file)) == EOF)
- break;
- if ((j = pack_getc(file)) == EOF)
- break;
- i |= ((j & 0xF0) << 4);
- j = (j & 0x0F) + THRESHOLD;
- for (k=0; k <= j; k++) {
- c = dat->text_buf[(i + k) & (N - 1)];
- dat->text_buf[r++] = c;
- r &= (N - 1);
- *(buf++) = c;
- if (++size >= s) {
- dat->state = 2;
- goto getout;
- }
- pos2:
- ;
- }
- }
- }
-
- dat->state = 0;
-
- getout:
-
- dat->i = i;
- dat->j = j;
- dat->k = k;
- dat->r = r;
- dat->c = c;
- dat->flags = flags;
-
- return size;
-}
-
-
-
-
-/* _al_file_isok:
- * Helper function to check if it is safe to access a file on a floppy
- * drive. This really only applies to the DOS library, so we don't bother
- * with it.
- */
-int _al_file_isok(const char *filename)
-{
- return TRUE;
-}
-
-
-
-/* _al_file_exists:
- * Checks whether the specified file exists.
- */
-int _al_file_exists(const char *filename, int attrib, int *aret)
-{
- struct _finddata_t info;
- long handle;
-
- errno = 0;
-
- if ((handle = _findfirst(filename, &info)) < 0) {
- return FALSE;
- }
-
- _findclose(handle);
-
- if (aret)
- *aret = info.attrib;
-
- info.attrib &= (FA_HIDDEN | FA_SYSTEM | FA_LABEL | FA_DIREC);
-
- if ((info.attrib & attrib) != info.attrib)
- return FALSE;
-
- return TRUE;
-}
-
-
-
-/* _al_file_size:
- * Measures the size of the specified file.
- */
-long _al_file_size(const char *filename)
-{
- struct _finddata_t info;
- long handle;
-
- errno = 0;
-
- if ((handle = _findfirst(filename, &info)) < 0) {
- return 0;
- }
-
- _findclose(handle);
-
- if (info.attrib & (FA_SYSTEM | FA_LABEL | FA_DIREC))
- return 0;
-
- return info.size;
-}
-
-
-
-/* _al_file_time:
- * Returns the timestamp of the specified file.
- */
-time_t _al_file_time(const char *filename)
-{
- struct _finddata_t info;
- long handle;
-
- errno = 0;
-
- if ((handle = _findfirst(filename, &info)) < 0) {
- return 0;
- }
-
- _findclose(handle);
-
- if (info.attrib & (FA_SYSTEM | FA_LABEL | FA_DIREC))
- return 0;
-
- return info.time_write;
-}
-
-
-
-/* information structure for use by the directory scanning routines */
-typedef struct FFIND_INFO {
- struct _finddata_t info;
- long handle;
- int attrib;
-} FFIND_INFO;
-
-
-
-/* _al_findfirst:
- * Initiates a directory search.
- */
-void *_al_findfirst(const char *name, int attrib, char *nameret, int *aret)
-{
- FFIND_INFO *info;
- int a;
-
- info = malloc(sizeof(FFIND_INFO));
-
- if (!info) {
- errno = ENOMEM;
- return NULL;
- }
-
- info->attrib = attrib;
-
- errno = 0;
-
- if ((info->handle = _findfirst(name, &info->info)) < 0) {
- free(info);
- return NULL;
- }
-
- a = info->info.attrib & (FA_HIDDEN | FA_SYSTEM | FA_LABEL | FA_DIREC);
-
- if ((a & attrib) != a) {
- if (_al_findnext(info, nameret, aret) != 0) {
- _findclose(info->handle);
- free(info);
- return NULL;
- }
- else
- return info;
- }
-
- strcpy(nameret, info->info.name);
-
- if (aret)
- *aret = info->info.attrib;
-
- return info;
-}
-
-
-
-/* _al_findnext:
- * Retrieves the next file from a directory search.
- */
-int _al_findnext(void *dta, char *nameret, int *aret)
-{
- FFIND_INFO *info = (FFIND_INFO *) dta;
- int a;
-
- do {
- if (_findnext(info->handle, &info->info) != 0) {
- return -1;
- }
-
- a = info->info.attrib & (FA_HIDDEN | FA_SYSTEM | FA_LABEL | FA_DIREC);
-
- } while ((a & info->attrib) != a);
-
- strcpy(nameret, info->info.name);
-
- if (aret)
- *aret = info->info.attrib;
-
- return 0;
-}
-
-
-
-/* _al_findclose:
- * Cleans up after a directory search.
- */
-void _al_findclose(void *dta)
-{
- FFIND_INFO *info = (FFIND_INFO *) dta;
-
- _findclose(info->handle);
- free(info);
-}
-
-
-
-/* _al_getdrive:
- * Returns the current drive number (0=A, 1=B, etc).
- */
-int _al_getdrive()
-{
- return _getdrive() - 1;
-}
-
-
-
-/* _al_getdcwd:
- * Returns the current directory on the specified drive.
- */
-void _al_getdcwd(int drive, char *buf, int size)
-{
- char tmp[256];
-
- if (_getdcwd(drive+1, tmp, sizeof(tmp)))
- strcpy(buf, tmp);
- else
- buf[0] = 0;
-}
-
+/* Mini Allegro - File and compression routines */
+/* Ripped from Allegro WIP */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <io.h>
+#include "minalleg.h"
+
+
+#ifndef _USE_LFN
+#define _USE_LFN 0
+#endif
+
+
+#if (!defined S_IRUSR) && (!defined SCAN_DEPEND)
+ #define S_IRUSR S_IREAD
+ #define S_IWUSR S_IWRITE
+#endif
+
+
+
+#define N 4096 /* 4k buffers for LZ compression */
+#define F 18 /* upper limit for LZ match length */
+#define THRESHOLD 2 /* LZ encode string into pos and length
+ if match size is greater than this */
+
+
+typedef struct PACK_DATA /* stuff for doing LZ compression */
+{
+ int state; /* where have we got to in the pack? */
+ int i, c, len, r, s;
+ int last_match_length, code_buf_ptr;
+ unsigned char mask;
+ char code_buf[17];
+ int match_position;
+ int match_length;
+ int lson[N+1]; /* left children, */
+ int rson[N+257]; /* right children, */
+ int dad[N+1]; /* and parents, = binary search trees */
+ unsigned char text_buf[N+F-1]; /* ring buffer, with F-1 extra bytes
+ for string comparison */
+} PACK_DATA;
+
+
+typedef struct UNPACK_DATA /* for reading LZ files */
+{
+ int state; /* where have we got to? */
+ int i, j, k, r, c;
+ int flags;
+ unsigned char text_buf[N+F-1]; /* ring buffer, with F-1 extra bytes
+ for string comparison */
+} UNPACK_DATA;
+
+
+static int refill_buffer(PACKFILE *f);
+static int flush_buffer(PACKFILE *f, int last);
+static void pack_inittree(PACK_DATA *dat);
+static void pack_insertnode(int r, PACK_DATA *dat);
+static void pack_deletenode(int p, PACK_DATA *dat);
+static int pack_write(PACKFILE *file, PACK_DATA *dat, int size, unsigned char *buf, int last);
+static int pack_read(PACKFILE *file, UNPACK_DATA *dat, int s, unsigned char *buf);
+
+static char the_password[256] = "";
+
+int _packfile_filesize = 0;
+int _packfile_datasize = 0;
+
+int _packfile_type = 0;
+
+
+#define FA_DAT_FLAGS (FA_RDONLY | FA_ARCH)
+
+
+int pack_getc(PACKFILE *f)
+{
+ f->buf_size--;
+ if (f->buf_size > 0)
+ return *(f->buf_pos++);
+ else
+ return _sort_out_getc(f);
+}
+
+
+int pack_putc(int c, PACKFILE *f)
+{
+ f->buf_size++;
+ if (f->buf_size >= F_BUF_SIZE)
+ return _sort_out_putc(c, f);
+ else
+ return (*(f->buf_pos++) = c);
+}
+
+
+/* fix_filename_case:
+ * Converts filename to upper case.
+ */
+char *fix_filename_case(char *filename)
+{
+ return filename;
+}
+
+
+
+/* fix_filename_slashes:
+ * Converts '/' or '\' to system specific path separator.
+ */
+char *fix_filename_slashes(char *filename)
+{
+ int pos, c;
+
+ for (pos=0; c = filename[pos]; pos++) {
+ if ((c == '/') || (c == '\\'))
+ filename[pos] = OTHER_PATH_SEPARATOR;
+ }
+
+ return filename;
+}
+
+
+
+/* fix_filename_path:
+ * Canonicalizes path.
+ */
+char *fix_filename_path(char *dest, char *path, int size)
+{
+ int saved_errno = errno;
+ char buf[512], buf2[512];
+ char *p;
+ int pos = 0;
+ int drive = -1;
+ int c1, i;
+
+ memset(buf, 0, sizeof(buf));
+
+ #if (DEVICE_SEPARATOR != 0) && (DEVICE_SEPARATOR != '\0')
+
+ /* check whether we have a drive letter */
+ c1 = tolower(path[0]);
+ if ((c1 >= 'a') && (c1 <= 'z')) {
+ int c2 = path[1];
+ if (c2 == DEVICE_SEPARATOR) {
+ drive = c1 - 'a';
+ path += 2;
+ }
+ }
+
+ /* if not, use the current drive */
+ if (drive < 0)
+ drive = _al_getdrive();
+
+ buf[pos] = drive + 'a'; pos++;
+ buf[pos] = DEVICE_SEPARATOR; pos++;
+ #endif
+
+ /* if the path is relative, make it absolute */
+ if ((path[0] != '/') && (path[0] != OTHER_PATH_SEPARATOR) && (path[0] != '#')) {
+ _al_getdcwd(drive, buf2, sizeof(buf2) - 1);
+ put_backslash(buf2);
+
+ p = buf2;
+ if ((tolower(p[0]) >= 'a') && (tolower(p[0]) <= 'z') && (p[1] == DEVICE_SEPARATOR))
+ p += 2;
+
+ memcpy(buf + pos, p, sizeof(buf) - pos);
+ pos = strlen(buf);
+ }
+
+ /* add our path, and clean it up a bit */
+ memcpy(buf + pos, path, sizeof(buf) - pos);
+
+ fix_filename_case(buf);
+ fix_filename_slashes(buf);
+
+ /* remove duplicate slashes */
+ buf2[0] = OTHER_PATH_SEPARATOR;
+ buf2[1] = OTHER_PATH_SEPARATOR;
+ buf2[2] = 0;
+ pos = 2;
+
+ while ((p = strstr(buf, buf2)) != NULL)
+ memmove(p, p + 1, strlen(p));
+
+ /* remove /./ patterns */
+ buf2[0] = OTHER_PATH_SEPARATOR;
+ buf2[1] = '.';
+ buf2[2] = OTHER_PATH_SEPARATOR;
+ buf2[3] = 0;
+ pos = 3;
+
+ while ((p = strstr(buf, buf2)) != NULL) {
+ memmove(p, p + 1, strlen(p));
+ memmove(p, p + 1, strlen(p));
+ }
+
+ /* collapse /../ patterns */
+ buf2[0] = OTHER_PATH_SEPARATOR;
+ buf2[1] = '.';
+ buf2[2] = '.';
+ buf2[3] = OTHER_PATH_SEPARATOR;
+ buf2[4] = 0;
+ pos = 4;
+
+ while ((p = strstr(buf, buf2)) != NULL) {
+ for (i = 0; buf + i < p; i++)
+ ;
+
+ while (--i > 0) {
+ c1 = buf[i];
+
+ if (c1 == OTHER_PATH_SEPARATOR)
+ break;
+
+ if (c1 == DEVICE_SEPARATOR) {
+ i++;
+ break;
+ }
+ }
+
+ if (i < 0)
+ i = 0;
+
+ p += strlen(buf2);
+ memmove(buf+i+1, p, strlen(p) + 1);
+ }
+
+ /* all done! */
+ memcpy(dest, buf, MIN(size, (int)strlen(buf)));
+
+ errno = saved_errno;
+
+ return dest;
+}
+
+
+
+/* replace_filename:
+ * Replaces filename in path with different one.
+ * It does not append '/' to the path.
+ */
+char *replace_filename(char *dest, char *path, char *filename, int size)
+{
+ char tmp[512];
+ int pos, c;
+
+ pos = strlen(path);
+
+ while (pos>0) {
+ c = path[pos - 1];
+ if ((c == '/') || (c == OTHER_PATH_SEPARATOR) || (c == DEVICE_SEPARATOR) || (c == '#'))
+ break;
+ pos--;
+ }
+ memset(tmp, 0, sizeof(tmp));
+ memcpy(tmp, path, MIN(sizeof(tmp), pos));
+ memcpy(tmp + MIN(sizeof(tmp), pos), filename, MIN(strlen(filename), sizeof(tmp) - pos));
+
+ memcpy(dest, tmp, MIN((int)strlen(tmp), size));
+
+ return dest;
+}
+
+
+
+/* replace_extension:
+ * Replaces extension in filename with different one.
+ * It appends '.' if it is not present in the filename.
+ */
+char *replace_extension(char *dest, char *filename, char *ext, int size)
+{
+ char tmp[512];
+ int pos, end, c;
+
+ pos = end = strlen(filename);
+
+ while (pos>0) {
+ c = filename[pos - 1];
+ if ((c == '.') || (c == '/') || (c == OTHER_PATH_SEPARATOR) || (c == DEVICE_SEPARATOR) || (c == '#'))
+ break;
+ pos--;
+ }
+
+ if (filename[pos - 1] == '.')
+ end = pos - 1;
+
+ memcpy(tmp, filename, MIN((int)sizeof(tmp), strlen(filename)));
+ if (strlen(tmp) < sizeof(tmp)-1) {
+ tmp[strlen(tmp)+1] = 0;
+ tmp[strlen(tmp)] = '.';
+ }
+ memcpy(tmp + strlen(tmp), ext, MIN(sizeof(tmp) - (int)strlen(tmp), (int)strlen(ext)));
+ memcpy(dest, tmp, MIN(size, sizeof(tmp)));
+
+ return dest;
+}
+
+
+
+/* append_filename:
+ * Append filename to path, adding separator if necessary.
+ */
+char *append_filename(char *dest, char *path, char *filename, int size)
+{
+ char tmp[512];
+ int pos, c;
+
+ memcpy(tmp, path, MIN(sizeof(tmp) - 1, strlen(path)));
+ tmp[511] = 0;
+ pos = strlen(tmp);
+
+ if ((pos > 0) && (tmp[pos] < ((int)sizeof(tmp) - 2))) {
+ c = tmp[pos - 1];
+
+ if ((c != '/') && (c != OTHER_PATH_SEPARATOR) && (c != DEVICE_SEPARATOR) && (c != '#')) {
+ tmp[pos] = OTHER_PATH_SEPARATOR;
+ pos++;
+ tmp[pos] = 0;
+ }
+ }
+
+ memcpy(tmp + strlen(tmp), filename, MIN(sizeof(tmp) - (int)strlen(tmp), (int)strlen(filename)));
+ memcpy(dest, tmp, MIN(sizeof(tmp), (int)strlen(tmp)));
+
+ return dest;
+}
+
+
+
+/* get_filename:
+ * When passed a completely specified file path, this returns a pointer
+ * to the filename portion. Both '\' and '/' are recognized as directory
+ * separators.
+ */
+char *get_filename(char *path)
+{
+ int pos, c;
+
+ pos = strlen(path);
+
+ while (pos>0) {
+ c = path[pos - 1];
+ if ((c == '/') || (c == OTHER_PATH_SEPARATOR) || (c == DEVICE_SEPARATOR) || (c == '#'))
+ break;
+ pos--;
+ }
+
+ return (char *)path + pos;
+}
+
+
+
+/* get_extension:
+ * When passed a complete filename (with or without path information)
+ * this returns a pointer to the file extension.
+ */
+char *get_extension(char *filename)
+{
+ int pos, c;
+
+ pos = strlen(filename);
+
+ while (pos>0) {
+ c = filename[pos - 1];
+ if ((c == '.') || (c == '/') || (c == OTHER_PATH_SEPARATOR) || (c == DEVICE_SEPARATOR) || (c == '#'))
+ break;
+ pos--;
+ }
+
+ if ((pos>0) && (filename[pos-1] == '.'))
+ return (char *)filename + pos;
+
+ return (char *)filename + strlen(filename);
+}
+
+
+
+/* put_backslash:
+ * If the last character of the filename is not a \, /, or #, this routine
+ * will concatenate a \ on to it.
+ */
+void put_backslash(char *filename)
+{
+ int c;
+
+ if (*filename) {
+ c = filename[strlen(filename)-1];
+
+ if ((c == '/') || (c == OTHER_PATH_SEPARATOR) || (c == DEVICE_SEPARATOR) || (c == '#'))
+ return;
+ }
+
+ filename += strlen(filename);
+ filename[0] = OTHER_PATH_SEPARATOR;
+ filename[1] = 0;
+}
+
+
+
+/* file_exists:
+ * Checks whether a file matching the given name and attributes exists,
+ * returning non zero if it does. The file attribute may contain any of
+ * the FA_* constants from dir.h. If aret is not null, it will be set
+ * to the attributes of the matching file. If an error occurs the system
+ * error code will be stored in errno.
+ */
+int file_exists(char *filename, int attrib, int *aret)
+{
+ int a;
+
+ if (!_al_file_isok(filename))
+ return 0;
+
+ if (!_al_file_exists(filename, attrib, &a))
+ return FALSE;
+
+ if (aret)
+ *aret = a;
+
+ return TRUE;
+}
+
+
+
+/* exists:
+ * Shortcut version of file_exists().
+ */
+int exists(char *filename)
+{
+ return file_exists(filename, FA_ARCH | FA_RDONLY, NULL);
+}
+
+
+
+/* file_size:
+ * Returns the size of a file, in bytes.
+ * If the file does not exist or an error occurs, it will return zero
+ * and store the system error code in errno.
+ */
+long file_size(char *filename)
+{
+
+ if (!_al_file_isok(filename))
+ return 0;
+
+ return _al_file_size(filename);
+}
+
+
+
+/* file_time:
+ * Returns a file time-stamp.
+ * If the file does not exist or an error occurs, it will return zero
+ * and store the system error code in errno.
+ */
+time_t file_time(char *filename)
+{
+ if (!_al_file_isok(filename))
+ return 0;
+
+ return _al_file_time(filename);
+}
+
+
+
+/* delete_file:
+ * Removes a file from the disk.
+ */
+int delete_file(char *filename)
+{
+ errno = 0;
+
+ if (!_al_file_isok(filename))
+ return errno;
+
+ unlink(filename);
+
+ return errno;
+}
+
+
+
+/* for_each_file:
+ * Finds all the files on the disk which match the given wildcard
+ * specification and file attributes, and executes callback() once for
+ * each. callback() will be passed three arguments, the first a string
+ * which contains the completed filename, the second being the attributes
+ * of the file, and the third an int which is simply a copy of param (you
+ * can use this for whatever you like). If an error occurs an error code
+ * will be stored in errno, and callback() can cause for_each_file() to
+ * abort by setting errno itself. Returns the number of successful calls
+ * made to callback(). The file attribute may contain any of the FA_*
+ * flags from dir.h.
+ */
+int for_each_file(char *name, int attrib, void (*callback)(char *filename, int attrib, int param), int param)
+{
+ char dta_name[512], buf[512];
+ void *dta;
+ int dta_attrib;
+ int c = 0;
+
+ if (!_al_file_isok(name))
+ return 0;
+
+ dta = _al_findfirst(name, attrib, dta_name, &dta_attrib);
+
+ if (!dta)
+ return 0;
+
+ do {
+ replace_filename(buf, name, dta_name, sizeof(buf));
+ (*callback)(buf, dta_attrib, param);
+ if (errno != 0)
+ break;
+ c++;
+ } while (_al_findnext(dta, dta_name, &dta_attrib) == 0);
+
+ _al_findclose(dta);
+
+ errno = 0;
+ return c;
+}
+
+
+
+/* packfile_password:
+ * Sets the password to be used by all future read/write operations.
+ */
+void packfile_password(char *password)
+{
+ int i = 0;
+ int c;
+
+ if (password) {
+ while ((c = *password) != 0) {
+ password++;
+ the_password[i++] = c;
+ if (i >= (int)sizeof(the_password)-1)
+ break;
+ }
+ }
+
+ the_password[i] = 0;
+}
+
+
+
+/* encrypt_id:
+ * Helper for encrypting magic numbers, using the current password.
+ */
+static long encrypt_id(long x, int new_format)
+{
+ long mask = 0;
+ int i, pos;
+
+ if (the_password[0]) {
+ for (i=0; the_password[i]; i++)
+ mask ^= ((long)the_password[i] << ((i&3) * 8));
+
+ for (i=0, pos=0; i<4; i++) {
+ mask ^= (long)the_password[pos++] << (24-i*8);
+ if (!the_password[pos])
+ pos = 0;
+ }
+
+ if (new_format)
+ mask ^= 42;
+ }
+
+ return x ^ mask;
+}
+
+
+
+/* clone_password:
+ * Sets up a local password string for use by this packfile.
+ */
+static int clone_password(PACKFILE *f)
+{
+ if (the_password[0]) {
+ if ((f->passdata = malloc(strlen(the_password)+1)) == NULL) {
+ errno = ENOMEM;
+ return FALSE;
+ }
+ strcpy(f->passdata, the_password);
+ }
+ else
+ f->passdata = NULL;
+
+ f->passpos = f->passdata;
+
+ return TRUE;
+}
+
+
+
+/* pack_fopen:
+ * Opens a file according to mode, which may contain any of the flags:
+ * 'r': open file for reading.
+ * 'w': open file for writing, overwriting any existing data.
+ * 'p': open file in 'packed' mode. Data will be compressed as it is
+ * written to the file, and automatically uncompressed during read
+ * operations. Files created in this mode will produce garbage if
+ * they are read without this flag being set.
+ * '!': open file for writing in normal, unpacked mode, but add the value
+ * F_NOPACK_MAGIC to the start of the file, so that it can be opened
+ * in packed mode and Allegro will automatically detect that the
+ * data does not need to be decompressed.
+ *
+ * Instead of these flags, one of the constants F_READ, F_WRITE,
+ * F_READ_PACKED, F_WRITE_PACKED or F_WRITE_NOPACK may be used as the second
+ * argument to fopen().
+ *
+ * On success, fopen() returns a pointer to a file structure, and on error
+ * it returns NULL and stores an error code in errno. An attempt to read a
+ * normal file in packed mode will cause errno to be set to EDOM.
+ */
+PACKFILE *pack_fopen(const char *filename, char *mode)
+{
+ PACKFILE *f, *f2;
+ long header = FALSE;
+ int c;
+
+ _packfile_type = 0;
+
+ if (!_al_file_isok(filename))
+ return NULL;
+
+ errno = 0;
+
+ if ((f = malloc(sizeof(PACKFILE))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ f->buf_pos = f->buf;
+ f->flags = 0;
+ f->buf_size = 0;
+ f->filename = NULL;
+ f->passdata = NULL;
+ f->passpos = NULL;
+
+ while ((c = *(mode++)) != 0) {
+ switch (c) {
+ case 'r': case 'R': f->flags &= ~PACKFILE_FLAG_WRITE; break;
+ case 'w': case 'W': f->flags |= PACKFILE_FLAG_WRITE; break;
+ case 'p': case 'P': f->flags |= PACKFILE_FLAG_PACK; break;
+ case '!': f->flags &= ~PACKFILE_FLAG_PACK; header = TRUE; break;
+ }
+ }
+
+ if (f->flags & PACKFILE_FLAG_WRITE) {
+ if (f->flags & PACKFILE_FLAG_PACK) {
+ /* write a packed file */
+ PACK_DATA *dat = malloc(sizeof(PACK_DATA));
+
+ if (!dat) {
+ errno = ENOMEM;
+ free(f);
+ return NULL;
+ }
+
+ if ((f->parent = pack_fopen(filename, F_WRITE)) == NULL) {
+ free(dat);
+ free(f);
+ return NULL;
+ }
+
+ pack_mputl(encrypt_id(F_PACK_MAGIC, TRUE), f->parent);
+
+ f->todo = 4;
+
+ for (c=0; c < N - F; c++)
+ dat->text_buf[c] = 0;
+
+ dat->state = 0;
+
+ f->pack_data = dat;
+ }
+ else {
+ /* write a 'real' file */
+ f->parent = NULL;
+ f->pack_data = NULL;
+
+ if (!clone_password(f)) {
+ free(f);
+ return NULL;
+ }
+#ifndef ALLEGRO_MPW
+ f->hndl = open(filename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+#else
+ f->hndl = _al_open(uconvert_toascii(filename, NULL), O_WRONLY | O_BINARY | O_CREAT | O_TRUNC);
+#endif
+ if (f->hndl < 0) {
+ if (f->passdata)
+ free(f->passdata);
+ free(f);
+ return NULL;
+ }
+
+ errno = 0;
+ f->todo = 0;
+
+ if (header)
+ pack_mputl(encrypt_id(F_NOPACK_MAGIC, TRUE), f);
+ }
+ }
+ else {
+ if (f->flags & PACKFILE_FLAG_PACK) {
+ /* read a packed file */
+ UNPACK_DATA *dat = malloc(sizeof(UNPACK_DATA));
+
+ if (!dat) {
+ errno = ENOMEM;
+ free(f);
+ return NULL;
+ }
+
+ if ((f->parent = pack_fopen(filename, F_READ)) == NULL) {
+ free(dat);
+ free(f);
+ return NULL;
+ }
+
+ header = pack_mgetl(f->parent);
+
+ if ((f->parent->passpos) &&
+ ((header == encrypt_id(F_PACK_MAGIC, FALSE)) ||
+ (header == encrypt_id(F_NOPACK_MAGIC, FALSE)))) {
+
+ /* backward compatibility mode */
+ pack_fclose(f->parent);
+
+ if (!clone_password(f)) {
+ free(dat);
+ free(f);
+ return NULL;
+ }
+
+ if ((f->parent = pack_fopen(filename, F_READ)) == NULL) {
+ free(dat);
+ free(f);
+ return NULL;
+ }
+
+ f->parent->flags |= PACKFILE_FLAG_OLD_CRYPT;
+ f->flags |= PACKFILE_FLAG_OLD_CRYPT;
+
+ pack_mgetl(f->parent);
+
+ if (header == encrypt_id(F_PACK_MAGIC, FALSE))
+ header = encrypt_id(F_PACK_MAGIC, TRUE);
+ else
+ header = encrypt_id(F_NOPACK_MAGIC, TRUE);
+ }
+
+ if (header == encrypt_id(F_PACK_MAGIC, TRUE)) {
+ for (c=0; c < N - F; c++)
+ dat->text_buf[c] = 0;
+ dat->state = 0;
+ f->todo = LONG_MAX;
+ f->pack_data = (char *)dat;
+ }
+ else if (header == encrypt_id(F_NOPACK_MAGIC, TRUE)) {
+ f2 = f->parent;
+ free(dat);
+ free(f);
+ return f2;
+ }
+ else {
+ pack_fclose(f->parent);
+ free(dat);
+ free(f);
+ if (errno == 0)
+ errno = EDOM;
+ return NULL;
+ }
+ }
+ else {
+ /* read a 'real' file */
+ f->parent = NULL;
+ f->pack_data = NULL;
+
+ f->todo = _al_file_size(filename);
+
+ if (errno) {
+ free(f);
+ return NULL;
+ }
+
+ if (!clone_password(f)) {
+ free(f);
+ return NULL;
+ }
+
+#ifndef ALLEGRO_MPW
+ f->hndl = open(filename, O_RDONLY | O_BINARY, S_IRUSR | S_IWUSR);
+#else
+ f->hndl = _al_open(uconvert_toascii(filename, NULL), O_RDONLY | O_BINARY);
+#endif
+
+ if (f->hndl < 0) {
+ if (f->passdata)
+ free(f->passdata);
+ free(f);
+ return NULL;
+ }
+ }
+ }
+
+ return f;
+}
+
+
+
+/* pack_fclose:
+ * Closes a file after it has been read or written.
+ * Returns zero on success. On error it returns an error code which is
+ * also stored in errno. This function can fail only when writing to
+ * files: if the file was opened in read mode it will always succeed.
+ */
+int pack_fclose(PACKFILE *f)
+{
+ if (f) {
+ if (f->flags & PACKFILE_FLAG_WRITE) {
+ if (f->flags & PACKFILE_FLAG_CHUNK)
+ return pack_fclose(pack_fclose_chunk(f));
+
+ flush_buffer(f, TRUE);
+ }
+
+ if (f->passdata)
+ free(f->passdata);
+
+ if (f->pack_data)
+ free(f->pack_data);
+
+ if (f->parent)
+ pack_fclose(f->parent);
+ else
+ close(f->hndl);
+
+ free(f);
+ return errno;
+ }
+
+ return 0;
+}
+
+
+
+/* pack_fopen_chunk:
+ * Opens a sub-chunk of the specified file, for reading or writing depending
+ * on the type of the file. The returned file pointer describes the sub
+ * chunk, and replaces the original file, which will no longer be valid.
+ * When writing to a chunk file, data is sent to the original file, but
+ * is prefixed with two length counts (32 bit, big-endian). For uncompressed
+ * chunks these will both be set to the length of the data in the chunk.
+ * For compressed chunks, created by setting the pack flag, the first will
+ * contain the raw size of the chunk, and the second will be the negative
+ * size of the uncompressed data. When reading chunks, the pack flag is
+ * ignored, and the compression type is detected from the sign of the
+ * second size value. The file structure used to read chunks checks the
+ * chunk size, and will return EOF if you try to read past the end of
+ * the chunk. If you don't read all of the chunk data, when you call
+ * pack_fclose_chunk(), the parent file will advance past the unused data.
+ * When you have finished reading or writing a chunk, you should call
+ * pack_fclose_chunk() to return to your original file.
+ */
+PACKFILE *pack_fopen_chunk(PACKFILE *f, int pack)
+{
+ PACKFILE *chunk;
+ char *name;
+ int c;
+
+ if (f->flags & PACKFILE_FLAG_WRITE) {
+
+ /* write a sub-chunk */
+ name = tmpnam(NULL);
+ chunk = pack_fopen(name, (pack ? F_WRITE_PACKED : F_WRITE_NOPACK));
+
+ if (chunk) {
+ chunk->filename = strdup(name);
+
+ if (pack)
+ chunk->parent->parent = f;
+ else
+ chunk->parent = f;
+
+ chunk->flags |= PACKFILE_FLAG_CHUNK;
+ }
+ }
+ else {
+ /* read a sub-chunk */
+ _packfile_filesize = pack_mgetl(f);
+ _packfile_datasize = pack_mgetl(f);
+
+ if ((chunk = malloc(sizeof(PACKFILE))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ chunk->buf_pos = chunk->buf;
+ chunk->flags = PACKFILE_FLAG_CHUNK;
+ chunk->buf_size = 0;
+ chunk->filename = NULL;
+ chunk->passdata = NULL;
+ chunk->passpos = NULL;
+ chunk->parent = f;
+
+ if (f->flags & PACKFILE_FLAG_OLD_CRYPT) {
+ /* backward compatibility mode */
+ if (f->passdata) {
+ if ((chunk->passdata = malloc(strlen(f->passdata)+1)) == NULL) {
+ errno = ENOMEM;
+ free(chunk);
+ return NULL;
+ }
+ strcpy(chunk->passdata, f->passdata);
+ chunk->passpos = chunk->passdata + (long)f->passpos - (long)f->passdata;
+ f->passpos = f->passdata;
+ }
+ chunk->flags |= PACKFILE_FLAG_OLD_CRYPT;
+ }
+
+ if (_packfile_datasize < 0) {
+ /* read a packed chunk */
+ UNPACK_DATA *dat = malloc(sizeof(UNPACK_DATA));
+
+ if (!dat) {
+ errno = ENOMEM;
+ if (chunk->passdata) free(chunk->passdata);
+ free(chunk);
+ return NULL;
+ }
+
+ for (c=0; c < N - F; c++)
+ dat->text_buf[c] = 0;
+
+ dat->state = 0;
+ _packfile_datasize = -_packfile_datasize;
+ chunk->todo = _packfile_datasize;
+ chunk->pack_data = (char *)dat;
+ chunk->flags |= PACKFILE_FLAG_PACK;
+ }
+ else {
+ /* read an uncompressed chunk */
+ chunk->todo = _packfile_datasize;
+ chunk->pack_data = NULL;
+ }
+ }
+
+ return chunk;
+}
+
+
+
+/* pack_fclose_chunk:
+ * Call after reading or writing a sub-chunk. This closes the chunk file,
+ * and returns a pointer to the original file structure (the one you
+ * passed to pack_fopen_chunk()), to allow you to read or write data
+ * after the chunk.
+ */
+PACKFILE *pack_fclose_chunk(PACKFILE *f)
+{
+ PACKFILE *parent = f->parent;
+ PACKFILE *tmp;
+ char *name = f->filename;
+ int header;
+
+ if (f->flags & PACKFILE_FLAG_WRITE) {
+ /* finish writing a chunk */
+ _packfile_datasize = f->todo + f->buf_size - 4;
+
+ if (f->flags & PACKFILE_FLAG_PACK) {
+ parent = parent->parent;
+ f->parent->parent = NULL;
+ }
+ else
+ f->parent = NULL;
+
+ f->flags &= ~PACKFILE_FLAG_CHUNK;
+ pack_fclose(f);
+
+ tmp = pack_fopen(name, F_READ);
+ _packfile_filesize = tmp->todo - 4;
+
+ header = pack_mgetl(tmp);
+
+ pack_mputl(_packfile_filesize, parent);
+
+ if (header == encrypt_id(F_PACK_MAGIC, TRUE))
+ pack_mputl(-_packfile_datasize, parent);
+ else
+ pack_mputl(_packfile_datasize, parent);
+
+ while (!pack_feof(tmp))
+ pack_putc(pack_getc(tmp), parent);
+
+ pack_fclose(tmp);
+
+ delete_file(name);
+ free(name);
+ }
+ else {
+ /* finish reading a chunk */
+ while (f->todo > 0)
+ pack_getc(f);
+
+ if ((f->passpos) && (f->flags & PACKFILE_FLAG_OLD_CRYPT))
+ parent->passpos = parent->passdata + (long)f->passpos - (long)f->passdata;
+
+ if (f->passdata)
+ free(f->passdata);
+
+ if (f->pack_data)
+ free(f->pack_data);
+
+ free(f);
+ }
+
+ return parent;
+}
+
+
+
+/* pack_fseek:
+ * Like the stdio fseek() function, but only supports forward seeks
+ * relative to the current file position.
+ */
+int pack_fseek(PACKFILE *f, int offset)
+{
+ int i;
+
+ if (f->flags & PACKFILE_FLAG_WRITE)
+ return -1;
+
+ errno = 0;
+
+ /* skip forward through the buffer */
+ if (f->buf_size > 0) {
+ i = MIN(offset, f->buf_size);
+ f->buf_size -= i;
+ f->buf_pos += i;
+ offset -= i;
+ if ((f->buf_size <= 0) && (f->todo <= 0))
+ f->flags |= PACKFILE_FLAG_EOF;
+ }
+
+ /* need to seek some more? */
+ if (offset > 0) {
+ i = MIN(offset, f->todo);
+
+ if ((f->flags & PACKFILE_FLAG_PACK) || (f->passpos)) {
+ /* for compressed files, we just have to read through the data */
+ while (i > 0) {
+ pack_getc(f);
+ i--;
+ }
+ }
+ else {
+ if (f->parent) {
+ /* pass the seek request on to the parent file */
+ pack_fseek(f->parent, i);
+ }
+ else {
+ /* do a real seek */
+ lseek(f->hndl, i, SEEK_CUR);
+ }
+ f->todo -= i;
+ if (f->todo <= 0)
+ f->flags |= PACKFILE_FLAG_EOF;
+ }
+ }
+
+ return errno;
+}
+
+
+
+/* pack_igetw:
+ * Reads a 16 bit word from a file, using intel byte ordering.
+ */
+int pack_igetw(PACKFILE *f)
+{
+ int b1, b2;
+
+ if ((b1 = pack_getc(f)) != EOF)
+ if ((b2 = pack_getc(f)) != EOF)
+ return ((b2 << 8) | b1);
+
+ return EOF;
+}
+
+
+
+/* pack_igetl:
+ * Reads a 32 bit long from a file, using intel byte ordering.
+ */
+long pack_igetl(PACKFILE *f)
+{
+ int b1, b2, b3, b4;
+
+ if ((b1 = pack_getc(f)) != EOF)
+ if ((b2 = pack_getc(f)) != EOF)
+ if ((b3 = pack_getc(f)) != EOF)
+ if ((b4 = pack_getc(f)) != EOF)
+ return (((long)b4 << 24) | ((long)b3 << 16) |
+ ((long)b2 << 8) | (long)b1);
+
+ return EOF;
+}
+
+
+
+/* pack_iputw:
+ * Writes a 16 bit int to a file, using intel byte ordering.
+ */
+int pack_iputw(int w, PACKFILE *f)
+{
+ int b1, b2;
+
+ b1 = (w & 0xFF00) >> 8;
+ b2 = w & 0x00FF;
+
+ if (pack_putc(b2,f)==b2)
+ if (pack_putc(b1,f)==b1)
+ return w;
+
+ return EOF;
+}
+
+
+
+/* pack_iputw:
+ * Writes a 32 bit long to a file, using intel byte ordering.
+ */
+long pack_iputl(long l, PACKFILE *f)
+{
+ int b1, b2, b3, b4;
+
+ b1 = (int)((l & 0xFF000000L) >> 24);
+ b2 = (int)((l & 0x00FF0000L) >> 16);
+ b3 = (int)((l & 0x0000FF00L) >> 8);
+ b4 = (int)l & 0x00FF;
+
+ if (pack_putc(b4,f)==b4)
+ if (pack_putc(b3,f)==b3)
+ if (pack_putc(b2,f)==b2)
+ if (pack_putc(b1,f)==b1)
+ return l;
+
+ return EOF;
+}
+
+
+
+/* pack_mgetw:
+ * Reads a 16 bit int from a file, using motorola byte-ordering.
+ */
+int pack_mgetw(PACKFILE *f)
+{
+ int b1, b2;
+
+ if ((b1 = pack_getc(f)) != EOF)
+ if ((b2 = pack_getc(f)) != EOF)
+ return ((b1 << 8) | b2);
+
+ return EOF;
+}
+
+
+
+/* pack_mgetl:
+ * Reads a 32 bit long from a file, using motorola byte-ordering.
+ */
+long pack_mgetl(PACKFILE *f)
+{
+ int b1, b2, b3, b4;
+
+ if ((b1 = pack_getc(f)) != EOF)
+ if ((b2 = pack_getc(f)) != EOF)
+ if ((b3 = pack_getc(f)) != EOF)
+ if ((b4 = pack_getc(f)) != EOF)
+ return (((long)b1 << 24) | ((long)b2 << 16) |
+ ((long)b3 << 8) | (long)b4);
+
+ return EOF;
+}
+
+
+
+/* pack_mputw:
+ * Writes a 16 bit int to a file, using motorola byte-ordering.
+ */
+int pack_mputw(int w, PACKFILE *f)
+{
+ int b1, b2;
+
+ b1 = (w & 0xFF00) >> 8;
+ b2 = w & 0x00FF;
+
+ if (pack_putc(b1,f)==b1)
+ if (pack_putc(b2,f)==b2)
+ return w;
+
+ return EOF;
+}
+
+
+
+/* pack_mputl:
+ * Writes a 32 bit long to a file, using motorola byte-ordering.
+ */
+long pack_mputl(long l, PACKFILE *f)
+{
+ int b1, b2, b3, b4;
+
+ b1 = (int)((l & 0xFF000000L) >> 24);
+ b2 = (int)((l & 0x00FF0000L) >> 16);
+ b3 = (int)((l & 0x0000FF00L) >> 8);
+ b4 = (int)l & 0x00FF;
+
+ if (pack_putc(b1,f)==b1)
+ if (pack_putc(b2,f)==b2)
+ if (pack_putc(b3,f)==b3)
+ if (pack_putc(b4,f)==b4)
+ return l;
+
+ return EOF;
+}
+
+
+
+/* pack_fread:
+ * Reads n bytes from f and stores them at memory location p. Returns the
+ * number of items read, which will be less than n if EOF is reached or an
+ * error occurs. Error codes are stored in errno.
+ */
+long pack_fread(void *p, long n, PACKFILE *f)
+{
+ unsigned char *cp = (unsigned char *)p;
+ long c;
+ int i;
+
+ for (c=0; c<n; c++) {
+ if (--(f->buf_size) > 0)
+ *(cp++) = *(f->buf_pos++);
+ else {
+ i = _sort_out_getc(f);
+ if (i == EOF)
+ return c;
+ else
+ *(cp++) = i;
+ }
+ }
+
+ return n;
+}
+
+
+
+/* pack_fwrite:
+ * Writes n bytes to the file f from memory location p. Returns the number
+ * of items written, which will be less than n if an error occurs. Error
+ * codes are stored in errno.
+ */
+long pack_fwrite(void *p, long n, PACKFILE *f)
+{
+ unsigned char *cp = (unsigned char *)p;
+ long c;
+
+ for (c=0; c<n; c++) {
+ if (++(f->buf_size) >= F_BUF_SIZE) {
+ if (_sort_out_putc(*cp,f) != *cp)
+ return c;
+ cp++;
+ }
+ else
+ *(f->buf_pos++)=*(cp++);
+ }
+
+ return n;
+}
+
+
+
+/* pack_ungetc:
+ * Puts a character back in the file's input buffer. Added by gfoot for
+ * use in the fgets function; maybe it should be in the API. It only works
+ * for characters just fetched by pack_getc.
+ */
+static void pack_ungetc (int ch, PACKFILE *f)
+{
+ *(--f->buf_pos) = (unsigned char) ch;
+ f->buf_size++;
+ f->flags &= ~PACKFILE_FLAG_EOF;
+}
+
+
+
+/* pack_fgets:
+ * Reads a line from a text file, storing it at location p. Stops when a
+ * linefeed is encountered, or max characters have been read. Returns a
+ * pointer to where it stored the text, or NULL on error. The end of line
+ * is handled by detecting optional '\r' characters optionally followed
+ * by '\n' characters. This supports CR-LF (DOS/Windows), LF (Unix), and
+ * CR (Mac) formats.
+ */
+char *pack_fgets(char *p, int max, PACKFILE *f)
+{
+ char *pmax;
+ int c;
+
+ errno = 0;
+
+ pmax = p+max - 1;
+
+ if (pack_feof(f)) {
+ if (1 < max) *p = 0;
+ return NULL;
+ }
+
+ while ((c = pack_getc (f)) != EOF) {
+
+ if (c == '\r' || c == '\n') {
+ /* Technically we should check there's space in the buffer, and if so,
+ * add a \n. But pack_fgets has never done this. */
+ if (c == '\r') {
+ /* eat the following \n, if any */
+ if ((c = pack_getc (f)) != '\n') pack_ungetc (c, f);
+ }
+ break;
+ }
+
+ /* is there room in the buffer? */
+ if (1 > pmax - p) {
+ pack_ungetc (c, f);
+ c = '\0';
+ break;
+ }
+
+ /* write the character */
+ *p = c;
+ p++;
+ }
+
+ /* terminate the string */
+ *p = 0;
+
+ if (c == '\0' || errno)
+ return NULL;
+
+ return p;
+}
+
+
+
+/* pack_fputs:
+ * Writes a string to a text file, returning zero on success, -1 on error.
+ */
+int pack_fputs(char *p, PACKFILE *f)
+{
+ char *s;
+
+ errno = 0;
+
+ s = p;
+
+ while (*s) {
+ if (*s == '\n')
+ pack_putc('\r', f);
+
+ pack_putc(*s, f);
+ s++;
+ }
+
+ if (errno)
+ return -1;
+ else
+ return 0;
+}
+
+
+
+/* _sort_out_getc:
+ * Helper function for the pack_getc() macro.
+ */
+int _sort_out_getc(PACKFILE *f)
+{
+ if (f->buf_size == 0) {
+ if (f->todo <= 0)
+ f->flags |= PACKFILE_FLAG_EOF;
+ return *(f->buf_pos++);
+ }
+ return refill_buffer(f);
+}
+
+
+
+/* refill_buffer:
+ * Refills the read buffer. The file must have been opened in read mode,
+ * and the buffer must be empty.
+ */
+static int refill_buffer(PACKFILE *f)
+{
+ int i, sz, done, offset;
+
+ if ((f->flags & PACKFILE_FLAG_EOF) || (f->todo <= 0)) {
+ f->flags |= PACKFILE_FLAG_EOF;
+ return EOF;
+ }
+
+ if (f->parent) {
+ if (f->flags & PACKFILE_FLAG_PACK) {
+ f->buf_size = pack_read(f->parent, (UNPACK_DATA *)f->pack_data, MIN(F_BUF_SIZE, f->todo), f->buf);
+ }
+ else {
+ f->buf_size = pack_fread(f->buf, MIN(F_BUF_SIZE, f->todo), f->parent);
+ }
+ if (f->parent->flags & PACKFILE_FLAG_EOF)
+ f->todo = 0;
+ if (f->parent->flags & PACKFILE_FLAG_ERROR)
+ goto err;
+ }
+ else {
+ f->buf_size = MIN(F_BUF_SIZE, f->todo);
+
+ offset = lseek(f->hndl, 0, SEEK_CUR);
+ done = 0;
+
+ errno = 0;
+ sz = read(f->hndl, f->buf, f->buf_size);
+
+ while (sz+done < f->buf_size) {
+ if ((sz < 0) && ((errno != EINTR) && (errno != EAGAIN)))
+ goto err;
+
+ if (sz > 0)
+ done += sz;
+
+ lseek(f->hndl, offset+done, SEEK_SET);
+ errno = 0;
+ sz = read(f->hndl, f->buf+done, f->buf_size-done);
+ }
+ errno = 0;
+
+ if (errno == EINTR)
+ errno = 0;
+
+ if ((f->passpos) && (!(f->flags & PACKFILE_FLAG_OLD_CRYPT))) {
+ for (i=0; i<f->buf_size; i++) {
+ f->buf[i] ^= *(f->passpos++);
+ if (!*f->passpos)
+ f->passpos = f->passdata;
+ }
+ }
+ }
+
+ f->todo -= f->buf_size;
+ f->buf_pos = f->buf;
+ f->buf_size--;
+ if (f->buf_size <= 0)
+ if (f->todo <= 0)
+ f->flags |= PACKFILE_FLAG_EOF;
+
+ return *(f->buf_pos++);
+
+ err:
+ errno = EFAULT;
+ f->flags |= PACKFILE_FLAG_ERROR;
+ return EOF;
+}
+
+
+
+/* _sort_out_putc:
+ * Helper function for the pack_putc() macro.
+ */
+int _sort_out_putc(int c, PACKFILE *f)
+{
+ f->buf_size--;
+
+ if (flush_buffer(f, FALSE))
+ return EOF;
+
+ f->buf_size++;
+ return (*(f->buf_pos++)=c);
+}
+
+
+
+/* flush_buffer:
+ * flushes a file buffer to the disk. The file must be open in write mode.
+ */
+static int flush_buffer(PACKFILE *f, int last)
+{
+ int i, sz, done, offset;
+
+ if (f->buf_size > 0) {
+ if (f->flags & PACKFILE_FLAG_PACK) {
+ if (pack_write(f->parent, (PACK_DATA *)f->pack_data, f->buf_size, f->buf, last))
+ goto err;
+ }
+ else {
+ if ((f->passpos) && (!(f->flags & PACKFILE_FLAG_OLD_CRYPT))) {
+ for (i=0; i<f->buf_size; i++) {
+ f->buf[i] ^= *(f->passpos++);
+ if (!*f->passpos)
+ f->passpos = f->passdata;
+ }
+ }
+
+ offset = lseek(f->hndl, 0, SEEK_CUR);
+ done = 0;
+
+ errno = 0;
+ sz = write(f->hndl, f->buf, f->buf_size);
+
+ while (sz+done < f->buf_size) {
+ if ((sz < 0) && ((errno != EINTR) && (errno != EAGAIN)))
+ goto err;
+
+ if (sz > 0)
+ done += sz;
+
+ lseek(f->hndl, offset+done, SEEK_SET);
+ errno = 0;
+ sz = write(f->hndl, f->buf+done, f->buf_size-done);
+ }
+ errno = 0;
+ }
+ f->todo += f->buf_size;
+ }
+ f->buf_pos = f->buf;
+ f->buf_size = 0;
+ return 0;
+
+ err:
+ errno = EFAULT;
+ f->flags |= PACKFILE_FLAG_ERROR;
+ return EOF;
+}
+
+
+
+/***************************************************
+ ************ LZSS compression routines ************
+ ***************************************************
+
+ This compression algorithm is based on the ideas of Lempel and Ziv,
+ with the modifications suggested by Storer and Szymanski. The algorithm
+ is based on the use of a ring buffer, which initially contains zeros.
+ We read several characters from the file into the buffer, and then
+ search the buffer for the longest string that matches the characters
+ just read, and output the length and position of the match in the buffer.
+
+ With a buffer size of 4096 bytes, the position can be encoded in 12
+ bits. If we represent the match length in four bits, the <position,
+ length> pair is two bytes long. If the longest match is no more than
+ two characters, then we send just one character without encoding, and
+ restart the process with the next letter. We must send one extra bit
+ each time to tell the decoder whether we are sending a <position,
+ length> pair or an unencoded character, and these flags are stored as
+ an eight bit mask every eight items.
+
+ This implementation uses binary trees to speed up the search for the
+ longest match.
+
+ Original code by Haruhiko Okumura, 4/6/1989.
+ 12-2-404 Green Heights, 580 Nagasawa, Yokosuka 239, Japan.
+
+ Modified for use in the Allegro filesystem by Shawn Hargreaves.
+
+ Use, distribute, and modify this code freely.
+*/
+
+
+
+/* pack_inittree:
+ * For i = 0 to N-1, rson[i] and lson[i] will be the right and left
+ * children of node i. These nodes need not be initialized. Also, dad[i]
+ * is the parent of node i. These are initialized to N, which stands for
+ * 'not used.' For i = 0 to 255, rson[N+i+1] is the root of the tree for
+ * strings that begin with character i. These are initialized to N. Note
+ * there are 256 trees.
+ */
+static void pack_inittree(PACK_DATA *dat)
+{
+ int i;
+
+ for (i=N+1; i<=N+256; i++)
+ dat->rson[i] = N;
+
+ for (i=0; i<N; i++)
+ dat->dad[i] = N;
+}
+
+
+
+/* pack_insertnode:
+ * Inserts a string of length F, text_buf[r..r+F-1], into one of the trees
+ * (text_buf[r]'th tree) and returns the longest-match position and length
+ * via match_position and match_length. If match_length = F, then removes
+ * the old node in favor of the new one, because the old one will be
+ * deleted sooner. Note r plays double role, as tree node and position in
+ * the buffer.
+ */
+static void pack_insertnode(int r, PACK_DATA *dat)
+{
+ int i, p, cmp;
+ unsigned char *key;
+ unsigned char *text_buf = dat->text_buf;
+
+ cmp = 1;
+ key = &text_buf[r];
+ p = N + 1 + key[0];
+ dat->rson[r] = dat->lson[r] = N;
+ dat->match_length = 0;
+
+ for (;;) {
+
+ if (cmp >= 0) {
+ if (dat->rson[p] != N)
+ p = dat->rson[p];
+ else {
+ dat->rson[p] = r;
+ dat->dad[r] = p;
+ return;
+ }
+ }
+ else {
+ if (dat->lson[p] != N)
+ p = dat->lson[p];
+ else {
+ dat->lson[p] = r;
+ dat->dad[r] = p;
+ return;
+ }
+ }
+
+ for (i = 1; i < F; i++)
+ if ((cmp = key[i] - text_buf[p + i]) != 0)
+ break;
+
+ if (i > dat->match_length) {
+ dat->match_position = p;
+ if ((dat->match_length = i) >= F)
+ break;
+ }
+ }
+
+ dat->dad[r] = dat->dad[p];
+ dat->lson[r] = dat->lson[p];
+ dat->rson[r] = dat->rson[p];
+ dat->dad[dat->lson[p]] = r;
+ dat->dad[dat->rson[p]] = r;
+ if (dat->rson[dat->dad[p]] == p)
+ dat->rson[dat->dad[p]] = r;
+ else
+ dat->lson[dat->dad[p]] = r;
+ dat->dad[p] = N; /* remove p */
+}
+
+
+
+/* pack_deletenode:
+ * Removes a node from a tree.
+ */
+static void pack_deletenode(int p, PACK_DATA *dat)
+{
+ int q;
+
+ if (dat->dad[p] == N)
+ return; /* not in tree */
+
+ if (dat->rson[p] == N)
+ q = dat->lson[p];
+ else
+ if (dat->lson[p] == N)
+ q = dat->rson[p];
+ else {
+ q = dat->lson[p];
+ if (dat->rson[q] != N) {
+ do {
+ q = dat->rson[q];
+ } while (dat->rson[q] != N);
+ dat->rson[dat->dad[q]] = dat->lson[q];
+ dat->dad[dat->lson[q]] = dat->dad[q];
+ dat->lson[q] = dat->lson[p];
+ dat->dad[dat->lson[p]] = q;
+ }
+ dat->rson[q] = dat->rson[p];
+ dat->dad[dat->rson[p]] = q;
+ }
+
+ dat->dad[q] = dat->dad[p];
+ if (dat->rson[dat->dad[p]] == p)
+ dat->rson[dat->dad[p]] = q;
+ else
+ dat->lson[dat->dad[p]] = q;
+
+ dat->dad[p] = N;
+}
+
+
+
+/* pack_write:
+ * Called by flush_buffer(). Packs size bytes from buf, using the pack
+ * information contained in dat. Returns 0 on success.
+ */
+static int pack_write(PACKFILE *file, PACK_DATA *dat, int size, unsigned char *buf, int last)
+{
+ int i = dat->i;
+ int c = dat->c;
+ int len = dat->len;
+ int r = dat->r;
+ int s = dat->s;
+ int last_match_length = dat->last_match_length;
+ int code_buf_ptr = dat->code_buf_ptr;
+ unsigned char mask = dat->mask;
+ int ret = 0;
+
+ if (dat->state==2)
+ goto pos2;
+ else
+ if (dat->state==1)
+ goto pos1;
+
+ dat->code_buf[0] = 0;
+ /* code_buf[1..16] saves eight units of code, and code_buf[0] works
+ as eight flags, "1" representing that the unit is an unencoded
+ letter (1 byte), "0" a position-and-length pair (2 bytes).
+ Thus, eight units require at most 16 bytes of code. */
+
+ code_buf_ptr = mask = 1;
+
+ s = 0;
+ r = N - F;
+ pack_inittree(dat);
+
+ for (len=0; (len < F) && (size > 0); len++) {
+ dat->text_buf[r+len] = *(buf++);
+ if (--size == 0) {
+ if (!last) {
+ dat->state = 1;
+ goto getout;
+ }
+ }
+ pos1:
+ ;
+ }
+
+ if (len == 0)
+ goto getout;
+
+ for (i=1; i <= F; i++)
+ pack_insertnode(r-i,dat);
+ /* Insert the F strings, each of which begins with one or
+ more 'space' characters. Note the order in which these
+ strings are inserted. This way, degenerate trees will be
+ less likely to occur. */
+
+ pack_insertnode(r,dat);
+ /* Finally, insert the whole string just read. match_length
+ and match_position are set. */
+
+ do {
+ if (dat->match_length > len)
+ dat->match_length = len; /* match_length may be long near the end */
+
+ if (dat->match_length <= THRESHOLD) {
+ dat->match_length = 1; /* not long enough match: send one byte */
+ dat->code_buf[0] |= mask; /* 'send one byte' flag */
+ dat->code_buf[code_buf_ptr++] = dat->text_buf[r]; /* send uncoded */
+ }
+ else {
+ /* send position and length pair. Note match_length > THRESHOLD */
+ dat->code_buf[code_buf_ptr++] = (unsigned char) dat->match_position;
+ dat->code_buf[code_buf_ptr++] = (unsigned char)
+ (((dat->match_position >> 4) & 0xF0) |
+ (dat->match_length - (THRESHOLD + 1)));
+ }
+
+ if ((mask <<= 1) == 0) { /* shift mask left one bit */
+ if ((file->passpos) && (file->flags & PACKFILE_FLAG_OLD_CRYPT)) {
+ dat->code_buf[0] ^= *file->passpos;
+ file->passpos++;
+ if (!*file->passpos)
+ file->passpos = file->passdata;
+ };
+
+ for (i=0; i<code_buf_ptr; i++) /* send at most 8 units of */
+ pack_putc(dat->code_buf[i], file); /* code together */
+
+ if (pack_ferror(file)) {
+ ret = EOF;
+ goto getout;
+ }
+ dat->code_buf[0] = 0;
+ code_buf_ptr = mask = 1;
+ }
+
+ last_match_length = dat->match_length;
+
+ for (i=0; (i < last_match_length) && (size > 0); i++) {
+ c = *(buf++);
+ if (--size == 0) {
+ if (!last) {
+ dat->state = 2;
+ goto getout;
+ }
+ }
+ pos2:
+ pack_deletenode(s,dat); /* delete old strings and */
+ dat->text_buf[s] = c; /* read new bytes */
+ if (s < F-1)
+ dat->text_buf[s+N] = c; /* if the position is near the end of
+ buffer, extend the buffer to make
+ string comparison easier */
+ s = (s+1) & (N-1);
+ r = (r+1) & (N-1); /* since this is a ring buffer,
+ increment the position modulo N */
+
+ pack_insertnode(r,dat); /* register the string in
+ text_buf[r..r+F-1] */
+ }
+
+ while (i++ < last_match_length) { /* after the end of text, */
+ pack_deletenode(s,dat); /* no need to read, but */
+ s = (s+1) & (N-1); /* buffer may not be empty */
+ r = (r+1) & (N-1);
+ if (--len)
+ pack_insertnode(r,dat);
+ }
+
+ } while (len > 0); /* until length of string to be processed is zero */
+
+ if (code_buf_ptr > 1) { /* send remaining code */
+ if ((file->passpos) && (file->flags & PACKFILE_FLAG_OLD_CRYPT)) {
+ dat->code_buf[0] ^= *file->passpos;
+ file->passpos++;
+ if (!*file->passpos)
+ file->passpos = file->passdata;
+ };
+
+ for (i=0; i<code_buf_ptr; i++) {
+ pack_putc(dat->code_buf[i], file);
+ if (pack_ferror(file)) {
+ ret = EOF;
+ goto getout;
+ }
+ }
+ }
+
+ dat->state = 0;
+
+ getout:
+
+ dat->i = i;
+ dat->c = c;
+ dat->len = len;
+ dat->r = r;
+ dat->s = s;
+ dat->last_match_length = last_match_length;
+ dat->code_buf_ptr = code_buf_ptr;
+ dat->mask = mask;
+
+ return ret;
+}
+
+
+
+/* pack_read:
+ * Called by refill_buffer(). Unpacks from dat into buf, until either
+ * EOF is reached or s bytes have been extracted. Returns the number of
+ * bytes added to the buffer
+ */
+static int pack_read(PACKFILE *file, UNPACK_DATA *dat, int s, unsigned char *buf)
+{
+ int i = dat->i;
+ int j = dat->j;
+ int k = dat->k;
+ int r = dat->r;
+ int c = dat->c;
+ unsigned int flags = dat->flags;
+ int size = 0;
+
+ if (dat->state==2)
+ goto pos2;
+ else
+ if (dat->state==1)
+ goto pos1;
+
+ r = N-F;
+ flags = 0;
+
+ for (;;) {
+ if (((flags >>= 1) & 256) == 0) {
+ if ((c = pack_getc(file)) == EOF)
+ break;
+
+ if ((file->passpos) && (file->flags & PACKFILE_FLAG_OLD_CRYPT)) {
+ c ^= *file->passpos;
+ file->passpos++;
+ if (!*file->passpos)
+ file->passpos = file->passdata;
+ };
+
+ flags = c | 0xFF00; /* uses higher byte to count eight */
+ }
+
+ if (flags & 1) {
+ if ((c = pack_getc(file)) == EOF)
+ break;
+ dat->text_buf[r++] = c;
+ r &= (N - 1);
+ *(buf++) = c;
+ if (++size >= s) {
+ dat->state = 1;
+ goto getout;
+ }
+ pos1:
+ ;
+ }
+ else {
+ if ((i = pack_getc(file)) == EOF)
+ break;
+ if ((j = pack_getc(file)) == EOF)
+ break;
+ i |= ((j & 0xF0) << 4);
+ j = (j & 0x0F) + THRESHOLD;
+ for (k=0; k <= j; k++) {
+ c = dat->text_buf[(i + k) & (N - 1)];
+ dat->text_buf[r++] = c;
+ r &= (N - 1);
+ *(buf++) = c;
+ if (++size >= s) {
+ dat->state = 2;
+ goto getout;
+ }
+ pos2:
+ ;
+ }
+ }
+ }
+
+ dat->state = 0;
+
+ getout:
+
+ dat->i = i;
+ dat->j = j;
+ dat->k = k;
+ dat->r = r;
+ dat->c = c;
+ dat->flags = flags;
+
+ return size;
+}
+
+
+
+
+/* _al_file_isok:
+ * Helper function to check if it is safe to access a file on a floppy
+ * drive. This really only applies to the DOS library, so we don't bother
+ * with it.
+ */
+int _al_file_isok(const char *filename)
+{
+ return TRUE;
+}
+
+
+
+/* _al_file_exists:
+ * Checks whether the specified file exists.
+ */
+int _al_file_exists(const char *filename, int attrib, int *aret)
+{
+ struct _finddata_t info;
+ long handle;
+
+ errno = 0;
+
+ if ((handle = _findfirst(filename, &info)) < 0) {
+ return FALSE;
+ }
+
+ _findclose(handle);
+
+ if (aret)
+ *aret = info.attrib;
+
+ info.attrib &= (FA_HIDDEN | FA_SYSTEM | FA_LABEL | FA_DIREC);
+
+ if ((info.attrib & attrib) != info.attrib)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+
+/* _al_file_size:
+ * Measures the size of the specified file.
+ */
+long _al_file_size(const char *filename)
+{
+ struct _finddata_t info;
+ long handle;
+
+ errno = 0;
+
+ if ((handle = _findfirst(filename, &info)) < 0) {
+ return 0;
+ }
+
+ _findclose(handle);
+
+ if (info.attrib & (FA_SYSTEM | FA_LABEL | FA_DIREC))
+ return 0;
+
+ return info.size;
+}
+
+
+
+/* _al_file_time:
+ * Returns the timestamp of the specified file.
+ */
+time_t _al_file_time(const char *filename)
+{
+ struct _finddata_t info;
+ long handle;
+
+ errno = 0;
+
+ if ((handle = _findfirst(filename, &info)) < 0) {
+ return 0;
+ }
+
+ _findclose(handle);
+
+ if (info.attrib & (FA_SYSTEM | FA_LABEL | FA_DIREC))
+ return 0;
+
+ return info.time_write;
+}
+
+
+
+/* information structure for use by the directory scanning routines */
+typedef struct FFIND_INFO {
+ struct _finddata_t info;
+ long handle;
+ int attrib;
+} FFIND_INFO;
+
+
+
+/* _al_findfirst:
+ * Initiates a directory search.
+ */
+void *_al_findfirst(const char *name, int attrib, char *nameret, int *aret)
+{
+ FFIND_INFO *info;
+ int a;
+
+ info = malloc(sizeof(FFIND_INFO));
+
+ if (!info) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ info->attrib = attrib;
+
+ errno = 0;
+
+ if ((info->handle = _findfirst(name, &info->info)) < 0) {
+ free(info);
+ return NULL;
+ }
+
+ a = info->info.attrib & (FA_HIDDEN | FA_SYSTEM | FA_LABEL | FA_DIREC);
+
+ if ((a & attrib) != a) {
+ if (_al_findnext(info, nameret, aret) != 0) {
+ _findclose(info->handle);
+ free(info);
+ return NULL;
+ }
+ else
+ return info;
+ }
+
+ strcpy(nameret, info->info.name);
+
+ if (aret)
+ *aret = info->info.attrib;
+
+ return info;
+}
+
+
+
+/* _al_findnext:
+ * Retrieves the next file from a directory search.
+ */
+int _al_findnext(void *dta, char *nameret, int *aret)
+{
+ FFIND_INFO *info = (FFIND_INFO *) dta;
+ int a;
+
+ do {
+ if (_findnext(info->handle, &info->info) != 0) {
+ return -1;
+ }
+
+ a = info->info.attrib & (FA_HIDDEN | FA_SYSTEM | FA_LABEL | FA_DIREC);
+
+ } while ((a & info->attrib) != a);
+
+ strcpy(nameret, info->info.name);
+
+ if (aret)
+ *aret = info->info.attrib;
+
+ return 0;
+}
+
+
+
+/* _al_findclose:
+ * Cleans up after a directory search.
+ */
+void _al_findclose(void *dta)
+{
+ FFIND_INFO *info = (FFIND_INFO *) dta;
+
+ _findclose(info->handle);
+ free(info);
+}
+
+
+
+/* _al_getdrive:
+ * Returns the current drive number (0=A, 1=B, etc).
+ */
+int _al_getdrive()
+{
+ return _getdrive() - 1;
+}
+
+
+
+/* _al_getdcwd:
+ * Returns the current directory on the specified drive.
+ */
+void _al_getdcwd(int drive, char *buf, int size)
+{
+ char tmp[256];
+
+ if (_getdcwd(drive+1, tmp, sizeof(tmp)))
+ strcpy(buf, tmp);
+ else
+ buf[0] = 0;
+}
+
diff --git a/plugins/dumb/dumb-kode54/winamp/out.h b/plugins/dumb/dumb-kode54/winamp/out.h
index 4dd42241..b4013a1c 100644
--- a/plugins/dumb/dumb-kode54/winamp/out.h
+++ b/plugins/dumb/dumb-kode54/winamp/out.h
@@ -1,71 +1,71 @@
-/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * out.h - Winamp plug-in header file. / / \ \
- * | < / \_
- * By Bob. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#define OUT_VER 0x10
-
-typedef struct
-{
- int version; // module version (OUT_VER)
- char *description; // description of module, with version string
- int id; // module id. each input module gets its own. non-nullsoft modules should
- // be >= 65536.
-
- HWND hMainWindow; // winamp's main window (filled in by winamp)
- HINSTANCE hDllInstance; // DLL instance handle (filled in by winamp)
-
- void (*Config)(HWND hwndParent); // configuration dialog
- void (*About)(HWND hwndParent); // about dialog
-
- void (*Init)(); // called when loaded
- void (*Quit)(); // called when unloaded
-
- int (*Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms);
- // returns >=0 on success, <0 on failure
- // NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins.
- // ... so don't expect the max latency returned to be what you asked for.
- // returns max latency in ms (0 for diskwriters, etc)
- // bufferlenms and prebufferms must be in ms. 0 to use defaults.
- // prebufferms must be <= bufferlenms
-
- void (*Close)(); // close the ol' output device.
-
- int (*Write)(char *buf, int len);
- // 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data.
- // 1 returns not able to write (yet). Non-blocking, always.
-
- int (*CanWrite)(); // returns number of bytes possible to write at a given time.
- // Never will decrease unless you call Write (or Close, heh)
-
- int (*IsPlaying)(); // non0 if output is still going or if data in buffers waiting to be
- // written (i.e. closing while IsPlaying() returns 1 would truncate the song
-
- int (*Pause)(int pause); // returns previous pause state
-
- void (*SetVolume)(int volume); // volume is 0-255
- void (*SetPan)(int pan); // pan is -128 to 128
-
- void (*Flush)(int t); // flushes buffers and restarts output at time t (in ms)
- // (used for seeking)
-
- int (*GetOutputTime)(); // returns played time in MS
- int (*GetWrittenTime)(); // returns time written in MS (used for synching up vis stuff)
-
-} Out_Module;
-
-
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * out.h - Winamp plug-in header file. / / \ \
+ * | < / \_
+ * By Bob. | \/ /\ /
+ * \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#define OUT_VER 0x10
+
+typedef struct
+{
+ int version; // module version (OUT_VER)
+ char *description; // description of module, with version string
+ int id; // module id. each input module gets its own. non-nullsoft modules should
+ // be >= 65536.
+
+ HWND hMainWindow; // winamp's main window (filled in by winamp)
+ HINSTANCE hDllInstance; // DLL instance handle (filled in by winamp)
+
+ void (*Config)(HWND hwndParent); // configuration dialog
+ void (*About)(HWND hwndParent); // about dialog
+
+ void (*Init)(); // called when loaded
+ void (*Quit)(); // called when unloaded
+
+ int (*Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms);
+ // returns >=0 on success, <0 on failure
+ // NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins.
+ // ... so don't expect the max latency returned to be what you asked for.
+ // returns max latency in ms (0 for diskwriters, etc)
+ // bufferlenms and prebufferms must be in ms. 0 to use defaults.
+ // prebufferms must be <= bufferlenms
+
+ void (*Close)(); // close the ol' output device.
+
+ int (*Write)(char *buf, int len);
+ // 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data.
+ // 1 returns not able to write (yet). Non-blocking, always.
+
+ int (*CanWrite)(); // returns number of bytes possible to write at a given time.
+ // Never will decrease unless you call Write (or Close, heh)
+
+ int (*IsPlaying)(); // non0 if output is still going or if data in buffers waiting to be
+ // written (i.e. closing while IsPlaying() returns 1 would truncate the song
+
+ int (*Pause)(int pause); // returns previous pause state
+
+ void (*SetVolume)(int volume); // volume is 0-255
+ void (*SetPan)(int pan); // pan is -128 to 128
+
+ void (*Flush)(int t); // flushes buffers and restarts output at time t (in ms)
+ // (used for seeking)
+
+ int (*GetOutputTime)(); // returns played time in MS
+ int (*GetWrittenTime)(); // returns time written in MS (used for synching up vis stuff)
+
+} Out_Module;
+
+
diff --git a/plugins/dumb/dumb-kode54/winamp/resource.h b/plugins/dumb/dumb-kode54/winamp/resource.h
index eee566da..16baf927 100644
--- a/plugins/dumb/dumb-kode54/winamp/resource.h
+++ b/plugins/dumb/dumb-kode54/winamp/resource.h
@@ -1,36 +1,36 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Developer Studio generated include file.
-// Used by config.rc
-//
-#define IDD_CONFIG 102
-#define IDC_8BPS 1000
-#define IDC_16BPS 1001
-#define IDC_STEREO 1002
-#define IDC_ALIASING 1003
-#define IDC_LINEAR 1004
-#define IDC_LINEAR_LOW_PASS 1005
-#define IDC_QUADRATIC 1006
-#define IDC_CUBIC 1007
-#define IDC_THREAD_PRI 1008
-#define IDC_11KHZ 1009
-#define IDC_22KHZ 1010
-#define IDC_44KHZ 1011
-#define IDC_48KHZ 1012
-#define IDC_OK 1013
-#define IDC_CANCEL 1014
-#define IDC_BUFFERSIZE 1015
-#define IDC_BUFFERSIZE2 1016
-#define IDC_DEFAULT 1017
-#define IDC_NICEST 1018
-#define IDC_FASTEST 1019
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 102
-#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1020
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by config.rc
+//
+#define IDD_CONFIG 102
+#define IDC_8BPS 1000
+#define IDC_16BPS 1001
+#define IDC_STEREO 1002
+#define IDC_ALIASING 1003
+#define IDC_LINEAR 1004
+#define IDC_LINEAR_LOW_PASS 1005
+#define IDC_QUADRATIC 1006
+#define IDC_CUBIC 1007
+#define IDC_THREAD_PRI 1008
+#define IDC_11KHZ 1009
+#define IDC_22KHZ 1010
+#define IDC_44KHZ 1011
+#define IDC_48KHZ 1012
+#define IDC_OK 1013
+#define IDC_CANCEL 1014
+#define IDC_BUFFERSIZE 1015
+#define IDC_BUFFERSIZE2 1016
+#define IDC_DEFAULT 1017
+#define IDC_NICEST 1018
+#define IDC_FASTEST 1019
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 102
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1020
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif