/* _______ ____ __ ___ ___ * \ _ \ \ / \ / \ \ / / ' ' ' * | | \ \ | | || | \/ | . . * | | | | | | || ||\ /| | * | | | | | | || || \/ | | ' ' ' * | | | | | | || || | | . . * | |_/ / \ \__// || | | * /_______/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" 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((char *)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((char *)sample->name, 28, f); sample->name[28] = 0; dumbfile_skip(f, 4); sample->flags &= ~IT_SAMPLE_EXISTS; return dumbfile_error(f); } *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((char *)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 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. * * "for a good reason" ? What's this nonsense? -kode54 * */ length = dumbfile_igetw(f); 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((char *)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 (int)(((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((char *)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_orders > 1024 || // Whoa, nelly. 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; }Lines 1–500 of 780. Load more
/* _______ ____ __ ___ ___ * \ _ \ \ / \ / \ \ / / ' ' ' * | | \ \ | | || | \/ | . . * | | | | | | || ||\ /| | * | | | | | | || || \/ | | ' ' ' * | | | | | | || || | | . . * | |_/ / \ \__// || | | * /_______/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" 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((char *)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((char *)sample->name, 28, f); sample->name[28] = 0; dumbfile_skip(f, 4); sample->flags &= ~IT_SAMPLE_EXISTS; return dumbfile_error(f); } *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((char *)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 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. * * "for a good reason" ? What's this nonsense? -kode54 * */ length = dumbfile_igetw(f); 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((char *)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 (int)(((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((char *)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_orders > 1024 || // Whoa, nelly. 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; }