shithub: dumb

Download patch

ref: 3be9ce486cf67827f18346b54d83478d487abd40
parent: 719dbbe38317512e9aabb2654953e9ba226caaf6
author: Chris Moeller <kode54@gmail.com>
date: Mon Jan 11 04:00:22 EST 2010

{10/6/2006 9:42:18 PM~10/6/2006 9:42:20 PM}2006-10-07 05:24 UTC - kode54
- Simplified volume ramping update code, reducing the size of the resampler code
  considerably.
- Bumped the volume ramping precision to 24 bits of fraction precision, which is
  needed by Sweetsin.xm.
- Moved sample rate reporting to dynamic info as requested by Peter, since it's
  not a property of the files themselves, but user configurable.
- Version is now 0.9.8.1

2006-10-07 03:42 UTC - kode54
- Changed DSMF sample loader to ignore unknown flags instead of blowing an error.

2006-09-25 17:39 UTC - kode54
- Added hack to MOD loader for when sample start is specified in bytes instead of
  words.

2006-09-19 15:05 UTC - kode54
- Shuffled finetune calculation into the correct position, immediately applied
  as delta is calculated from note.
- Promoted IT_SAMPLE finetune property to signed short as char is insufficient
  for full semitone range. (+/- 256)
- Changed resampler to use full 64-bit comparison for todo variable range checking
  which should hopefully eliminate any further problems with pitch slides which go
  out of range.
- Version is now 0.9.8

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

--- a/dumb/include/internal/it.h
+++ b/dumb/include/internal/it.h
@@ -229,7 +229,7 @@
 	unsigned char vibrato_rate;
 	unsigned char vibrato_waveform;
 
-	signed char   finetune;
+	signed short   finetune;
 
 	void *data;
 
--- a/dumb/src/helpers/resamp2.inc
+++ b/dumb/src/helpers/resamp2.inc
@@ -106,11 +106,11 @@
 #define VOLUME_VARIABLES lvol, lvolr, lvold, lvolt, lvolm, rvol, rvolr, rvold, rvolt, rvolm
 #define SET_VOLUME_VARIABLES { \
 	if ( volume_left ) { \
-		lvolr = (int)(volume_left->volume * 65536.0); \
-		lvold = (int)(volume_left->delta * 65536.0); \
-		lvolt = (int)(volume_left->target * 65536.0); \
+		lvolr = (int)(volume_left->volume * 16777216.0); \
+		lvold = (int)(volume_left->delta * 16777216.0); \
+		lvolt = (int)(volume_left->target * 16777216.0); \
 		lvolm = (int)(volume_left->mix * 65536.0); \
-		lvol = MULSC( lvolr, lvolm ); \
+		lvol = MULSC( lvolr >> 8, lvolm ); \
 		if ( lvolr == lvolt ) volume_left = NULL; \
 	} else { \
 		lvol = 0; \
@@ -117,11 +117,11 @@
 		lvolt = 0; \
 	} \
 	if ( volume_right ) { \
-		rvolr = (int)(volume_right->volume * 65536.0); \
-		rvold = (int)(volume_right->delta * 65536.0); \
-		rvolt = (int)(volume_right->target * 65536.0); \
+		rvolr = (int)(volume_right->volume * 16777216.0); \
+		rvold = (int)(volume_right->delta * 16777216.0); \
+		rvolt = (int)(volume_right->target * 16777216.0); \
 		rvolm = (int)(volume_right->mix * 65536.0); \
-		rvol = MULSC( rvolr, rvolm ); \
+		rvol = MULSC( rvolr >> 8, rvolm ); \
 		if ( rvolr == rvolt ) volume_right = NULL; \
 	} else { \
 		rvol = 0; \
@@ -129,8 +129,8 @@
 	} \
 }
 #define RETURN_VOLUME_VARIABLES { \
-	if ( volume_left ) volume_left->volume = (float)lvolr / 65536.0f; \
-	if ( volume_right ) volume_right->volume = (float)rvolr / 65536.0f; \
+	if ( volume_left ) volume_left->volume = (float)lvolr / 16777216.0f; \
+	if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \
 }
 #define VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
 #define MIX_ALIAS(op, upd, offset) STEREO_DEST_MIX_ALIAS(op, upd, offset)
