shithub: dumb

Download patch

ref: bbee7ab76b3e04fa2ae1cff8a23f9a61e214c6bf
parent: 5ed3b0ec86820172d2cff9a19529e60a9c39a93a
author: Chris Moeller <kode54@gmail.com>
date: Mon Jan 11 04:00:08 EST 2010

{6/9/2006 9:34:08 AM~6/9/2006 9:34:10 AM}Ported changes over from DUMB 0.9.3.

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

--- a/dumb/include/dumb.h
+++ b/dumb/include/dumb.h
@@ -14,7 +14,7 @@
  * which you wish to use the DUMB functions           \_  /  > /
  * and variables.                                       | \ / /
  *                                                      |  ' /
- *                                                       \__/
+ * Allegro users, you will probably want aldumb.h.       \__/
  */
 
 #ifndef DUMB_H
@@ -36,22 +36,22 @@
 
 #define DUMB_MAJOR_VERSION    0
 #define DUMB_MINOR_VERSION    9
-#define DUMB_REVISION_VERSION 2
+#define DUMB_REVISION_VERSION 3
 
 #define DUMB_VERSION (DUMB_MAJOR_VERSION*10000 + DUMB_MINOR_VERSION*100 + DUMB_REVISION_VERSION)
 
-#define DUMB_VERSION_STR "0.9.2"
+#define DUMB_VERSION_STR "0.9.3"
 
 #define DUMB_NAME "DUMB v"DUMB_VERSION_STR
 
-#define DUMB_YEAR  2003
-#define DUMB_MONTH 11
-#define DUMB_DAY   8
+#define DUMB_YEAR  2005
+#define DUMB_MONTH 8
+#define DUMB_DAY   7
 
-#define DUMB_YEAR_STR2  "03"
-#define DUMB_YEAR_STR4  "2003"
-#define DUMB_MONTH_STR1 "11"
-#define DUMB_DAY_STR1   "8"
+#define DUMB_YEAR_STR2  "05"
+#define DUMB_YEAR_STR4  "2005"
+#define DUMB_MONTH_STR1 "8"
+#define DUMB_DAY_STR1   "7"
 
 #if DUMB_MONTH < 10
 #define DUMB_MONTH_STR2 "0"DUMB_MONTH_STR1
@@ -246,13 +246,33 @@
  * is undocumented, so contact me and I shall try to help. Contact details
  * are in readme.txt.)
  */
-#endif
 
 typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data, const sample_t *const *samples, int n_channels, long length);
+/* This is deprecated, but is not marked as such because GCC tends to
+ * complain spuriously when the typedef is used later. See comments below.
+ */
 
 void duh_sigrenderer_set_analyser_callback(
 	DUH_SIGRENDERER *sigrenderer,
 	DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data
+) DUMB_DEPRECATED;
+/* This is deprecated because the meaning of the 'samples' parameter in the
+ * callback needed to change. For stereo applications, the array used to be
+ * indexed with samples[channel][pos]. It is now indexed with
+ * samples[0][pos*2+channel]. Mono sample data are still indexed with
+ * samples[0][pos]. The array is still 2D because samples will probably only
+ * ever be interleaved in twos. In order to fix your code, adapt it to the
+ * new sample layout and then call
+ * duh_sigrenderer_set_sample_analyser_callback below instead of this
+ * function.
+ */
+#endif
+
+typedef void (*DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK)(void *data, const sample_t *const *samples, int n_channels, long length);
+
+void duh_sigrenderer_set_sample_analyser_callback(
+	DUH_SIGRENDERER *sigrenderer,
+	DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data
 );
 
 int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer);
@@ -260,10 +280,23 @@
 
 void duh_sigrenderer_set_sigparam(DUH_SIGRENDERER *sigrenderer, unsigned char id, long value);
 
+#ifdef DUMB_DECLARE_DEPRECATED
 long duh_sigrenderer_get_samples(
 	DUH_SIGRENDERER *sigrenderer,
 	float volume, float delta,
 	long size, sample_t **samples
+) DUMB_DEPRECATED;
+/* The sample format has changed, so if you were using this function,
+ * you should switch to duh_sigrenderer_generate_samples() and change
+ * how you interpret the samples array. See the comments for
+ * duh_sigrenderer_set_analyser_callback().
+ */
+#endif
+
+long duh_sigrenderer_generate_samples(
+	DUH_SIGRENDERER *sigrenderer,
+	float volume, float delta,
+	long size, sample_t **samples
 );
 
 void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, float volume, sample_t *samples);
@@ -287,8 +320,8 @@
 	float volume, float delta,
 	long size, sample_t **samples
 ) DUMB_DEPRECATED;
-/* Please use duh_sigrenderer_get_samples(). Arguments and functionality are
- * identical.
+/* Please use duh_sigrenderer_generate_samples(), and see the
+ * comments for the deprecated duh_sigrenderer_get_samples() too.
  */
 
 typedef DUH_SIGRENDERER DUH_RENDERER DUMB_DEPRECATED;
@@ -373,6 +406,35 @@
 DUH *dumb_read_riff(DUMBFILE *f);
 DUH *dumb_read_asy(DUMBFILE *f);
 
+DUH *dumb_load_it_quick(const char *filename);
+DUH *dumb_load_xm_quick(const char *filename);
+DUH *dumb_load_s3m_quick(const char *filename);
+DUH *dumb_load_stm_quick(const char *filename);
+DUH *dumb_load_mod_quick(const char *filename, int restrict);
+DUH *dumb_load_ptm_quick(const char *filename);
+DUH *dumb_load_669_quick(const char *filename);
+DUH *dumb_load_psm_quick(const char *filename, int subsong);
+DUH *dumb_load_old_psm_quick(const char * filename);
+DUH *dumb_load_mtm_quick(const char *filename);
+DUH *dumb_load_riff_quick(const char *filename);
+DUH *dumb_load_asy_quick(const char *filename);
+
+DUH *dumb_read_it_quick(DUMBFILE *f);
+DUH *dumb_read_xm_quick(DUMBFILE *f);
+DUH *dumb_read_s3m_quick(DUMBFILE *f);
+DUH *dumb_read_stm_quick(DUMBFILE *f);
+DUH *dumb_read_mod_quick(DUMBFILE *f, int restrict);
+DUH *dumb_read_ptm_quick(DUMBFILE *f);
+DUH *dumb_read_669_quick(DUMBFILE *f);
+DUH *dumb_read_psm_quick(DUMBFILE *f, int subsong);
+DUH *dumb_read_old_psm_quick(DUMBFILE *f);
+DUH *dumb_read_mtm_quick(DUMBFILE *f);
+DUH *dumb_read_riff_quick(DUMBFILE *f);
+DUH *dumb_read_asy_quick(DUMBFILE *f);
+
+long dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata, int startorder);
+void dumb_it_do_initial_runthrough(DUH *duh);
+
 int dumb_get_psm_subsong_count(DUMBFILE *f);
 
 const unsigned char *dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd);
@@ -421,6 +483,9 @@
 int dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel);
 void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, int volume);
 
+int dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel);
+void dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel, int muted);
+
 typedef struct DUMB_IT_CHANNEL_STATE DUMB_IT_CHANNEL_STATE;
 
 struct DUMB_IT_CHANNEL_STATE
@@ -483,7 +548,7 @@
 	unsigned char id, long value
 );
 
-typedef long (*DUH_SIGRENDERER_GET_SAMPLES)(
+typedef long (*DUH_SIGRENDERER_GENERATE_SAMPLES)(
 	sigrenderer_t *sigrenderer,
 	float volume, float delta,
 	long size, sample_t **samples
@@ -508,7 +573,7 @@
 	DUH_LOAD_SIGDATA                   load_sigdata;
 	DUH_START_SIGRENDERER              start_sigrenderer;
 	DUH_SIGRENDERER_SET_SIGPARAM       sigrenderer_set_sigparam;
-	DUH_SIGRENDERER_GET_SAMPLES        sigrenderer_get_samples;
+	DUH_SIGRENDERER_GENERATE_SAMPLES   sigrenderer_generate_samples;
 	DUH_SIGRENDERER_GET_CURRENT_SAMPLE sigrenderer_get_current_sample;
 	DUH_END_SIGRENDERER                end_sigrenderer;
 	DUH_UNLOAD_SIGDATA                 unload_sigdata;
@@ -528,12 +593,19 @@
 
 /* Standard Signal Types */
 
-void dumb_register_sigtype_sample(void);
+//void dumb_register_sigtype_sample(void);
 
 
 /* Sample Buffer Allocation Helpers */
 
-sample_t **create_sample_buffer(int n_channels, long length);
+#ifdef DUMB_DECLARE_DEPRECATED
+sample_t **create_sample_buffer(int n_channels, long length) DUMB_DEPRECATED;
+/* DUMB has been changed to interleave stereo samples. Use
+ * allocate_sample_buffer() instead, and see the comments for
+ * duh_sigrenderer_set_analyser_callback().
+ */
+#endif
+sample_t **allocate_sample_buffer(int n_channels, long length);
 void destroy_sample_buffer(sample_t **samples);
 
 
@@ -548,7 +620,7 @@
 
 DUMB_CLICK_REMOVER *dumb_create_click_remover(void);
 void dumb_record_click(DUMB_CLICK_REMOVER *cr, long pos, sample_t step);
-void dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, long length, float halflife);
+void dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, long length, int step, float halflife);
 sample_t dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr);
 void dumb_destroy_click_remover(DUMB_CLICK_REMOVER *cr);
 
@@ -570,6 +642,8 @@
 
 typedef struct DUMB_RESAMPLER DUMB_RESAMPLER;
 
+typedef struct DUMB_VOLUME_RAMP_INFO DUMB_VOLUME_RAMP_INFO;
+
 typedef void (*DUMB_RESAMPLE_PICKUP)(DUMB_RESAMPLER *resampler, void *data);
 
 struct DUMB_RESAMPLER
@@ -584,35 +658,67 @@
 	int quality;
 	/* Everything below this point is internal: do not use. */
 	union {
-		sample_t x24[3];
-		short x16[3];
-		signed char x8[3];
+		sample_t x24[3*2];
+		short x16[3*2];
+		signed char x8[3*2];
 	} x;
 	int overshot;
 };
 
-void dumb_reset_resampler(DUMB_RESAMPLER *resampler, sample_t *src, long pos, long start, long end, int quality);
-DUMB_RESAMPLER *dumb_start_resampler(sample_t *src, long pos, long start, long end, int quality);
-long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, float * volume, float volume_delta, float volume_target, float volume_mix, float delta);
-sample_t dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, float volume);
+struct DUMB_VOLUME_RAMP_INFO
+{
+	float volume;
+	float delta;
+	float target;
+	float mix;
+};
+
+void dumb_reset_resampler(DUMB_RESAMPLER *resampler, sample_t *src, int src_channels, long pos, long start, long end, int quality);
+DUMB_RESAMPLER *dumb_start_resampler(sample_t *src, int src_channels, long pos, long start, long end, int quality);
+long dumb_resample_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta);
+long dumb_resample_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+void dumb_resample_get_current_sample_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
+void dumb_resample_get_current_sample_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
 void dumb_end_resampler(DUMB_RESAMPLER *resampler);
 
-void dumb_reset_resampler_16(DUMB_RESAMPLER *resampler, short *src, long pos, long start, long end, int quality);
-DUMB_RESAMPLER *dumb_start_resampler_16(short *src, long pos, long start, long end, int quality);
-long dumb_resample_16(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, float * volume, float volume_delta, float volume_target, float volume_mix, float delta);
-sample_t dumb_resample_get_current_sample_16(DUMB_RESAMPLER *resampler, float volume);
+void dumb_reset_resampler_16(DUMB_RESAMPLER *resampler, short *src, int src_channels, long pos, long start, long end, int quality);
+DUMB_RESAMPLER *dumb_start_resampler_16(short *src, int src_channels, long pos, long start, long end, int quality);
+long dumb_resample_16_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta);
+long dumb_resample_16_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_16_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_16_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+void dumb_resample_get_current_sample_16_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
+void dumb_resample_get_current_sample_16_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_16_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_16_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
 void dumb_end_resampler_16(DUMB_RESAMPLER *resampler);
 
-void dumb_reset_resampler_8(DUMB_RESAMPLER *resampler, signed char *src, long pos, long start, long end, int quality);
-DUMB_RESAMPLER *dumb_start_resampler_8(signed char *src, long pos, long start, long end, int quality);
-long dumb_resample_8(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, float * volume, float volume_delta, float volume_target, float volume_mix, float delta);
-sample_t dumb_resample_get_current_sample_8(DUMB_RESAMPLER *resampler, float volume);
+void dumb_reset_resampler_8(DUMB_RESAMPLER *resampler, signed char *src, int src_channels, long pos, long start, long end, int quality);
+DUMB_RESAMPLER *dumb_start_resampler_8(signed char *src, int src_channels, long pos, long start, long end, int quality);
+long dumb_resample_8_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta);
+long dumb_resample_8_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_8_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_8_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+void dumb_resample_get_current_sample_8_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
+void dumb_resample_get_current_sample_8_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_8_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_8_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
 void dumb_end_resampler_8(DUMB_RESAMPLER *resampler);
 
-void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, long pos, long start, long end, int quality);
-DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, long pos, long start, long end, int quality);
-long dumb_resample_n(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, float * volume, float volume_delta, float volume_target, float volume_mix, float delta);
-sample_t dumb_resample_get_current_sample_n(int n, DUMB_RESAMPLER *resampler, float volume);
+void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, int src_channels, long pos, long start, long end, int quality);
+DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels, long pos, long start, long end, int quality);
+long dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta);
+long dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+long dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta);
+void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst);
+void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
+void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
 void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler);
 
 
@@ -626,6 +732,8 @@
 	DUH_SIGTYPE_DESC *desc[],
 	sigdata_t *sigdata[]
 );
+
+void duh_set_length(DUH *duh, long length);
 
 
 #ifdef __cplusplus
--- a/dumb/include/internal/dumb.h
+++ b/dumb/include/internal/dumb.h
@@ -17,9 +17,10 @@
  *                                                       \__/
  * ...
  *
- * I mean it, people. You don't need access to anything in this file. If you
- * disagree, contact the authors. In the unlikely event that you make a good
- * case, we'll add what you need to dumb.h. Thanking you kindly.
+ * Seriously. You don't need access to anything in this file. All right, you
+ * probably do actually. But if you use it, you will be relying on a specific
+ * version of DUMB, so please check DUMB_VERSION defined in dumb.h. Please
+ * contact the authors so that we can provide a public API for what you need.
  */
 
 #ifndef INTERNAL_DUMB_H
--- a/dumb/include/internal/it.h
+++ b/dumb/include/internal/it.h
@@ -11,10 +11,17 @@
  * internal/it.h - Internal stuff for IT playback     / / \  \
  *                 and MOD/XM/S3M conversion.        | <  /   \_
  *                                                   |  \/ /\   /
- *                                                    \_  /  > /
- *                                                      | \ / /
- *                                                      |  ' /
- *                                                       \__/
+ * This header file provides access to the            \_  /  > /
+ * internal structure of DUMB, and is liable            | \ / /
+ * to change, mutate or cease to exist at any           |  ' /
+ * moment. Include it at your own peril.                 \__/
+ *
+ * ...
+ *
+ * Seriously. You don't need access to anything in this file. All right, you
+ * probably do actually. But if you use it, you will be relying on a specific
+ * version of DUMB, so please check DUMB_VERSION defined in dumb.h. Please
+ * contact the authors so that we can provide a public API for what you need.
  */
 
 #ifndef INTERNAL_IT_H
@@ -110,7 +117,7 @@
 
 struct IT_FILTER_STATE
 {
-	float currsample, prevsample;
+	sample_t currsample, prevsample;
 };
 
 
@@ -221,8 +228,7 @@
 	unsigned char vibrato_rate;
 	unsigned char vibrato_waveform;
 
-	void *left;
-	void *right;
+	void *data;
 
 	int max_resampling_quality;
 };
@@ -274,20 +280,21 @@
 #define IT_MIDI_MACRO            26 //see MIDI.TXT
 
 /* Some effects needed for XM compatibility */
-#define IT_XM_PORTAMENTO_DOWN    27
-#define IT_XM_PORTAMENTO_UP      28
-#define IT_XM_FINE_VOLSLIDE_DOWN 29
-#define IT_XM_FINE_VOLSLIDE_UP   30
-#define IT_XM_RETRIGGER_NOTE     31
-#define IT_XM_KEY_OFF            32
+#define IT_XM_PORTAMENTO_DOWN       27
+#define IT_XM_PORTAMENTO_UP         28
+#define IT_XM_FINE_VOLSLIDE_DOWN    29
+#define IT_XM_FINE_VOLSLIDE_UP      30
+#define IT_XM_RETRIGGER_NOTE        31
+#define IT_XM_KEY_OFF               32
+#define IT_XM_SET_ENVELOPE_POSITION 33
 
 /* More effects needed for PTM compatibility */
-#define IT_PTM_NOTE_SLIDE_DOWN   33
-#define IT_PTM_NOTE_SLIDE_UP     34
-#define IT_PTM_NOTE_SLIDE_DOWN_RETRIG 35
-#define IT_PTM_NOTE_SLIDE_UP_RETRIG 36
+#define IT_PTM_NOTE_SLIDE_DOWN        34
+#define IT_PTM_NOTE_SLIDE_UP          35
+#define IT_PTM_NOTE_SLIDE_DOWN_RETRIG 36
+#define IT_PTM_NOTE_SLIDE_UP_RETRIG   37
 
-#define IT_N_EFFECTS             37
+#define IT_N_EFFECTS                  38
 
 /* These represent the top nibble of the command value. */
 #define IT_S_SET_FILTER              0 /* Greyed out in IT... */
@@ -511,7 +518,7 @@
 
 	IT_FILTER_STATE filter_state[2]; /* Left and right */
 
-	DUMB_RESAMPLER resampler[2];
+	DUMB_RESAMPLER resampler;
 
 	/* time_lost is used to emulate Impulse Tracker's sample looping
 	 * characteristics. When time_lost is added to pos, the result represents
@@ -616,6 +623,7 @@
 	unsigned char lastS;
 	unsigned char pat_loop_row;
 	unsigned char pat_loop_count;
+	//unsigned char pat_loop_end_row; /* Used to catch infinite pattern loops */
 	unsigned char lastW;
 
 	unsigned char xm_lastE1;
@@ -734,10 +742,6 @@
 void _dumb_it_unload_sigdata(sigdata_t *vsigdata);
 
 extern DUH_SIGTYPE_DESC _dumb_sigtype_it;
-
-
-
-long _dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata, int startorder);
 
 
 
--- a/dumb/src/core/duhlen.c
+++ b/dumb/src/core/duhlen.c
@@ -8,8 +8,8 @@
  * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
  *                                                      /  \
  *                                                     / .  \
- * duhlen.c - Function to return the length of        / / \  \
- *            a DUH.                                 | <  /   \_
+ * duhlen.c - Functions to set and return the         / / \  \
+ *            length of a DUH.                       | <  /   \_
  *                                                   |  \/ /\   /
  * By entheh.                                         \_  /  > /
  *                                                      | \ / /
@@ -31,4 +31,12 @@
 long duh_get_length(DUH *duh)
 {
 	return duh ? duh->length : 0;
+}
+
+
+
+void duh_set_length(DUH *duh, long length)
+{
+	if (duh)
+		duh->length = length;
 }
--- a/dumb/src/core/makeduh.c
+++ b/dumb/src/core/makeduh.c
@@ -30,7 +30,7 @@
 	DUH_SIGNAL *signal;
 
 	ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer));
-	ASSERT(desc->sigrenderer_get_samples && desc->sigrenderer_get_current_sample);
+	ASSERT(desc->sigrenderer_generate_samples && desc->sigrenderer_get_current_sample);
 
 	signal = malloc(sizeof(*signal));
 
--- a/dumb/src/core/register.c
+++ b/dumb/src/core/register.c
@@ -62,7 +62,7 @@
 
 	ASSERT((desc->load_sigdata && desc->unload_sigdata) || (!desc->load_sigdata && !desc->unload_sigdata));
 	ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer));
