shithub: dumb

Download patch

ref: 4e1db2adb05e53c50fe38102676889c22a4f2e66
parent: 3527875388468d5343c7958d4781f250d4c333d6
author: Chris Moeller <[email protected]>
date: Mon Jan 11 03:59:57 EST 2010

{5/26/2006 10:58:10 PM~5/26/2006 10:58:12 PM}2006-05-22 21:44 UTC - kode54
- XM reader now supports up to 256 instruments, even though FT2 only
  supports up to 128. ModPlug Tracker again.

2006-05-22 18:43 UTC - kode54
- S3M reader was using the incorrect index into component for sample packing
  when reading sample data. Was using n, should have been m.

2006-05-22 17:26 UTC - kode54
- IT renderer may have a bug with its time_lost / loop handling. Switchover
  from sustain loop would compound time_lost onto itself for every note-off.
  I'm not sure if this crap is even doing the right thing, especially in the
  case of a sample with a sustain loop, but no main loop. Working around for
  now by zeroing time_lost after note-off. (hall8.it)
- S3M reader ignores effects outside of 1-25 range so nothing can hit
  internal effects which are XM or PTM only. (N4.S3M)
- IT reader now supports ModPlug Tracker extensions for up to 4000 samples
  and mapping them with instruments. (hallowe.it.it)
- XM reader now supports instrument vibrato 4, random. Yet another ModPlug
  extension. (hcw-st.xm)

2006-05-21 02:11 UTC - kode54
- S3M reader correctly reads all 24 bits of the sample memory segment
  offset, fixing at least one file with >1MB of sample data (d-t-x_x.s3m)
- XM reader stops reading instruments when it has at least one valid
  instrument and encounters an error, fixing at least one file with
  too high instrument count in the header (drx-chri.xm)
- IT reader ignores instrument header signatures, since there seem to
  be files with bad signatures on unused/filler instruments (dsouls.it)
- MOD reader can now be restricted to handling 31 sample files with
  legal/known signatures only, so frontend can fall back on restricted
  MOD loading for files with incorrect extensions (dreamer_0g.s3m)

2006-05-20 xx:xx UTC - kode54
- Modified silence skipping to hack around some "S L O W" effects crap
  and a misused break to row effect

git-tfs-id: [http://localhost:8080/tfs/DefaultCollection/]$/foobar2000/files/plugins.root;C84

--- a/dumb/include/dumb.h
+++ b/dumb/include/dumb.h
@@ -350,7 +350,7 @@
 DUH *dumb_load_it(const char *filename);
 DUH *dumb_load_xm(const char *filename);
 DUH *dumb_load_s3m(const char *filename);
-DUH *dumb_load_mod(const char *filename);
+DUH *dumb_load_mod(const char *filename, int restrict);
 DUH *dumb_load_ptm(const char *filename);
 DUH *dumb_load_669(const char *filename);
 DUH *dumb_load_psm(const char *filename, int subsong);
@@ -361,7 +361,7 @@
 DUH *dumb_read_it(DUMBFILE *f);
 DUH *dumb_read_xm(DUMBFILE *f);
 DUH *dumb_read_s3m(DUMBFILE *f);
-DUH *dumb_read_mod(DUMBFILE *f);
+DUH *dumb_read_mod(DUMBFILE *f, int restrict);
 DUH *dumb_read_ptm(DUMBFILE *f);
 DUH *dumb_read_669(DUMBFILE *f);
 DUH *dumb_read_psm(DUMBFILE *f, int subsong);
--- a/dumb/include/internal/it.h
+++ b/dumb/include/internal/it.h
@@ -61,6 +61,8 @@
 #define IT_INSTRUMENT_SIGNATURE DUMB_ID('I', 'M', 'P', 'I')
 #define IT_SAMPLE_SIGNATURE     DUMB_ID('I', 'M', 'P', 'S')
 
+// olivier sux
+#define IT_MPTX_SIGNATURE       DUMB_ID('X', 'T', 'P', 'M')
 
 
 /* 1 minute per 4 rows, each row 6 ticks; this is divided by the tempo to get
--- a/dumb/src/it/itread.c
+++ b/dumb/src/it/itread.c
@@ -339,8 +339,10 @@
 {
 	int n;
 
-	if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE)
-		return -1;
+	/*if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE)
+		return -1;*/
+	// XXX
+	dumbfile_skip(f, 4);
 
 	dumbfile_getnc(instrument->filename, 13, f);
 	instrument->filename[13] = 0;
@@ -445,13 +447,18 @@
 
 
 
-static int it_read_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f)
+static int it_read_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f, int maxlen)
 {
-	int n;
+	int n, len;
 
-	if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE)
-		return -1;
+	/*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;
 
@@ -492,6 +499,20 @@
 	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;
+	}
+
 	return 0;
 }
 
@@ -876,7 +897,7 @@
 typedef struct IT_COMPONENT
 {
 	unsigned char type;
-	unsigned char n;
+	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 */
@@ -904,7 +925,7 @@
 	IT_COMPONENT *component;
 	int n_components = 0;
 