--- a/dumb/src/helpers/resamp3.inc
+++ b/dumb/src/helpers/resamp3.inc
@@ -50,6 +50,7 @@
 	int VOLUME_VARIABLES;
 	long done;
 	long todo;
+	LONG_LONG todo64;
 	int quality;
 
 	if (!resampler || resampler->dir == 0) return 0;
@@ -75,14 +76,16 @@
 			dt = -dt;
 
 		if (resampler->dir < 0)
-			todo = (long)((((LONG_LONG)(resampler->pos - resampler->start) << 16) + resampler->subpos - dt) / -dt);
+			todo64 = ((((LONG_LONG)(resampler->pos - resampler->start) << 16) + resampler->subpos - dt) / -dt);
 		else
-			todo = (long)((((LONG_LONG)(resampler->end - resampler->pos) << 16) - resampler->subpos - 1 + dt) / dt);
+			todo64 = ((((LONG_LONG)(resampler->end - resampler->pos) << 16) - resampler->subpos - 1 + dt) / dt);
 
-		if (todo < 0)
+		if (todo64 < 0)
 			todo = 0;
-		else if (todo > dst_size - done)
+		else if (todo64 > dst_size - done)
 			todo = dst_size - done;
+		else
+			todo = (long) todo64;
 
 		done += todo;
 