-	ASSERT(desc->sigrenderer_get_samples && desc->sigrenderer_get_current_sample);
+	ASSERT(desc->sigrenderer_generate_samples && desc->sigrenderer_get_current_sample);
 
 	if (desc_link) {
 		do {
--- a/dumb/src/core/rendduh.c
+++ b/dumb/src/core/rendduh.c
@@ -107,7 +107,7 @@
 	 */
 	ASSERT(n_channels <= 2);
 
-	sampptr = create_sample_buffer(n_channels, size);
+	sampptr = allocate_sample_buffer(n_channels, size);
 
 	if (!sampptr)
 		return 0;
@@ -114,37 +114,19 @@
 
 	dumb_silence(sampptr[0], n_channels * size);
 
-	size = duh_sigrenderer_get_samples(sigrenderer, volume, delta, size, sampptr);
+	size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, sampptr);
 
 	if (bits == 16) {
 		int signconv = unsign ? 0x8000 : 0x0000;
 
-		if (n_channels == 2) {
-			for (n = 0; n < size; n++) {
-				CONVERT16(sampptr[0][n], n << 1, signconv);
-			}
-			for (n = 0; n < size; n++) {
-				CONVERT16(sampptr[1][n], (n << 1) + 1, signconv);
-			}
-		} else {
-			for (n = 0; n < size; n++) {
-				CONVERT16(sampptr[0][n], n, signconv);
-			}
+		for (n = 0; n < size * n_channels; n++) {
+			CONVERT16(sampptr[0][n], n, signconv);
 		}
 	} else {
 		char signconv = unsign ? 0x80 : 0x00;
 
-		if (n_channels == 2) {
-			for (n = 0; n < size; n++) {
-				CONVERT8(sampptr[0][n], n << 1, signconv);
-			}
-			for (n = 0; n < size; n++) {
-				CONVERT8(sampptr[1][n], (n << 1) + 1, signconv);
-			}
-		} else {
-			for (n = 0; n < size; n++) {
-				CONVERT8(sampptr[0][n], n, signconv);
-			}
+		for (n = 0; n < size * n_channels; n++) {
+			CONVERT8(sampptr[0][n], n, signconv);
 		}
 	}
 
--- a/dumb/src/core/rendsig.c
+++ b/dumb/src/core/rendsig.c
@@ -35,7 +35,7 @@
 	long pos;
 	int subpos;
 
-	DUH_SIGRENDERER_ANALYSER_CALLBACK callback;
+	DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback;
 	void *callback_data;
 };
 
@@ -111,6 +111,21 @@
 	DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data
 )
 {
+	(void)sigrenderer;
+	(void)callback;
+	(void)data;
+	fprintf(stderr,
+		"Call to deprecated function duh_sigrenderer_set_analyser_callback(). The\n"
+		"callback was not installed. See dumb/docs/deprec.txt for how to fix this.\n");
+}
+
+
+
+void duh_sigrenderer_set_sample_analyser_callback(
+	DUH_SIGRENDERER *sigrenderer,
+	DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data
+)
+{
 	if (sigrenderer) {
 		sigrenderer->callback = callback;
 		sigrenderer->callback_data = data;
@@ -157,7 +172,7 @@
 
 
 
-long duh_sigrenderer_get_samples(
+long duh_sigrenderer_generate_samples(
 	DUH_SIGRENDERER *sigrenderer,
 	float volume, float delta,
 	long size, sample_t **samples
@@ -168,7 +183,7 @@
 
 	if (!sigrenderer) return 0;
 
-	rendered = (*sigrenderer->desc->sigrenderer_get_samples)
+	rendered = (*sigrenderer->desc->sigrenderer_generate_samples)
 				(sigrenderer->sigrenderer, volume, delta, size, samples);
 
 	if (rendered) {
@@ -188,6 +203,31 @@
 
 
 /* DEPRECATED */
+long duh_sigrenderer_get_samples(
+	DUH_SIGRENDERER *sigrenderer,
+	float volume, float delta,
+	long size, sample_t **samples
+)
+{
+	sample_t **s;
+	long rendered;
+	long i;
+	int j;
+	if (!samples) return duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, NULL);
+	s = allocate_sample_buffer(sigrenderer->n_channels, size);
+	if (!s) return 0;
+	dumb_silence(s[0], sigrenderer->n_channels * size);
+	rendered = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, s);
+	for (j = 0; j < sigrenderer->n_channels; j++)
+		for (i = 0; i < rendered; i++)
+			samples[j][i] += s[0][i*sigrenderer->n_channels+j];
+	destroy_sample_buffer(s);
+	return rendered;
+}
+
+
+
+/* DEPRECATED */
 long duh_render_signal(
 	DUH_SIGRENDERER *sigrenderer,
 	float volume, float delta,
@@ -194,15 +234,18 @@
 	long size, sample_t **samples
 )
 {
-	sample_t **s = create_sample_buffer(sigrenderer->n_channels, size);
+	sample_t **s;
 	long rendered;
 	long i;
 	int j;
+	if (!samples) return duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, NULL);
+	s = allocate_sample_buffer(sigrenderer->n_channels, size);
 	if (!s) return 0;
-	rendered = duh_sigrenderer_get_samples(sigrenderer, volume, delta, size, s);
+	dumb_silence(s[0], sigrenderer->n_channels * size);
+	rendered = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, s);
 	for (j = 0; j < sigrenderer->n_channels; j++)
 		for (i = 0; i < rendered; i++)
-			samples[j][i] += s[j][i] >> 8;
+			samples[j][i] += s[0][i*sigrenderer->n_channels+j] >> 8;
 	destroy_sample_buffer(s);
 	return rendered;
 }
--- a/dumb/src/helpers/clickrem.c
+++ b/dumb/src/helpers/clickrem.c
@@ -125,7 +125,7 @@
 
 
 
-void dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, long length, float halflife)
+void dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, long length, int step, float halflife)
 {
 	DUMB_CLICK *click;
 	long pos = 0;
@@ -140,21 +140,26 @@
 	cr->click = NULL;
 	cr->n_clicks = 0;
 
+	length *= step;
+
 	while (click) {
 		DUMB_CLICK *next = click->next;
-		ASSERT(click->pos <= length);
+		int end = click->pos * step;
+		ASSERT(end <= length);
 		offset = cr->offset;
 		if (offset < 0) {
 			offset = -offset;
-			while (pos < click->pos) {
-				samples[pos++] -= offset;
+			while (pos < end) {
+				samples[pos] -= offset;
 				offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32);
+				pos += step;
 			}
 			offset = -offset;
 		} else {
-			while (pos < click->pos) {
-				samples[pos++] += offset;
+			while (pos < end) {
+				samples[pos] += offset;
 				offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32);
+				pos += step;
 			}
 		}
 		cr->offset = offset - click->step;
@@ -166,14 +171,16 @@
 	if (offset < 0) {
 		offset = -offset;
 		while (pos < length) {
-			samples[pos++] -= offset;
+			samples[pos] -= offset;
 			offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
+			pos += step;
 		}
 		offset = -offset;
 	} else {
 		while (pos < length) {
-			samples[pos++] += offset;
+			samples[pos] += offset;
 			offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
+			pos += step;
 		}
 	}
 	cr->offset = offset;
@@ -242,8 +249,12 @@
 {
 	if (cr) {
 		int i;
-		for (i = 0; i < n; i++)
-			dumb_remove_clicks(cr[i], samples[i], length, halflife);
+		for (i = 0; i < n >> 1; i++) {
+			dumb_remove_clicks(cr[i << 1], samples[i], length, 2, halflife);
+			dumb_remove_clicks(cr[(i << 1) + 1], samples[i] + 1, length, 2, halflife);
+		}
+		if (n & 1)
+			dumb_remove_clicks(cr[i << 1], samples[i], length, 1, halflife);
 	}
 }
 
--- /dev/null
+++ b/dumb/src/helpers/resamp2.inc
@@ -1,0 +1,160 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * resamp2.inc - Resampling helper template.          / / \  \
+ *                                                   | <  /   \_
+ * By Bob and entheh.                                |  \/ /\   /
+ *                                                    \_  /  > /
+ * In order to find a good trade-off between            | \ / /
+ * speed and accuracy in this code, some tests          |  ' /
+ * were carried out regarding the behaviour of           \__/
+ * long long ints with gcc. The following code
+ * was tested:
+ *
+ * int a, b, c;
+ * c = ((long long)a * b) >> 16;
+ *
+ * DJGPP GCC Version 3.0.3 generated the following assembly language code for
+ * the multiplication and scaling, leaving the 32-bit result in EAX.
+ *
+ * movl  -8(%ebp), %eax    ; read one int into EAX
+ * imull -4(%ebp)          ; multiply by the other; result goes in EDX:EAX
+ * shrdl $16, %edx, %eax   ; shift EAX right 16, shifting bits in from EDX
+ *
+ * Note that a 32*32->64 multiplication is performed, allowing for high
+ * accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally),
+ * so it is a minor concern when four multiplications are being performed
+ * (the cubic resampler). On the Pentium MMX and earlier, it takes four or
+ * more cycles, so this method is unsuitable for use in the low-quality
+ * resamplers.
+ *
+ * Since "long long" is a gcc-specific extension, we use LONG_LONG instead,
+ * defined in dumb.h. We may investigate later what code MSVC generates, but
+ * if it seems too slow then we suggest you use a good compiler.
+ *
+ * FIXME: these comments are somewhat out of date now.
+ */
+
+
+
+#define SUFFIX3 _1
+
+/* For convenience, returns nonzero on stop. */
+static int process_pickup(DUMB_RESAMPLER *resampler)
+{
+	if (resampler->overshot < 0) {
+		resampler->overshot = 0;
+		dumb_resample(resampler, NULL, 2, MONO_DEST_VOLUME_ZEROS, 1.0f); /* Doesn't matter which SUFFIX3. */
+		COPYSRC(resampler->X, 0, resampler->X, 1);
+	}
+
+	for (;;) {
+		SRCTYPE *src = resampler->src;
+
+		if (resampler->dir < 0) {
+			if (resampler->overshot >= 3 && resampler->pos+3 >= resampler->start) COPYSRC(resampler->X, 0, src, resampler->pos+3);
+			if (resampler->overshot >= 2 && resampler->pos+2 >= resampler->start) COPYSRC(resampler->X, 1, src, resampler->pos+2);
+			if (resampler->overshot >= 1 && resampler->pos+1 >= resampler->start) COPYSRC(resampler->X, 2, src, resampler->pos+1);
+			resampler->overshot = resampler->start - resampler->pos - 1;
+		} else {
+			if (resampler->overshot >= 3 && resampler->pos-3 < resampler->end) COPYSRC(resampler->X, 0, src, resampler->pos-3);
+			if (resampler->overshot >= 2 && resampler->pos-2 < resampler->end) COPYSRC(resampler->X, 1, src, resampler->pos-2);
+			if (resampler->overshot >= 1 && resampler->pos-1 < resampler->end) COPYSRC(resampler->X, 2, src, resampler->pos-1);
+			resampler->overshot = resampler->pos - resampler->end;
+		}
+
+		if (resampler->overshot < 0) {
+			resampler->overshot = 0;
+			return 0;
+		}
+
+		if (!resampler->pickup) {
+			resampler->dir = 0;
+			return 1;
+		}
+		(*resampler->pickup)(resampler, resampler->pickup_data);
+		if (resampler->dir == 0) return 1;
+		ASSERT(resampler->dir == -1 || resampler->dir == 1);
+	}
+}
+
+
+
+/* Create mono destination resampler. */
+/* SUFFIX3 was set above. */
+#define VOLUME_PARAMETERS MONO_DEST_VOLUME_PARAMETERS
+#define VOLUME_VARIABLES MONO_DEST_VOLUME_VARIABLES
+#define SET_VOLUME_VARIABLES SET_MONO_DEST_VOLUME_VARIABLES
+#define RETURN_VOLUME_VARIABLES RETURN_MONO_DEST_VOLUME_VARIABLES
+#define VOLUMES_ARE_ZERO MONO_DEST_VOLUMES_ARE_ZERO
+#define MIX_ALIAS(op, upd, offset) MONO_DEST_MIX_ALIAS(op, upd, offset)
+#define MIX_LINEAR(op, upd, o0, o1) MONO_DEST_MIX_LINEAR(op, upd, o0, o1)
+#define MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) MONO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3)
+#define MIX_ZEROS(op) *dst++ op 0
+#include "resamp3.inc"
+
+/* Create stereo destination resampler. */
+#define SUFFIX3 _2
+#define VOLUME_PARAMETERS DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right
+#define VOLUME_VARIABLES lvol, lvolr, lvold, lvolt, lvolm, rvol, rvolr, rvold, rvolt, rvolm
+#define SET_VOLUME_VARIABLES { \
+	if ( volume_left ) { \
+		lvolr = (int)floor(volume_left->volume * 65536.0 + 0.5); \
+		lvold = (int)floor(volume_left->delta * 65536.0 + 0.5); \
+		lvolt = (int)floor(volume_left->target * 65536.0 + 0.5); \
+		lvolm = (int)floor(volume_left->mix * 65536.0 + 0.5); \
+		lvol = MULSC( lvolr, lvolm ); \
+		if ( lvolr == lvolt ) volume_left = NULL; \
+	} else { \
+		lvol = 0; \
+		lvolt = 0; \
+	} \
+	if ( volume_right ) { \
+		rvolr = (int)floor(volume_right->volume * 65536.0 + 0.5); \
+		rvold = (int)floor(volume_right->delta * 65536.0 + 0.5); \
+		rvolt = (int)floor(volume_right->target * 65536.0 + 0.5); \
+		rvolm = (int)floor(volume_right->mix * 65536.0 + 0.5); \
+		rvol = MULSC( rvolr, rvolm ); \
+		if ( rvolr == rvolt ) volume_left = NULL; \
+	} else { \
+		rvol = 0; \
+		rvolt = 0; \
+	} \
+}
+#define RETURN_VOLUME_VARIABLES { \
+	if ( volume_left ) volume_left->volume = (float)lvolr / 65536.0f; \
+	if ( volume_right ) volume_right->volume = (float)rvolr / 65536.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)
+#define MIX_LINEAR(op, upd, o0, o1) STEREO_DEST_MIX_LINEAR(op, upd, o0, o1)
+#define MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) STEREO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3)
+#define MIX_ZEROS(op) { *dst++ op 0; *dst++ op 0; }
+#include "resamp3.inc"
+
+
+
+#undef STEREO_DEST_MIX_CUBIC
+#undef MONO_DEST_MIX_CUBIC
+#undef STEREO_DEST_MIX_LINEAR
+#undef MONO_DEST_MIX_LINEAR
+#undef STEREO_DEST_MIX_ALIAS
+#undef MONO_DEST_MIX_ALIAS
+#undef MONO_DEST_VOLUMES_ARE_ZERO
+#undef SET_MONO_DEST_VOLUME_VARIABLES
+#undef RETURN_MONO_DEST_VOLUME_VARIABLES
+#undef MONO_DEST_VOLUME_ZEROS
+#undef MONO_DEST_VOLUME_VARIABLES
+#undef MONO_DEST_VOLUME_PARAMETERS
+#undef COPYSRC2
+#undef COPYSRC
+#undef DIVIDE_BY_SRC_CHANNELS
+#undef SRC_CHANNELS
+#undef SUFFIX2
--- /dev/null
+++ b/dumb/src/helpers/resamp3.inc
@@ -1,0 +1,372 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * resamp3.inc - Resampling helper template.          / / \  \
+ *                                                   | <  /   \_
+ * By Bob and entheh.                                |  \/ /\   /
+ *                                                    \_  /  > /
+ * In order to find a good trade-off between            | \ / /
+ * speed and accuracy in this code, some tests          |  ' /
+ * were carried out regarding the behaviour of           \__/
+ * long long ints with gcc. The following code
+ * was tested:
+ *
+ * int a, b, c;
+ * c = ((long long)a * b) >> 16;
+ *
+ * DJGPP GCC Version 3.0.3 generated the following assembly language code for
+ * the multiplication and scaling, leaving the 32-bit result in EAX.
+ *
+ * movl  -8(%ebp), %eax    ; read one int into EAX
+ * imull -4(%ebp)          ; multiply by the other; result goes in EDX:EAX
+ * shrdl $16, %edx, %eax   ; shift EAX right 16, shifting bits in from EDX
+ *
+ * Note that a 32*32->64 multiplication is performed, allowing for high
+ * accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally),
+ * so it is a minor concern when four multiplications are being performed
+ * (the cubic resampler). On the Pentium MMX and earlier, it takes four or
+ * more cycles, so this method is unsuitable for use in the low-quality
+ * resamplers.
+ *
+ * Since "long long" is a gcc-specific extension, we use LONG_LONG instead,
+ * defined in dumb.h. We may investigate later what code MSVC generates, but
+ * if it seems too slow then we suggest you use a good compiler.
+ *
+ * FIXME: these comments are somewhat out of date now.
+ */
+
+
+
+long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, VOLUME_PARAMETERS, float delta)
+{
+	int dt;
+	int VOLUME_VARIABLES;
+	long done;
+	long todo;
+	int quality;
+
+	if (!resampler || resampler->dir == 0) return 0;
+	ASSERT(resampler->dir == -1 || resampler->dir == 1);
+
+	done = 0;
+	dt = (int)(delta * 65536.0 + 0.5);
+	SET_VOLUME_VARIABLES;
+
+	if (VOLUMES_ARE_ZERO) dst = NULL;
+
+	init_cubic();
+
+	quality = resampler->quality;
+
+	while (done < dst_size) {
+		if (process_pickup(resampler)) {
+			RETURN_VOLUME_VARIABLES;
+			return done;
+		}
+
+		if ((resampler->dir ^ dt) < 0)
+			dt = -dt;
+
+		if (resampler->dir < 0)
+			todo = (long)((((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);
+
+		if (todo < 0)
+			todo = 0;
+		else if (todo > dst_size - done)
+			todo = dst_size - done;
+
+		done += todo;
+
+		{
+			SRCTYPE *src = resampler->src;
+			long pos = resampler->pos;
+			int subpos = resampler->subpos;
+			long diff = pos;
+			long overshot;
+			if (resampler->dir < 0) {
+				if (!dst) {
+					/* Silence or simulation */
+					LONG_LONG new_subpos = subpos + (LONG_LONG)dt * todo;
+					pos += (long)(new_subpos >> 16);
+					subpos = (long)new_subpos & 65535;
+				} else if (quality <= DUMB_RQ_ALIASING) {
+					/* Aliasing, backwards */
+					SRCTYPE xbuf[2*SRC_CHANNELS];
+					SRCTYPE *x = &xbuf[0];
+					SRCTYPE *xstart;
+					COPYSRC(xbuf, 0, resampler->X, 1);
+					COPYSRC(xbuf, 1, resampler->X, 2);
+					while (todo && x < &xbuf[2*SRC_CHANNELS]) {
+						// TODO: check what happens when multiple tempo slides occur per row
+						HEAVYASSERT(pos >= resampler->start);
+						MIX_ALIAS(+=, 1, 0);
+						subpos += dt;
+						pos += subpos >> 16;
+						x -= (subpos >> 16) * SRC_CHANNELS;
+						subpos &= 65535;
+						todo--;
+					}
+					x = xstart = &src[pos*SRC_CHANNELS];
+					LOOP4(todo,
+						MIX_ALIAS(+=, 1, 2);
+						subpos += dt;
+						x += (subpos >> 16) * SRC_CHANNELS;
+						subpos &= 65535;
+					);
+					pos += DIVIDE_BY_SRC_CHANNELS(x - xstart);
+				} else if (quality <= DUMB_RQ_LINEAR) {
+					/* Linear interpolation, backwards */
+					SRCTYPE xbuf[3*SRC_CHANNELS];
+					SRCTYPE *x = &xbuf[1*SRC_CHANNELS];
+					COPYSRC(xbuf, 0, resampler->X, 1);
+					COPYSRC(xbuf, 1, resampler->X, 2);
+					COPYSRC(xbuf, 2, src, pos);
+					while (todo && x < &xbuf[3*SRC_CHANNELS]) {
+						HEAVYASSERT(pos >= resampler->start);
+						MIX_LINEAR(+=, 1, 0, -1);
+						subpos += dt;
+						pos += subpos >> 16;
+						x -= (subpos >> 16) * SRC_CHANNELS;
+						subpos &= 65535;
+						todo--;
+					}
+					// TODO: use xstart for others too
+					x = &src[pos*SRC_CHANNELS];
+					LOOP4(todo,
+						HEAVYASSERT(pos >= resampler->start);
+						MIX_LINEAR(+=, 1, 1, 2);
+						subpos += dt;
+						pos += subpos >> 16;
+						x += (subpos >> 16) * SRC_CHANNELS;
+						subpos &= 65535;
+					);
+				} else {
+					/* Cubic interpolation, backwards */
+					SRCTYPE xbuf[6*SRC_CHANNELS];
+					SRCTYPE *x = &xbuf[3*SRC_CHANNELS];
+					COPYSRC(xbuf, 0, resampler->X, 0);
+					COPYSRC(xbuf, 1, resampler->X, 1);
+					COPYSRC(xbuf, 2, resampler->X, 2);
+					COPYSRC(xbuf, 3, src, pos);
+					if (pos-1 >= resampler->start) COPYSRC(xbuf, 4, src, pos-1);
+					if (pos-2 >= resampler->start) COPYSRC(xbuf, 5, src, pos-2);
+					while (todo && x < &xbuf[6*SRC_CHANNELS]) {
+						HEAVYASSERT(pos >= resampler->start);
+						MIX_CUBIC(+=, 1, x, x, 0, -1, -2, -3);
+						subpos += dt;
+						pos += subpos >> 16;
+						x -= (subpos >> 16) * SRC_CHANNELS;
+						subpos &= 65535;
+						todo--;
+					}
+					x = &src[pos*SRC_CHANNELS];
+					LOOP4(todo,
+						HEAVYASSERT(pos >= resampler->start);
+						MIX_CUBIC(+=, 1, x, x, 0, 1, 2, 3);
+						subpos += dt;
+						pos += subpos >> 16;
+						x += (subpos >> 16) * SRC_CHANNELS;
+						subpos &= 65535;
+					);
+				}
+				diff = diff - pos;
+				overshot = resampler->start - pos - 1;
+				if (diff >= 3) {
+					COPYSRC2(resampler->X, 0, overshot < 3, src, pos+3);
+					COPYSRC2(resampler->X, 1, overshot < 2, src, pos+2);
+					COPYSRC2(resampler->X, 2, overshot < 1, src, pos+1);
+				} else if (diff >= 2) {
+					COPYSRC(resampler->X, 0, resampler->X, 2);
+					COPYSRC2(resampler->X, 1, overshot < 2, src, pos+2);
+					COPYSRC2(resampler->X, 2, overshot < 1, src, pos+1);
+				} else if (diff >= 1) {
+					COPYSRC(resampler->X, 0, resampler->X, 1);
+					COPYSRC(resampler->X, 1, resampler->X, 2);
+					COPYSRC2(resampler->X, 2, overshot < 1, src, pos+1);
+				}
+			} else {
+				if (!dst) {
+					/* Silence or simulation */
+					LONG_LONG new_subpos = subpos + (LONG_LONG)dt * todo;
+					pos += (long)(new_subpos >> 16);
+					subpos = (long)new_subpos & 65535;
+				} else if (dumb_resampling_quality <= DUMB_RQ_ALIASING) {
+					/* Aliasing, forwards */
+					SRCTYPE xbuf[2*SRC_CHANNELS];
+					SRCTYPE *x = &xbuf[0];
+					SRCTYPE *xstart;
+					COPYSRC(xbuf, 0, resampler->X, 1);
+					COPYSRC(xbuf, 1, resampler->X, 2);
+					while (todo && x < &xbuf[2*SRC_CHANNELS]) {
+						HEAVYASSERT(pos < resampler->end);
+						MIX_ALIAS(+=, 1, 0);
+						subpos += dt;
+						pos += subpos >> 16;
+						x += (subpos >> 16) * SRC_CHANNELS;
+						subpos &= 65535;
+						todo--;
+					}
+					x = xstart = &src[pos*SRC_CHANNELS];
+					LOOP4(todo,
+						MIX_ALIAS(+=, 1, -2);
+						subpos += dt;
+						x += (subpos >> 16) * SRC_CHANNELS;
+						subpos &= 65535;
+					);
+					pos += DIVIDE_BY_SRC_CHANNELS(x - xstart);
+				} else if (dumb_resampling_quality <= DUMB_RQ_LINEAR) {
+					/* Linear interpolation, forwards */
+					SRCTYPE xbuf[3*SRC_CHANNELS];
+					SRCTYPE *x = &xbuf[1*SRC_CHANNELS];
+					COPYSRC(xbuf, 0, resampler->X, 1);
+					COPYSRC(xbuf, 1, resampler->X, 2);
+					COPYSRC(xbuf, 2, src, pos);
+					while (todo && x < &xbuf[3*SRC_CHANNELS]) {
+						HEAVYASSERT(pos < resampler->end);
+						MIX_LINEAR(+=, 1, -1, 0);
+						subpos += dt;
+						pos += subpos >> 16;
+						x += (subpos >> 16) * SRC_CHANNELS;
+						subpos &= 65535;
+						todo--;
+					}
+					x = &src[pos*SRC_CHANNELS];
+					LOOP4(todo,
+						HEAVYASSERT(pos < resampler->end);
+						MIX_LINEAR(+=, 1, -2, -1);
+						subpos += dt;
+						pos += subpos >> 16;
+						x += (subpos >> 16) * SRC_CHANNELS;
+						subpos &= 65535;
+					);
+				} else {
+					/* Cubic interpolation, forwards */
+					SRCTYPE xbuf[6*SRC_CHANNELS];
+					SRCTYPE *x = &xbuf[3*SRC_CHANNELS];
+					COPYSRC(xbuf, 0, resampler->X, 0);
+					COPYSRC(xbuf, 1, resampler->X, 1);
+					COPYSRC(xbuf, 2, resampler->X, 2);
+					COPYSRC(xbuf, 3, src, pos);
+					if (pos+1 < resampler->end) COPYSRC(xbuf, 4, src, pos+1);
+					if (pos+2 < resampler->end) COPYSRC(xbuf, 5, src, pos+2);
+					while (todo && x < &xbuf[6*SRC_CHANNELS]) {
+						HEAVYASSERT(pos < resampler->end);
+						MIX_CUBIC(+=, 1, x, x, -3, -2, -1, 0);
+						subpos += dt;
+						pos += subpos >> 16;
+						x += (subpos >> 16) * SRC_CHANNELS;
+						subpos &= 65535;
+						todo--;
+					}
+					x = &src[pos*SRC_CHANNELS];
+					LOOP4(todo,
+						HEAVYASSERT(pos < resampler->end);
+						MIX_CUBIC(+=, 1, x, x, -3, -2, -1, 0);
+						subpos += dt;
+						pos += subpos >> 16;
+						x += (subpos >> 16) * SRC_CHANNELS;
+						subpos &= 65535;
+					);
+				}
+				diff = pos - diff;
+				overshot = pos - resampler->end;
+				if (diff >= 3) {
+					COPYSRC2(resampler->X, 0, overshot < 3, src, pos-3);
+					COPYSRC2(resampler->X, 1, overshot < 2, src, pos-2);
+					COPYSRC2(resampler->X, 2, overshot < 1, src, pos-1);
+				} else if (diff >= 2) {
+					COPYSRC(resampler->X, 0, resampler->X, 2);
+					COPYSRC2(resampler->X, 1, overshot < 2, src, pos-2);
+					COPYSRC2(resampler->X, 2, overshot < 1, src, pos-1);
+				} else if (diff >= 1) {
+					COPYSRC(resampler->X, 0, resampler->X, 1);
+					COPYSRC(resampler->X, 1, resampler->X, 2);
+					COPYSRC2(resampler->X, 2, overshot < 1, src, pos-1);
+				}
+			}
+			resampler->pos = pos;
+			resampler->subpos = subpos;
+		}
+	}
+
+	RETURN_VOLUME_VARIABLES;
+	return done;
+}
+
+
+
+void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETERS, sample_t *dst)
+{
+	int VOLUME_VARIABLES;
+	SRCTYPE *src;
+	long pos;
+	int subpos;
+	int quality;
+	SRCTYPE *x;
+
+	if (!resampler || resampler->dir == 0) { MIX_ZEROS(=); return; }
+	ASSERT(resampler->dir == -1 || resampler->dir == 1);
+
+	if (process_pickup(resampler)) { MIX_ZEROS(=); return; }
+
+	SET_VOLUME_VARIABLES;
+
+	if (VOLUMES_ARE_ZERO) { MIX_ZEROS(=); return; }
+
+	init_cubic();
+
+	quality = resampler->quality;
+
+	src = resampler->src;
+	pos = resampler->pos;
+	subpos = resampler->subpos;
+	x = resampler->X;
+
+	if (resampler->dir < 0) {
+		HEAVYASSERT(pos >= resampler->start);
+		if (dumb_resampling_quality <= DUMB_RQ_ALIASING) {
+			/* Aliasing, backwards */
+			MIX_ALIAS(=, 0, 1);
+		} else if (quality <= DUMB_RQ_LINEAR) {
+			/* Linear interpolation, backwards */
+			MIX_LINEAR(=, 0, 2, 1);
+		} else {
+			/* Cubic interpolation, backwards */
+			MIX_CUBIC(=, 0, src, x, pos, 2, 1, 0);
+		}
+	} else {
+		HEAVYASSERT(pos < resampler->end);
+		if (dumb_resampling_quality <= DUMB_RQ_ALIASING) {
+			/* Aliasing */
+			MIX_ALIAS(=, 0, 1);
+		} else if (dumb_resampling_quality <= DUMB_RQ_LINEAR) {
+			/* Linear interpolation, forwards */
+			MIX_LINEAR(=, 0, 1, 2);
+		} else {
+			/* Cubic interpolation, forwards */
+			MIX_CUBIC(=, 0, x, src, 0, 1, 2, pos);
+		}
+	}
+}
+
+
+
+#undef MIX_ZEROS
+#undef MIX_CUBIC
+#undef MIX_LINEAR
+#undef MIX_ALIAS
+#undef VOLUMES_ARE_ZERO
+#undef SET_VOLUME_VARIABLES
+#undef RETURN_VOLUME_VARIABLES
+#undef VOLUME_VARIABLES
+#undef VOLUME_PARAMETERS
+#undef SUFFIX3
--- a/dumb/src/helpers/resample.c
+++ b/dumb/src/helpers/resample.c
@@ -59,6 +59,13 @@
 
 
 
+/* Make MSVC shut the hell up about if ( upd ) UPDATE_VOLUME() conditions being constant */
+#ifdef _MSC_VER
+#pragma warning(disable:4127 4701)
+#endif
+
+
+
 /* A global variable for controlling resampling quality wherever a local
  * specification doesn't override it. The following values are valid:
  *
@@ -108,13 +115,6 @@
 #define PASTERAW(a, b) a ## b /* This does not expand macros in b ... */
 #define PASTE(a, b) PASTERAW(a, b) /* ... but b is expanded during this substitution. */
 
-#define dumb_reset_resampler PASTE(dumb_reset_resampler, SUFFIX)
-#define dumb_start_resampler PASTE(dumb_start_resampler, SUFFIX)
-#define process_pickup PASTE(process_pickup, SUFFIX)
-#define dumb_resample PASTE(dumb_resample, SUFFIX)
-#define dumb_resample_get_current_sample PASTE(dumb_resample_get_current_sample, SUFFIX)
-#define dumb_end_resampler PASTE(dumb_end_resampler, SUFFIX)
-
 #define X PASTE(x.x, SRCBITS)
 
 
@@ -154,18 +154,29 @@
 	if (done) return;
 	done = 1;
 	for (t = 0; t < 1025; t++) {
-		cubicA0[t] = -(  t*t*t >> 17) + (  t*t >> 6) - (t << 3);
-		cubicA1[t] =  (3*t*t*t >> 17) - (5*t*t >> 7)            + (1 << 14);
+		/* int casts to pacify warnings about negating unsigned values */
+		cubicA0[t] = -(int)(  t*t*t >> 17) + (int)(  t*t >> 6) - (int)(t << 3);
+		cubicA1[t] =  (int)(3*t*t*t >> 17) - (int)(5*t*t >> 7)                 + (int)(1 << 14);
 	}
 }
 
 
 
-#define SUFFIX
+/* Create resamplers for 24-in-32-bit source samples. */
+
+/* #define SUFFIX
+ * MSVC warns if we try to paste a null SUFFIX, so instead we define
+ * special macros for the function names that don't bother doing the
+ * corresponding paste. The more generic definitions are further down.
+ */
+#define process_pickup PASTE(process_pickup, SUFFIX2)
+#define dumb_resample PASTE(PASTE(dumb_resample, SUFFIX2), SUFFIX3)
+#define dumb_resample_get_current_sample PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX2), SUFFIX3)
+
 #define SRCTYPE sample_t
 #define SRCBITS 24
-#define ALIAS(x) MULSC(x, vol)
-#define LINEAR(x0, x1) MULSC(x0 + MULSC(x1 - x0, subpos), vol)
+#define ALIAS(x, vol) MULSC(x, vol)
+#define LINEAR(x0, x1) (x0 + MULSC(x1 - x0, subpos))
 /*
 #define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
 	a = (3 * (x1 - x2) + (x3 - x0)) >> 1; \
@@ -174,18 +185,34 @@
 }
 #define CUBIC(d) MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + d, vol)
 */
-#define CUBIC(x0, x1, x2, x3) MULSC( \
+#define CUBIC(x0, x1, x2, x3) ( \
 	MULSC(x0, cubicA0[subpos >> 6] << 2) + \
 	MULSC(x1, cubicA1[subpos >> 6] << 2) + \
 	MULSC(x2, cubicA1[1 + (subpos >> 6 ^ 1023)] << 2) + \
-	MULSC(x3, cubicA0[1 + (subpos >> 6 ^ 1023)] << 2), vol)
+	MULSC(x3, cubicA0[1 + (subpos >> 6 ^ 1023)] << 2))
+#define CUBICVOL(x, vol) MULSC(x, vol)
 #include "resample.inc"
 