-	unsigned char sample_convert[256];
+	unsigned char sample_convert[4096];
 
 	int n;
 
@@ -962,7 +983,8 @@
 	dumbfile_getnc(sigdata->channel_pan, DUMB_IT_N_CHANNELS, f);
 	dumbfile_getnc(sigdata->channel_volume, DUMB_IT_N_CHANNELS, f);
 
-	if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_instruments > 256 || sigdata->n_samples > 256 || sigdata->n_patterns > 256) {
+	// 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;
 	}
@@ -1188,7 +1210,7 @@
 				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);
+					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);
--- a/dumb/src/it/itrender.c
+++ b/dumb/src/it/itrender.c
@@ -1322,6 +1322,8 @@
 		}
 
 		playing->resampler[1].pos = playing->resampler[0].pos += playing->time_lost;
+		// XXX what
+		playing->time_lost = 0;
 	}
 }
 
@@ -4981,6 +4983,10 @@
 
 					case IT_S:
 						switch (entry->effectvalue >> 4) {
+							case 0: // meh bastard
+								if ( entry->effectvalue != 0 ) return 0;
+								break;
+
 							case IT_S_FINE_PATTERN_DELAY:
 							case IT_S_PATTERN_LOOP:
 							case IT_S_PATTERN_DELAY:
@@ -4997,6 +5003,18 @@
 						}
 						break;
 
+					// clever idiot with his S L O W crap; do nothing
+					case IT_VOLSLIDE_TONEPORTA:
+					case IT_SET_SAMPLE_OFFSET:
+					case IT_GLOBAL_VOLUME_SLIDE:
+						if ( entry->effectvalue != 0 ) return 0;
+						break;
+
+					// genius also uses this instead of jump to order by mistake, meh, and it's bloody BCD
+					case IT_BREAK_TO_ROW:						
+						if ( ( ( entry->effectvalue >> 4 ) * 10 + ( entry->effectvalue & 15 ) ) != order ) return 0;
+						break;
+
 					default:
 						return 0;
 				}
@@ -5075,7 +5093,7 @@
 
 	for (n = 0; n < sigdata->n_orders; n++) {
 		if ((sigdata->order[n] >= sigdata->n_patterns) ||
-			(is_pattern_silent(&sigdata->pattern[sigdata->order[n]], n)))
+			(is_pattern_silent(&sigdata->pattern[sigdata->order[n]], n) > 1))
 			bit_array_set(ba_played, n * 256);
 	}
 
--- a/dumb/src/it/loadmod.c
+++ b/dumb/src/it/loadmod.c
@@ -26,7 +26,7 @@
  * 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(const char *filename)
+DUH *dumb_load_mod(const char *filename, int restrict)
 {
 	DUH *duh;
 	DUMBFILE *f = dumbfile_open(filename);
@@ -34,7 +34,7 @@
 	if (!f)
 		return NULL;
 
-	duh = dumb_read_mod(f);
+	duh = dumb_read_mod(f, restrict);
 
 	dumbfile_close(f);
 
--- a/dumb/src/it/readam.c
+++ b/dumb/src/it/readam.c
@@ -93,7 +93,7 @@
 		return 0;
 	}
 
-	if ( flags & ~( 0x80 | 0x20 | 0x10 | 0x08 | 0x04 ) )
+	if ( flags & ~( 0x8000 | 0x80 | 0x20 | 0x10 | 0x08 | 0x04 ) )
 		return -1;
 
 	length_bytes = length << ( ( flags & 0x04 ) >> 2 );