--- a/dumb/src/helpers/resample.inc
+++ b/dumb/src/helpers/resample.inc
@@ -85,24 +85,14 @@
 
 #define UPDATE_VOLUME( pvol, vol ) {                               \
 	if (pvol) {                                                    \
-		if (vol##d < 0) {                                          \
-			if (vol##t - vol##r > vol##d) {                        \
-				pvol->volume = pvol->target;                       \
-				pvol = NULL;                                       \
-				vol = MULSC( vol##t, vol##m );                     \
-			} else {                                               \
-				vol##r += vol##d;                                  \
-				vol = MULSC( vol##r, vol##m );                     \
-			}                                                      \
+		vol##r += vol##d;                                          \
+		if ((vol##d < 0 && vol##r <= vol##t) ||                    \
+			(vol##d > 0 && vol##r >= vol##t)) {                    \
+			pvol->volume = pvol->target;                           \
+			pvol = NULL;                                           \
+			vol = MULSC( vol##t >> 8, vol##m );                    \
 		} else {                                                   \
-			if (vol##t - vol##r < vol##d) {                        \
-				pvol->volume = pvol->target;                       \
-				pvol = NULL;                                       \
-				vol = MULSC( vol##t, vol##m );                     \
-			} else {                                               \
-				vol##r += vol##d;                                  \
-				vol = MULSC( vol##r, vol##m );                     \
-			}                                                      \
+			vol = MULSC( vol##r >> 8, vol##m );                    \
 		}                                                          \
 	}                                                              \
 }
@@ -120,11 +110,11 @@
 #define MONO_DEST_VOLUME_ZEROS 0
 #define SET_MONO_DEST_VOLUME_VARIABLES { \
 	if ( volume ) { \
-		volr = (int)(volume->volume * 65536.0); \
-		vold = (int)(volume->delta * 65536.0); \
-		volt = (int)(volume->target * 65536.0); \
+		volr = (int)(volume->volume * 16777216.0); \
+		vold = (int)(volume->delta * 16777216.0); \
+		volt = (int)(volume->target * 16777216.0); \
 		volm = (int)(volume->mix * 65536.0); \
-		vol = MULSC( volr, volm ); \
+		vol = MULSC( volr >> 8, volm ); \
 		if ( volr == volt ) volume = NULL; \
 	} else { \
 		vol = 0; \
@@ -131,7 +121,7 @@
 		volt = 0; \
 	} \
 }
-#define RETURN_MONO_DEST_VOLUME_VARIABLES if ( volume ) volume->volume = (float)volr / 65536.0f
+#define RETURN_MONO_DEST_VOLUME_VARIABLES if ( volume ) volume->volume = (float)volr / 16777216.0f
 #define MONO_DEST_VOLUMES_ARE_ZERO (vol == 0 && volt == 0)
 #define MONO_DEST_MIX_ALIAS(op, upd, offset) { \
 	*dst++ op ALIAS(x[offset], vol); \
@@ -191,11 +181,11 @@
 #define MONO_DEST_VOLUME_ZEROS 0, 0
 #define SET_MONO_DEST_VOLUME_VARIABLES { \
 	if ( volume_left ) { \
-		lvolr = (int)(volume_left->volume * 65536.0); \
-		lvold = (int)(volume_left->delta * 65536.0); \
-		lvolt = (int)(volume_left->target * 65536.0); \
+		lvolr = (int)(volume_left->volume * 16777216.0); \
+		lvold = (int)(volume_left->delta * 16777216.0); \
+		lvolt = (int)(volume_left->target * 16777216.0); \
 		lvolm = (int)(volume_left->mix * 65536.0); \
-		lvol = MULSC( lvolr, lvolm ); \
+		lvol = MULSC( lvolr >> 8, lvolm ); \
 		if ( lvolr == lvolt ) volume_left = NULL; \
 	} else { \
 		lvol = 0; \
@@ -202,11 +192,11 @@
 		lvolt = 0; \
 	} \
 	if ( volume_right ) { \
-		rvolr = (int)(volume_right->volume * 65536.0); \
-		rvold = (int)(volume_right->delta * 65536.0); \
-		rvolt = (int)(volume_right->target * 65536.0); \
+		rvolr = (int)(volume_right->volume * 16777216.0); \
+		rvold = (int)(volume_right->delta * 16777216.0); \
+		rvolt = (int)(volume_right->target * 16777216.0); \
 		rvolm = (int)(volume_right->mix * 65536.0); \
-		rvol = MULSC( rvolr, rvolm ); \
+		rvol = MULSC( rvolr >> 8, rvolm ); \
 		if ( rvolr == rvolt ) volume_right = NULL; \
 	} else { \
 		rvol = 0; \
@@ -214,8 +204,8 @@
 	} \
 }
 #define RETURN_MONO_DEST_VOLUME_VARIABLES { \
-	if ( volume_left ) volume_left->volume = (float)lvolr / 65536.0f; \
-	if ( volume_right ) volume_right->volume = (float)rvolr / 65536.0f; \
+	if ( volume_left ) volume_left->volume = (float)lvolr / 16777216.0f; \
+	if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \
 }
 #define MONO_DEST_VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
 #define MONO_DEST_MIX_ALIAS(op, upd, offset) { \
--- a/dumb/src/it/itread.c
+++ b/dumb/src/it/itread.c
@@ -587,6 +587,7 @@
 		sample->vibrato_rate = 0;
 		sample->vibrato_waveform = 0;
 	}
+	sample->finetune = 0;
 	sample->max_resampling_quality = -1;
 
 	return dumbfile_error(f);
@@ -686,7 +687,7 @@
 
 
 
-#define DETECT_DUPLICATE_CHANNELS
+//#define DETECT_DUPLICATE_CHANNELS
 #ifdef DETECT_DUPLICATE_CHANNELS
 #include <stdio.h>
 #endif
--- a/dumb/src/it/itrender.c
+++ b/dumb/src/it/itrender.c
@@ -1639,7 +1639,7 @@
 	channel->playing->sample_vibrato_waveform = channel->playing->sample->vibrato_waveform;
 	channel->playing->sample_vibrato_depth = 0;
 	channel->playing->slide = 0;
-	channel->playing->finetune = 0;
+	channel->playing->finetune = channel->playing->sample->finetune;
 
 	if (flags & 1) {
 		channel->playing->volume_envelope = volume_envelope;
@@ -3023,7 +3023,7 @@
 			channel->playing->sample_vibrato_waveform = channel->playing->sample->vibrato_waveform;
 			channel->playing->sample_vibrato_depth = 0;
 			channel->playing->slide = 0;
-			channel->playing->finetune = 0;
+			channel->playing->finetune = channel->playing->sample->finetune;
 			it_reset_filter_state(&channel->playing->filter_state[0]); // Are these
 			it_reset_filter_state(&channel->playing->filter_state[1]); // necessary?
 			it_playing_reset_resamplers(channel->playing, 0);
@@ -3492,6 +3492,38 @@
 	return (int)note;
 }
 
+// Period table for Protracker octaves 0-5:
+static const unsigned short ProTrackerPeriodTable[6*12] =
+{
+	1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907,
+	856,808,762,720,678,640,604,570,538,508,480,453,
+	428,404,381,360,339,320,302,285,269,254,240,226,
+	214,202,190,180,170,160,151,143,135,127,120,113,
+	107,101,95,90,85,80,75,71,67,63,60,56,
+	53,50,47,45,42,40,37,35,33,31,30,28
+};
+
+
+static const unsigned short ProTrackerTunedPeriods[16*12] = 
+{
+	1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907,
+	1700,1604,1514,1430,1348,1274,1202,1134,1070,1010,954,900,
+	1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,894,
+	1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,888,
+	1664,1570,1482,1398,1320,1246,1176,1110,1048,990,934,882,
+	1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,874,
+	1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,868,
+	1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914,862,
+	1814,1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,
+	1800,1700,1604,1514,1430,1350,1272,1202,1134,1070,1010,954,
+	1788,1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,
+	1774,1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,
+	1762,1664,1570,1482,1398,1320,1246,1176,1110,1048,988,934,
+	1750,1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,
+	1736,1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,
+	1724,1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914 
+};
+
 static void process_all_playing(DUMB_IT_SIGRENDERER *sigrenderer)
 {
 	DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
@@ -3557,7 +3589,8 @@
 
 			if (sigdata->flags & IT_LINEAR_SLIDES) {
 				int currpitch = ((playing->note - 60) << 8) + playing->slide
-				                                            + vibrato_shift;
+				                                            + vibrato_shift
+															+ playing->finetune;
 
 				/* We add a feature here, which is that of keeping the pitch
 				 * within range. Otherwise it crashes. Trust me. It happened.
@@ -3573,7 +3606,7 @@
 			} else {
 				int slide = playing->slide + vibrato_shift;
 
-				playing->delta = (float)pow(DUMB_SEMITONE_BASE, 60 - playing->note);
+				playing->delta = (float)pow(DUMB_PITCH_BASE, ((60 - playing->note) << 8) - playing->finetune );
 				/* playing->delta is 1.0 for C-5, 0.5 for C-6, etc. */
 
 				playing->delta *= 1.0f / playing->sample->C5_speed;
@@ -3605,9 +3638,6 @@
 				}
 				else*/ playing->delta *= (float)pow(DUMB_SEMITONE_BASE, channel->arpeggio >> 8);/*
 			}*/
-
-			if (playing->finetune)
-				playing->delta *= (float)pow(DUMB_PITCH_BASE, playing->finetune);
 
 			playing->filter_cutoff = channel->filter_cutoff;
 			playing->filter_resonance = channel->filter_resonance;
--- a/dumb/src/it/read669.c
+++ b/dumb/src/it/read669.c
@@ -199,6 +199,7 @@
 	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;
--- a/dumb/src/it/readam.c
+++ b/dumb/src/it/readam.c
@@ -118,6 +118,7 @@
 	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 )
--- a/dumb/src/it/readasy.c
+++ b/dumb/src/it/readasy.c
@@ -124,7 +124,8 @@
 	sample->flags = IT_SAMPLE_EXISTS;
 
 	sample->default_pan = 0;
-	sample->C5_speed = ( long )( 16726.0 * pow( DUMB_PITCH_BASE, finetune * 32 ) );
+	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 ) )
--- a/dumb/src/it/readdsmf.c
+++ b/dumb/src/it/readdsmf.c
@@ -48,8 +48,8 @@
 		return 0;
 	}
 
-	if ( flags & ~( 2 | 1 ) )
-		return -1;
+	/*if ( flags & ~( 2 | 1 ) )
+		return -1;*/
 
 	if ( sample->length + 64 > len )
 		return -1;
@@ -62,6 +62,7 @@
 	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 )