+/* Undefine the simplified macros. */
+#undef dumb_resample_get_current_sample
+#undef dumb_resample
+#undef process_pickup
+
+
+/* Now define the proper ones that use SUFFIX. */
+#define dumb_reset_resampler PASTE(dumb_reset_resampler, SUFFIX)
+#define dumb_start_resampler PASTE(dumb_start_resampler, SUFFIX)
+#define process_pickup PASTE(PASTE(process_pickup, SUFFIX), SUFFIX2)
+#define dumb_resample PASTE(PASTE(PASTE(dumb_resample, SUFFIX), SUFFIX2), SUFFIX3)
+#define dumb_resample_get_current_sample PASTE(PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX), SUFFIX2), SUFFIX3)
+#define dumb_end_resampler PASTE(dumb_end_resampler, SUFFIX)
+
+/* Create resamplers for 16-bit source samples. */
 #define SUFFIX _16
 #define SRCTYPE short
 #define SRCBITS 16
-#define ALIAS(x) MULSC16(x, vol)
-#define LINEAR(x0, x1) MULSC((x0 << 8) + MULSC16(x1 - x0, subpos), vol)
+#define ALIAS(x, vol) (x * vol >> 8)
+#define LINEAR(x0, x1) ((x0 << 8) + MULSC16(x1 - x0, subpos))
 /*
 #define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
 	a = (3 * (x1 - x2) + (x3 - x0)) << 7; \
@@ -194,18 +221,20 @@
 }
 #define CUBIC(d) MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + (d << 8), vol)
 */
-#define CUBIC(x0, x1, x2, x3) (int)((LONG_LONG)( \
+#define CUBIC(x0, x1, x2, x3) ( \
 	x0 * cubicA0[subpos >> 6] + \
 	x1 * cubicA1[subpos >> 6] + \
 	x2 * cubicA1[1 + (subpos >> 6 ^ 1023)] + \
-	x3 * cubicA0[1 + (subpos >> 6 ^ 1023)]) * (vol << 10) >> 32)
+	x3 * cubicA0[1 + (subpos >> 6 ^ 1023)])
+#define CUBICVOL(x, vol) (int)((LONG_LONG)(x) * (vol << 10) >> 32)
 #include "resample.inc"
 
+/* Create resamplers for 8-bit source samples. */
 #define SUFFIX _8
 #define SRCTYPE signed char
 #define SRCBITS 8
-#define ALIAS(x) (x * vol)
-#define LINEAR(x0, x1) MULSC((x0 << 16) + (x1 - x0) * subpos, vol)
+#define ALIAS(x, vol) (x * vol)
+#define LINEAR(x0, x1) ((x0 << 16) + (x1 - x0) * subpos)
 /*
 #define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
 	a = 3 * (x1 - x2) + (x3 - x0); \
@@ -214,15 +243,15 @@
 }
 #define CUBIC(d) MULSC(MULSC(MULSC((a * subpos >> 1) + b, subpos) + c, subpos) + (d << 16), vol)
 */
-#define CUBIC(x0, x1, x2, x3) (int)((LONG_LONG)(( \
+#define CUBIC(x0, x1, x2, x3) (( \
 	x0 * cubicA0[subpos >> 6] + \
 	x1 * cubicA1[subpos >> 6] + \
 	x2 * cubicA1[1 + (subpos >> 6 ^ 1023)] + \
-	x3 * cubicA0[1 + (subpos >> 6 ^ 1023)]) << 6) * (vol << 12) >> 32)
+	x3 * cubicA0[1 + (subpos >> 6 ^ 1023)]) << 6)
+#define CUBICVOL(x, vol) (int)((LONG_LONG)(x) * (vol << 12) >> 32)
 #include "resample.inc"
 
 
-
 #undef dumb_reset_resampler
 #undef dumb_start_resampler
 #undef process_pickup
@@ -232,712 +261,132 @@
 
 
 
-void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, long pos, long start, long end, int quality)
+void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, int src_channels, long pos, long start, long end, int quality)
 {
 	if (n == 8)
-		dumb_reset_resampler_8(resampler, src, pos, start, end, quality);
+		dumb_reset_resampler_8(resampler, src, src_channels, pos, start, end, quality);
 	else if (n == 16)
-		dumb_reset_resampler_16(resampler, src, pos, start, end, quality);
+		dumb_reset_resampler_16(resampler, src, src_channels, pos, start, end, quality);
 	else
-		dumb_reset_resampler(resampler, src, pos, start, end, quality);
+		dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality);
 }
 
 
 
-DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, long pos, long start, long end, int quality)
+DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels, long pos, long start, long end, int quality)
 {
 	if (n == 8)
-		return dumb_start_resampler_8(src, pos, start, end, quality);
+		return dumb_start_resampler_8(src, src_channels, pos, start, end, quality);
 	else if (n == 16)
-		return dumb_start_resampler_16(src, pos, start, end, quality);
+		return dumb_start_resampler_16(src, src_channels, pos, start, end, quality);
 	else
-		return dumb_start_resampler(src, pos, start, end, quality);
+		return dumb_start_resampler(src, src_channels, pos, start, end, quality);
 }
 
 
 
-long dumb_resample_n(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, float * volume, float volume_delta, float volume_target, float volume_mix, float delta)
+long dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta)
 {
 	if (n == 8)
-		return dumb_resample_8(resampler, dst, dst_size, volume, volume_delta, volume_target, volume_mix, delta);
+		return dumb_resample_8_1_1(resampler, dst, dst_size, volume, delta);
 	else if (n == 16)
-		return dumb_resample_16(resampler, dst, dst_size, volume, volume_delta, volume_target, volume_mix, delta);
+		return dumb_resample_16_1_1(resampler, dst, dst_size, volume, delta);
 	else
-		return dumb_resample(resampler, dst, dst_size, volume, volume_delta, volume_target, volume_mix, delta);
+		return dumb_resample_1_1(resampler, dst, dst_size, volume, delta);
 }
 
 
 
-sample_t dumb_resample_get_current_sample_n(int n, DUMB_RESAMPLER *resampler, float volume)
+long dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
 {
 	if (n == 8)
-		return dumb_resample_get_current_sample_8(resampler, volume);
+		return dumb_resample_8_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
 	else if (n == 16)
-		return dumb_resample_get_current_sample_16(resampler, volume);
+		return dumb_resample_16_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
 	else
-		return dumb_resample_get_current_sample(resampler, volume);
+		return dumb_resample_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
 }
 
 
 
-void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler)
+long dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
 {
 	if (n == 8)
-		return dumb_end_resampler_8(resampler);
+		return dumb_resample_8_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
 	else if (n == 16)
-		return dumb_end_resampler_16(resampler);
+		return dumb_resample_16_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
 	else
-		return dumb_end_resampler(resampler);
+		return dumb_resample_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
 }
 
 
 
-#if 0
-/* The following macro is used to overcome the fact that most C
- * compilers (including gcc and MSVC) can't correctly multiply signed
- * integers outside the range -32768 to 32767. i86 assembler versions
- * don't need to use this method, since the processor does in fact
- * have instructions to multiply large numbers correctly - which
- * means using assembly language could make a significant difference
- * to the speed.
- *
- * The basic method is as follows. We halve the subposition (how far
- * we are between samples), so it never exceeds 32767. We also halve
- * the delta, which is the amount to be added to the subposition each
- * time. Then we unroll the loop twofold, so that we can add the lost
- * one every other time if necessary (since the halving may have
- * resulted in rounding down).
- *
- * This method doesn't incur any cumulative inaccuracies. There is a
- * very slight loss of quality, which I challenge anyone to notice -
- * but the position will advance at *exactly* the same rate as it
- * would if we didn't use this method. This also means the pitch is
- * exactly the same, which may even make a difference to trained
- * musicians when resampling down a lot :)
- *
- * Each time this macro is invoked, DO_RESAMPLE(inc) must be defined
- * to calculate the samples by the appropriate equation (linear,
- * cubic, etc.). See the individual cases for examples of how this is
- * done.
- */
-#define MAKE_RESAMPLER()							\
-{													\
-	if (dt & 1) {									\
-		long todo2;									\
-													\
-		dt >>= 1;									\
-													\
-		if (src_subpos & 1) {						\
-			src_subpos >>= 1;						\
-			DO_RESAMPLE(1);							\
-			todo--;									\
-		} else										\
-			src_subpos >>= 1;						\
-													\
-		todo2 = todo >> 1;							\
-													\
-		while (todo2) {								\
-			DO_RESAMPLE(0);							\
-			DO_RESAMPLE(1);							\
-			todo2--;								\
-		}											\
-													\
-		if (todo & 1) {								\
-			DO_RESAMPLE(0);							\
-			src_subpos = (src_subpos << 1) | 1;		\
-		} else										\
-			src_subpos <<= 1;						\
-													\
-		todo = 0;									\
-		dt = (dt << 1) | 1;							\
-	} else {										\
-		long subposbit = src_subpos & 1;			\
-		dt >>= 1;									\
-		src_subpos >>= 1;							\
-													\
-		if (todo & 1) {								\
-			DO_RESAMPLE(0);							\
-		}											\
-													\
-		todo >>= 1;									\
-													\
-		while (todo) {								\
-			DO_RESAMPLE(0);							\
-			DO_RESAMPLE(0);							\
-			todo--;									\
-		}											\
-													\
-		src_subpos = (src_subpos << 1) | subposbit; \
-		dt <<= 1;									\
-	}												\
+long dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
+{
+	if (n == 8)
+		return dumb_resample_8_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
+	else if (n == 16)
+		return dumb_resample_16_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
+	else
+		return dumb_resample_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
 }
 
 
 
-sample_t dumb_resample_get_current_sample(
-	sample_t *src, long *_src_pos, int *_src_subpos,
-	long src_start, long src_end,
-	float volume, int *_dir,
-	DUMB_RESAMPLE_PICKUP pickup, void *pickup_data
-)
+void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst)
 {
-	long src_pos = *_src_pos;
-	int src_subpos = *_src_subpos;
-	int dir = _dir ? *_dir : 1;
+	if (n == 8)
+		dumb_resample_get_current_sample_8_1_1(resampler, volume, dst);
+	else if (n == 16)
+		dumb_resample_get_current_sample_16_1_1(resampler, volume, dst);
+	else
+		dumb_resample_get_current_sample_1_1(resampler, volume, dst);
+}
 
-	sample_t value = 0;
 
-	if (dir == 0)
-		return 0;
 
-	ASSERT(dir == 1 || dir == -1);
+void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
+{
+	if (n == 8)
+		dumb_resample_get_current_sample_8_1_2(resampler, volume_left, volume_right, dst);
+	else if (n == 16)
+		dumb_resample_get_current_sample_16_1_2(resampler, volume_left, volume_right, dst);
+	else
+		dumb_resample_get_current_sample_1_2(resampler, volume_left, volume_right, dst);
+}
 
-	if (dir < 0 ? (src_pos < src_start) : (src_pos >= src_end)) {
 
-		/* If there's no pick-up function, we stop. */
-		if (!pickup) {
-			dir = 0;
-			goto end;
-		}
 
-		/* Process the pick-up. It may need invoking more than once. */
-		do {
-			dir = (*pickup)(src, &src_pos, &src_subpos, &src_start, &src_end, dir, pickup_data);
-
-			if (dir == 0)
-				goto end;
-
-			ASSERT(dir == 1 || dir == -1);
-		} while (dir < 0 ? (src_pos < src_start) : (src_pos >= src_end));
-	}
-
-	HEAVYASSERT(dir < 0 ? (src_pos >= src_start) : (src_pos < src_end));
-
-	if (dumb_resampling_quality == 0) {
-		/* Aliasing (coarse) */
-		int volume_fact = (int)(volume * 16384.0);
-		value = (src[src_pos] * volume_fact) >> 14;
-	} else if (dumb_resampling_quality <= 2) {
-		/* Linear interpolation */
-		int volume_fact = (int)(volume * 16384.0);
-		int subpos = src_subpos >> 1;
-		value = ((src[src_pos] + ((((src[src_pos + 1] - src[src_pos]) >> 1) * subpos) >> 14)) * volume_fact) >> 14;
-	} else if (dumb_resampling_quality == 3) {
-		/* Quadratic interpolation */
-		int volume_fact = (int)(volume * 16384.0);
-		int a, b;
-		sample_t *x;
-		int subpos = src_subpos >> 1;
-		x = &src[src_pos];
-		a = ((x[0] + x[2]) >> 1) - x[1];
-		b = ((x[2] - x[0]) >> 1) - (a << 1);
-		value = (((((((a * subpos) >> 15) + b) * subpos) >> 15) + x[0]) * volume_fact) >> 14;
-	} else {
-		/* Cubic interpolation */
-		int volume_fact = (int)(volume * 16384.0);
-		int a, b, c;
-		sample_t *x;
-		int subpos = src_subpos >> 1;
-		x = &src[src_pos];
-		a = (((x[1] - x[2]) << 1) + (x[1] - x[2]) + (x[3] - x[0])) >> 1;
-		b = (x[2] << 1) + x[0] - ((5 * x[1] + x[3]) >> 1);
-		c = (x[2] - x[0]) >> 1;
-		value = (((int)(((LONG_LONG)((int)(((LONG_LONG)((int)(((LONG_LONG)a * subpos) >> 15) + b) * subpos) >> 15) + c) * subpos) >> 15) + x[1]) * volume_fact) >> 14;
-	}
-
-	end:
-
-	*_src_pos = src_pos;
-	*_src_subpos = src_subpos;
-	if (_dir) *_dir = dir;
-
-	return value;
+void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
+{
+	if (n == 8)
+		dumb_resample_get_current_sample_8_2_1(resampler, volume_left, volume_right, dst);
+	else if (n == 16)
+		dumb_resample_get_current_sample_16_2_1(resampler, volume_left, volume_right, dst);
+	else
+		dumb_resample_get_current_sample_2_1(resampler, volume_left, volume_right, dst);
 }
 
 
 
-long dumb_resample(
-	sample_t *src, long *_src_pos, int *_src_subpos,
-	long src_start, long src_end,
-	sample_t *dst, long dst_size,
-	float volume, float delta, int *_dir,
-	DUMB_RESAMPLE_PICKUP pickup, void *pickup_data
-)
+void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
 {
-	int dt = (int)(delta * 65536.0 + 0.5);
-	long s = 0; /* Current position in the destination buffer */
+	if (n == 8)
+		dumb_resample_get_current_sample_8_2_2(resampler, volume_left, volume_right, dst);
+	else if (n == 16)
+		dumb_resample_get_current_sample_16_2_2(resampler, volume_left, volume_right, dst);
+	else
+		dumb_resample_get_current_sample_2_2(resampler, volume_left, volume_right, dst);
+}
 
-	long src_pos = *_src_pos;
-	int src_subpos = *_src_subpos;
-	int dir = _dir ? *_dir : 1;
 
-	int linear_average;
 
-	if (dir == 0)
-		return 0;
-
-	ASSERT(dir == 1 || dir == -1);
-
-	linear_average = dst && dumb_resampling_quality >= 2 && dt > 65536;
-
-	if (dir < 0) dt = -dt;
-
-	if (linear_average)
-		volume /= delta;
-
-	while (s < dst_size) {
-
-		long todo;
-
-		/* Process pick-ups first, just in case. */
-
-		if (linear_average) {
-
-			/* For linear average, the pick-up point could split a sum into
-			 * two parts. We handle this by putting the pick-up code inside
-			 * the summing loop. Note that this code is only executed when we
-			 * know that a pick-up is necessary somewhere during this sum
-			 * (although it is always executed once for the first sample).
-			 * We use a separate loop further down when we know we won't have
-			 * to do a pick-up, so the condition does not need testing inside
-			 * the loop.
-			 */
-
-			float sum;
-			long i;
-			int advance;
-			int x[3];
-
-			advance = src_subpos + dt;
-
-			/* Make these negative. Then they stay within the necessary
-			 * range for integer multiplication, -32768 to 32767 ;)
-			 */
-			x[0] = ~(src_subpos >> 1); /* = -1 - (src_subpos >> 1) */
-			x[2] = x[0] ^ 0x7FFF; /* = -32768 + (src_subpos >> 1) */
-
-			sum = (float)(-((src[src_pos] * (x+1)[dir]) >> 15));
-
-			i = src_pos + (advance >> 16);
-			src_pos += dir;
-			src_subpos = (dir >> 1) & 65535; /* changes 1,-1 to 0,65535 */
-
-			advance &= 65535;
-
-			/* i is the index of the first sample NOT to sum fully,
-			 * regardless of the direction of resampling.
-			 */
-
-			while (dir < 0 ? (i < src_start) : (i >= src_end)) {
-				if (dir < 0) {
-					while (src_pos >= src_start)
-						sum += src[src_pos--];
-				} else {
-					while (src_pos < src_end)
-						sum += src[src_pos++];
-				}
-
-				i -= src_pos;
-				/* i is now the number of samples left to sum fully, except
-				 * it's negative if we're going backwards.
-				 */
-
-				if (!pickup) {
-					dir = 0;
-					goto endsum;
-				}
-
-				dir = (*pickup)(src, &src_pos, &src_subpos, &src_start, &src_end, dir, pickup_data);
-
-				if (dir == 0)
-					goto endsum;
-
-				ASSERT(dir == 1 || dir == -1);
-
-				if ((dir ^ dt) < 0) {
-					dt = -dt;
-					advance ^= 65535;
-					i = -i;
-				}
-
-				i += src_pos;
-				/* There, i is back to normal. */
-			}
-
-			for (; src_pos != i; src_pos += dir)
-				sum += src[src_pos];
-
-			src_subpos = advance;
-
-			x[2] = src_subpos >> 1;
-			x[0] = x[2] ^ 0x7FFF; /* = 32767 - (src_subpos >> 1) */
-
-			sum += (src[src_pos] * (x+1)[dir]) >> 15;
-
-			endsum:
-
-			sum *= volume;
-			dst[s] += (int)sum;
-
-			s++;
-
-			if (dir == 0)
-				break;
-
-		} else if (dir < 0 ? (src_pos < src_start) : (src_pos >= src_end)) {
-
-			/* If there's no pick-up function, we stop. */
-			if (!pickup) {
-				dir = 0;
-				break;
-			}
-
-			/* Process the pick-up. It may need invoking more than once. */
-			do {
-				dir = (*pickup)(src, &src_pos, &src_subpos, &src_start, &src_end, dir, pickup_data);
-
-				if (dir == 0)
-					goto end;
-
-				ASSERT(dir == 1 || dir == -1);
-			} while (dir < 0 ? (src_pos < src_start) : (src_pos >= src_end));
-
-			/* Update sign of dt to match that of dir. */
-			if ((dir ^ dt) < 0)
-				dt = -dt;
-		}
-
-		/* Work out how many contiguous samples we can now render. */
-		if (dir < 0)
-			todo = (long)((((LONG_LONG)(src_pos - src_start) << 16) + src_subpos) / -dt);
-		else
-			todo = (long)((((LONG_LONG)(src_end - src_pos) << 16) - src_subpos - 1) / dt);
-
-		/* The above equations work out how many complete dt-sized
-		 * intervals there are between the current position and the loop
-		 * point (provided there is a little fractional extra). The linear
-		 * average function needs complete intervals - but the other
-		 * resamplers only read a sample from the beginning of each interval,
-		 * so they can process one extra sample in their main loops (so we
-		 * increment todo in a moment).
-		 *
-		 * The linear average function makes up the extra sample using the
-		 * specialised pick-up code above.
-		 *
-		 * Note that our above pick-up process should have absolutely ensured
-		 * that the result of this function will be nonnegative.
-		 */
-
-		ASSERT(todo >= 0);
-
-		if (!linear_average)
-			todo++;
-
-		/* Of course we don't want to overrun the output buffer! */
-		if (todo > dst_size - s)
-			todo = dst_size - s;
-
-		if (!dst) {
-
-			LONG_LONG t = src_subpos + (LONG_LONG)dt * todo;
-			src_pos += (long)(t >> 16);
-			src_subpos = (int)t & 0xFFFFl;
-
-			s += todo;
-
-		} else if (linear_average) {
-
-			float sum;
-			long i;
-			int advance;
-			int x[3];
-
-			while (todo) {
-
-				advance = src_subpos + dt;
-
-				/* Make these negative. Then they stay within the necessary
-				 * range for integer multiplication, -32768 to 32767 ;)
-				 */
-				x[0] = ~(src_subpos >> 1); /* = -1 - (src_subpos >> 1) */
-				x[2] = x[0] ^ 0x7FFF; /* = -32768 + (src_subpos >> 1) */
-
-				sum = (float)(-((src[src_pos] * (x+1)[dir]) >> 15));
-
-				i = src_pos + (advance >> 16);
-				src_pos += dir;
-				src_subpos = (dir >> 1) & 65535; /* changes 1,-1 to 0,65535 */
-
-				advance &= 65535;
-
-				/* i is the index of the first sample NOT to sum fully,
-				 * regardless of the direction of resampling.
-				 */
-
-				HEAVYASSERT(dir < 0 ? (i >= src_start) : (i < src_end));
-
-				for (; src_pos != i; src_pos += dir)
-					sum += src[src_pos];
-
-				src_subpos = advance;
-
-				x[2] = src_subpos >> 1;
-				x[0] = x[2] ^ 0x7FFF; /* = 32767 - (src_subpos >> 1) */
-
-				sum += (src[src_pos] * (x+1)[dir]) >> 15;
-
-				sum *= volume;
-				dst[s] += (int)sum;
-
-				s++;
-				todo--;
-			}
-
-		} else if (dumb_resampling_quality == 0 || (dumb_resampling_quality == 1 && delta >= 1.0)) {
-
-			/* Aliasing (coarse) */
-			int volume_fact = (int)(volume * 16384.0);
-
-			do {
-				HEAVYASSERT(dir < 0 ? (src_pos >= src_start) : (src_pos < src_end));
-				dst[s] += ((src[src_pos] * volume_fact) >> 14);
-				src_subpos += dt;
-				src_pos += src_subpos >> 16;
-				src_subpos &= 0xFFFFl;
-				s++;
-			} while (--todo);
-
-		} else if (dumb_resampling_quality <= 2) {
-
-			/* Linear interpolation */
-			int volume_fact = (int)(volume * 16384.0);
-
-			#define DO_RESAMPLE(inc)		 \
-			{								 \
-				HEAVYASSERT(dir < 0 ? (src_pos >= src_start) : (src_pos < src_end)); \
-											 \
-				dst[s] += (((src[src_pos] + ((((src[src_pos + 1] - src[src_pos]) >> 1) * src_subpos) >> 14)) * volume_fact) >> 14); \
-											 \
-				src_subpos += dt + inc;		 \
-				src_pos += src_subpos >> 15; \
-				src_subpos &= 0x7FFFl;		 \
-				s++;						 \
-			}
-
-			MAKE_RESAMPLER();
-
-			#undef DO_RESAMPLE
-
-		} else if (dumb_resampling_quality == 3) {
-
-			/* Quadratic interpolation */
-
-			int volume_fact = (int)(volume * 16384.0);
-			int a = 0, b = 0;
-			sample_t *x = NULL;
-			int last_src_pos = -1;
-
-			/* AIM: no integer multiplicands must transcend the range -32768 to 32767.
-			 * This limitation is imposed by most compilers, including gcc and MSVC.
-			 *
-			 * a = 0.5 * (s0 + s2) - s1
-			 * b = -1.5 * s0 + 2 * s1 - 0.5 * s2
-			 * c = s0
-			 *
-			 * s = (a * t + b) * t + c
-			 *
-			 * In fixed-point:
-			 *
-			 * a = ((s0 + s2) >> 1) - s1
-			 * b = ((-3 * s0 - s2) >> 1) + (s1 << 1)
-			 *
-			 * s = (((((a * t) >> 16) + b) * t) >> 16) + s0
-			 *
-			 * With t halved (since t can reach 65535):
-			 *
-			 * s = (((((a * t) >> 15) + b) * t) >> 15) + s0
-			 *
-			 * a currently reaches 65536
-			 * b currently reaches 131072
-			 *
-			 * So we must use aon2
-			 *
-			 * s = (((((aon2 * t) >> 14) + b) * t) >> 15) + s0
-			 *
-			 * ((aon2 * t) >> 14) + b is 5 times too big
-			 * so we must divide by 8
-			 *
-			 * s = (((((aon2 * t) >> 17) + bon8) * t) >> 12) + s0
-			 *
-			 * aon2 = ((s0 + s2) >> 2) - (s1 >> 1)
-			 * bon8 = ((-3 * s0 - s2) >> 4) + (s1 >> 2)
-			 * or:
-			 * bon8 = ((s2 - s0) >> 4) - (aon2 >> 1)
-			 */
-
-			/* Unh4x0r3d version:
-			#define DO_RESAMPLE(inc)						\
-			{												\
-				HEAVYASSERT(dir < 0 ? (src_pos >= src_start) : (src_pos < src_end)); \
-															\
-				if (src_pos != last_src_pos) {				\
-					last_src_pos = src_pos;					\
-					x = &src[src_pos];						\
-					a = ((x[0] + x[2]) >> 2) - (x[1] >> 1); \
-					b = ((x[2] - x[0]) >> 4) - (a >> 1);	\
-				}											\
-															\
-				dst[s] += ((((((((a * src_subpos) >> 17) + b) * src_subpos) >> 12) + x[0]) * volume_fact) >> 14); \
-															\
-				src_subpos += dt + inc;						\
-				src_pos += src_subpos >> 15;				\
-				src_subpos &= 0x7FFFl;						\
-				s++;										\
-			}
-			*/
-
-			/* H4x0r3d version: */
-			#define DO_RESAMPLE(inc)						\
-			{												\
-				HEAVYASSERT(dir < 0 ? (src_pos >= src_start) : (src_pos < src_end)); \
-															\
-				if (src_pos != last_src_pos) {				\
-					last_src_pos = src_pos;					\
-					x = &src[src_pos];						\
-					a = ((x[0] + x[2]) >> 1) - x[1];		\
-					b = ((x[2] - x[0]) >> 1) - (a << 1);	\
-				}											\
-															\
-				dst[s] += ((((((((a * src_subpos) >> 15) + b) * src_subpos) >> 15) + x[0]) * volume_fact) >> 14); \
-															\
-				src_subpos += dt + inc;						\
-				src_pos += src_subpos >> 15;				\
-				src_subpos &= 0x7FFFl;						\
-				s++;										\
-			}
-
-			MAKE_RESAMPLER();
-
-			#undef DO_RESAMPLE
-
-		} else {
-
-			/* Cubic interpolation */
-
-			int volume_fact = (int)(volume * 16384.0);
-			int a = 0, b = 0, c = 0;
-			sample_t *x = NULL;
-			int last_src_pos = -1;
-
-			/* AIM: never multiply integers outside the range -32768 to 32767.
-			 *
-			 * a = 1.5f * (x[1] - x[2]) + (x[3] - x[0]) * 0.5f;
-			 * b = 2.0f * x[2] + x[0] - 2.5f * x[1] - x[3] * 0.5f;
-			 * c = (x[2] - x[0]) * 0.5f;
-			 *
-			 * s = ((a * t + b) * t + c) * t + x[1];
-			 *
-			 * Fixed-point version:
-			 *
-			 * a = (((x[1] - x[2]) << 1) + (x[1] - x[2]) + (x[3] - x[0])) >> 1;
-			 * b = (x[2] << 1) + x[0] - ((5 * x[1] + x[3]) >> 1);
-			 * c = (x[2] - x[0]) >> 1;
-			 *
-			 * s = ((((((((a * t) >> 15) + b) * t) >> 15) + c) * t) >> 15) + x[1];
-			 *   (with t already halved, maximum 32767)
-			 *
-			 * a is in (((1+1)*2)+(1+1)+(1+1))/2 = 8 times the required range
-			 * b is in (1*2)+1+((5*1+1)/2) = 6 times
-			 * c is in the required range
-			 *
-			 * We must use aon8
-			 *
-			 * s = ((((((((aon8 * t) >> 12) + b) * t) >> 15) + c) * t) >> 15) + x[1];
-			 *
-			 * But ((aon8 * t) >> 12) is in 2^(15+15-12) = 2^18 = 8 times
-			 * b is in 6 times
-			 * so we divide both ((aon8 * t) >> 12) and b by 16
-			 *
-			 * s = ((((((((aon8 * t) >> 16) + bon16) * t) >> 11) + c) * t) >> 15) + x[1];
-			 *
-			 * ((... + bon16) * t) >> 11 is 16 times too big
-			 * c is in the correct range
-			 * we must divide both by 32
-			 *
-			 * s = ((((((((aon8 * t) >> 16) + bon16) * t) >> 16) + con32) * t) >> 10) + x[1];
-			 *
-			 * aon8  = (((x[1] - x[2]) << 1) + (x[1] - x[2]) + (x[3] - x[0])) >> 4;
-			 * bon16 = ((x[2] << 2) + (x[0] << 1) - (5 * x[1] + x[3])) >> 5;
-			 * con32 = (x[2] - x[0]) >> 6;
-			 *
-			 * A lot of accuracy is lost here. It is quite likely that some
-			 * of the above would cancel anyway, so the scaling down wouldn't
-			 * have to be so severe. However, I'm not in the mood to work it
-			 * out now :P
-			 *
-			 * It may also be worth investigating whether doing this stuff
-			 * in floats would be faster.
-			 */
-
-			/* Unh4x0r3d version:
-			#define DO_RESAMPLE(inc)		   \
-			{								   \
-				HEAVYASSERT(dir < 0 ? (src_pos >= src_start) : (src_pos < src_end)); \
-											   \
-				if (src_pos != last_src_pos) { \
-					last_src_pos = src_pos;	   \
-					x = &src[src_pos];		   \
-					a = (((x[1] - x[2]) << 1) + (x[1] - x[2]) + (x[3] - x[0])) >> 4; \
-					b = ((x[2] << 2) + (x[0] << 1) - (5 * x[1] + x[3])) >> 5; \
-					c = (x[2] - x[0]) >> 6;	   \
-				}							   \
-											   \
-				dst[s] += ((((((((((a * src_subpos) >> 16) + b) * src_subpos) >> 16) + c) * src_subpos) >> 10) + x[1]) * volume_fact) >> 14; \
-											   \
-				src_subpos += dt + inc;		   \
-				src_pos += src_subpos >> 15;   \
-				src_subpos &= 0x7FFFl;		   \
-				s++;						   \
-			}
-			*/
-
-			/* H4x0r3d version: */
-			#define DO_RESAMPLE(inc)		   \
-			{								   \
-				HEAVYASSERT(dir < 0 ? (src_pos >= src_start) : (src_pos < src_end)); \
-											   \
-				if (src_pos != last_src_pos) { \
-					last_src_pos = src_pos;	   \
-					x = &src[src_pos];		   \
-					a = (((x[1] - x[2]) << 1) + (x[1] - x[2]) + (x[3] - x[0])) >> 1; \
-					b = (x[2] << 1) + x[0] - ((5 * x[1] + x[3]) >> 1); \
-					c = (x[2] - x[0]) >> 1;	   \
-				}							   \
-											   \
-				dst[s] += (((int)(((LONG_LONG)((int)(((LONG_LONG)((int)(((LONG_LONG)a * src_subpos) >> 15) + b) * src_subpos) >> 15) + c) * src_subpos) >> 15) + x[1]) * volume_fact) >> 14; \
-											   \
-				src_subpos += dt + inc;		   \
-				src_pos += src_subpos >> 15;   \
-				src_subpos &= 0x7FFFl;		   \
-				s++;						   \
-			}
-
-			MAKE_RESAMPLER();
-
-			#undef DO_RESAMPLE
-
-		}
-
-	}
-
-	end:
-
-	ASSERT(s <= dst_size);
-
-	*_src_pos = src_pos;
-	*_src_subpos = src_subpos;
-	if (_dir) *_dir = dir;
-
-	return s;
+void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler)
+{
+	if (n == 8)
+		dumb_end_resampler_8(resampler);
+	else if (n == 16)
+		dumb_end_resampler_16(resampler);
+	else
+		dumb_end_resampler(resampler);
 }