@@ -298,11 +298,11 @@
 
 		case DUMB_ID( 'I', 'N', 'S', 'T' ):
 			{
-				if ( c->size < 0x121 ) goto error;
+				if ( c->size < 0xE1 ) goto error;
 				ptr = ( unsigned char * ) c->data;
 				if ( ptr[ 1 ] >= sigdata->n_samples ) sigdata->n_samples = ptr[ 1 ] + 1;
-				if ( ptr[ 0xE1 ] == 'S' && ptr[ 0xE2 ] == 'A' &&
-					ptr[ 0xE3 ] == 'M' && ptr[ 0xE4 ] == 'P' )
+				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;
@@ -409,11 +409,10 @@
 		case DUMB_ID( 'I', 'N', 'S', 'T' ):
 			{
 				IT_SAMPLE * sample;
-				if ( c->size < 0x121 ) goto error;
 				ptr = ( unsigned char * ) c->data;
 				sample = sigdata->sample + ptr[ 1 ];
-				if ( ptr[ 0xE1 ] == 'S' && ptr[ 0xE2 ] == 'A' &&
-					ptr[ 0xE3 ] == 'M' && ptr[ 0xE4 ] == 'P' )
+				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;
--- a/dumb/src/it/readmod.c
+++ b/dumb/src/it/readmod.c
@@ -437,7 +437,7 @@
 }
 
 
-static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f)
+static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
 {
 	DUMB_IT_SIGDATA *sigdata;
 	int n_channels;
@@ -545,6 +545,14 @@
 			}
 	}
 
+	// 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));
@@ -725,7 +733,7 @@
 
 
 
-DUH *dumb_read_mod(DUMBFILE *f)
+DUH *dumb_read_mod(DUMBFILE *f, int restrict)
 {
 	sigdata_t *sigdata;
 	long length;
@@ -732,7 +740,7 @@
 
 	DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
 
-	sigdata = it_mod_load_sigdata(f);
+	sigdata = it_mod_load_sigdata(f, restrict);
 
 	if (!sigdata)
 		return NULL;
--- a/dumb/src/it/readptm.c
+++ b/dumb/src/it/readptm.c
@@ -313,24 +313,24 @@
  * trouble.
  */
 
-#define IT_COMPONENT_INSTRUMENT 1
-#define IT_COMPONENT_PATTERN    2
-#define IT_COMPONENT_SAMPLE     3
+#define PTM_COMPONENT_INSTRUMENT 1
+#define PTM_COMPONENT_PATTERN    2
+#define PTM_COMPONENT_SAMPLE     3
 
-typedef struct IT_COMPONENT
+typedef struct PTM_COMPONENT
 {
 	unsigned char type;
 	unsigned char n;
 	long offset;
 }
-IT_COMPONENT;
+PTM_COMPONENT;
 
 
 
-static int it_component_compare(const void *e1, const void *e2)
+static int ptm_component_compare(const void *e1, const void *e2)
 {
-	return ((const IT_COMPONENT *)e1)->offset -
-	       ((const IT_COMPONENT *)e2)->offset;
+	return ((const PTM_COMPONENT *)e1)->offset -
+	       ((const PTM_COMPONENT *)e2)->offset;
 }
 
 
@@ -339,7 +339,7 @@
 {
 	DUMB_IT_SIGDATA *sigdata;
 
-	IT_COMPONENT *component;
+	PTM_COMPONENT *component;
 	int n_components = 0;
 
 	int n;
@@ -460,7 +460,7 @@
 	}
 
 	for (n = 0; n < sigdata->n_patterns; n++) {
-		component[n_components].type = IT_COMPONENT_PATTERN;
+		component[n_components].type = PTM_COMPONENT_PATTERN;
 		component[n_components].n = n;
 		component[n_components].offset = dumbfile_igetw(f) << 4;
 		n_components++;
@@ -477,12 +477,12 @@
 			return NULL;
 		}
 		if (!(sigdata->sample[n].flags & IT_SAMPLE_EXISTS)) continue;
-		component[n_components].type = IT_COMPONENT_SAMPLE;
+		component[n_components].type = PTM_COMPONENT_SAMPLE;
 		component[n_components].n = n;
 		n_components++;
 	}
 
