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 ], buffer[ pos + 3 ], entry, 1 ); if ( entry->mask ) ++entry; } pos += 4; } IT_SET_END_ROW( entry ); ++entry; } pattern->n_entries = (int)(entry - pattern->entry); return 0; }
static int it_okt_read_pattern(IT_PATTERN *pattern, const unsigned char *data, int length, int n_channels) { int pos; int channel; int row; int n_rows; IT_ENTRY *entry; if (length < 2) return -1; n_rows = (data[0] << 8) | data[1]; if (!n_rows) n_rows = 64; if (length < 2 + (n_rows * n_channels * 4)) return -1; pattern->n_rows = n_rows; /* compute number of entries */ pattern->n_entries = n_rows; /* Account for the row end markers */ pos = 2; for (row = 0; row < pattern->n_rows; row++) { for (channel = 0; channel < n_channels; channel++) { if (data[pos+0] | data[pos+2]) pattern->n_entries++; pos += 4; } } pattern->entry = (IT_ENTRY *) malloc(pattern->n_entries * sizeof(*pattern->entry)); if (!pattern->entry) return -1; entry = pattern->entry; pos = 2; for (row = 0; row < n_rows; row++) { for (channel = 0; channel < n_channels; channel++) { if (data[pos+0] | data[pos+2]) { entry->channel = channel; entry->mask = 0; if (data[pos+0] > 0 && data[pos+0] <= 36) { entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT; entry->note = data[pos+0] + 35; entry->instrument = data[pos+1] + 1; } entry->effect = 0; entry->effectvalue = data[pos+3]; switch (data[pos+2]) { case 2: if (data[pos+3]) entry->effect = IT_PORTAMENTO_DOWN; break; // XXX code calls this rs_portu, but it's adding to the period, which decreases the pitch case 13: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_DOWN; break; case 21: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_DOWN_ROW; break; case 1: if (data[pos+3]) entry->effect = IT_PORTAMENTO_UP; break; // XXX same deal here, increasing the pitch case 17: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_UP; break; case 30: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_UP_ROW; break; case 10: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_3; break; case 11: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_4; break; case 12: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_5; break; case 15: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_SET_FILTER, data[pos+3] & 0x0F); break; case 25: entry->effect = IT_JUMP_TO_ORDER; break; case 27: entry->note = IT_NOTE_OFF; entry->mask |= IT_ENTRY_NOTE; break; case 28: entry->effect = IT_SET_SPEED; break; case 31: if ( data[pos+3] <= 0x40 ) entry->effect = IT_SET_CHANNEL_VOLUME; else if ( data[pos+3] <= 0x50 ) { entry->effect = IT_OKT_VOLUME_SLIDE_DOWN; entry->effectvalue = data[pos+3] - 0x40; } else if ( data[pos+3] <= 0x60 ) { entry->effect = IT_OKT_VOLUME_SLIDE_UP; entry->effectvalue = data[pos+3] - 0x50; } else if ( data[pos+3] <= 0x70 ) { entry->effect = IT_OKT_VOLUME_SLIDE_DOWN; entry->effectvalue = data[pos+3] - 0x50; } else if ( data[pos+3] <= 0x80 ) { entry->effect = IT_OKT_VOLUME_SLIDE_UP; entry->effectvalue = data[pos+3] - 0x60; } break; } if ( entry->effect ) entry->mask |= IT_ENTRY_EFFECT; entry++; } pos += 4; } IT_SET_END_ROW(entry); entry++; } return 0; }
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((char *)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_riff_dsmf_process_pattern( IT_PATTERN * pattern, DUMBFILE * f, int len ) { int length, row; unsigned flags; long start, end; int p, q, r; IT_ENTRY * entry; length = dumbfile_igetw( f ); if ( length > len ) return -1; len = length - 2; pattern->n_rows = 64; pattern->n_entries = 64; row = 0; start = dumbfile_pos( f ); end = start + len; while ( (row < 64) && !dumbfile_error( f ) && (dumbfile_pos( f ) < end) ) { p = dumbfile_getc( f ); if ( ! p ) { ++ row; continue; } flags = p & 0xF0; if (flags) { ++ pattern->n_entries; if (flags & 0x80) dumbfile_skip( f, 1 ); if (flags & 0x40) dumbfile_skip( f, 1 ); if (flags & 0x20) dumbfile_skip( f, 1 ); if (flags & 0x10) dumbfile_skip( f, 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; if ( dumbfile_seek( f, start, DFS_SEEK_SET ) ) return -1; while ( ( row < 64 ) && !dumbfile_error( f ) && ( dumbfile_pos( f ) < end ) ) { p = dumbfile_getc( f ); if ( ! p ) { IT_SET_END_ROW( entry ); ++ entry; ++ row; continue; } flags = p; entry->channel = flags & 0x0F; entry->mask = 0; if ( flags & 0xF0 ) { if ( flags & 0x80 ) { q = dumbfile_getc( f ); if ( q ) { entry->mask |= IT_ENTRY_NOTE; entry->note = q - 1; } } if ( flags & 0x40 ) { q = dumbfile_getc( f ); if ( q ) { entry->mask |= IT_ENTRY_INSTRUMENT; entry->instrument = q; } } if ( flags & 0x20 ) { entry->mask |= IT_ENTRY_VOLPAN; entry->volpan = dumbfile_getc( f ); } if ( flags & 0x10 ) { q = dumbfile_getc( f ); r = dumbfile_getc( f ); _dumb_it_xm_convert_effect( q, r, entry, 0 ); } 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 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 = (int)(entry - pattern->entry); if ( ! pattern->n_entries ) return -1; return 0; }
static int it_s3m_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer) { 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 [email protected] so I can look at it. */ /* Discard the length. */ dumbfile_skip(f, 2); if (dumbfile_error(f)) 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; 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, 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; } 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++]; if (entry->effect != 255) { entry->mask |= IT_ENTRY_EFFECT; if (entry->effect == IT_BREAK_TO_ROW) entry->effectvalue -= (entry->effectvalue >> 4) * 6; }