-#endif
--- a/dumb/src/helpers/resample.inc
+++ b/dumb/src/helpers/resample.inc
@@ -42,31 +42,11 @@
  * FIXME: these comments are somewhat out of date now.
  */
 
-#include <math.h>
-#include "dumb.h"
 
 
-
-/* Compile with -DHEAVYDEBUG if you want to make sure the pick-up function is
- * called when it should be. There will be a considerable performance hit,
- * since at least one condition has to be tested for every sample generated.
- */
-#ifdef HEAVYDEBUG
-#define HEAVYASSERT(cond) ASSERT(cond)
-#else
-#define HEAVYASSERT(cond)
-#endif
-
-
-
-//#define MULSC(a, b) ((int)((LONG_LONG)(a) * (b) >> 16))
-//#define MULSC(a, b) ((a) * ((b) >> 2) >> 14)
-#define MULSC(a, b) ((int)((LONG_LONG)((a) << 4) * ((b) << 12) >> 32))
-
-
-
-void dumb_reset_resampler(DUMB_RESAMPLER *resampler, SRCTYPE *src, long pos, long start, long end, int quality)
+void dumb_reset_resampler(DUMB_RESAMPLER *resampler, SRCTYPE *src, int src_channels, long pos, long start, long end, int quality)
 {
+	int i;
 	resampler->src = src;
 	resampler->pos = pos;
 	resampler->subpos = 0;
@@ -87,458 +67,193 @@
 	{
 		resampler->quality = quality;
 	}
-	resampler->X[2] = resampler->X[1] = resampler->X[0] = 0;
+	for (i = 0; i < src_channels*3; i++) resampler->X[i] = 0;
 	resampler->overshot = -1;
 }
 
 
 
-DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, long pos, long start, long end, int quality)
+DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, long start, long end, int quality)
 {
 	DUMB_RESAMPLER *resampler = malloc(sizeof(*resampler));
 	if (!resampler) return NULL;
-	dumb_reset_resampler(resampler, src, pos, start, end, quality);
+	dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality);
 	return resampler;
 }
 
 
 
-/* For convenience, returns nonzero on stop. */
-static int process_pickup(DUMB_RESAMPLER *resampler)
-{
-	if (resampler->overshot < 0) {
-		resampler->overshot = 0;
-		dumb_resample(resampler, NULL, 2, 0, 0, 0, 0, 1.0f);
-		resampler->X[0] = resampler->X[1];
-	}
-
-	for (;;) {
-		SRCTYPE *src = resampler->src;
-
-		if (resampler->dir < 0) {
-			if (resampler->overshot >= 3 && resampler->pos+3 >= resampler->start) resampler->X[0] = src[resampler->pos+3];
-			if (resampler->overshot >= 2 && resampler->pos+2 >= resampler->start) resampler->X[1] = src[resampler->pos+2];
-			if (resampler->overshot >= 1 && resampler->pos+1 >= resampler->start) resampler->X[2] = src[resampler->pos+1];
-			resampler->overshot = resampler->start - resampler->pos - 1;
-		} else {
-			if (resampler->overshot >= 3 && resampler->pos-3 < resampler->end) resampler->X[0] = src[resampler->pos-3];
-			if (resampler->overshot >= 2 && resampler->pos-2 < resampler->end) resampler->X[1] = src[resampler->pos-2];
-			if (resampler->overshot >= 1 && resampler->pos-1 < resampler->end) resampler->X[2] = src[resampler->pos-1];
-			resampler->overshot = resampler->pos - resampler->end;
-		}
-
-		if (resampler->overshot < 0) {
-			resampler->overshot = 0;
-			return 0;
-		}
-
-		if (!resampler->pickup) {
-			resampler->dir = 0;
-			return 1;
-		}
-		(*resampler->pickup)(resampler, resampler->pickup_data);
-		if (resampler->dir == 0) return 1;
-		ASSERT(resampler->dir == -1 || resampler->dir == 1);
-	}
-}
-
-
-
-/* Executes the content 'iterator' times.
- * Clobbers the 'iterator' variable.
- * The loop is unrolled by four.
- */
-#define LOOP4(iterator, CONTENT) \
-{ \
-	if ((iterator) & 2) { \
-		CONTENT; \
-		CONTENT; \
-	} \
-	if ((iterator) & 1) { \
-		CONTENT; \
-	} \
-	(iterator) >>= 2; \
-	while (iterator) { \
-		CONTENT; \
-		CONTENT; \
-		CONTENT; \
-		CONTENT; \
-		(iterator)--; \
-	} \
-}
-
-#define UPDATE_VOLUME                                              \
-	if (volume) {                                                  \
-		if (volume_delta < 0) {                                    \
-			if (volume_target - *volume > volume_delta) {          \
-				*volume = volume_target;                           \
-				volume = NULL;                                     \
-				vol = (int)(volume_target * volume_mix * 65536.0 + 0.5);        \
+#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 {                                               \
-				*volume += volume_delta;                           \
-				vol = (int)(*volume * volume_mix * 65536.0 + 0.5);              \
+				vol##r += vol##d;                                  \
+				vol = MULSC( vol##r, vol##m );                     \
 			}                                                      \
 		} else {                                                   \
-			if (volume_target - *volume < volume_delta) {          \
-				*volume = volume_target;                           \
-				volume = NULL;                                     \
-				vol = (int)(volume_target * volume_mix * 65536.0 + 0.5);        \
+			if (vol##t - vol##r < vol##d) {                        \
+				pvol->volume = pvol->target;                       \
+				pvol = NULL;                                       \
+				vol = MULSC( vol##t, vol##m );                     \
 			} else {                                               \
-				*volume += volume_delta;                           \
-				vol = (int)(*volume * volume_mix * 65536.0 + 0.5);              \
+				vol##r += vol##d;                                  \
+				vol = MULSC( vol##r, vol##m );                     \
 			}                                                      \
 		}                                                          \
-	}
+	}                                                              \
+}
 
-long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, float * volume, float volume_delta, float volume_target, float volume_mix, float delta)
-{
-	int dt;
-	int vol;
-	long done;
-	long todo;
-	int quality;
 
-	if (!resampler || resampler->dir == 0) return 0;
-	ASSERT(resampler->dir == -1 || resampler->dir == 1);
 
-	done = 0;
-	dt = (int)(delta * 65536.0 + 0.5);
-	if (volume) {
-		vol = (int)(*volume * volume_mix * 65536.0 + 0.5);
-		if (*volume == volume_target) volume = NULL;
-	}
-	else vol = 0;
+/* Create mono source resampler. */
+#define SUFFIX2 _1
+#define SRC_CHANNELS 1
+#define DIVIDE_BY_SRC_CHANNELS(x) (x)
+#define COPYSRC(dstarray, dstindex, srcarray, srcindex) (dstarray)[dstindex] = (srcarray)[srcindex]
+#define COPYSRC2(dstarray, dstindex, condition, srcarray, srcindex) (dstarray)[dstindex] = condition ? (srcarray)[srcindex] : 0
+#define MONO_DEST_VOLUME_PARAMETERS DUMB_VOLUME_RAMP_INFO * volume
+#define MONO_DEST_VOLUME_VARIABLES vol, volr, vold, volt, volm
+#define MONO_DEST_VOLUME_ZEROS 0
+#define SET_MONO_DEST_VOLUME_VARIABLES { \
+	if ( volume ) { \
+		volr = (int)floor(volume->volume * 65536.0 + 0.5); \
+		vold = (int)floor(volume->delta * 65536.0 + 0.5); \
+		volt = (int)floor(volume->target * 65536.0 + 0.5); \
+		volm = (int)floor(volume->mix * 65536.0 + 0.5); \
+		vol = MULSC( volr, volm ); \
+		if ( volr == volt ) volume = NULL; \
+	} else { \
+		vol = 0; \
+		volt = 0; \
+	} \
+}
+#define RETURN_MONO_DEST_VOLUME_VARIABLES if ( volume ) volume->volume = (float)volr / 65536.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); \
+	if ( upd ) UPDATE_VOLUME( volume, vol ); \
+}
+#define STEREO_DEST_MIX_ALIAS(op, upd, offset) { \
+	int xm = x[offset]; \
+	*dst++ op ALIAS(xm, lvol); \
+	*dst++ op ALIAS(xm, rvol); \
+	if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
+	if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
+}
+#define MONO_DEST_MIX_LINEAR(op, upd, o0, o1) { \
+	*dst++ op MULSC(LINEAR(x[o0], x[o1]), vol); \
+	if ( upd ) UPDATE_VOLUME( volume, vol ); \
+}
+#define STEREO_DEST_MIX_LINEAR(op, upd, o0, o1) { \
+	int xm = LINEAR(x[o0], x[o1]); \
+	*dst++ op MULSC(xm, lvol); \
+	*dst++ op MULSC(xm, rvol); \
+	if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
+	if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
+}
+#define MONO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) { \
+	*dst++ op CUBICVOL(CUBIC(x0[o0], x[o1], x[o2], x3[o3]), vol); \
+	if ( upd ) UPDATE_VOLUME( volume, vol ); \
+}
+#define STEREO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) { \
+	int xm = CUBIC(x0[o0], x[o1], x[o2], x3[o3]); \
+	*dst++ op CUBICVOL(xm, lvol); \
+	*dst++ op CUBICVOL(xm, rvol); \
+	if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
+	if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
+}
+#include "resamp2.inc"
 
-	if (vol == 0 && volume_target == 0) dst = NULL;
-
-	init_cubic();
-
-	quality = resampler->quality;
-
-	while (done < dst_size) {
-		if (process_pickup(resampler)) return done;
-
-		if ((resampler->dir ^ dt) < 0)
-			dt = -dt;
-
-		if (!dt)
-			todo = 0;
-		else if (resampler->dir < 0)
-			todo = (long)((((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);
-
-		if ((todo <= 0) ||
-			(todo > dst_size - done))
-			todo = dst_size - done;
-
-		done += todo;
-
-		{
-			SRCTYPE *src = resampler->src;
-			long pos = resampler->pos;
-			int subpos = resampler->subpos;
-			long diff = pos;
-			long overshot;
-			if (resampler->dir < 0) {
-				if (!dst) {
-					/* Silence or simulation */
-					LONG_LONG new_subpos = subpos + (LONG_LONG)dt * todo;
-					pos += (long)(new_subpos >> 16);
-					subpos = (long)new_subpos & 65535;
-				} else if (quality <= DUMB_RQ_ALIASING) {
-					/* Aliasing, backwards */
-					SRCTYPE xbuf[2];
-					SRCTYPE *x = &xbuf[0];
-					SRCTYPE *xstart;
-					xbuf[0] = resampler->X[1];
-					xbuf[1] = resampler->X[2];
-					while (todo && x < &xbuf[2]) {
-						HEAVYASSERT(pos >= resampler->start);
-						*dst++ += ALIAS(x[0]);
-						subpos += dt;
-						pos += subpos >> 16;
-						x -= subpos >> 16;
-						subpos &= 65535;
-						todo--;
-						UPDATE_VOLUME;
-					}
-					x = xstart = &src[pos];
-					LOOP4(todo,
-						*dst++ += ALIAS(x[2]);
-						subpos += dt;
-						x += subpos >> 16;
-						subpos &= 65535;
-						UPDATE_VOLUME;
-					);
-					pos += x - xstart;
-				} else if (quality <= DUMB_RQ_LINEAR) {
-					/* Linear interpolation, backwards */
-					SRCTYPE xbuf[3];
-					SRCTYPE *x = &xbuf[1];
-					xbuf[0] = resampler->X[1];
-					xbuf[1] = resampler->X[2];
-					xbuf[2] = src[pos];
-					while (todo && x < &xbuf[3]) {
-						HEAVYASSERT(pos >= resampler->start);
-						*dst++ += LINEAR(x[0], x[-1]);
-						subpos += dt;
-						pos += subpos >> 16;
-						x -= subpos >> 16;
-						subpos &= 65535;
-						todo--;
-						UPDATE_VOLUME;
-					}
-					x = &src[pos];
-					LOOP4(todo,
-						HEAVYASSERT(pos >= resampler->start);
-						*dst++ += LINEAR(x[1], x[2]);
-						subpos += dt;
-						pos += subpos >> 16;
-						x += subpos >> 16;
-						subpos &= 65535;
-						UPDATE_VOLUME;
-					);
-				} else {
-					/* Cubic interpolation, backwards */
-					SRCTYPE xbuf[6];
-					SRCTYPE *x = &xbuf[3];
-					//SRCTYPE *lastx = NULL;
-					//int a = 0, b = 0, c = 0;
-					xbuf[0] = resampler->X[0];
-					xbuf[1] = resampler->X[1];
-					xbuf[2] = resampler->X[2];
-					xbuf[3] = src[pos];
-					if (pos-1 >= resampler->start) xbuf[4] = src[pos-1];
-					if (pos-2 >= resampler->start) xbuf[5] = src[pos-2];
-					while (todo && x < &xbuf[6]) {
-						HEAVYASSERT(pos >= resampler->start);
-						//if (lastx != x) {
-						//	lastx = x;
-						//	SET_CUBIC_COEFFICIENTS(x[0], x[-1], x[-2], x[-3]);
-						//}
-						*dst++ += CUBIC(x[0], x[-1], x[-2], x[-3]);
-						subpos += dt;
-						pos += subpos >> 16;
-						x -= subpos >> 16;
-						subpos &= 65535;
-						todo--;
-						UPDATE_VOLUME;
-					}
-					x = &src[pos];
-					//lastx = NULL;
-					LOOP4(todo,
-						HEAVYASSERT(pos >= resampler->start);
-						//if (lastx != x) {
-						//	lastx = x;
-						//	SET_CUBIC_COEFFICIENTS(x[0], x[1], x[2], x[3]);
-						//}
-						*dst++ += CUBIC(x[0], x[1], x[2], x[3]);
-						subpos += dt;
-						pos += subpos >> 16;
-						x += subpos >> 16;
-						subpos &= 65535;
-						UPDATE_VOLUME;
-					);
-				}
-				diff = diff - pos;
-				overshot = resampler->start - pos - 1;
-				if (diff >= 3) {
-					resampler->X[0] = overshot >= 3 ? 0 : src[pos+3];
-					resampler->X[1] = overshot >= 2 ? 0 : src[pos+2];
-					resampler->X[2] = overshot >= 1 ? 0 : src[pos+1];
-				} else if (diff >= 2) {
-					resampler->X[0] = resampler->X[2];
-					resampler->X[1] = overshot >= 2 ? 0 : src[pos+2];
-					resampler->X[2] = overshot >= 1 ? 0 : src[pos+1];
-				} else if (diff >= 1) {
-					resampler->X[0] = resampler->X[1];
-					resampler->X[1] = resampler->X[2];
-					resampler->X[2] = overshot >= 1 ? 0 : src[pos+1];
-				}
-			} else {
-				if (!dst) {
-					/* Silence or simulation */
-					LONG_LONG new_subpos = subpos + (LONG_LONG)dt * todo;
-					pos += (long)(new_subpos >> 16);
-					subpos = (long)new_subpos & 65535;
-				} else if (quality <= DUMB_RQ_ALIASING) {
-					/* Aliasing, forwards */
-					SRCTYPE xbuf[2];
-					SRCTYPE *x = &xbuf[0];
-					SRCTYPE *xstart;
-					xbuf[0] = resampler->X[1];
-					xbuf[1] = resampler->X[2];
-					while (todo && x < &xbuf[2]) {
-						HEAVYASSERT(pos < resampler->end);
-						*dst++ += ALIAS(x[0]);
-						subpos += dt;
-						pos += subpos >> 16;
-						x += subpos >> 16;
-						subpos &= 65535;
-						todo--;
-						UPDATE_VOLUME;
-					}
-					x = xstart = &src[pos];
-					LOOP4(todo,
-						*dst++ += ALIAS(x[-2]);
-						subpos += dt;
-						x += subpos >> 16;
-						subpos &= 65535;
-						UPDATE_VOLUME;
-					);
-					pos += x - xstart;
-				} else if (quality <= DUMB_RQ_LINEAR) {
-					/* Linear interpolation, forwards */
-					SRCTYPE xbuf[3];
-					SRCTYPE *x = &xbuf[1];
-					xbuf[0] = resampler->X[1];
-					xbuf[1] = resampler->X[2];
-					xbuf[2] = src[pos];
-					while (todo && x < &xbuf[3]) {
-						HEAVYASSERT(pos < resampler->end);
-						*dst++ += LINEAR(x[-1], x[0]);
-						subpos += dt;
-						pos += subpos >> 16;
-						x += subpos >> 16;
-						subpos &= 65535;
-						todo--;
-						UPDATE_VOLUME;
-					}
-					x = &src[pos];
-					LOOP4(todo,
-						HEAVYASSERT(pos < resampler->end);
-						*dst++ += LINEAR(x[-2], x[-1]);
-						subpos += dt;
-						pos += subpos >> 16;
-						x += subpos >> 16;
-						subpos &= 65535;
-						UPDATE_VOLUME;
-					);
-				} else {
-					/* Cubic interpolation, forwards */
-					SRCTYPE xbuf[6];
-					SRCTYPE *x = &xbuf[3];
-					//SRCTYPE *lastx = NULL;
-					//int a = 0, b = 0, c = 0;
-					xbuf[0] = resampler->X[0];
-					xbuf[1] = resampler->X[1];
-					xbuf[2] = resampler->X[2];
-					xbuf[3] = src[pos];
-					if (pos+1 < resampler->end) xbuf[4] = src[pos+1];
-					if (pos+2 < resampler->end) xbuf[5] = src[pos+2];
-					while (todo && x < &xbuf[6]) {
-						HEAVYASSERT(pos < resampler->end);
-						//if (lastx != x) {
-						//	lastx = x;
-						//	SET_CUBIC_COEFFICIENTS(x[-3], x[-2], x[-1], x[0]);
-						//}
-						*dst++ += CUBIC(x[-3], x[-2], x[-1], x[0]);
-						subpos += dt;
-						pos += subpos >> 16;
-						x += subpos >> 16;
-						subpos &= 65535;
-						todo--;
-						UPDATE_VOLUME;
-					}
-					x = &src[pos];
-					//lastx = NULL;
-					LOOP4(todo,
-						HEAVYASSERT(pos < resampler->end);
-						//if (lastx != x) {
-						//	lastx = x;
-						//	SET_CUBIC_COEFFICIENTS(x[-3], x[-2], x[-1], x[0]);
-						//}
-						*dst++ += CUBIC(x[-3], x[-2], x[-1], x[0]);
-						subpos += dt;
-						pos += subpos >> 16;
-						x += subpos >> 16;
-						subpos &= 65535;
-						UPDATE_VOLUME;
-					);
-				}
-				diff = pos - diff;
-				overshot = pos - resampler->end;
-				if (diff >= 3) {
-					resampler->X[0] = overshot >= 3 ? 0 : src[pos-3];
-					resampler->X[1] = overshot >= 2 ? 0 : src[pos-2];
-					resampler->X[2] = overshot >= 1 ? 0 : src[pos-1];
-				} else if (diff >= 2) {
-					resampler->X[0] = resampler->X[2];
-					resampler->X[1] = overshot >= 2 ? 0 : src[pos-2];
-					resampler->X[2] = overshot >= 1 ? 0 : src[pos-1];
-				} else if (diff >= 1) {
-					resampler->X[0] = resampler->X[1];
-					resampler->X[1] = resampler->X[2];
-					resampler->X[2] = overshot >= 1 ? 0 : src[pos-1];
-				}
-			}
-			resampler->pos = pos;
-			resampler->subpos = subpos;
-		}
-	}
-
-	return done;
+/* Create stereo source resampler. */
+#define SUFFIX2 _2
+#define SRC_CHANNELS 2
+#define DIVIDE_BY_SRC_CHANNELS(x) ((x) >> 1)
+#define COPYSRC(dstarray, dstindex, srcarray, srcindex) { \
+	(dstarray)[(dstindex)*2] = (srcarray)[(srcindex)*2]; \
+	(dstarray)[(dstindex)*2+1] = (srcarray)[(srcindex)*2+1]; \
 }
+#define COPYSRC2(dstarray, dstindex, condition, srcarray, srcindex) { \
+	if (condition) { \
+		(dstarray)[(dstindex)*2] = (srcarray)[(srcindex)*2]; \
+		(dstarray)[(dstindex)*2+1] = (srcarray)[(srcindex)*2+1]; \
+	} else { \
+		(dstarray)[(dstindex)*2] = 0; \
+		(dstarray)[(dstindex)*2+1] = 0; \
+	} \
+}
 
-
-
-sample_t dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, float volume)
-{
-	int vol;
-	SRCTYPE *src;
-	long pos;
-	int subpos;
-	int quality;
-
-	if (!resampler || resampler->dir == 0) return 0;
-	ASSERT(resampler->dir == -1 || resampler->dir == 1);
-
-	if (process_pickup(resampler)) return 0;
-
-	vol = (int)floor(volume * 65536.0 + 0.5);
-	if (vol == 0) return 0;
-
-	init_cubic();
-
-	quality = resampler->quality;
-
-	src = resampler->src;
-	pos = resampler->pos;
-	subpos = resampler->subpos;
-
-	if (resampler->dir < 0) {
-		HEAVYASSERT(pos >= resampler->start);
-		if (quality <= DUMB_RQ_ALIASING) {
-			/* Aliasing, backwards */
-			return ALIAS(src[pos]);
-		} else if (quality <= DUMB_RQ_LINEAR) {
-			/* Linear interpolation, backwards */
-			return LINEAR(resampler->X[2], resampler->X[1]);
-		} else {
-			/* Cubic interpolation, backwards */
-			SRCTYPE *x = resampler->X;
-			//int a, b, c;
-			//SET_CUBIC_COEFFICIENTS(src[pos], x[2], x[1], x[0]);
-			return CUBIC(src[pos], x[2], x[1], x[0]);
-		}
-	} else {
-		HEAVYASSERT(pos < resampler->end);
-		if (quality <= DUMB_RQ_ALIASING) {
-			/* Aliasing */
-			return ALIAS(src[pos]);
-		} else if (quality <= DUMB_RQ_LINEAR) {
-			/* Linear interpolation, forwards */
-			return LINEAR(resampler->X[1], resampler->X[2]);
-		} else {
-			/* Cubic interpolation, forwards */
-			SRCTYPE *x = resampler->X;
-			//int a, b, c;
-			//SET_CUBIC_COEFFICIENTS(x[0], x[1], x[2], src[pos]);
-			return CUBIC(x[0], x[1], x[2], src[pos]);
-		}
-	}
+#define MONO_DEST_VOLUME_PARAMETERS DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right
+#define MONO_DEST_VOLUME_VARIABLES lvol, lvolr, lvold, lvolt, lvolm, rvol, rvolr, rvold, rvolt, rvolm
+#define MONO_DEST_VOLUME_ZEROS 0, 0
+#define SET_MONO_DEST_VOLUME_VARIABLES { \
+	if ( volume_left ) { \
+		lvolr = (int)floor(volume_left->volume * 65536.0 + 0.5); \
+		lvold = (int)floor(volume_left->delta * 65536.0 + 0.5); \
+		lvolt = (int)floor(volume_left->target * 65536.0 + 0.5); \
+		lvolm = (int)floor(volume_left->mix * 65536.0 + 0.5); \
+		lvol = MULSC( lvolr, lvolm ); \
+		if ( lvolr == lvolt ) volume_left = NULL; \
+	} else { \
+		lvol = 0; \
+		lvolt = 0; \
+	} \
+	if ( volume_right ) { \
+		rvolr = (int)floor(volume_right->volume * 65536.0 + 0.5); \
+		rvold = (int)floor(volume_right->delta * 65536.0 + 0.5); \
+		rvolt = (int)floor(volume_right->target * 65536.0 + 0.5); \
+		rvolm = (int)floor(volume_right->mix * 65536.0 + 0.5); \
+		rvol = MULSC( rvolr, rvolm ); \
+		if ( rvolr == rvolt ) volume_right = NULL; \
+	} else { \
+		rvol = 0; \
+		rvolt = 0; \
+	} \
 }