-	qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare);
+	qsort(component, n_components, sizeof(PTM_COMPONENT), &ptm_component_compare);
 
 	{
 		int i;
@@ -518,7 +518,7 @@
 
 		switch (component[n].type) {
 
-			case IT_COMPONENT_PATTERN:
+			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);
@@ -527,7 +527,7 @@
 				}
 				break;
 
-			case IT_COMPONENT_SAMPLE:
+			case PTM_COMPONENT_SAMPLE:
 				if (it_ptm_read_sample_data(&sigdata->sample[component[n].n], (n + 1 == n_components), f)) {
 					free(buffer);
 					free(component);
--- a/dumb/src/it/reads3m.c
+++ b/dumb/src/it/reads3m.c
@@ -24,6 +24,8 @@
 #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)
 {
@@ -53,10 +55,11 @@
 		/** WARNING: no adlib support */
 	}
 
-	dumbfile_getnc(sample->filename, 13, f);
-	sample->filename[13] = 0;
+	dumbfile_getnc(sample->filename, 12, f);
+	sample->filename[12] = 0;
 
-	*offset = dumbfile_igetw(f) << 4;
+	*offset = dumbfile_getc(f) << 20;
+	*offset += dumbfile_igetw(f) << 4;
 
 	sample->length = dumbfile_igetl(f);
 	sample->loop_start = dumbfile_igetl(f);
@@ -66,14 +69,16 @@
 
 	dumbfile_skip(f, 1);
 
-	*pack = dumbfile_getc(f);
+	flags = dumbfile_getc(f);
 
-	if (*pack < 0 || (*pack != 0 && *pack != 4))
+	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;
@@ -277,7 +282,10 @@
 		pattern->n_entries++;
 		if (b) {
 			if (buflen + used[b] >= 65536) return -1;
-			dumbfile_getnc(buffer + buflen, used[b], f);
+			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 */
@@ -380,7 +388,8 @@
 			if (b & 128) {
 				entry->effect = buffer[bufpos++];
 				entry->effectvalue = buffer[bufpos++];
-				if (entry->effect != 255) {
+				// XXX woot
+				if (entry->effect && entry->effect < IT_MIDI_MACRO /*!= 255*/) {
 					entry->mask |= IT_ENTRY_EFFECT;
 					switch (entry->effect) {
 					case IT_BREAK_TO_ROW:
@@ -429,11 +438,11 @@
  * trouble.
  */
 
-#define IT_COMPONENT_INSTRUMENT 1
-#define IT_COMPONENT_PATTERN    2
-#define IT_COMPONENT_SAMPLE     3
+#define S3M_COMPONENT_INSTRUMENT 1
+#define S3M_COMPONENT_PATTERN    2
+#define S3M_COMPONENT_SAMPLE     3
 
-typedef struct IT_COMPONENT
+typedef struct S3M_COMPONENT
 {
 	unsigned char type;
 	unsigned char n;
@@ -441,14 +450,14 @@
 	short sampfirst; /* component[sampfirst] = first sample data after this */
 	short sampnext; /* sampnext is used to create linked lists of sample data */
 }
-IT_COMPONENT;
+S3M_COMPONENT;
 
 
 
-static int it_component_compare(const void *e1, const void *e2)
+static int s3m_component_compare(const void *e1, const void *e2)
 {
-	return ((const IT_COMPONENT *)e1)->offset -
-	       ((const IT_COMPONENT *)e2)->offset;
+	return ((const S3M_COMPONENT *)e1)->offset -
+	       ((const S3M_COMPONENT *)e2)->offset;
 }
 
 
@@ -464,7 +473,7 @@
 
 	unsigned char sample_pack[256];
 
-	IT_COMPONENT *component;
+	S3M_COMPONENT *component;
 	int n_components = 0;
 
 	int n;
@@ -605,7 +614,7 @@
 	}
 
 	for (n = 0; n < sigdata->n_samples; n++) {
-		component[n_components].type = IT_COMPONENT_SAMPLE;
+		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;
@@ -615,7 +624,7 @@
 	for (n = 0; n < sigdata->n_patterns; n++) {
 		long offset = dumbfile_igetw(f) << 4;
 		if (offset) {
-			component[n_components].type = IT_COMPONENT_PATTERN;
+			component[n_components].type = S3M_COMPONENT_PATTERN;
 			component[n_components].n = n;
 			component[n_components].offset = offset;
 			component[n_components].sampfirst = -1;
@@ -627,7 +636,7 @@
 		}
 	}
 
-	qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare);
+	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
@@ -674,10 +683,10 @@
 	 */
 
 	for (n = 0; n < n_components; n++) {
-		if (component[n].type == IT_COMPONENT_PATTERN) {
+		if (component[n].type == S3M_COMPONENT_PATTERN) {
 			int m;
 			for (m = n + 1; m < n_components; m++) {
-				if (component[m].type == IT_COMPONENT_PATTERN) {
+				if (component[m].type == S3M_COMPONENT_PATTERN) {
 					if (component[n].offset == component[m].offset) {
 						int o, pattern;
 						pattern = component[m].n;
@@ -703,6 +712,9 @@
 	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);
@@ -713,7 +725,7 @@
 
 		switch (component[n].type) {
 
-			case IT_COMPONENT_PATTERN:
+			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);
@@ -722,7 +734,7 @@
 				}
 				break;
 
-			case IT_COMPONENT_SAMPLE:
+			case S3M_COMPONENT_SAMPLE:
 				if (it_s3m_read_sample_header(&sigdata->sample[component[n].n], &offset, &sample_pack[component[n].n], *cwtv, f)) {
 					free(buffer);
 					free(component);
@@ -752,20 +764,58 @@
 
 		m = component[n].sampfirst;
 
+#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
+		last = -1;
+#endif
+
 		while (m >= 0) {
-			if (it_seek(f, component[m].offset)) {
-				free(buffer);
-				free(component);
-				_dumb_it_unload_sigdata(sigdata);
-				return NULL;
-			}
+			// 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 (it_s3m_read_sample_data(&sigdata->sample[component[m].n], ffi, sample_pack[component[n].n], f)) {
-				free(buffer);
-				free(component);
-				_dumb_it_unload_sigdata(sigdata);
-				return NULL;
+			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;
 		}
--- a/dumb/src/it/readxm.c
+++ b/dumb/src/it/readxm.c
@@ -91,7 +91,8 @@
 	IT_VIBRATO_SINE,
 	IT_VIBRATO_XM_SQUARE,
 	IT_VIBRATO_RAMP_DOWN,
-	IT_VIBRATO_RAMP_UP
+	IT_VIBRATO_RAMP_UP,
+	IT_VIBRATO_RANDOM
 };
 
 
@@ -367,7 +368,8 @@
 
 	if (extra->n_samples) {
 		/* sample header size */
-		if (dumbfile_igetl(f) != 0x28) {
+		i = dumbfile_igetl(f);
+		if (i && i != 0x28) { // XXX some crap with 0 here
 			TRACE("XM error: unexpected sample header size\n");
 			return -1;
 		}
@@ -443,7 +445,7 @@
 		extra->vibrato_depth = dumbfile_getc(f);
 		extra->vibrato_speed = dumbfile_getc(f);
 
-		if (dumbfile_error(f) || extra->vibrato_type >= 4)
+		if (dumbfile_error(f) || extra->vibrato_type > 4) // XXX
 			return -1;
 
 		/** WARNING: lossy approximation */
@@ -647,7 +649,7 @@
  * (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)
+static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
 {
 	DUMB_IT_SIGDATA *sigdata;
 	char id_text[18];
@@ -724,7 +726,7 @@
 	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 */
+	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?
@@ -731,7 +733,8 @@
 	sigdata->tempo            = dumbfile_igetw(f);
 
 	/* sanity checks */
-	if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_orders > 256 || sigdata->n_patterns > 256 || sigdata->n_instruments > 128 || n_channels > DUMB_IT_N_CHANNELS) {
+	// XXX
+	if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_orders > 256 || sigdata->n_patterns > 256 || sigdata->n_instruments > 256 || n_channels > DUMB_IT_N_CHANNELS) {
 		_dumb_it_unload_sigdata(sigdata);
 		return NULL;
 	}
@@ -814,9 +817,18 @@
 			XM_INSTRUMENT_EXTRA extra;
 
 			if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) {
-				TRACE("XM error: instrument %d\n", i+1);
-				_dumb_it_unload_sigdata(sigdata);
-				return NULL;
+				// 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) {