--- a/dumb/src/it/readmod.c
+++ b/dumb/src/it/readmod.c
@@ -120,7 +120,7 @@
 
 static int it_mod_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
 {
-	int finetune;
+	int finetune, loop_start, loop_length;
 
 /**
      21       22   Chars     Sample 1 name.  If the name is not a full
@@ -141,8 +141,12 @@
 /** 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?
-	sample->loop_start = dumbfile_mgetw(f) << 1;
-	sample->loop_end = sample->loop_start + (dumbfile_mgetw(f) << 1);
+	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
@@ -160,7 +164,8 @@
 	sample->flags = IT_SAMPLE_EXISTS;
 
 	sample->default_pan = 0;
-	sample->C5_speed = (long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
+	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)
@@ -485,8 +490,8 @@
 			 * 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;
+			/*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'):
@@ -611,6 +616,10 @@
 		//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."
@@ -688,7 +697,6 @@
 			}
 		}
 	}
-	
 
 	/* And finally, the sample data */
 	for (i = 0; i < sigdata->n_samples; i++) {
@@ -699,6 +707,24 @@
 			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. */
--- a/dumb/src/it/readmtm.c
+++ b/dumb/src/it/readmtm.c
@@ -125,7 +125,8 @@
 	}
 
 	sample->default_pan = 0;
-	sample->C5_speed = (long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
+	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)
--- a/dumb/src/it/readoldpsm.c
+++ b/dumb/src/it/readoldpsm.c
@@ -96,8 +96,10 @@
 		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->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) {
--- a/dumb/src/it/readpsm.c
+++ b/dumb/src/it/readpsm.c
@@ -108,6 +108,7 @@
 	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) {
@@ -443,6 +444,8 @@
 
 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;
@@ -593,14 +596,14 @@
 
 	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 */
-			found = 0;
 			if (c->len == 6) {
-				found = 0;
 				length = c->len;
 				ptr = c->data;
 				while (length > 0) {
@@ -790,7 +793,7 @@
 					length = c->len;
 					if (found == PSMV_OLD) {
 						if (length < 8) goto error_ev;
-						if (!memcmp(ptr + 4, e->data, 4)) {
+						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;
@@ -803,7 +806,7 @@
 						}
 					} else if (found == PSMV_NEW) {
 						if (length < 12) goto error_ev;
-						if (!memcmp(ptr + 4, e->data, 8)) {
+						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;
@@ -1192,6 +1195,52 @@
 	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 ( 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 ( 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;
@@ -1205,6 +1254,7 @@
 		return NULL;
 
 	{
+		int n_tags = 2;
 		char version[16];
 		const char *tag[3][2];
 		tag[0][0] = "TITLE";
@@ -1211,9 +1261,13 @@
 		tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
 		tag[1][0] = "FORMAT";
 		tag[1][1] = "PSM";
-		tag[2][0] = "FORMATVERSION";
-		itoa(ver, version, 10);
-		tag[2][1] = (const char *) &version;
-		return make_duh(-1, 3, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+		if ( ver )
+		{
+			tag[2][0] = "FORMATVERSION";
+			itoa(ver, version, 10);
+			tag[2][1] = (const char *) &version;
+			++n_tags;
+		}
+		return make_duh(-1, n_tags, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
 	}
 }
--- a/dumb/src/it/readptm.c
+++ b/dumb/src/it/readptm.c
@@ -119,6 +119,7 @@
 	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);
--- a/dumb/src/it/reads3m.c
+++ b/dumb/src/it/reads3m.c
@@ -148,6 +148,7 @@
 	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);
--- a/dumb/src/it/readstm.c
+++ b/dumb/src/it/readstm.c
@@ -84,6 +84,7 @@
 	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);
--- a/dumb/src/it/readxm.c
+++ b/dumb/src/it/readxm.c
@@ -525,7 +525,8 @@
 	if (dumbfile_error(f))
 		return -1;
 
-	sample->C5_speed = (long)(16726.0*pow(DUMB_SEMITONE_BASE, relative_note_number)*pow(DUMB_PITCH_BASE, finetune*2));
+	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;