+#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; \
+}
+#define MONO_DEST_VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
+#define MONO_DEST_MIX_ALIAS(op, upd, offset) { \
+	*dst++ op ALIAS(x[(offset)*2], lvol) + ALIAS(x[(offset)*2+1], rvol); \
+	if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
+	if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
+}
+#define STEREO_DEST_MIX_ALIAS(op, upd, offset) { \
+	*dst++ op ALIAS(x[(offset)*2], lvol); \
+	*dst++ op ALIAS(x[(offset)*2+1], rvol); \
+	if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
+	if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
+}
+#define MONO_DEST_MIX_LINEAR(op, upd, o0, o1) { \
+	*dst++ op MULSC(LINEAR(x[(o0)*2], x[(o1)*2]), lvol) + MULSC(LINEAR(x[(o0)*2+1], x[(o1)*2+1]), rvol); \
+	if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
+	if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
+}
+#define STEREO_DEST_MIX_LINEAR(op, upd, o0, o1) { \
+	*dst++ op MULSC(LINEAR(x[(o0)*2], x[(o1)*2]), lvol); \
+	*dst++ op MULSC(LINEAR(x[(o0)*2+1], x[(o1)*2+1]), rvol); \
+	if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
+	if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
+}
+#define MONO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) { \
+	*dst++ op \
+		CUBICVOL(CUBIC(x0[(o0)*2], x[(o1)*2], x[(o2)*2], x3[(o3)*2]), lvol) + \
+		CUBICVOL(CUBIC(x0[(o0)*2+1], x[(o1)*2+1], x[(o2)*2+1], x3[(o3)*2+1]), rvol); \
+	if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
+	if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
+}
+#define STEREO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) { \
+	*dst++ op CUBICVOL(CUBIC(x0[(o0)*2], x[(o1)*2], x[(o2)*2], x3[(o3)*2]), lvol); \
+	*dst++ op CUBICVOL(CUBIC(x0[(o0)*2+1], x[(o1)*2+1], x[(o2)*2+1], x3[(o3)*2+1]), rvol); \
+	if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
+	if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
+}
+#include "resamp2.inc"
 
 
 
@@ -550,8 +265,8 @@
 
 
 
+#undef CUBICVOL
 #undef CUBIC
-//#undef SET_CUBIC_COEFFICIENTS
 #undef LINEAR
 #undef ALIAS
 #undef SRCBITS
--- a/dumb/src/helpers/sampbuf.c
+++ b/dumb/src/helpers/sampbuf.c
@@ -22,6 +22,7 @@
 
 
 
+/* DEPRECATED */
 sample_t **create_sample_buffer(int n_channels, long length)
 {
 	int i;
@@ -33,6 +34,22 @@
 		return NULL;
 	}
 	for (i = 1; i < n_channels; i++) samples[i] = samples[i-1] + length;
+	return samples;
+}
+
+
+
+sample_t **allocate_sample_buffer(int n_channels, long length)
+{
+	int i;
+	sample_t **samples = malloc(((n_channels + 1) >> 1) * sizeof(*samples));
+	if (!samples) return NULL;
+	samples[0] = malloc(n_channels * length * sizeof(*samples[0]));
+	if (!samples[0]) {
+		free(samples);
+		return NULL;
+	}
+	for (i = 1; i < (n_channels + 1) >> 1; i++) samples[i] = samples[i-1] + length*2;
 	return samples;
 }
 
--- a/dumb/src/it/itload.c
+++ b/dumb/src/it/itload.c
@@ -22,11 +22,11 @@
 
 
 
-/* dumb_load_it(): loads an IT file into a DUH struct, returning a pointer 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.
+/* dumb_load_it_quick(): loads an IT file into a DUH struct, returning a
+ * pointer 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_it(const char *filename)
+DUH *dumb_load_it_quick(const char *filename)
 {
 	DUH *duh;
 	DUMBFILE *f = dumbfile_open(filename);
@@ -34,7 +34,7 @@
 	if (!f)
 		return NULL;
 
-	duh = dumb_read_it(f);
+	duh = dumb_read_it_quick(f);
 
 	dumbfile_close(f);
 
--- /dev/null
+++ b/dumb/src/it/itload2.c
@@ -1,0 +1,29 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * itload2.c - Function to read an Impulse Tracker    / / \  \
+ *             file, opening and closing it for      | <  /   \_
+ *             you, and do an initial run-through.   |  \/ /\   /
+ *                                                    \_  /  > /
+ * Split off from itload.c by entheh.                   | \ / /
+ *                                                      |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_load_it(const char *filename)
+{
+	DUH *duh = dumb_load_it_quick(filename);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/itmisc.c
+++ b/dumb/src/it/itmisc.c
@@ -226,3 +226,22 @@
 {
 	if (sr) sr->channel[channel].channelvolume = volume;
 }
+
+
+
+void dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel, int muted)
+{
+	if (sr) {
+		if (muted)
+			sr->channel[channel].flags |= IT_CHANNEL_MUTED;
+		else
+			sr->channel[channel].flags &= ~IT_CHANNEL_MUTED;
+	}
+}
+
+
+
+int dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel)
+{
+	return sr ? (sr->channel[channel].flags & IT_CHANNEL_MUTED) != 0 : 0;
+}
--- a/dumb/src/it/itread.c
+++ b/dumb/src/it/itread.c
@@ -122,7 +122,7 @@
 /** WARNING - do we even need to pass `right`? */
 /** WARNING - why bother memsetting at all? The whole array is written... */
 // if we do memset, dumb_silence() would be neater...
-static int decompress8(DUMBFILE *f, signed char *left, signed char *right, int len, int cmwt)
+static int decompress8(DUMBFILE *f, signed char *data, int len, int cmwt)
 {
 	int blocklen, blockpos;
 	byte bitwidth;
@@ -132,11 +132,7 @@
 
 	memset(&crap, 0, sizeof(crap));
 
-	memset(left, 0, len * sizeof(*left));
-	if (right) {
-		memset(right, 0, len * sizeof(*right));
-		len <<= 1;
-	}
+	memset(data, 0, len * sizeof(*data));
 
 	while (len > 0) {
 		//Read a block of compressed data:
@@ -201,10 +197,7 @@
 			/* Version 2.15 was an unofficial version with hacked compression
 			 * code. Yay, better compression :D
 			 */
-			if (right && (len & 1))
-				*right++ = cmwt == 0x215 ? d2 : d1;
-			else
-				*left++ = cmwt == 0x215 ? d2 : d1;
+			*data++ = cmwt == 0x215 ? d2 : d1;
 			len--;
 			blockpos++;
 		}
@@ -215,7 +208,7 @@
 
 
 
-static int decompress16(DUMBFILE *f, short *left, short *right, int len, int cmwt)
+static int decompress16(DUMBFILE *f, short *data, int len, int cmwt)
 {
 	int blocklen, blockpos;
 	byte bitwidth;
@@ -225,11 +218,7 @@
 
 	memset(&crap, 0, sizeof(crap));
 
-	memset(left, 0, len * sizeof(*left));
-	if (right) {
-		memset(right, 0, len * sizeof(*right));
-		len <<= 1;
-	}
+	memset(data, 0, len * sizeof(*data));
 
 	while (len > 0) {
 		//Read a block of compressed data:
@@ -293,10 +282,7 @@
 			/* Version 2.15 was an unofficial version with hacked compression
 			 * code. Yay, better compression :D
 			 */
-			if (right && (len & 1))
-				*right++ = cmwt == 0x215 ? d2 : d1;
-			else
-				*left++ = cmwt == 0x215 ? d2 : d1;
+			*data++ = cmwt == 0x215 ? d2 : d1;
 			len--;
 			blockpos++;
 		}
@@ -613,7 +599,7 @@
 	signed char compression_table[16];
 	if (dumbfile_getnc(compression_table, 16, f) != 16)
 		return -1;
-	ptr = (signed char *) sample->left;
+	ptr = (signed char *) sample->data;
 	delta = 0;
 
 	end = ptr + sample->length;
@@ -636,16 +622,13 @@
 {
 	long n;
 
-	sample->left = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
-	if (!sample->left)
+	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 (sample->flags & IT_SAMPLE_STEREO) {
-		sample->right = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
-		if (!sample->right)
-			return -1;
-	}
-
 	if (!(sample->flags & IT_SAMPLE_16BIT) && (convert == 0xFF)) {
 		if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
 			return -1;
@@ -655,7 +638,7 @@
 		/** WARNING - unresolved business here... test with ModPlug? */
 
 		if (sample->flags & IT_SAMPLE_STEREO)
-			//exit(37);
+			//exit(37); // TODO: if this ever happens, maybe sample->length should be doubled below?
 			return -1;
 
 /*
@@ -664,38 +647,19 @@
 //#endif
 */
 		if (sample->flags & IT_SAMPLE_16BIT)
-			decompress16(f, sample->left, sample->right, sample->length, cmwt);
+			decompress16(f, sample->data, datasize, cmwt);
 		else
-			decompress8(f, sample->left, sample->right, sample->length, cmwt);
-	} else if (sample->flags & IT_SAMPLE_STEREO) {
-		if (sample->flags & IT_SAMPLE_16BIT) {
-			if (convert & 2) {
-				for (n = 0; n < sample->length; n++) {
-					((short *)sample->left)[n] = dumbfile_mgetw(f);
-					((short *)sample->right)[n] = dumbfile_mgetw(f);
-				}
-			} else {
-				for (n = 0; n < sample->length; n++) {
-					((short *)sample->left)[n] = dumbfile_igetw(f);
-					((short *)sample->right)[n] = dumbfile_igetw(f);
-				}
-			}
-		} else {
-			for (n = 0; n < sample->length; n++) {
-				((signed char *)sample->left)[n] = dumbfile_getc(f);
-				((signed char *)sample->right)[n] = dumbfile_getc(f);
-			}
-		}
-	} else if (sample->flags & IT_SAMPLE_16BIT) {
-		if (convert & 2)
-			for (n = 0; n < sample->length; n++)
-				((short *)sample->left)[n] = dumbfile_mgetw(f);
-		else
-			for (n = 0; n < sample->length; n++)
-				((short *)sample->left)[n] = dumbfile_igetw(f);
-	} else
-		for (n = 0; n < sample->length; n++)
-			((signed char *)sample->left)[n] = dumbfile_getc(f);
+			decompress8(f, sample->data, datasize, cmwt);
+ 	} else if (sample->flags & IT_SAMPLE_16BIT) {
+ 		if (convert & 2)
+			for (n = 0; n < datasize; n++)
+				((short *)sample->data)[n] = dumbfile_mgetw(f);
+ 		else
+			for (n = 0; n < datasize; n++)
+				((short *)sample->data)[n] = dumbfile_igetw(f);
+ 	} else
+		for (n = 0; n < datasize; n++)
+			((signed char *)sample->data)[n] = dumbfile_getc(f);
 
 	if (dumbfile_error(f))
 		return -1;
@@ -703,20 +667,11 @@
 	if (!(convert & 1)) {
 		/* Convert to signed. */
 		if (sample->flags & IT_SAMPLE_16BIT)
-			for (n = 0; n < sample->length; n++)
-				((short *)sample->left)[n] ^= 0x8000;
+			for (n = 0; n < datasize; n++)
+				((short *)sample->data)[n] ^= 0x8000;
 		else
-			for (n = 0; n < sample->length; n++)
-				((signed char *)sample->left)[n] ^= 0x80;
-
-		if (sample->right) {
-			if (sample->flags & IT_SAMPLE_16BIT)
-				for (n = 0; n < sample->length; n++)
-					((short *)sample->right)[n] ^= 0x8000;
-			else
-				for (n = 0; n < sample->length; n++)
-					((signed char *)sample->right)[n] ^= 0x80;
-		}
+			for (n = 0; n < datasize; n++)
+				((signed char *)sample->data)[n] ^= 0x80;
 	}
 
 	/* NOT SUPPORTED:
@@ -1027,7 +982,7 @@
 			return NULL;
 		}
 		for (n = 0; n < sigdata->n_samples; n++)
-			sigdata->sample[n].right = sigdata->sample[n].left = NULL;
+			sigdata->sample[n].data = NULL;
 	}
 
 	if (sigdata->n_patterns) {
@@ -1326,10 +1281,9 @@
 
 
 
-DUH *dumb_read_it(DUMBFILE *f)
+DUH *dumb_read_it_quick(DUMBFILE *f)
 {
 	sigdata_t *sigdata;
-	long length;
 
 	DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
 
@@ -1338,12 +1292,10 @@
 	if (!sigdata)
 		return NULL;
 
-	length = 0; /*_dumb_it_build_checkpoints(sigdata, 0);*/
-
 	{
 		const char *tag[1][2];
-                tag[0][0] = "TITLE";
-                tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
-		return make_duh(length, 1, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+		tag[0][0] = "TITLE";
+		tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
+		return make_duh(-1, 1, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
 	}
 }
--- /dev/null
+++ b/dumb/src/it/itread2.c
@@ -1,0 +1,29 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * itread2.c - Function to read an Impulse Tracker    / / \  \
+ *             module from an open file and do an    | <  /   \_
+ *             initial run-through.                  |  \/ /\   /
+ *                                                    \_  /  > /
+ * Split off from itread.c by entheh.                   | \ / /
+ *                                                      |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_read_it(DUMBFILE *f)
+{
+	DUH *duh = dumb_read_it_quick(f);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/itrender.c
+++ b/dumb/src/it/itrender.c
@@ -116,9 +116,8 @@
 	dst->filter_state[0] = src->filter_state[0];
 	dst->filter_state[1] = src->filter_state[1];
 
-	dst->resampler[0] = src->resampler[0];
-	dst->resampler[1] = src->resampler[1];
-	dst->resampler[1].pickup_data = dst->resampler[0].pickup_data = dst;
+	dst->resampler = src->resampler;
+	dst->resampler.pickup_data = dst;
 	dst->time_lost = src->time_lost;
 
 	return dst;
@@ -203,6 +202,7 @@
 	dst->lastS = src->lastS;
 	dst->pat_loop_row = src->pat_loop_row;
 	dst->pat_loop_count = src->pat_loop_count;
+	//dst->pat_loop_end_row = src->pat_loop_end_row;
 	dst->lastW = src->lastW;
 
 	dst->xm_lastE1 = src->xm_lastE1;
@@ -493,13 +493,15 @@
  * output starting at dst[pos]. The pos parameter is required for getting
  * click removal right.
  */
-static void it_filter(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, long pos, sample_t *src, long size, int sampfreq, int cutoff, int resonance)
+static void it_filter(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, long pos, sample_t *src, long size, int step, int sampfreq, int cutoff, int resonance)
 {
-	float currsample = state->currsample;
-	float prevsample = state->prevsample;
+	sample_t currsample = state->currsample;
+	sample_t prevsample = state->prevsample;
 
 	float a, b, c;
 
+	long datasize;
+
 	{
 		float inv_angle = (float)(sampfreq * pow(0.5, 0.25 + cutoff*(1.0/(24<<IT_ENVELOPE_SHIFT))) * (1.0/(2*3.14159265358979323846*110.0)));
 		float loss = (float)exp(resonance*(-LOG10*1.2/128.0));
@@ -523,13 +525,9 @@
 #endif
 	}
 
-	dst += pos;
+	dst += pos * step;
+	datasize = size * step;
 
-	if (cr) {
-		float startstep = src[0]*a + currsample*b + prevsample*c;
-		dumb_record_click(cr, pos, (sample_t)startstep);
-	}
-
 #define INT_FILTERS
 #ifdef INT_FILTERS
 #define MULSCA(a, b) ((int)((LONG_LONG)((a) << 4) * (b) >> 32))
@@ -538,21 +536,34 @@
 		int ai = (int)(a * (1 << (16+SCALEB)));
 		int bi = (int)(b * (1 << (16+SCALEB)));
 		int ci = (int)(c * (1 << (16+SCALEB)));
-		sample_t csi = (sample_t)currsample;
-		sample_t psi = (sample_t)prevsample;
-		sample_t *dst_end = dst + size;
-		while (dst < dst_end) {
+		int i;
+
+		if (cr) {
+			sample_t startstep = MULSCA(src[0], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci);
+			dumb_record_click(cr, pos, startstep);
+		}
+
+		for (i = 0; i < datasize; i += step) {
 			{
-				sample_t nsi = MULSCA(*src++, ai) + MULSCA(csi, bi) + MULSCA(psi, ci);
-				psi = csi;
-				csi = nsi;
+				sample_t newsample = MULSCA(src[i], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci);
+				prevsample = currsample;
+				currsample = newsample;
 			}
-			*dst++ += csi;
+			dst[i] += currsample;
 		}
-		currsample = csi;
-		prevsample = psi;
+
+		if (cr) {
+			sample_t endstep = MULSCA(src[datasize], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci);
+			dumb_record_click(cr, pos + size, -endstep);
+		}
 	}
 #else
+#error This version is broken - it does not use step, and state should contain floats for it
+	if (cr) {
+		float startstep = src[0]*a + currsample*b + prevsample*c;
+		dumb_record_click(cr, pos, (sample_t)startstep);
+	}
+
 	{
 		int i = size % 3;
 		while (i > 0) {
@@ -574,12 +585,12 @@
 			i--;
 		}
 	}
-#endif
 
 	if (cr) {
-		float endstep = *src*a + currsample*b + prevsample*c;
+		float endstep = src[datasize]*a + currsample*b + prevsample*c;
 		dumb_record_click(cr, pos + size, -(sample_t)endstep);
 	}
+#endif
 
 	state->currsample = currsample;
 	state->prevsample = prevsample;
@@ -814,32 +825,28 @@
 static void it_playing_update_resamplers(IT_PLAYING *playing)
 {
 	if ((playing->sample->flags & IT_SAMPLE_SUS_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) {
-		playing->resampler[0].start = playing->sample->sus_loop_start;
-		playing->resampler[0].end = playing->sample->sus_loop_end;
+		playing->resampler.start = playing->sample->sus_loop_start;
+		playing->resampler.end = playing->sample->sus_loop_end;
 		if (playing->sample->flags & IT_SAMPLE_PINGPONG_SUS_LOOP)
-			playing->resampler[0].pickup = &it_pickup_pingpong_loop;
+			playing->resampler.pickup = &it_pickup_pingpong_loop;
 		else
-			playing->resampler[0].pickup = &it_pickup_loop;
+			playing->resampler.pickup = &it_pickup_loop;
 	} else if (playing->sample->flags & IT_SAMPLE_LOOP) {
-		playing->resampler[0].start = playing->sample->loop_start;
-		playing->resampler[0].end = playing->sample->loop_end;
+		playing->resampler.start = playing->sample->loop_start;
+		playing->resampler.end = playing->sample->loop_end;
 		if (playing->sample->flags & IT_SAMPLE_PINGPONG_LOOP)
-			playing->resampler[0].pickup = &it_pickup_pingpong_loop;
+			playing->resampler.pickup = &it_pickup_pingpong_loop;
 		else
-			playing->resampler[0].pickup = &it_pickup_loop;
+			playing->resampler.pickup = &it_pickup_loop;
 	} else {
 		if (playing->sample->flags & IT_SAMPLE_SUS_LOOP)
-			playing->resampler[0].start = playing->sample->sus_loop_start;
+			playing->resampler.start = playing->sample->sus_loop_start;
 		else
-			playing->resampler[0].start = 0;
-		playing->resampler[0].end = playing->sample->length;
-		playing->resampler[0].pickup = &it_pickup_stop_at_end;
+			playing->resampler.start = 0;
+		playing->resampler.end = playing->sample->length;
+		playing->resampler.pickup = &it_pickup_stop_at_end;
 	}
-	playing->resampler[1].start = playing->resampler[0].start;
-	playing->resampler[1].end = playing->resampler[0].end;
-	playing->resampler[1].pickup = playing->resampler[0].pickup;
-	ASSERT(playing->resampler[0].pickup_data == playing);
-	ASSERT(playing->resampler[1].pickup_data == playing);
+	ASSERT(playing->resampler.pickup_data == playing);
 }
 
 
@@ -849,11 +856,11 @@
 {
 	int bits = playing->sample->flags & IT_SAMPLE_16BIT ? 16 : 8;
 	int quality = playing->resampling_quality;
+	int channels = playing->sample->flags & IT_SAMPLE_STEREO ? 2 : 1;
 	if (playing->sample->max_resampling_quality >= 0 && quality > playing->sample->max_resampling_quality)
 		quality = playing->sample->max_resampling_quality;
-	dumb_reset_resampler_n(bits, &playing->resampler[0], playing->sample->left, pos, 0, 0, quality);
-	dumb_reset_resampler_n(bits, &playing->resampler[1], playing->sample->right, pos, 0, 0, quality);
-	playing->resampler[1].pickup_data = playing->resampler[0].pickup_data = playing;
+	dumb_reset_resampler_n(bits, &playing->resampler, playing->sample->data, channels, pos, 0, 0, quality);
+	playing->resampler.pickup_data = playing;
 	playing->time_lost = 0;
 	playing->flags &= ~IT_PLAYING_DEAD;
 	it_playing_update_resamplers(playing);
@@ -1321,13 +1328,13 @@
 {
 	if ((playing->sample->flags & (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP)) ==
 	                              (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP)) {
-		if (playing->resampler[0].dir < 0) {
-			playing->resampler[1].pos = playing->resampler[0].pos = (playing->sample->sus_loop_end << 1) - 1 - playing->resampler[0].pos;
-			playing->resampler[1].subpos = playing->resampler[0].subpos ^= 65535;
-			playing->resampler[1].dir = playing->resampler[0].dir = 1;
+		if (playing->resampler.dir < 0) {
+			playing->resampler.pos = (playing->sample->sus_loop_end << 1) - 1 - playing->resampler.pos;
+			playing->resampler.subpos ^= 65535;
+			playing->resampler.dir = 1;
 		}
 
-		playing->resampler[1].pos = playing->resampler[0].pos += playing->time_lost;
+		playing->resampler.pos += playing->time_lost;
 		// XXX what
 		playing->time_lost = 0;
 	}
@@ -1704,7 +1711,7 @@
 		IT_INSTRUMENT *instrument = &sigdata->instrument[channel->instrument-1];
 		int truepan = channel->truepan;
 		truepan += (channel->note - instrument->pp_centre) * instrument->pp_separation << (IT_ENVELOPE_SHIFT - 3);
-		channel->truepan = MID(0, truepan, 64 << IT_ENVELOPE_SHIFT);
+		channel->truepan = (unsigned short)MID(0, truepan, 64 << IT_ENVELOPE_SHIFT);
 	}
 }
 
@@ -1821,6 +1828,32 @@
 	}
 }
 
+
+
+static void xm_envelope_calculate_value(IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe)
+{
+	if (pe->next_node <= 0)
+		pe->value = envelope->node_y[0] << IT_ENVELOPE_SHIFT;
+	else if (pe->next_node >= envelope->n_nodes)
+		pe->value = envelope->node_y[envelope->n_nodes-1] << IT_ENVELOPE_SHIFT;
+	else {
+		int ys = envelope->node_y[pe->next_node-1] << IT_ENVELOPE_SHIFT;
+		int ts = envelope->node_t[pe->next_node-1];
+		int te = envelope->node_t[pe->next_node];
+
+		if (ts == te)
+			pe->value = ys;
+		else {
+			int ye = envelope->node_y[pe->next_node] << IT_ENVELOPE_SHIFT;
+			int t = pe->tick;
+
+			pe->value = ys + (ye - ys) * (t - ts) / (te - ts);
+		}
+	}
+}
+
+
+
 extern const char xm_convert_vibrato[];
 
 /* Returns 1 if a callback caused termination of playback. */
@@ -2508,11 +2541,25 @@
 						int i, j;
 						for (i = 0, j = 1; i < n; i++, j <<= 1)
 							it_send_midi(sigrenderer, channel,
-								midi->SFmacroz[channel->SFmacro] & j ?
-									entry->effectvalue : midi->SFmacro[channel->SFmacro][i]);
+								(unsigned char)(midi->SFmacroz[channel->SFmacro] & j ?
+									entry->effectvalue : midi->SFmacro[channel->SFmacro][i]));
 					}
 				}
 				break;
+			case IT_XM_SET_ENVELOPE_POSITION:
+				if (channel->playing && channel->playing->env_instrument) {
+					IT_ENVELOPE *envelope = &channel->playing->env_instrument->volume_envelope;
+					if (envelope->flags & IT_ENVELOPE_ON) {
+						IT_PLAYING_ENVELOPE *pe = &channel->playing->volume_envelope;
+						pe->tick = entry->effectvalue;
+						if (pe->tick >= envelope->node_t[envelope->n_nodes-1])
+							pe->tick = envelope->node_t[envelope->n_nodes-1];
+						pe->next_node = 0;
+						while (pe->tick > envelope->node_t[pe->next_node]) pe->next_node++;
+						xm_envelope_calculate_value(envelope, pe);
+					}
+				}
+				break;
 
 			/* uggly plain portamento for now */
 			case IT_PTM_NOTE_SLIDE_DOWN:
@@ -3168,6 +3215,7 @@
 static int envelope_get_y(IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe)
 {
 #if 1
+	(void)envelope; //TODO: remove the parameter
 	return pe->value;
 #else
 	int ys, ye;
@@ -3328,24 +3376,7 @@
 		}
 	}
 
-	if (pe->next_node <= 0)
-		pe->value = envelope->node_y[0] << IT_ENVELOPE_SHIFT;
-	else if (pe->next_node >= envelope->n_nodes)
-		pe->value = envelope->node_y[envelope->n_nodes-1] << IT_ENVELOPE_SHIFT;
-	else {
-		int ys = envelope->node_y[pe->next_node-1] << IT_ENVELOPE_SHIFT;
-		int ts = envelope->node_t[pe->next_node-1];
-		int te = envelope->node_t[pe->next_node];
-
-		if (ts == te)
-			pe->value = ys;
-		else {
-			int ye = envelope->node_y[pe->next_node] << IT_ENVELOPE_SHIFT;
-			int t = pe->tick;
-
-			pe->value = ys + (ye - ys) * (t - ts) / (te - ts);
-		}
-	}
+	xm_envelope_calculate_value(envelope, pe);
 }
 
 
