diff options
Diffstat (limited to 'plugins/dumb/dumb-kode54/src/it')
49 files changed, 11369 insertions, 11326 deletions
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; +} |