shithub: dumb

Download patch

ref: f9fef91057834185b03a4cf8418bdf859b72b092
parent: 9acd29b47bd6aaae698e958bc1f4906ead27e2cb
author: Chris Moeller <[email protected]>
date: Mon Jan 11 03:58:42 EST 2010

{10/12/2005 4:52:14 PM}XM format v1.02 and v1.03 support

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

--- a/dumb/src/it/readxm.c
+++ b/dumb/src/it/readxm.c
@@ -692,7 +692,7 @@
 
 	/* version number */
 	version = dumbfile_igetw(f);
-	if (version != 0x0104 && version != 0x0102) {
+	if (version > 0x0104 || version < 0x0102) {
 		TRACE("XM error: wrong format version\n");
 		free(sigdata);
 		return NULL;
@@ -754,116 +754,237 @@
 		return NULL;
 	}
 
-	/*
-		--------------------
-		---   Patterns   ---
-		--------------------
-	*/
+	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) {
+		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++) {
-			if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, buffer) != 0) {
-				free(buffer);
+		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);
 		}
-		free(buffer);
-	}
 
-	/*
+		/*
 		-----------------------------------
 		---   Instruments and Samples   ---
 		-----------------------------------
-	*/
+		*/
 
-	sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
-	if (!sigdata->instrument) {
-		_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;
+		}
 
-	/* 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;
+		/* 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;
+		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);
+			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;
+			}
+
+			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].right = sigdata->sample[j].left = 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;
 		}
 
-		if (extra.n_samples) {
-			unsigned char roguebytes[XM_MAX_SAMPLES_PER_INSTRUMENT];
+		sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
+		if (!sigdata->instrument) {
+			_dumb_it_unload_sigdata(sigdata);
+			return NULL;
+		}
 
-			/* adjust instrument sample map (make indices absolute) */
-			for (j = 0; j < 96; j++)
-				sigdata->instrument[i].map_sample[j] += total_samples;
+		total_samples = 0;
+		sigdata->sample = NULL;
 
-			sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples));
-			if (!sigdata->sample) {
+		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].right = sigdata->sample[j].left = 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) {
+			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;
 				}
-				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.
+				for (j = total_samples; j < total_samples+extra.n_samples; j++)
+					sigdata->sample[j].right = sigdata->sample[j].left = 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;
+					sample->vibrato_waveform = xm_convert_vibrato[extra.vibrato_type];
+					sample->max_resampling_quality = -1;
+				}
+				total_samples += extra.n_samples;
 			}
-			for (j = 0; j < extra.n_samples; j++) {
-				if (it_xm_read_sample_data(&sigdata->sample[total_samples+j], roguebytes[j], f) != 0) {
+		}
+
+		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;
 				}
 			}
-			total_samples += extra.n_samples;
+			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->n_samples = total_samples;
 
 	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?