@@ -3381,7 +3412,7 @@
 
 	if ((sigrenderer->n_channels == 2) && (sigdata->flags & IT_STEREO)) {
 		pan = apply_pan_envelope(playing);
-		if ((sigdata->flags & IT_WAS_AN_S3M) && (pan > (64<<8))) {
+		if ((sigdata->flags & IT_WAS_AN_S3M) && IT_IS_SURROUND_SHIFTED(pan)) {
 			volume = -1.0f * (float)(pan) * (1.0f / (64.0f * 256.0f));
 		} else {
 			volume = 1.0f;
@@ -4000,8 +4031,13 @@
 {
 	int bits;
 
+	int pan;
+	float span; /* separated pan, range -1 to 1; garbage for surround */
+
 	long size_rendered;
 
+	DUMB_VOLUME_RAMP_INFO lvol, rvol;
+
 	if (playing->flags & IT_PLAYING_DEAD)
 		return 0;
 
@@ -4013,83 +4049,104 @@
 		int quality = sigrenderer->resampling_quality;
 		if (playing->sample->max_resampling_quality >= 0 && quality > playing->sample->max_resampling_quality)
 			quality = playing->sample->max_resampling_quality;
-		playing->resampler[0].quality = quality;
-		playing->resampler[1].quality = quality;
+		playing->resampler.quality = quality;
 	}
 #endif
 
 	bits = playing->sample->flags & IT_SAMPLE_16BIT ? 16 : 8;
 
-#define RESAMPLERV(rv, resampler, dst, rampvol, rampdelta, volume, mix_volume)						 \
-{																	 \
-	rv = dumb_resample_n(bits, resampler, dst, size, rampvol, rampdelta, volume, mix_volume, delta); \
-	if (store_end_sample)											 \
-		(dst)[rv] = RESAMPLE_VALUE(resampler, *(rampvol) * mix_volume);				 \
-}
-
-#define RESAMPLE(resampler, dst, rampvol, rampdelta, volume, mix_volume)   \
-{										   \
-	int i;								   \
-	RESAMPLERV(i, resampler, dst, rampvol, rampdelta, volume, mix_volume); \
-}
-
-#define RESAMPLE_VALUE(resampler, volume) \
-	dumb_resample_get_current_sample_n(bits, resampler, volume)
-
 	if (volume == 0) {
-		size_rendered = dumb_resample_n(bits, &playing->resampler[0], NULL, size, 0, 0, 0, 0, delta);
 		if (playing->sample->flags & IT_SAMPLE_STEREO)
-			dumb_resample_n(bits, &playing->resampler[1], NULL, size, 0, 0, 0, 0, delta);
+			size_rendered = dumb_resample_n_2_1(bits, &playing->resampler, NULL, size, 0, 0, delta);
+		else
+			size_rendered = dumb_resample_n_1_1(bits, &playing->resampler, NULL, size, 0, delta);
 	} else {
+		lvol.volume = playing->ramp_volume [0];
+		rvol.volume = playing->ramp_volume [1];
+		lvol.delta  = playing->ramp_delta [0] * main_delta;
+		rvol.delta  = playing->ramp_delta [1] * main_delta;
+		lvol.target = playing->float_volume [0];
+		rvol.target = playing->float_volume [1];
+		rvol.mix = lvol.mix = volume;
 		if (sigrenderer->n_channels == 2) {
-			DUMB_RESAMPLER start = playing->resampler[0];
-			if ((cr_record_which & 1) && sigrenderer->click_remover && sigrenderer->click_remover[0])
-				dumb_record_click(sigrenderer->click_remover[0], pos, RESAMPLE_VALUE(&playing->resampler[0], playing->ramp_volume[0] * volume));
-			RESAMPLERV(size_rendered, &playing->resampler[0], samples[0] + pos, &playing->ramp_volume[0], playing->ramp_delta[0] * main_delta, playing->float_volume[0], volume);
-			if ((cr_record_which & 2) && sigrenderer->click_remover && sigrenderer->click_remover[0])
-				dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -RESAMPLE_VALUE(&playing->resampler[0], playing->ramp_volume[0] * volume));
 			if (playing->sample->flags & IT_SAMPLE_STEREO) {
-				if ((cr_record_which & 1) && sigrenderer->click_remover && sigrenderer->click_remover[1])
-					dumb_record_click(sigrenderer->click_remover[1], pos, RESAMPLE_VALUE(&playing->resampler[1], playing->ramp_volume[1] * volume));
-				RESAMPLE(&playing->resampler[1], samples[1] + pos, &playing->ramp_volume[1], playing->ramp_delta[1] * main_delta, playing->float_volume[1], volume);
-				if ((cr_record_which & 2) && sigrenderer->click_remover && sigrenderer->click_remover[1])
-					dumb_record_click(sigrenderer->click_remover[1], pos + size_rendered, -RESAMPLE_VALUE(&playing->resampler[1], playing->ramp_volume[1] * volume));
+				if ((cr_record_which & 1) && sigrenderer->click_remover) {
+					sample_t click[2];
+					dumb_resample_get_current_sample_n_2_2(bits, &playing->resampler, &lvol, &rvol, click);
+					dumb_record_click(sigrenderer->click_remover[0], pos, click[0]);
+					dumb_record_click(sigrenderer->click_remover[1], pos, click[1]);
+				}
+				size_rendered = dumb_resample_n_2_2(bits, &playing->resampler, samples[0] + pos*2, size, &lvol, &rvol, delta);
+				if (store_end_sample) {
+					sample_t click[2];
+					dumb_resample_get_current_sample_n_2_2(bits, &playing->resampler, &lvol, &rvol, click);
+					samples[0][(pos + size_rendered) * 2] = click[0];
+					samples[0][(pos + size_rendered) * 2 + 1] = click[1];
+				}
+				if ((cr_record_which & 2) && sigrenderer->click_remover) {
+					sample_t click[2];
+					dumb_resample_get_current_sample_n_2_2(bits, &playing->resampler, &lvol, &rvol, click);
+					dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click[0]);
+					dumb_record_click(sigrenderer->click_remover[1], pos + size_rendered, -click[1]);
+				}
 			} else {
-				playing->resampler[0] = start;
-				if ((cr_record_which & 1) && sigrenderer->click_remover && sigrenderer->click_remover[1])
-					dumb_record_click(sigrenderer->click_remover[1], pos, RESAMPLE_VALUE(&playing->resampler[0], playing->ramp_volume[1] * volume));
-				RESAMPLE(&playing->resampler[0], samples[1] + pos, &playing->ramp_volume[1], playing->ramp_delta[1] * main_delta, playing->float_volume[1], volume);
-				if ((cr_record_which & 2) && sigrenderer->click_remover && sigrenderer->click_remover[1])
-					dumb_record_click(sigrenderer->click_remover[1], pos + size_rendered, -RESAMPLE_VALUE(&playing->resampler[0], playing->ramp_volume[1] * volume));
+				if ((cr_record_which & 1) && sigrenderer->click_remover) {
+					sample_t click[2];
+					dumb_resample_get_current_sample_n_1_2(bits, &playing->resampler, &lvol, &rvol, click);
+					dumb_record_click(sigrenderer->click_remover[0], pos, click[0]);
+					dumb_record_click(sigrenderer->click_remover[1], pos, click[1]);
+				}
+				size_rendered = dumb_resample_n_1_2(bits, &playing->resampler, samples[0] + pos*2, size, &lvol, &rvol, delta);
+				if (store_end_sample) {
+					sample_t click[2];
+					dumb_resample_get_current_sample_n_1_2(bits, &playing->resampler, &lvol, &rvol, click);
+					samples[0][(pos + size_rendered) * 2] = click[0];
+					samples[0][(pos + size_rendered) * 2 + 1] = click[1];
+				}
+				if ((cr_record_which & 2) && sigrenderer->click_remover) {
+					sample_t click[2];
+					dumb_resample_get_current_sample_n_1_2(bits, &playing->resampler, &lvol, &rvol, click);
+					dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click[0]);
+					dumb_record_click(sigrenderer->click_remover[1], pos + size_rendered, -click[1]);
+				}
 			}
 		} else {
 			if (playing->sample->flags & IT_SAMPLE_STEREO) {
-				if (cr_record_which && sigrenderer->click_remover && sigrenderer->click_remover[0]) {
-					sample_t startstep, endstep;
-					startstep = RESAMPLE_VALUE(&playing->resampler[0], playing->ramp_volume[0] * volume);
-					RESAMPLE(&playing->resampler[0], samples[0] + pos, &playing->ramp_volume[0], playing->ramp_delta[0] * main_delta, playing->float_volume[0], volume);
-					endstep = RESAMPLE_VALUE(&playing->resampler[0], playing->ramp_volume[0] * volume);
-					startstep += RESAMPLE_VALUE(&playing->resampler[1], playing->ramp_volume[1] * volume);
-					RESAMPLERV(size_rendered, &playing->resampler[1], samples[0] + pos, &playing->ramp_volume[1], playing->ramp_delta[1] * main_delta, playing->float_volume[1], volume);
-					endstep += RESAMPLE_VALUE(&playing->resampler[1], playing->ramp_volume[1] * volume);
-					if (cr_record_which & 1) dumb_record_click(sigrenderer->click_remover[0], pos, startstep);
-					if (cr_record_which & 2) dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -endstep);
-				} else {
-					RESAMPLE(&playing->resampler[0], samples[0] + pos, &playing->ramp_volume[0], playing->ramp_delta[0] * main_delta, playing->float_volume[0], volume);
-					RESAMPLERV(size_rendered, &playing->resampler[1], samples[0] + pos, &playing->ramp_volume[1], playing->ramp_delta[1] * main_delta, playing->float_volume[1], volume);
+				if ((cr_record_which & 1) && sigrenderer->click_remover) {
+					sample_t click;
+					dumb_resample_get_current_sample_n_2_1(bits, &playing->resampler, &lvol, &rvol, &click);
+					dumb_record_click(sigrenderer->click_remover[0], pos, click);
 				}
+				size_rendered = dumb_resample_n_2_1(bits, &playing->resampler, samples[0] + pos, size, &lvol, &rvol, delta);
+				if (store_end_sample)
+					dumb_resample_get_current_sample_n_2_1(bits, &playing->resampler, &lvol, &rvol, &samples[0][pos + size_rendered]);
+				if ((cr_record_which & 2) && sigrenderer->click_remover) {
+					sample_t click;
+					dumb_resample_get_current_sample_n_2_1(bits, &playing->resampler, &lvol, &rvol, &click);
+					dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click);
+				}
 			} else {
-				if ((cr_record_which & 1) && sigrenderer->click_remover && sigrenderer->click_remover[0])
-					dumb_record_click(sigrenderer->click_remover[0], pos, RESAMPLE_VALUE(&playing->resampler[0], playing->ramp_volume[0] * volume));
-				RESAMPLERV(size_rendered, &playing->resampler[0], samples[0] + pos, &playing->ramp_volume[0], playing->ramp_delta[0] * main_delta, playing->float_volume[0], volume);
-				if ((cr_record_which & 2) && sigrenderer->click_remover && sigrenderer->click_remover[0])
-					dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -RESAMPLE_VALUE(&playing->resampler[0], playing->ramp_volume[0] * volume));
+				if ((cr_record_which & 1) && sigrenderer->click_remover) {
+					sample_t click;
+					dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, &lvol, &click);
+					dumb_record_click(sigrenderer->click_remover[0], pos, click);
+				}
+				size_rendered = dumb_resample_n_1_1(bits, &playing->resampler, samples[0] + pos, size, &lvol, delta);
+				if (store_end_sample)
+					dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, &lvol, &samples[0][pos + size_rendered]);
+				if ((cr_record_which & 2) && sigrenderer->click_remover) {
+					sample_t click;
+					dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, &lvol, &click);
+					dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click);
+				}
 			}
 		}
+		playing->ramp_volume [0] = lvol.volume;
+		playing->ramp_volume [1] = rvol.volume;
 		(*left_to_mix)--;
 	}
 
-	if (playing->resampler[0].dir == 0)
+	if (playing->resampler.dir == 0)
 		playing->flags |= IT_PLAYING_DEAD;
 
 	return size_rendered;
@@ -4109,8 +4166,7 @@
 		int quality = sigrenderer->resampling_quality;
 		if (playing->sample->max_resampling_quality >= 0 && quality > playing->sample->max_resampling_quality)
 			quality = playing->sample->max_resampling_quality;
-		playing->resampler[0].quality = quality;
-		playing->resampler[1].quality = quality;
+		playing->resampler.quality = quality;
 	}
 
 	if (ramp_style)
@@ -4336,7 +4392,7 @@
 
 		if (volume && (playing->true_filter_cutoff != 127 << IT_ENVELOPE_SHIFT || playing->true_filter_resonance != 0)) {
 			if (!samples_to_filter) {
-				samples_to_filter = create_sample_buffer(sigrenderer->n_channels, size + 1);
+				samples_to_filter = allocate_sample_buffer(sigrenderer->n_channels, size + 1);
 				if (!samples_to_filter) {
 					render_playing_ramp(sigrenderer, playing, 0, delta, note_delta, pos, size, NULL, 0, &left_to_mix, ramp_style);
 					continue;
@@ -4349,12 +4405,17 @@
 				sigrenderer->click_remover = NULL;
 				size_rendered = render_playing_ramp(sigrenderer, playing, volume, delta, note_delta, 0, size, samples_to_filter, 1, &left_to_mix, ramp_style);
 				sigrenderer->click_remover = cr;
-				it_filter(cr ? cr[0] : NULL, &playing->filter_state[0], samples[0], pos, samples_to_filter[0], size_rendered,
-					65536.0f/delta, playing->true_filter_cutoff, playing->true_filter_resonance);
-				if (sigrenderer->n_channels == 2)
-					it_filter(cr ? cr[1] : NULL, &playing->filter_state[1], samples[1], pos, samples_to_filter[1], size_rendered,
-						65536.0f/delta, playing->true_filter_cutoff, playing->true_filter_resonance);
-				// warning: filtering is not prevented by low left_to_mix!
+				if (sigrenderer->n_channels == 2) {
+					it_filter(cr ? cr[0] : NULL, &playing->filter_state[0], samples[0], pos, samples_to_filter[0], size_rendered,
+						2, (int)(65536.0f/delta), playing->true_filter_cutoff, playing->true_filter_resonance);
+					it_filter(cr ? cr[1] : NULL, &playing->filter_state[1], samples[0]+1, pos, samples_to_filter[0]+1, size_rendered,
+						2, (int)(65536.0f/delta), playing->true_filter_cutoff, playing->true_filter_resonance);
+				} else {
+					it_filter(cr ? cr[0] : NULL, &playing->filter_state[0], samples[0], pos, samples_to_filter[0], size_rendered,
+						1, (int)(65536.0f/delta), playing->true_filter_cutoff, playing->true_filter_resonance);
+				}
+				// FIXME: filtering is not prevented by low left_to_mix!
+				// FIXME: change 'warning' to 'FIXME' everywhere
 			}
 		} else {
 			it_reset_filter_state(&playing->filter_state[0]);
@@ -4560,8 +4621,7 @@
 			{
 				IT_PLAYING * playing = sigrenderer->channel[i].playing;
 				playing->resampling_quality = quality;
-				playing->resampler[0].quality = quality;
-				playing->resampler[1].quality = quality;
+				playing->resampler.quality = quality;
 			}
 		}
 		for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
@@ -4568,8 +4628,7 @@
 			if (sigrenderer->playing[i]) {
 				IT_PLAYING * playing = sigrenderer->playing[i];
 				playing->resampling_quality = quality;
-				playing->resampler[0].quality = quality;
-				playing->resampler[1].quality = quality;
+				playing->resampler.quality = quality;
 			}
 		}
 	}
@@ -4655,7 +4714,7 @@
 {
 	DUMB_IT_SIGDATA *itsd = duh_get_it_sigdata(duh);
 	DUMB_IT_SIGRENDERER *itsr = dumb_it_init_sigrenderer(itsd, n_channels, startorder);
-	/*duh->length = _dumb_it_build_checkpoints(itsd, startorder);*/
+	/*duh->length = dumb_it_build_checkpoints(itsd, startorder);*/
 	return duh_encapsulate_it_sigrenderer(itsr, n_channels, 0);
 }
 
@@ -4759,7 +4818,8 @@
 	sigrenderer->sub_time_left = (long)t & 65535;
 	sigrenderer->time_left += (long)(t >> 16);
 
-	if (volume) dumb_remove_clicks_array(sigrenderer->n_channels, sigrenderer->click_remover, samples, pos, 512.0f / delta);
+	if (samples)
+		dumb_remove_clicks_array(sigrenderer->n_channels, sigrenderer->click_remover, samples, pos, 512.0f / delta);
 
 	return pos;
 }
@@ -4900,9 +4960,19 @@
 #define FUCKIT_THRESHOLD (120 * 60 * 65536) /* two hours? probably a pattern loop mess... */
 
 /* Returns the length of the module, up until it first loops. */
-long _dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata, int startorder)
+long dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata, int startorder)
 {
-	IT_CHECKPOINT *checkpoint = malloc(sizeof(*checkpoint));
+	IT_CHECKPOINT *checkpoint;
+	if (!sigdata) return 0;
+	checkpoint = sigdata->checkpoint;
+	while (checkpoint) {
+		IT_CHECKPOINT *next = checkpoint->next;
+		_dumb_it_end_sigrenderer(checkpoint->sigrenderer);
+		free(checkpoint);
+		checkpoint = next;
+	}
+	sigdata->checkpoint = NULL;
+	checkpoint = malloc(sizeof(*checkpoint));
 	if (!checkpoint) return 0;
 	checkpoint->time = 0;
 	checkpoint->sigrenderer = dumb_it_init_sigrenderer(sigdata, 0, startorder);
@@ -4960,6 +5030,18 @@
 	}
 }
 
+
+
+void dumb_it_do_initial_runthrough(DUH *duh)
+{
+	if (duh) {
+		DUMB_IT_SIGDATA *sigdata = duh_get_it_sigdata(duh);
+
+		if (sigdata)
+			duh_set_length(duh, dumb_it_build_checkpoints(sigdata, 0));
+	}
+}
+
 static int is_pattern_silent(IT_PATTERN * pattern, int order) {
 	int ret = 1;
 	IT_ENTRY * entry, * end;
@@ -5096,7 +5178,7 @@
 
 	if (n < 0) return -1;
 
-	/*duh->length = _dumb_it_build_checkpoints(sigdata, 0);*/
+	/*duh->length = dumb_it_build_checkpoints(sigdata, 0);*/
 
 	return 0;
 }
--- a/dumb/src/it/itunload.c
+++ b/dumb/src/it/itunload.c
@@ -40,12 +40,10 @@
 			free(sigdata->instrument);
 
 		if (sigdata->sample) {
-			for (n = 0; n < sigdata->n_samples; n++) {
-				if (sigdata->sample[n].left)
-					free(sigdata->sample[n].left);
-				if (sigdata->sample[n].right)
-					free(sigdata->sample[n].right);
-			}
+			for (n = 0; n < sigdata->n_samples; n++)
+				if (sigdata->sample[n].data)
+					free(sigdata->sample[n].data);
+
 			free(sigdata->sample);
 		}
 
--- a/dumb/src/it/load669.c
+++ b/dumb/src/it/load669.c
@@ -12,8 +12,8 @@
  *             file, opening and closing it for      | <  /   \_
  *             you.                                  |  \/ /\   /
  *                                                    \_  /  > /
- * By Chris Moeller, mostly based on loadmod.c          | \ / /
- * by entheh.                                           |  ' /
+ * By Chris Moeller                                     | \ / /
+ *                                                      |  ' /
  *                                                       \__/
  */
 
@@ -22,11 +22,11 @@
 
 
 
-/* dumb_load_669(): loads a 669 file into a DUH struct, returning a pointer
- * 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.
+/* dumb_load_669_quick(): loads a 669 file into a DUH struct, returning a
+ * pointer 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_669(const char *filename)
+DUH *dumb_load_669_quick(const char *filename)
 {
 	DUH *duh;
 	DUMBFILE *f = dumbfile_open(filename);
@@ -34,7 +34,7 @@
 	if (!f)
 		return NULL;
 
-	duh = dumb_read_669(f);
+	duh = dumb_read_669_quick(f);
 
 	dumbfile_close(f);
 
--- /dev/null
+++ b/dumb/src/it/load6692.c
@@ -1,0 +1,34 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * loadmod2.c - Code to read a 669 Composer module    / / \  \
+ *              file, opening and closing it for     | <  /   \_
+ *              you, and do an initial run-through.  |  \/ /\   /
+ *                                                    \_  /  > /
+ * By Chris Moeller                                     | \ / /
+ *                                                      |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_669(): loads a 669 file into a DUH struct, returning a pointer
+ * 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_669(const char *filename)
+{
+	DUH *duh = dumb_load_669_quick(filename);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/loadasy.c
+++ b/dumb/src/it/loadasy.c
@@ -22,11 +22,11 @@
 
 
 
-/* dumb_load_asy(): loads a AMF file into a DUH struct, returning a pointer
- * 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.
+/* dumb_load_asy_quick(): loads a AMF file into a DUH struct, returning a
+ * pointer 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_asy(const char *filename)
+DUH *dumb_load_asy_quick(const char *filename)
 {
 	DUH *duh;
 	DUMBFILE *f = dumbfile_open(filename);
@@ -34,7 +34,7 @@
 	if (!f)
 		return NULL;
 
-	duh = dumb_read_asy(f);
+	duh = dumb_read_asy_quick(f);
 
 	dumbfile_close(f);
 
--- /dev/null
+++ b/dumb/src/it/loadasy2.c
@@ -1,0 +1,34 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * loadasy2.c - Code to read an ASYLUM Music Format   / / \  \
+ *              module file, opening and closing it  | <  /   \_
+ *              for you, and do an initial run-      |  \/ /\   /
+ *              through.                              \_  /  > /
+ *                                                      | \ / /
+ * By Chris Moeller.                                    |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_asy(): loads a AMF file into a DUH struct, returning a pointer
+ * 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_asy(const char *filename)
+{
+	DUH *duh = dumb_load_asy_quick(filename);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/loadmod.c
+++ b/dumb/src/it/loadmod.c
@@ -22,11 +22,11 @@
 
 
 
-/* dumb_load_mod(): loads a MOD file into a DUH struct, returning a pointer
- * 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.
+/* dumb_load_mod_quick(): loads a MOD file into a DUH struct, returning a
+ * pointer 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, int restrict)
+DUH *dumb_load_mod_quick(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, restrict);
+	duh = dumb_read_mod_quick(f, restrict);
 
 	dumbfile_close(f);
 
--- /dev/null
+++ b/dumb/src/it/loadmod2.c
@@ -1,0 +1,29 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * loadmod2.c - Function to read a good old-          / / \  \
+ *              fashioned Amiga module file,         | <  /   \_
+ *              opening and closing it for you,      |  \/ /\   /
+ *              and do an initial run-through.        \_  /  > /
+ *                                                      | \ / /
+ * Split off from loadmod.c by entheh.                  |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_load_mod(const char *filename, int restrict)
+{
+	DUH *duh = dumb_load_mod_quick(filename, restrict);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/loadmtm.c
+++ b/dumb/src/it/loadmtm.c
@@ -12,8 +12,8 @@
  *             file, opening and closing it for      | <  /   \_
  *             you.                                  |  \/ /\   /
  *                                                    \_  /  > /
- * By Chris Moeller, mostly based on loadmod.c          | \ / /
- * by entheh.                                           |  ' /
+ * By Chris Moeller                                     | \ / /
+ *                                                      |  ' /
  *                                                       \__/
  */
 
@@ -22,11 +22,11 @@
 
 
 
-/* dumb_load_mtm(): loads a MTM file into a DUH struct, returning a pointer
- * 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.
+/* dumb_load_mtm_quick(): loads a MTM file into a DUH struct, returning a
+ * pointer 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_mtm(const char *filename)
+DUH *dumb_load_mtm_quick(const char *filename)
 {
 	DUH *duh;
 	DUMBFILE *f = dumbfile_open(filename);
@@ -34,7 +34,7 @@
 	if (!f)
 		return NULL;
 
-	duh = dumb_read_mtm(f);
+	duh = dumb_read_mtm_quick(f);
 
 	dumbfile_close(f);
 
--- /dev/null
+++ b/dumb/src/it/loadmtm2.c
@@ -1,0 +1,34 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * loadmtm2.c - Code to read a MultiTracker Module    / / \  \
+ *              file, opening and closing it for     | <  /   \_
+ *              you, and do an initial run-through.  |  \/ /\   /
+ *                                                    \_  /  > /
+ * By Chris Moeller                                     | \ / /
+ *                                                      |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_mtm(): loads a MTM file into a DUH struct, returning a pointer
+ * 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_mtm(const char *filename)
+{
+	DUH *duh = dumb_load_mtm_quick(filename);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/loadoldpsm.c
+++ b/dumb/src/it/loadoldpsm.c
@@ -8,9 +8,9 @@
  * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
  *                                                      /  \
  *                                                     / .  \
- * loads3m.c - Code to read a ProTracker Studio       / / \  \
- *             file, opening and closing it for      | <  /   \_
- *             you.                                  |  \/ /\   /
+ * loadoldpsm.c - Code to read a ProTracker Studio    / / \  \
+ *                file, opening and closing it for   | <  /   \_
+ *                you.                               |  \/ /\   /
  *                                                    \_  /  > /
  * By Chris Moeller.                                    | \ / /
  *                                                      |  ' /
@@ -22,11 +22,12 @@
 
 
 
-/* dumb_load_psm(): loads an old PSM file into a DUH struct, returning a pointer
- * 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.
+/* dumb_load_old_psm_quick(): loads an old PSM file into a DUH struct,
+ * returning a pointer 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_old_psm(const char *filename)
+DUH *dumb_load_old_psm_quick(const char *filename)
 {
 	DUH *duh;
 	DUMBFILE *f = dumbfile_open(filename);
@@ -34,7 +35,7 @@
 	if (!f)
 		return NULL;
 
-	duh = dumb_read_old_psm(f);
+	duh = dumb_read_old_psm_quick(f);
 
 	dumbfile_close(f);
 
--- /dev/null
+++ b/dumb/src/it/loadoldpsm2.c
@@ -1,0 +1,34 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * loadoldpsm2.c - Code to read a ProTracker Studio   / / \  \
+ *                 file, opening and closing it for  | <  /   \_
+ *                 you, and do an initial run-       |  \/ /\   /
+ *                 through.                           \_  /  > /
+ *                                                      | \ / /
+ * By Chris Moeller.                                    |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_old_psm(): loads an old PSM file into a DUH struct, returning
+ * a pointer 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_old_psm(const char *filename)
+{
+	DUH *duh = dumb_load_old_psm_quick(filename);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/loadpsm.c
+++ b/dumb/src/it/loadpsm.c
@@ -22,11 +22,11 @@
 
 
 
-/* dumb_load_psm(): loads a PSM file into a DUH struct, returning a pointer
- * 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.
+/* dumb_load_psm_quick(): loads a PSM file into a DUH struct, returning a
+ * pointer 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_psm(const char *filename, int subsong)
+DUH *dumb_load_psm_quick(const char *filename, int subsong)
 {
 	DUH *duh;
 	DUMBFILE *f = dumbfile_open(filename);
@@ -34,7 +34,7 @@
 	if (!f)
 		return NULL;
 
-	duh = dumb_read_psm(f, subsong);
+	duh = dumb_read_psm_quick(f, subsong);
 
 	dumbfile_close(f);
 
--- /dev/null
+++ b/dumb/src/it/loadpsm2.c
@@ -1,0 +1,34 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * loadpsm2.c - Code to read a ProTracker Studio      / / \  \
+ *              file, opening and closing it for     | <  /   \_
+ *              you, and do an initial run-through.  |  \/ /\   /
+ *                                                    \_  /  > /
+ * By Chris Moeller.                                    | \ / /
+ *                                                      |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_psm(): loads a PSM file into a DUH struct, returning a pointer
+ * 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_psm(const char *filename, int subsong)
+{
+	DUH *duh = dumb_load_psm_quick(filename, subsong);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- /dev/null
+++ b/dumb/src/it/loadptm.c
@@ -1,0 +1,42 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * loadptm.c - Code to read a Poly Tracker v2.03      / / \  \
+ *             file, opening and closing it for      | <  /   \_
+ *             you.                                  |  \/ /\   /
+ *                                                    \_  /  > /
+ * By Chris Moeller.                                    | \ / /
+ *                                                      |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_ptm_quick(): loads a PTM file into a DUH struct, returning a
+ * pointer 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_ptm_quick(const char *filename)
+{
+	DUH *duh;
+	DUMBFILE *f = dumbfile_open(filename);
+
+	if (!f)
+		return NULL;
+
+	duh = dumb_read_ptm_quick(f);
+
+	dumbfile_close(f);
+
+	return duh;
+}
--- /dev/null
+++ b/dumb/src/it/loadptm2.c
@@ -1,0 +1,34 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * loadptm2.c - Code to read a Poly Tracker v2.03     / / \  \
+ *              file, opening and closing it for     | <  /   \_
+ *              you, and do an initial run-through.  |  \/ /\   /
+ *                                                    \_  /  > /
+ * By Chris Moeller.                                    | \ / /
+ *                                                      |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+#include "internal/it.h"
+
+
+
+/* dumb_load_ptm(): loads a PTM file into a DUH struct, returning a pointer
+ * 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_ptm(const char *filename)
+{
+	DUH *duh = dumb_load_ptm_quick(filename);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/loadriff.c
+++ b/dumb/src/it/loadriff.c
@@ -22,11 +22,11 @@
 
 
 
-/* dumb_load_riff(): loads a RIFF file into a DUH struct, returning a pointer
- * 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.
+/* dumb_load_riff_quick(): loads a RIFF file into a DUH struct, returning
+ * a pointer 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_riff( const char *filename )
+DUH * dumb_load_riff_quick( const char *filename )
 {
 	DUH * duh;
 	DUMBFILE * f = dumbfile_open( filename );
@@ -34,7 +34,7 @@
 	if ( ! f )
 		return NULL;
 
-	duh = dumb_read_riff( f );
+	duh = dumb_read_riff_quick( f );
 
 	dumbfile_close( f );
 
--- /dev/null
+++ b/dumb/src/it/loadriff2.c
@@ -1,0 +1,29 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * loadriff2.c - Code to read a RIFF module file      / / \  \
+ *               opening and closing it for you,     | <  /   \_
+ *               and do an initial run-through.      |  \/ /\   /
+ *                                                    \_  /  > /
+ * By Chris Moeller.                                    | \ / /
+ *                                                      |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_load_riff(const char *filename)
+{
+	DUH *duh = dumb_load_riff_quick(filename);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/loads3m.c
+++ b/dumb/src/it/loads3m.c
@@ -22,11 +22,11 @@
 
 
 
-/* dumb_load_s3m(): loads an S3M file into a DUH struct, returning a pointer
- * 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.
+/* dumb_load_s3m_quick(): loads an S3M file into a DUH struct, returning
+ * a pointer 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_s3m(const char *filename)
+DUH *dumb_load_s3m_quick(const char *filename)
 {
 	DUH *duh;
 	DUMBFILE *f = dumbfile_open(filename);
@@ -34,7 +34,7 @@
 	if (!f)
 		return NULL;
 
-	duh = dumb_read_s3m(f);
+	duh = dumb_read_s3m_quick(f);
 
 	dumbfile_close(f);
 
--- /dev/null
+++ b/dumb/src/it/loads3m2.c
@@ -1,0 +1,29 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * loads3m2.c - Function to read a ScreamTracker 3    / / \  \
+ *              file, opening and closing it for     | <  /   \_
+ *              you, and do an initial run-through.  |  \/ /\   /
+ *                                                    \_  /  > /
+ * Split off from loads3m.c by entheh.                  | \ / /
+ *                                                      |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_load_s3m(const char *filename)
+{
+	DUH *duh = dumb_load_s3m_quick(filename);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/loadstm.c
+++ b/dumb/src/it/loadstm.c
@@ -22,11 +22,11 @@
 
 
 
-/* dumb_load_stm(): loads an STM file into a DUH struct, returning a pointer
- * 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.
+/* dumb_load_stm_quick(): loads an STM file into a DUH struct, returning a
+ * pointer 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_stm(const char *filename)
+DUH *dumb_load_stm_quick(const char *filename)
 {
 	DUH *duh;
 	DUMBFILE *f = dumbfile_open(filename);
@@ -34,7 +34,7 @@
 	if (!f)
 		return NULL;
 
-	duh = dumb_read_stm(f);
+	duh = dumb_read_stm_quick(f);
 
 	dumbfile_close(f);
 
--- /dev/null
+++ b/dumb/src/it/loadstm2.c
@@ -1,0 +1,29 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * loadstm2.c - Function to read a ScreamTracker 2    / / \  \
+ *              file, opening and closing it for     | <  /   \_
+ *              you, and do an initial run-through.  |  \/ /\   /
+ *                                                    \_  /  > /
+ * By Chris Moeller.                                    | \ / /
+ *                                                      |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_load_stm(const char *filename)
+{
+	DUH *duh = dumb_load_stm_quick(filename);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/loadxm.c
+++ b/dumb/src/it/loadxm.c
@@ -22,11 +22,11 @@
 
 
 
-/* dumb_load_xm(): loads an XM file into a DUH struct, returning a pointer
- * 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.
+/* dumb_load_xm_quick(): loads an XM file into a DUH struct, returning a
+ * pointer 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_xm(const char *filename)
+DUH *dumb_load_xm_quick(const char *filename)
 {
 	DUH *duh;
 	DUMBFILE *f = dumbfile_open(filename);
@@ -34,7 +34,7 @@
 	if (!f)
 		return NULL;
 
-	duh = dumb_read_xm(f);
+	duh = dumb_read_xm_quick(f);
 
 	dumbfile_close(f);
 
--- /dev/null
+++ b/dumb/src/it/loadxm2.c
@@ -1,0 +1,29 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * loadxm2.c - Function to read a Fast Tracker II     / / \  \
+ *             file, opening and closing it for      | <  /   \_
+ *             you, and do an initial run-through.   |  \/ /\   /
+ *                                                    \_  /  > /
+ * Split off from loadxm.c by entheh.                   | \ / /
+ *                                                      |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_load_xm(const char *filename)
+{
+	DUH *duh = dumb_load_xm_quick(filename);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/read669.c
+++ b/dumb/src/it/read669.c
@@ -219,14 +219,14 @@
 		truncated_size = 0;
 	}
 
-	sample->left = malloc(sample->length);
+	sample->data = malloc(sample->length);
 
-	if (!sample->left)
+	if (!sample->data)
 		return -1;
 
 	if (sample->length)
 	{
-		i = dumbfile_getnc(sample->left, sample->length, f);
+		i = dumbfile_getnc(sample->data, sample->length, f);
 		
 		if (i < sample->length) {
 			//return -1;
@@ -246,7 +246,7 @@
 		}
 
 		for (i = 0; i < sample->length; i++)
-			((signed char *)sample->left)[i] ^= 0x80;
+			((signed char *)sample->data)[i] ^= 0x80;
 	}
 
 	return 0;
@@ -352,7 +352,7 @@
 	}
 
 	for (i = 0; i < sigdata->n_samples; i++)
-		sigdata->sample[i].right = sigdata->sample[i].left = NULL;
+		sigdata->sample[i].data = NULL;
 
 	for (i = 0; i < sigdata->n_samples; i++) {
 		if (it_669_read_sample_header(&sigdata->sample[i], f)) {
@@ -427,10 +427,9 @@
 
 
 
-DUH *dumb_read_669(DUMBFILE *f)
+DUH *dumb_read_669_quick(DUMBFILE *f)
 {
 	sigdata_t *sigdata;
-	long length;
 	int ext;
 
 	DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
@@ -440,8 +439,6 @@
 	if (!sigdata)
 		return NULL;
 
-	length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
-
 	{
 		const char *tag[2][2];
 		tag[0][0] = "TITLE";
@@ -448,6 +445,6 @@
 		tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
 		tag[1][0] = "FORMAT";
 		tag[1][1] = ext ? "669 Extended" : "669";
-		return make_duh(length, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+		return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
 	}
 }
--- a/dumb/src/it/readam.c
+++ b/dumb/src/it/readam.c
@@ -133,11 +133,11 @@
 
 	length_bytes = sample->length << ( ( flags & 0x04 ) >> 2 );
 
-	sample->left = malloc( length_bytes );
-	if ( ! sample->left )
+	sample->data = malloc( length_bytes );
+	if ( ! sample->data )
 		return -1;
 
-	memcpy( sample->left, data + header_length, length_bytes );
+	memcpy( sample->data, data + header_length, length_bytes );
 
 	return 0;
 }
@@ -381,7 +381,7 @@
 	for ( n = 0; n < sigdata->n_samples; ++n )
 	{
 		IT_SAMPLE * sample = sigdata->sample + n;
-		sample->right = sample->left = NULL;
+		sample->data = NULL;
 		sample->flags = 0;
 		sample->name[ 0 ] = 0;
 	}
@@ -606,7 +606,7 @@
 	for ( n = 0; n < sigdata->n_samples; ++n )
 	{
 		IT_SAMPLE * sample = sigdata->sample + n;
-		sample->right = sample->left = NULL;
+		sample->data = NULL;
 		sample->flags = 0;
 		sample->name[ 0 ] = 0;
 	}
@@ -732,7 +732,6 @@
 DUH *dumb_read_riff_am( struct riff * stream )
 {
 	sigdata_t *sigdata;
-	long length;
 
 	DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
 
@@ -741,8 +740,6 @@
 	if (!sigdata)
 		return NULL;
 
-	length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
-
 	{
 		const char *tag[2][2];
 		tag[0][0] = "TITLE";
@@ -749,6 +746,6 @@
 		tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
 		tag[1][0] = "FORMAT";
 		tag[1][1] = "RIFF AM";
-		return make_duh( length, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
+		return make_duh( -1, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
 	}
 }
--- a/dumb/src/it/readasy.c
+++ b/dumb/src/it/readasy.c
@@ -153,13 +153,13 @@
 		truncated_size = 0;
 	}
 
-	sample->left = malloc( sample->length );
+	sample->data = malloc( sample->length );
 
-	if ( !sample->left )
+	if ( !sample->data )
 		return -1;
 
 	if ( sample->length )
-		dumbfile_getnc( sample->left, sample->length, f );
+		dumbfile_getnc( sample->data, sample->length, f );
 
 	dumbfile_skip( f, truncated_size );
 
@@ -235,7 +235,7 @@
 	sigdata->n_instruments = 0;
 
 	for ( i = 0; i < sigdata->n_samples; ++i )
-		sigdata->sample[i].right = sigdata->sample[i].left = NULL;
+		sigdata->sample[i].data = NULL;
 
 	for ( i = 0; i < sigdata->n_samples; ++i ) {
 		if ( it_asy_read_sample_header( &sigdata->sample[i], f ) ) {
@@ -309,10 +309,9 @@
 
 
 
-DUH *dumb_read_asy(DUMBFILE *f)
+DUH *dumb_read_asy_quick(DUMBFILE *f)
 {
 	sigdata_t *sigdata;
-	long length;
 
 	DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
 
@@ -321,8 +320,6 @@
 	if (!sigdata)
 		return NULL;
 
-	length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
-
 	{
 		const char *tag[2][2];
 		tag[0][0] = "TITLE";
@@ -329,6 +326,6 @@
 		tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
 		tag[1][0] = "FORMAT";
 		tag[1][1] = "ASYLUM Music Format";
-		return make_duh(length, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+		return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
 	}
 }
--- a/dumb/src/it/readdsmf.c
+++ b/dumb/src/it/readdsmf.c
@@ -75,16 +75,16 @@
 		}
 	}
 
-	sample->left = malloc( sample->length );
-	if ( ! sample->left )
+	sample->data = malloc( sample->length );
+	if ( ! sample->data )
 		return -1;
 
-	memcpy( sample->left, data + 64, sample->length );
+	memcpy( sample->data, data + 64, sample->length );
 
 	if ( ! ( flags & 2 ) )
 	{
 		for ( flags = 0; flags < sample->length; ++flags )
-			( ( signed char * ) sample->left ) [ flags ] ^= 0x80;
+			( ( signed char * ) sample->data ) [ flags ] ^= 0x80;
 	}
 
 	return 0;
@@ -314,7 +314,7 @@
 	for ( n = 0; n < sigdata->n_samples; ++n )
 	{
 		IT_SAMPLE * sample = sigdata->sample + n;
-		sample->right = sample->left = NULL;
+		sample->data = NULL;
 	}
 
 	sigdata->n_samples = 0;
@@ -353,7 +353,6 @@
 DUH *dumb_read_riff_dsmf( struct riff * stream )
 {
 	sigdata_t *sigdata;
-	long length;
 
 	DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
 
@@ -362,8 +361,6 @@
 	if (!sigdata)
 		return NULL;
 
-	length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
-
 	{
 		const char *tag[2][2];
 		tag[0][0] = "TITLE";
@@ -370,6 +367,6 @@
 		tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
 		tag[1][0] = "FORMAT";
 		tag[1][1] = "RIFF DSMF";
-		return make_duh( length, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
+		return make_duh( -1, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
 	}
 }
--- a/dumb/src/it/readmod.c
+++ b/dumb/src/it/readmod.c
@@ -11,7 +11,7 @@
  * readmod.c - Code to read a good old-fashioned      / / \  \
  *             Amiga module from an open file.       | <  /   \_
  *                                                   |  \/ /\   /
- * By Ben Davis.                                      \_  /  > /
+ * By entheh.                                         \_  /  > /
  *                                                      | \ / /
  *                                                      |  ' /
  *                                                       \__/
@@ -193,25 +193,24 @@
 		truncated_size = 0;
 	}
 
-	sample->left = malloc(sample->length);
+	if (sample->length) {
+		sample->data = malloc(sample->length);
 
-	if (!sample->left)
-		return -1;
+		if (!sample->data)
+			return -1;
 
-	/* Sample data are stored in "8-bit two's compliment format" (sic). */
-	/*
-	for (i = 0; i < sample->length; i++)
-		((signed char *)sample->left)[i] = dumbfile_getc(f);
-	*/
-	if (sample->length)
-	{
+		/* Sample data are stored in "8-bit two's compliment format" (sic). */
+		/*
+		for (i = 0; i < sample->length; i++)
+			((signed char *)sample->left)[i] = dumbfile_getc(f);
+		*/
 		/* F U Olivier Lapicque */
 		if (sample->length >= 5)
 		{
-			i = dumbfile_getnc(sample->left, 5, f);
+			i = dumbfile_getnc(sample->data, 5, f);
 			if (i == 5)
 			{
-				if (!memcmp(sample->left, "ADPCM", 5))
+				if (!memcmp(sample->data, "ADPCM", 5))
 				{
 					if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
 						return -1;
@@ -220,13 +219,13 @@
 				}
 				else
 				{
-					i += dumbfile_getnc(((char *)sample->left) + 5, sample->length - 5, f);
+					i += dumbfile_getnc(((char *)sample->data) + 5, sample->length - 5, f);
 				}
 			}
 		}
 		else
 		{
-			i = dumbfile_getnc(sample->left, sample->length, f);
+			i = dumbfile_getnc(sample->data, sample->length, f);
 		}
 		if (i < sample->length)
 		{
@@ -255,8 +254,8 @@
 		if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) {
 			int delta = 0;
 			for (i = 0; i < sample->length; i++) {
-				delta += ((signed char *)sample->left)[i];
-				((signed char *)sample->left)[i] = delta;
+				delta += ((signed char *)sample->data)[i];
+				((signed char *)sample->data)[i] = delta;
 			}
 		}
 	}
@@ -572,7 +571,7 @@
 	sigdata->n_instruments = 0;
 
 	for (i = 0; i < sigdata->n_samples; i++)
-		sigdata->sample[i].right = sigdata->sample[i].left = NULL;
+		sigdata->sample[i].data = NULL;
 
 	for (i = 0; i < sigdata->n_samples; i++) {
 		if (it_mod_read_sample_header(&sigdata->sample[i], f)) {
@@ -733,10 +732,9 @@
 
 
 
-DUH *dumb_read_mod(DUMBFILE *f, int restrict)
+DUH *dumb_read_mod_quick(DUMBFILE *f, int restrict)
 {
 	sigdata_t *sigdata;
-	long length;
 
 	DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
 
@@ -745,8 +743,6 @@
 	if (!sigdata)
 		return NULL;
 
-	length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
-
 	{
 		const char *tag[2][2];
 		tag[0][0] = "TITLE";
@@ -753,6 +749,6 @@
 		tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
 		tag[1][0] = "FORMAT";
 		tag[1][1] = "MOD";
-		return make_duh(length, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+		return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
 	}
 }
--- /dev/null
+++ b/dumb/src/it/readmod2.c
@@ -1,0 +1,29 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * readmod2.c - Function to read a good old-          / / \  \
+ *              fashioned Amiga module from an       | <  /   \_
+ *              open file and do an initial          |  \/ /\   /
+ *              run-through.                          \_  /  > /
+ *                                                      | \ / /
+ * Split off from readmod.c by entheh.                  |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_read_mod(DUMBFILE *f, int restrict)
+{
+	DUH *duh = dumb_read_mod_quick(f, restrict);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/readmtm.c
+++ b/dumb/src/it/readmtm.c
@@ -156,19 +156,20 @@
 		truncated_size = 0;
 	}
 
-	sample->left = malloc(sample->length);
+	sample->data = malloc(sample->length);
 
-	if (!sample->left)
+	if (!sample->data)
 		return -1;
 
-	for (i = 0; i < sample->length; i++)
-		((signed char *)sample->left)[i] = dumbfile_getc(f) ^ 0x80;
-
+	dumbfile_getnc((char *)sample->data, sample->length, f);
 	dumbfile_skip(f, truncated_size);
 
 	if (dumbfile_error(f))
 		return -1;
 
+	for (i = 0; i < sample->length; i++)
+		((signed char *)sample->data)[i] ^= 0x80;
+
 	return 0;
 }
 
@@ -257,7 +258,7 @@
 	sigdata->n_pchannels = n_channels;
 
 	for (n = 0; n < sigdata->n_samples; n++)
-		sigdata->sample[n].right = sigdata->sample[n].left = NULL;
+		sigdata->sample[n].data = NULL;
 
 	for (n = 0; n < sigdata->n_samples; n++) {
 		if (it_mtm_read_sample_header(&sigdata->sample[n], f)) goto error_usd;
@@ -377,10 +378,9 @@
 	else return in + 'A' - 10;
 }
 
-DUH *dumb_read_mtm(DUMBFILE *f)
+DUH *dumb_read_mtm_quick(DUMBFILE *f)
 {
 	sigdata_t *sigdata;
-	long length;
 	int ver;
 
 	DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
@@ -390,8 +390,6 @@
 	if (!sigdata)
 		return NULL;
 
-	length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
-
 	{
 		char version[16];
 		const char *tag[2][2];
@@ -408,6 +406,6 @@
 		version[7] = hexdigit(ver & 15);
 		version[8] = 0;
 		tag[1][1] = (const char *) &version;
-		return make_duh(length, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+		return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
 	}
 }
--- a/dumb/src/it/readoldpsm.c
+++ b/dumb/src/it/readoldpsm.c
@@ -59,7 +59,7 @@
 		IT_SAMPLE * meh = realloc(*sample, true_num * sizeof(*meh));
 		if (!meh) goto error_fb;
 		for (n = count; n < true_num; n++) {
-			meh[n].right = meh[n].left = NULL;
+			meh[n].data = NULL;
 		}
 		*sample = meh;
 		*num = true_num;
@@ -125,8 +125,8 @@
 		s->vibrato_waveform = IT_VIBRATO_SINE;
 		s->max_resampling_quality = -1;
 
-		s->left = malloc(s->length * ((flags & 4) ? 2 : 1));
-		if (!s->left) goto error_fb;
+		s->data = malloc(s->length * ((flags & 4) ? 2 : 1));
+		if (!s->data) goto error_fb;
 
 		if ((offset >= data_pos) &&
 			((offset + s->length * ((flags & 4) ? 2 : 1)) <= (data_pos + data_size))) {
@@ -146,17 +146,17 @@
 			if (flags & 8) {
 				if (flags & 4) {
 					for (o = 0; o < s->length; o++)
-						((short *)s->left)[o] = (sdata[o * 2] | (sdata[(o * 2) + 1] << 8)) ^ 0x8000;
+						((short *)s->data)[o] = (sdata[o * 2] | (sdata[(o * 2) + 1] << 8)) ^ 0x8000;
 				} else {
 					for (o = 0; o < s->length; o++)
-						((signed char *)s->left)[o] = sdata[o] ^ 0x80;
+						((signed char *)s->data)[o] = sdata[o] ^ 0x80;
 				}
 			} else {
 				if (flags & 4) {
 					for (o = 0; o < s->length; o++)
-						((short *)s->left)[o] = sdata[o * 2] | (sdata[(o * 2) + 1] << 8);
+						((short *)s->data)[o] = sdata[o * 2] | (sdata[(o * 2) + 1] << 8);
 				} else {
-					memcpy(s->left, sdata, s->length);
+					memcpy(s->data, sdata, s->length);
 				}
 			}
 		} else {
@@ -166,12 +166,12 @@
 				if (flags & 4) {
 					for (o = 0; o < s->length; o++) {
 						delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8));
-						((short *)s->left)[o] = delta ^ 0x8000;
+						((short *)s->data)[o] = delta ^ 0x8000;
 					}
 				} else {
 					for (o = 0; o < s->length; o++) {
 						delta += (signed char)sdata[o];
-						((signed char *)s->left)[o] = delta ^ 0x80;
+						((signed char *)s->data)[o] = delta ^ 0x80;
 					}
 				}
 			} else {
@@ -178,12 +178,12 @@
 				if (flags & 4) {
 					for (o = 0; o < s->length; o++) {
 						delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8));
-						((short *)s->left)[o] = delta;
+						((short *)s->data)[o] = delta;
 					}
 				} else {
 					for (o = 0; o < s->length; o++) {
 						delta += (signed char)sdata[o];
-						((signed char *)s->left)[o] = delta;
+						((signed char *)s->data)[o] = delta;
 					}
 				}
 			}
@@ -584,7 +584,7 @@
 		sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
 		if (!sigdata->sample) goto error_usd;
 		for (n = 0; n < sigdata->n_samples; n++)
-			sigdata->sample[n].right = sigdata->sample[n].left = NULL;
+			sigdata->sample[n].data = NULL;
 	}
 
 	if (sigdata->n_patterns) {
@@ -703,10 +703,9 @@
 	return NULL;
 }
 
-DUH *dumb_read_old_psm(DUMBFILE *f)
+DUH *dumb_read_old_psm_quick(DUMBFILE *f)
 {
 	sigdata_t *sigdata;
-	long length;
 
 	DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
 
@@ -715,8 +714,6 @@
 	if (!sigdata)
 		return NULL;
 
-	length = 0; /*_dumb_it_build_checkpoints(sigdata, 0);*/
-
 	{
 		const char *tag[2][2];
 		tag[0][0] = "TITLE";
@@ -723,6 +720,6 @@
 		tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
 		tag[1][0] = "FORMAT";
 		tag[1][1] = "PSM (old)";
-		return make_duh(length, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+		return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
 	}
 }
--- a/dumb/src/it/readpsm.c
+++ b/dumb/src/it/readpsm.c
@@ -118,8 +118,8 @@
 		}
 	}
 
-	sample->left = malloc(sample->length);
-	if (!sample->left)
+	sample->data = malloc(sample->length);
+	if (!sample->data)
 		return -1;
 
 	flags = 0;
@@ -127,7 +127,7 @@
 
 	for (insno = 0; insno < sample->length; insno++) {
 		flags += (signed char)(*data++);
-		((signed char *)sample->left)[insno] = flags;
+		((signed char *)sample->data)[insno] = flags;
 	}
 
 	return 0;
@@ -920,7 +920,7 @@
 	sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
 	if (!sigdata->sample) goto error_ev;
 	for (n = 0; n < sigdata->n_samples; n++)
-		sigdata->sample[n].right = sigdata->sample[n].left = NULL;
+		sigdata->sample[n].data = NULL;
 
 	o = 0;
 	for (n = 0; n < n_chunks; n++) {
@@ -1192,10 +1192,9 @@
 	return subsongs;
 }
 
-DUH *dumb_read_psm(DUMBFILE *f, int subsong)
+DUH *dumb_read_psm_quick(DUMBFILE *f, int subsong)
 {
 	sigdata_t *sigdata;
-	long length;
 	int ver;
 
 	DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
@@ -1205,8 +1204,6 @@
 	if (!sigdata)
 		return NULL;
 
-	length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
-
 	{
 		char version[16];
 		const char *tag[3][2];
@@ -1217,6 +1214,6 @@
 		tag[2][0] = "FORMATVERSION";
 		itoa(ver, version, 10);
 		tag[2][1] = (const char *) &version;
-		return make_duh(length, 3, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+		return make_duh(-1, 3, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
 	}
 }
--- a/dumb/src/it/readptm.c
+++ b/dumb/src/it/readptm.c
@@ -137,8 +137,8 @@
 	long n;
 	int s;
 
-	sample->left = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
-	if (!sample->left)
+	sample->data = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
+	if (!sample->data)
 		return -1;
 
 	s = 0;
@@ -148,12 +148,12 @@
 		for (n = 0; n < sample->length; n++) {
 			a = s += (signed char) it_ptm_read_byte(f);
 			b = s += (signed char) it_ptm_read_byte(f);
-			((short *)sample->left)[n] = a | (b << 8);
+			((short *)sample->data)[n] = a | (b << 8);
 		}
 	} else {
 		for (n = 0; n < sample->length; n++) {
 			s += (signed char) it_ptm_read_byte(f);
-			((signed char *)sample->left)[n] = s;
+			((signed char *)sample->data)[n] = s;
 		}
 	}
 
@@ -407,7 +407,7 @@
 			return NULL;
 		}
 		for (n = 0; n < sigdata->n_samples; n++)
-			sigdata->sample[n].right = sigdata->sample[n].left = NULL;
+			sigdata->sample[n].data = NULL;
 	}
 
 	if (sigdata->n_patterns) {
@@ -551,10 +551,9 @@
 	else return in + 'A' - 10;
 }
 
-DUH *dumb_read_ptm(DUMBFILE *f)
+DUH *dumb_read_ptm_quick(DUMBFILE *f)
 {
 	sigdata_t *sigdata;
-	long length;
 
 	DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
 
@@ -563,8 +562,6 @@
 	if (!sigdata)
 		return NULL;
 
-	length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
-
 	{
 		const char *tag[2][2];
 		tag[0][0] = "TITLE";
@@ -571,6 +568,6 @@
 		tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
 		tag[1][0] = "FORMAT";
 		tag[1][1] = "PTM";
-		return make_duh(length, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+		return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
 	}
 }
--- a/dumb/src/it/readriff.c
+++ b/dumb/src/it/readriff.c
@@ -26,11 +26,11 @@
 DUH *dumb_read_riff_am( struct riff * stream );
 DUH *dumb_read_riff_dsmf( struct riff * stream );
 
-/* dumb_read_riff(): reads a RIFF file into a DUH struct, returning a pointer
- * 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.
+/* dumb_read_riff_quick(): reads a RIFF file into a DUH struct, returning a
+ * pointer 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_read_riff( DUMBFILE * f )
+DUH *dumb_read_riff_quick( DUMBFILE * f )
 {
 	DUH * duh;
 	struct riff * stream;
--- a/dumb/src/it/reads3m.c
+++ b/dumb/src/it/reads3m.c
@@ -159,16 +159,13 @@
 {
 	long n;
 
-	sample->left = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
-	if (!sample->left)
+	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 (sample->flags & IT_SAMPLE_STEREO) {
-		sample->right = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
-		if (!sample->right)
-			return -1;
-	}
-
 	if (pack == 4) {
 		if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
 			return -1;
@@ -175,22 +172,22 @@
 	}
 	else if (sample->flags & IT_SAMPLE_STEREO) {
 		if (sample->flags & IT_SAMPLE_16BIT) {
-			for (n = 0; n < sample->length; n++)
-				((short *)sample->left)[n] = dumbfile_igetw(f);
-			for (n = 0; n < sample->length; n++)
-				((short *)sample->right)[n] = dumbfile_igetw(f);
+			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 < sample->length; n++)
-				((signed char *)sample->left)[n] = dumbfile_getc(f);
-			for (n = 0; n < sample->length; n++)
-				((signed char *)sample->right)[n] = dumbfile_getc(f);
+			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->left)[n] = dumbfile_igetw(f);
+			((short *)sample->data)[n] = dumbfile_igetw(f);
 	else
 		for (n = 0; n < sample->length; n++)
-			((signed char *)sample->left)[n] = dumbfile_getc(f);
+			((signed char *)sample->data)[n] = dumbfile_getc(f);
 
 	if (dumbfile_error(f))
 		return -1;
@@ -198,20 +195,11 @@
 	if (ffi != 1) {
 		/* Convert to signed. */
 		if (sample->flags & IT_SAMPLE_16BIT)
-			for (n = 0; n < sample->length; n++)
-				((short *)sample->left)[n] ^= 0x8000;
+			for (n = 0; n < datasize; n++)
+				((short *)sample->data)[n] ^= 0x8000;
 		else
-			for (n = 0; n < sample->length; n++)
-				((signed char *)sample->left)[n] ^= 0x80;
-
-		if (sample->right) {
-			if (sample->flags & IT_SAMPLE_16BIT)
-				for (n = 0; n < sample->length; n++)
-					((short *)sample->right)[n] ^= 0x8000;
-			else
-				for (n = 0; n < sample->length; n++)
-					((signed char *)sample->right)[n] ^= 0x80;
-		}
+			for (n = 0; n < datasize; n++)
+				((signed char *)sample->data)[n] ^= 0x80;
 	}
 
 	return 0;
@@ -483,7 +471,6 @@
 	sigdata = malloc(sizeof(*sigdata));
 	if (!sigdata) return NULL;
 
-	/* Skip song name. */
 	dumbfile_getnc(sigdata->name, 28, f);
 	sigdata->name[28] = 0;
 
@@ -532,7 +519,7 @@
 			return NULL;
 		}
 		for (n = 0; n < sigdata->n_samples; n++)
-			sigdata->sample[n].right = sigdata->sample[n].left = NULL;
+			sigdata->sample[n].data = NULL;
 	}
 
 	if (sigdata->n_patterns) {
@@ -836,10 +823,9 @@
 	else return in + 'A' - 10;
 }
 
-DUH *dumb_read_s3m(DUMBFILE *f)
+DUH *dumb_read_s3m_quick(DUMBFILE *f)
 {
 	sigdata_t *sigdata;
-	long length;
 	int cwtv;
 
 	DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
@@ -849,8 +835,6 @@
 	if (!sigdata)
 		return NULL;
 
-	length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
-
 	{
 		char version[8];
 		const char *tag[3][2];
@@ -865,6 +849,6 @@
 		version[3] = hexdigit(cwtv & 15);
 		version[4] = 0;
 		tag[2][1] = (const char *) &version;
-		return make_duh(length, 3, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+		return make_duh(-1, 3, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
 	}
 }
--- /dev/null
+++ b/dumb/src/it/reads3m2.c
@@ -1,0 +1,29 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * reads3m2.c - Function to read a ScreamTracker 3    / / \  \
+ *              module from an open file and do an   | <  /   \_
+ *              initial run-through.                 |  \/ /\   /
+ *                                                    \_  /  > /
+ * Split off from reads3m.c by entheh.                  | \ / /
+ *                                                      |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_read_s3m(DUMBFILE *f)
+{
+	DUH *duh = dumb_read_s3m_quick(f);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/readstm.c
+++ b/dumb/src/it/readstm.c
@@ -101,11 +101,11 @@
 			return -1;
 	}
 
-	sample->left = malloc( sample->length );
-	if (!sample->left)
+	sample->data = malloc( sample->length );
+	if (!sample->data)
 		return -1;
 
-	if ( dumbfile_getnc( sample->left, sample->length, f ) != sample->length )
+	if ( dumbfile_getnc( sample->data, sample->length, f ) != sample->length )
 		return -1;
 
 	return 0;
@@ -278,7 +278,7 @@
 		return NULL;
 	}
 	for (n = 0; n < sigdata->n_samples; n++)
-		sigdata->sample[n].right = sigdata->sample[n].left = NULL;
+		sigdata->sample[n].data = NULL;
 
 	if (sigdata->n_patterns) {
 		sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
@@ -360,10 +360,9 @@
 	else return in + 'A' - 10;
 }*/
 
-DUH *dumb_read_stm(DUMBFILE *f)
+DUH *dumb_read_stm_quick(DUMBFILE *f)
 {
 	sigdata_t *sigdata;
-	long length;
 	int ver;
 
 	DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
@@ -373,8 +372,6 @@
 	if (!sigdata)
 		return NULL;
 
-	length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
-
 	{
 		/*char version[16];*/
 		const char *tag[2][2];
@@ -393,6 +390,6 @@
 		version[8] = hexdigit(ver & 15);
 		version[9] = 0;
 		tag[1][1] = (const char *) &version;*/
-		return make_duh(length, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+		return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
 	}
 }
--- /dev/null
+++ b/dumb/src/it/readstm2.c
@@ -1,0 +1,29 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * readstm2.c - Function to read a ScreamTracker 2    / / \  \
+ *              module from an open file and do an   | <  /   \_
+ *              initial run-through.                 |  \/ /\   /
+ *                                                    \_  /  > /
+ * By Chris Moeller.                                    | \ / /
+ *                                                      |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_read_stm(DUMBFILE *f)
+{
+	DUH *duh = dumb_read_stm_quick(f);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/readxm.c
+++ b/dumb/src/it/readxm.c
@@ -29,7 +29,6 @@
 /** TODO:
 
  * XM_TREMOLO                        doesn't sound quite right...
- * XM_E_SET_FINETUNE                 todo.
  * XM_SET_ENVELOPE_POSITION          todo.
 
  * VIBRATO conversion needs to be checked (sample/effect/volume). Plus check
@@ -583,6 +582,8 @@
 	int old;
 	long i;
 	long truncated_size;
+	int n_channels;
+	long datasize;
 
 	if (!(sample->flags & IT_SAMPLE_EXISTS))
 		return dumbfile_skip(f, roguebytes);
@@ -595,16 +596,13 @@
 		truncated_size = 0;
 	}
 
-	sample->left = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
-	if (!sample->left)
+	n_channels = sample->flags & IT_SAMPLE_STEREO ? 2 : 1;
+	datasize = sample->length * n_channels;
+
+	sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
+	if (!sample->data)
 		return -1;
 
-	if (sample->flags & IT_SAMPLE_STEREO) {
-		sample->right = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
-		if (!sample->right)
-			return -1;
-	}
-
 	if (roguebytes == 4)
 	{
 		if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
@@ -617,10 +615,10 @@
 		old = 0;
 		if (sample->flags & IT_SAMPLE_16BIT)
 			for (i = 0; i < sample->length; i++)
-				((short *)sample->left)[i] = old += dumbfile_igetw(f);
+				((short *)sample->data)[i*n_channels] = old += dumbfile_igetw(f);
 		else
 			for (i = 0; i < sample->length; i++)
-				((signed char *)sample->left)[i] = old += dumbfile_getc(f);
+				((signed char *)sample->data)[i*n_channels] = old += dumbfile_getc(f);
 	}
 
 	/* skip truncated data */
@@ -629,11 +627,11 @@
 	if (sample->flags & IT_SAMPLE_STEREO) {
 		old = 0;
 		if (sample->flags & IT_SAMPLE_16BIT)
-			for (i = 0; i < sample->length; i++)
-				((short *)sample->right)[i] = old += dumbfile_igetw(f);
+			for (i = 1; i < datasize; i += 2)
+				((short *)sample->data)[i] = old += dumbfile_igetw(f);
 		else
-			for (i = 0; i < sample->length; i++)
-				((signed char *)sample->right)[i] = old += dumbfile_getc(f);
+			for (i = 1; i < datasize; i += 2)
+				((signed char *)sample->data)[i] = old += dumbfile_getc(f);
 
 		/* skip truncated data */
 		dumbfile_skip(f, (sample->flags & IT_SAMPLE_16BIT) ? (2*truncated_size) : (truncated_size));
@@ -850,7 +848,7 @@
 					return NULL;
 				}
 				for (j = total_samples; j < total_samples+extra.n_samples; j++)
-					sigdata->sample[j].right = sigdata->sample[j].left = NULL;
+					sigdata->sample[j].data = NULL;
 
 				/* read instrument's samples */
 				for (j = 0; j < extra.n_samples; j++) {
@@ -929,7 +927,7 @@
 					return NULL;
 				}
 				for (j = total_samples; j < total_samples+extra.n_samples; j++)
-					sigdata->sample[j].right = sigdata->sample[j].left = NULL;
+					sigdata->sample[j].data = NULL;
 
 				/* read instrument's samples */
 				for (j = 0; j < extra.n_samples; j++) {
@@ -1069,7 +1067,7 @@
 
 	/* for each PATTERN */
 	for (order = 0; order < sigdata->n_orders; order++) {
-		
+
 		if (sigdata->order[order] == IT_ORDER_END) break;
 		if (sigdata->order[order] == IT_ORDER_SKIP) continue;
 
@@ -1174,10 +1172,9 @@
 	else return in + 'A' - 10;
 }
 
-DUH *dumb_read_xm(DUMBFILE *f)
+DUH *dumb_read_xm_quick(DUMBFILE *f)
 {
 	sigdata_t *sigdata;
-	long length;
 	int ver;
 
 	DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
@@ -1187,8 +1184,6 @@
 	if (!sigdata)
 		return NULL;
 
-	length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
-
 	{
 		char version[16];
 		const char *tag[2][2];
@@ -1205,6 +1200,6 @@
 		version[7] = hexdigit( ver & 15 );
 		version[8] = 0;
 		tag[1][1] = ( const char * ) & version;
-		return make_duh(length, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
+		return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
 	}
 }
--- /dev/null
+++ b/dumb/src/it/readxm2.c
@@ -1,0 +1,29 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
+ *                                                      /  \
+ *                                                     / .  \
+ * readxm2.c - Function to read a Fast Tracker II     / / \  \
+ *             module from an open file and do an    | <  /   \_
+ *             initial run-through.                  |  \/ /\   /
+ *                                                    \_  /  > /
+ * Split off from readxm.c by entheh.                   | \ / /
+ *                                                      |  ' /
+ *                                                       \__/
+ */
+
+#include "dumb.h"
+
+
+
+DUH *dumb_read_xm(DUMBFILE *f)
+{
+	DUH *duh = dumb_read_xm_quick(f);
+	dumb_it_do_initial_runthrough(duh);
+	return duh;
+}
--- a/dumb/src/it/xmeffect.c
+++ b/dumb/src/it/xmeffect.c
@@ -170,10 +170,11 @@
 			break;
 
 		case XM_KEY_OFF:
-			/** WARNING: In FT2, the value seems to do something... Oh well,
-			 * this is undocumented anyway!
-			 */
 			effect = IT_XM_KEY_OFF;
+			break;
+
+		case XM_SET_ENVELOPE_POSITION:
+			effect = IT_XM_SET_ENVELOPE_POSITION;
 			break;
 
 		case EBASE+XM_E_SET_FILTER:            effect = SBASE+IT_S_SET_FILTER;            break;
--- a/dumb/vc6/dumb/dumb.vcproj
+++ b/dumb/vc6/dumb/dumb.vcproj
@@ -779,42 +779,35 @@
 					</FileConfiguration>
 				</File>
 				<File
-					RelativePath="..\..\src\helpers\resample.c"
+					RelativePath="..\..\src\helpers\resamp2.inc"
 					>
 					<FileConfiguration
 						Name="Release|Win32"
+						ExcludedFromBuild="true"
 						>
 						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
+							Name="VCCustomBuildTool"
 						/>
 					</FileConfiguration>
 					<FileConfiguration
 						Name="Debug|Win32"
+						ExcludedFromBuild="true"
 						>
 						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
+							Name="VCCustomBuildTool"
 						/>
 					</FileConfiguration>
 					<FileConfiguration
 						Name="Release staticlink|Win32"
+						ExcludedFromBuild="true"
 						>
 						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
+							Name="VCCustomBuildTool"
 						/>
 					</FileConfiguration>
 				</File>
 				<File
-					RelativePath="..\..\src\helpers\resample.inc"
+					RelativePath="..\..\src\helpers\resamp3.inc"
 					>
 					<FileConfiguration
 						Name="Release|Win32"
@@ -842,12 +835,8 @@
 					</FileConfiguration>
 				</File>
 				<File
-					RelativePath="..\..\src\helpers\riff.c"
+					RelativePath="..\..\src\helpers\resample.c"
 					>
-				</File>
-				<File
-					RelativePath="..\..\src\helpers\sampbuf.c"
-					>
 					<FileConfiguration
 						Name="Release|Win32"
 						>
@@ -881,43 +870,40 @@
 					</FileConfiguration>
 				</File>
 				<File
-					RelativePath="..\..\src\helpers\silence.c"
+					RelativePath="..\..\src\helpers\resample.inc"
 					>
 					<FileConfiguration
 						Name="Release|Win32"
+						ExcludedFromBuild="true"
 						>
 						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
+							Name="VCCustomBuildTool"
 						/>
 					</FileConfiguration>
 					<FileConfiguration
 						Name="Debug|Win32"
+						ExcludedFromBuild="true"
 						>
 						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
+							Name="VCCustomBuildTool"
 						/>
 					</FileConfiguration>
 					<FileConfiguration
 						Name="Release staticlink|Win32"
+						ExcludedFromBuild="true"
 						>
 						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
+							Name="VCCustomBuildTool"
 						/>
 					</FileConfiguration>
 				</File>
 				<File
-					RelativePath="..\..\src\helpers\stdfile.c"
+					RelativePath="..\..\src\helpers\riff.c"
 					>
+				</File>
+				<File
+					RelativePath="..\..\src\helpers\sampbuf.c"
+					>
 					<FileConfiguration
 						Name="Release|Win32"
 						>
@@ -950,12 +936,8 @@
 						/>
 					</FileConfiguration>
 				</File>
-			</Filter>
-			<Filter
-				Name="it"
-				>
 				<File
-					RelativePath="..\..\src\it\itload.c"
+					RelativePath="..\..\src\helpers\silence.c"
 					>
 					<FileConfiguration
 						Name="Release|Win32"
@@ -990,7 +972,7 @@
 					</FileConfiguration>
 				</File>
 				<File
-					RelativePath="..\..\src\it\itmisc.c"
+					RelativePath="..\..\src\helpers\stdfile.c"
 					>
 					<FileConfiguration
 						Name="Release|Win32"
@@ -1024,8 +1006,12 @@
 						/>
 					</FileConfiguration>
 				</File>
+			</Filter>
+			<Filter
+				Name="it"
+				>
 				<File
-					RelativePath="..\..\src\it\itorder.c"
+					RelativePath="..\..\src\it\itmisc.c"
 					>
 					<FileConfiguration
 						Name="Release|Win32"
@@ -1060,7 +1046,7 @@
 					</FileConfiguration>
 				</File>
 				<File
-					RelativePath="..\..\src\it\itread.c"
+					RelativePath="..\..\src\it\itorder.c"
 					>
 					<FileConfiguration
 						Name="Release|Win32"
@@ -1165,7 +1151,7 @@
 					</FileConfiguration>
 				</File>
 				<File
-					RelativePath="..\..\src\it\load669.c"
+					RelativePath="..\..\src\it\ptmeffect.c"
 					>
 					<FileConfiguration
 						Name="Release|Win32"
@@ -1200,12 +1186,8 @@
 					</FileConfiguration>
 				</File>
 				<File
-					RelativePath="..\..\src\it\loadasy.c"
+					RelativePath="..\..\src\it\xmeffect.c"
 					>
-				</File>
-				<File
-					RelativePath="..\..\src\it\loadmod.c"
-					>
 					<FileConfiguration
 						Name="Release|Win32"
 						>
@@ -1238,559 +1220,717 @@
 						/>
 					</FileConfiguration>
 				</File>
-				<File
-					RelativePath="..\..\src\it\loadmtm.c"
+				<Filter
+					Name="loaders"
 					>
-					<FileConfiguration
-						Name="Release|Win32"
+					<File
+						RelativePath="..\..\src\it\itload.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\itload2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\load669.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
-				<File
-					RelativePath="..\..\src\it\loadoldpsm.c"
-					>
-					<FileConfiguration
-						Name="Release|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\load6692.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadasy.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadasy2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
-				<File
-					RelativePath="..\..\src\it\loadpsm.c"
-					>
-					<FileConfiguration
-						Name="Release|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadmod.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadmod2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadmtm.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
-				<File
-					RelativePath="..\..\src\it\loadriff.c"
-					>
-				</File>
-				<File
-					RelativePath="..\..\src\it\loads3m.c"
-					>
-					<FileConfiguration
-						Name="Release|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadmtm2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadoldpsm.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadoldpsm2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
-				<File
-					RelativePath="..\..\src\it\loadstm.c"
-					>
-				</File>
-				<File
-					RelativePath="..\..\src\it\loadxm.c"
-					>
-					<FileConfiguration
-						Name="Release|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadpsm.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadpsm2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadptm.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
-				<File
-					RelativePath="..\..\src\it\ptmeffect.c"
-					>
-					<FileConfiguration
-						Name="Release|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadptm2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadriff.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadriff2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
-				<File
-					RelativePath="..\..\src\it\read669.c"
-					>
-					<FileConfiguration
-						Name="Release|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\loads3m.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\loads3m2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadstm.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
-				<File
-					RelativePath="..\..\src\it\readam.c"
-					>
-				</File>
-				<File
-					RelativePath="..\..\src\it\readasy.c"
-					>
-				</File>
-				<File
-					RelativePath="..\..\src\it\readdsmf.c"
-					>
-				</File>
-				<File
-					RelativePath="..\..\src\it\readmod.c"
-					>
-					<FileConfiguration
-						Name="Release|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadstm2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadxm.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\loadxm2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
-				<File
-					RelativePath="..\..\src\it\readmtm.c"
+					</File>
+				</Filter>
+				<Filter
+					Name="readers"
 					>
-					<FileConfiguration
-						Name="Release|Win32"
+					<File
+						RelativePath="..\..\src\it\itread.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\itread2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\read669.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
-				<File
-					RelativePath="..\..\src\it\readoldpsm.c"
-					>
-					<FileConfiguration
-						Name="Release|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\read6692.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\readam.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\readasy.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
-				<File
-					RelativePath="..\..\src\it\readpsm.c"
-					>
-					<FileConfiguration
-						Name="Release|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\readdsmf.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\readmod.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\readmod2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
-				<File
-					RelativePath="..\..\src\it\readptm.c"
-					>
-					<FileConfiguration
-						Name="Release|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\readmtm.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\readoldpsm.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\readpsm.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
-				<File
-					RelativePath="..\..\src\it\readriff.c"
-					>
-				</File>
-				<File
-					RelativePath="..\..\src\it\reads3m.c"
-					>
-					<FileConfiguration
-						Name="Release|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\readptm.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\readriff.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\reads3m.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
-				<File
-					RelativePath="..\..\src\it\readstm.c"
-					>
-				</File>
-				<File
-					RelativePath="..\..\src\it\readxm.c"
-					>
-					<FileConfiguration
-						Name="Release|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\reads3m2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\readstm.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\readstm2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
-				<File
-					RelativePath="..\..\src\it\xmeffect.c"
-					>
-					<FileConfiguration
-						Name="Release|Win32"
+					</File>
+					<File
+						RelativePath="..\..\src\it\readxm.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Debug|Win32"
+						<FileConfiguration
+							Name="Release|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="0"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+								BasicRuntimeChecks="3"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release staticlink|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								Optimization="2"
+								AdditionalIncludeDirectories=""
+								PreprocessorDefinitions=""
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\..\src\it\readxm2.c"
 						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="0"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-							BasicRuntimeChecks="3"
-						/>
-					</FileConfiguration>
-					<FileConfiguration
-						Name="Release staticlink|Win32"
-						>
-						<Tool
-							Name="VCCLCompilerTool"
-							Optimization="2"
-							AdditionalIncludeDirectories=""
-							PreprocessorDefinitions=""
-						/>
-					</FileConfiguration>
-				</File>
+					</File>
+				</Filter>
 			</Filter>
 		</Filter>
 		<Filter