changeset 2216:3673c7ec4ea2

Sync with schism's modplug engine. Suggested by G¸«ärkan Seng¸«än.
author William Pitcock <nenolod@atheme.org>
date Fri, 07 Dec 2007 12:08:47 -0600
parents 32f9f1e4a9ec
children 6a4d667a9183
files src/modplug/fastmix.cxx src/modplug/it_defs.h src/modplug/load_669.cxx src/modplug/load_amf.cxx src/modplug/load_ams.cxx src/modplug/load_dbm.cxx src/modplug/load_dmf.cxx src/modplug/load_dsm.cxx src/modplug/load_far.cxx src/modplug/load_it.cxx src/modplug/load_mdl.cxx src/modplug/load_med.cxx src/modplug/load_mid.cxx src/modplug/load_mod.cxx src/modplug/load_mt2.cxx src/modplug/load_mtm.cxx src/modplug/load_okt.cxx src/modplug/load_psm.cxx src/modplug/load_ptm.cxx src/modplug/load_s3m.cxx src/modplug/load_stm.cxx src/modplug/load_ult.cxx src/modplug/load_wav.cxx src/modplug/load_xm.cxx src/modplug/snd_dsp.cxx src/modplug/snd_eq.cxx src/modplug/snd_flt.cxx src/modplug/snd_fx.cxx src/modplug/sndfile.cxx src/modplug/sndfile.h src/modplug/sndmix.cxx src/modplug/stdafx.h src/modplug/tables.cxx
diffstat 33 files changed, 3475 insertions(+), 2283 deletions(-) [+]
line wrap: on
line diff
--- a/src/modplug/fastmix.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/fastmix.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -1,8 +1,5 @@
 /*
- * This program is  free software; you can redistribute it  and modify it
- * under the terms of the GNU  General Public License as published by the
- * Free Software Foundation; either version 2  of the license or (at your
- * option) any later version.
+ * This source code is public domain.
  *
  * Authors: Olivier Lapicque <olivierl@jps.net>
  *          Markus Fick <webmaster@mark-f.de> spline + fir-resampler
@@ -12,10 +9,6 @@
 #include "sndfile.h"
 #include <math.h>
 
-#ifdef MSC_VER
-#pragma bss_seg(".modplug")
-#endif
-
 // Front Mix Buffer (Also room for interleaved rear mix)
 int MixSoundBuffer[MIXBUFFERSIZE*4];
 
@@ -25,14 +18,8 @@
 extern UINT gnReverbSend;
 #endif
 
-#ifndef MODPLUG_FASTSOUNDLIB
 int MixRearBuffer[MIXBUFFERSIZE*2];
 float MixFloatBuffer[MIXBUFFERSIZE*2];
-#endif
-
-#ifdef MSC_VER
-#pragma bss_seg()
-#endif
 
 
 extern LONG gnDryROfsVol;
@@ -530,37 +517,39 @@
 // Resonant Filters
 
 // Mono
-#define MIX_BEGIN_FILTER\
-	int fy1 = pChannel->nFilter_Y1;\
-	int fy2 = pChannel->nFilter_Y2;\
+#define MIX_BEGIN_FILTER \
+	double fy1 = pChannel->nFilter_Y1;\
+	double fy2 = pChannel->nFilter_Y2;\
+	double ta;
 
-#define MIX_END_FILTER\
+#define MIX_END_FILTER \
 	pChannel->nFilter_Y1 = fy1;\
 	pChannel->nFilter_Y2 = fy2;
 
-#define SNDMIX_PROCESSFILTER\
-	vol = (vol * pChn->nFilter_A0 + fy1 * pChn->nFilter_B0 + fy2 * pChn->nFilter_B1 + 4096) >> 13;\
-	fy2 = fy1;\
-	fy1 = vol;\
+#define SNDMIX_PROCESSFILTER \
+ta = ((double)vol * pChn->nFilter_A0 + fy1 * pChn->nFilter_B0 + fy2 * pChn->nFilter_B1);\
+fy2 = fy1;\
+fy1 = ta;vol=(int)ta;
 
 // Stereo
-#define MIX_BEGIN_STEREO_FILTER\
-	int fy1 = pChannel->nFilter_Y1;\
-	int fy2 = pChannel->nFilter_Y2;\
-	int fy3 = pChannel->nFilter_Y3;\
-	int fy4 = pChannel->nFilter_Y4;\
+#define MIX_BEGIN_STEREO_FILTER \
+double fy1 = pChannel->nFilter_Y1;\
+double fy2 = pChannel->nFilter_Y2;\
+double fy3 = pChannel->nFilter_Y3;\
+double fy4 = pChannel->nFilter_Y4;\
+double ta, tb;
 
-#define MIX_END_STEREO_FILTER\
-	pChannel->nFilter_Y1 = fy1;\
-	pChannel->nFilter_Y2 = fy2;\
-	pChannel->nFilter_Y3 = fy3;\
-	pChannel->nFilter_Y4 = fy4;\
+#define MIX_END_STEREO_FILTER \
+pChannel->nFilter_Y1 = fy1;\
+pChannel->nFilter_Y2 = fy2;\
+pChannel->nFilter_Y3 = fy3;\
+pChannel->nFilter_Y4 = fy4;\
 
-#define SNDMIX_PROCESSSTEREOFILTER\
-	vol_l = (vol_l * pChn->nFilter_A0 + fy1 * pChn->nFilter_B0 + fy2 * pChn->nFilter_B1 + 4096) >> 13;\
-	vol_r = (vol_r * pChn->nFilter_A0 + fy3 * pChn->nFilter_B0 + fy4 * pChn->nFilter_B1 + 4096) >> 13;\
-	fy2 = fy1; fy1 = vol_l;\
-	fy4 = fy3; fy3 = vol_r;\
+#define SNDMIX_PROCESSSTEREOFILTER \
+ta = ((double)vol_l * pChn->nFilter_A0 + fy1 * pChn->nFilter_B0 + fy2 * pChn->nFilter_B1);\
+tb = ((double)vol_r * pChn->nFilter_A0 + fy3 * pChn->nFilter_B0 + fy4 * pChn->nFilter_B1);\
+fy2 = fy1; fy1 = ta;vol_l=(int)ta;\
+fy4 = fy3; fy3 = tb;vol_r=(int)tb;
 
 //////////////////////////////////////////////////////////
 // Interfaces
@@ -659,11 +648,17 @@
 /////////////////////////////////////////////////////
 //
 
-void MPPASMCALL X86_InitMixBuffer(int *pBuffer, UINT nSamples);
-void MPPASMCALL X86_EndChannelOfs(MODCHANNEL *pChannel, int *pBuffer, UINT nSamples);
-void MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs);
-void X86_StereoMixToFloat(const int *, float *, float *, UINT nCount);
-void X86_FloatToStereoMix(const float *pIn1, const float *pIn2, int *pOut, UINT nCount);
+extern void StereoMixToFloat(const int *pSrc, float *pOut1, float *pOut2, UINT nCount, const float _i2fc);
+extern void FloatToStereoMix(const float *pIn1, const float *pIn2, int *pOut, UINT nCount, const float _f2ic);
+extern void MonoMixToFloat(const int *pSrc, float *pOut, UINT nCount, const float _i2fc);
+extern void FloatToMonoMix(const float *pIn, int *pOut, UINT nCount, const float _f2ic);
+
+void InitMixBuffer(int *pBuffer, UINT nSamples);
+void EndChannelOfs(MODCHANNEL *pChannel, int *pBuffer, UINT nSamples);
+void StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs);
+
+void StereoMixToFloat(const int *, float *, float *, UINT nCount);
+void FloatToStereoMix(const float *pIn1, const float *pIn2, int *pOut, UINT nCount);
 
 /////////////////////////////////////////////////////
 // Mono samples functions
@@ -1466,9 +1461,7 @@
 	DWORD nchused, nchmixed;
 
 	if (!count) return 0;
-#ifndef MODPLUG_FASTSOUNDLIB
-	if (gnChannels > 2) X86_InitMixBuffer(MixRearBuffer, count*2);
-#endif
+	if (gnChannels > 2) InitMixBuffer(MixRearBuffer, count*2);
 	nchused = nchmixed = 0;
 	for (UINT nChn=0; nChn<m_nMixChannels; nChn++)
 	{
@@ -1489,15 +1482,16 @@
 	#ifndef NO_FILTER
 		if (pChannel->dwFlags & CHN_FILTER) nFlags |= MIXNDX_FILTER;
 	#endif
-		if (!(pChannel->dwFlags & CHN_NOIDO))
+		if (!(pChannel->dwFlags & CHN_NOIDO)
+		&& !(gdwSoundSetup & SNDMIX_NORESAMPLING))
 		{
 			// use hq-fir mixer?
 			if( (gdwSoundSetup & (SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE)) == (SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE) )
-				nFlags += MIXNDX_FIRSRC;
-			else if( (gdwSoundSetup & (SNDMIX_HQRESAMPLER)) == SNDMIX_HQRESAMPLER )
-				nFlags += MIXNDX_SPLINESRC;
+				nFlags |= MIXNDX_FIRSRC;
+			else if( (gdwSoundSetup & SNDMIX_HQRESAMPLER))
+				nFlags |= MIXNDX_SPLINESRC;
 			else
-				nFlags += MIXNDX_LINEARSRC; // use
+				nFlags |= MIXNDX_LINEARSRC; // use
 		}
 		if ((nFlags < 0x40) && (pChannel->nLeftVol == pChannel->nRightVol)
 		 && ((!pChannel->nRampLength) || (pChannel->nLeftRamp == pChannel->nRightRamp)))
@@ -1536,7 +1530,7 @@
 			pChannel->nPos = 0;
 			pChannel->nPosLo = 0;
 			pChannel->nRampLength = 0;
-			X86_EndChannelOfs(pChannel, pbuffer, nsamples);
+			EndChannelOfs(pChannel, pbuffer, nsamples);
 			*pOfsR += pChannel->nROfs;
 			*pOfsL += pChannel->nLOfs;
 			pChannel->nROfs = pChannel->nLOfs = 0;
@@ -1557,6 +1551,10 @@
 		} else
 		// Do mixing
 		{
+			if (pChannel->nLength) {
+				pChannel->topnote_offset = ((pChannel->nPos << 16) | pChannel->nPosLo) % pChannel->nLength;
+			}
+
 			// Choose function for mixing
 			LPMIXINTERFACE pMixFunc;
 			pMixFunc = (pChannel->nRampLength) ? pMixFuncTable[nFlags|MIXNDX_RAMP] : pMixFuncTable[nFlags];
@@ -1593,81 +1591,59 @@
 	return nchused;
 }
 
+static float f2ic = (float)(1 << 28);
+static float i2fc = (float)(1.0 / (1 << 28));
 
-#ifdef MSC_VER
-#pragma warning (disable:4100)
-#endif
+VOID CSoundFile::StereoMixToFloat(const int *pSrc, float *pOut1, float *pOut2, UINT nCount)
+//-----------------------------------------------------------------------------------------
+{
+	for (UINT i = 0; i < nCount; i++) {
+		*pOut1++ = *pSrc * i2fc; /*!*/
+		pSrc++;
+
+		*pOut2++ = *pSrc * i2fc; /*!*/
+		pSrc++;
+	}
+}
+
+
+VOID CSoundFile::FloatToStereoMix(const float *pIn1, const float *pIn2, int *pOut, UINT nCount)
+//---------------------------------------------------------------------------------------------
+{
+	for (UINT i = 0; i < nCount; i++) {
+		*pOut++ = (int)(*pIn1 * f2ic);
+		*pOut++ = (int)(*pIn2 * f2ic);
+		pIn1++;
+		pIn2++;
+	}
+}
+
+
+VOID CSoundFile::MonoMixToFloat(const int *pSrc, float *pOut, UINT nCount)
+//------------------------------------------------------------------------
+{
+	for (UINT i = 0; i < nCount; i++) {
+		*pOut++ = *pSrc * i2fc; /*!*/
+		pSrc++;
+	}
+}
+
+
+VOID CSoundFile::FloatToMonoMix(const float *pIn, int *pOut, UINT nCount)
+//-----------------------------------------------------------------------
+{
+	for (UINT i = 0; i < nCount; i++) {
+		*pOut++ = (int)(*pIn * f2ic); /*!*/
+		pIn++;
+	}
+}
+
 
 // Clip and convert to 8 bit
-#ifdef MSC_VER
-__declspec(naked) DWORD MPPASMCALL X86_Convert32To8(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
-//----------------------------------------------------------------------------------------------------------------------------
-{
-    _asm {
-        push ebx
-	push esi
-	push edi
-	mov ebx, 16[esp]		// ebx = 8-bit buffer
-	mov esi, 20[esp]		// esi = pBuffer
-	mov edi, 24[esp]		// edi = lSampleCount
-	mov eax, 28[esp]
-	mov ecx, dword ptr [eax]	// ecx = clipmin
-	mov eax, 32[esp]
-	mov edx, dword ptr [eax]	// edx = clipmax
-cliploop:
-	mov eax, dword ptr [esi]
-	inc ebx
-	cdq
-	and edx, (1 << (24-MIXING_ATTENUATION)) - 1
-	add eax, edx
-	cmp eax, MIXING_CLIPMIN
-	jl cliplow
-	cmp eax, MIXING_CLIPMAX
-	jg cliphigh
-	cmp eax, ecx
-	jl updatemin
-	cmp eax, edx
-	jg updatemax
-cliprecover:
-	add esi, 4
-	sar eax, 24-MIXING_ATTENUATION
-	xor eax, 0x80
-	dec edi
-	mov byte ptr [ebx-1], al
-	jnz cliploop
-	mov eax, 28[esp]
-	mov dword ptr [eax], ecx
-	mov eax, 32[esp]
-	mov dword ptr [eax], edx
-	mov eax, 24[esp]
-	pop edi
-	pop esi
-	pop ebx
-	ret
-updatemin:
-	mov ecx, eax
-	jmp cliprecover
-updatemax:
-	mov edx, eax
-	jmp cliprecover
-cliplow:
-	mov ecx, MIXING_CLIPMIN
-	mov edx, MIXING_CLIPMAX
-	mov eax, MIXING_CLIPMIN
-	jmp cliprecover
-cliphigh:
-	mov ecx, MIXING_CLIPMIN
-	mov edx, MIXING_CLIPMAX
-	mov eax, MIXING_CLIPMAX
-	jmp cliprecover
-	}
-}
-#else //MSC_VER
 //---GCCFIX: Asm replaced with C function
 // The C version was written by Rani Assaf <rani@magic.metawire.com>, I believe
-DWORD MPPASMCALL X86_Convert32To8(LPVOID lp8, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
+DWORD Convert32To8(LPVOID lp8, int *pBuffer, DWORD lSampleCount, LONG mins[2], LONG maxs[2])
 {
-	int vumin = *lpMin, vumax = *lpMax;
 	unsigned char *p = (unsigned char *)lp8;
 	for (UINT i=0; i<lSampleCount; i++)
 	{
@@ -1676,92 +1652,18 @@
 			n = MIXING_CLIPMIN;
 		else if (n > MIXING_CLIPMAX)
 			n = MIXING_CLIPMAX;
-		if (n < vumin)
-			vumin = n;
-		else if (n > vumax)
-			vumax = n;
+		if (n < mins[i&1])
+			mins[i&1]= n;
+		else if (n > maxs[i&1])
+			maxs[i&1] = n;
 		p[i] = (n >> (24-MIXING_ATTENUATION)) ^ 0x80;	// 8-bit unsigned
 	}
-	*lpMin = vumin;
-	*lpMax = vumax;
 	return lSampleCount;
 }
-#endif //MSC_VER, else
-
-
-#ifdef MSC_VER
-// Clip and convert to 16 bit
-__declspec(naked) DWORD MPPASMCALL X86_Convert32To16(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
-//-----------------------------------------------------------------------------------------------------------------------------
-{
-	_asm {
-	push ebx
-	push esi
-	push edi
-	mov ebx, 16[esp]		// ebx = 16-bit buffer
-	mov eax, 28[esp]
-	mov esi, 20[esp]		// esi = pBuffer
-	mov ecx, dword ptr [eax]	// ecx = clipmin
-	mov edi, 24[esp]		// edi = lSampleCount
-	mov eax, 32[esp]
-	push ebp
-	mov ebp, dword ptr [eax]	// edx = clipmax
-cliploop:
-	mov eax, dword ptr [esi]
-	add ebx, 2
-	cdq
-	and edx, (1 << (16-MIXING_ATTENUATION)) - 1
-	add esi, 4
-	add eax, edx
-	cmp eax, MIXING_CLIPMIN
-	jl cliplow
-	cmp eax, MIXING_CLIPMAX
-	jg cliphigh
-	cmp eax, ecx
-	jl updatemin
-	cmp eax, ebp
-	jg updatemax
-cliprecover:
-	sar eax, 16-MIXING_ATTENUATION
-	dec edi
-	mov word ptr [ebx-2], ax
-	jnz cliploop
-	mov edx, ebp
-	pop ebp
-	mov eax, 28[esp]
-	mov dword ptr [eax], ecx
-	mov eax, 32[esp]
-	mov dword ptr [eax], edx
-	mov eax, 24[esp]
-	pop edi
-	shl eax, 1
-	pop esi
-	pop ebx
-	ret
-updatemin:
-	mov ecx, eax
-	jmp cliprecover
-updatemax:
-	mov ebp, eax
-	jmp cliprecover
-cliplow:
-	mov ecx, MIXING_CLIPMIN
-	mov ebp, MIXING_CLIPMAX
-	mov eax, MIXING_CLIPMIN
-	jmp cliprecover
-cliphigh:
-	mov ecx, MIXING_CLIPMIN
-	mov ebp, MIXING_CLIPMAX
-	mov eax, MIXING_CLIPMAX
-	jmp cliprecover
-	}
-}
-#else //MSC_VER
 //---GCCFIX: Asm replaced with C function
 // The C version was written by Rani Assaf <rani@magic.metawire.com>, I believe
-DWORD MPPASMCALL X86_Convert32To16(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
+DWORD Convert32To16(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LONG mins[2], LONG maxs[2])
 {
-	int vumin = *lpMin, vumax = *lpMax;
 	signed short *p = (signed short *)lp16;
 	for (UINT i=0; i<lSampleCount; i++)
 	{
@@ -1770,323 +1672,78 @@
 			n = MIXING_CLIPMIN;
 		else if (n > MIXING_CLIPMAX)
 			n = MIXING_CLIPMAX;
-		if (n < vumin)
-			vumin = n;
-		else if (n > vumax)
-			vumax = n;
+		if (n < mins[i&1])
+			mins[i&1]= n;
+		else if (n > maxs[i&1])
+			maxs[i&1] = n;
 		p[i] = n >> (16-MIXING_ATTENUATION);	// 16-bit signed
 	}
-	*lpMin = vumin;
-	*lpMax = vumax;
 	return lSampleCount * 2;
 }
-#endif //MSC_VER, else
-
-#ifdef MSC_VER
-// Clip and convert to 24 bit
-__declspec(naked) DWORD MPPASMCALL X86_Convert32To24(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
-//-----------------------------------------------------------------------------------------------------------------------------
-{
-	_asm {
-	push ebx
-	push esi
-	push edi
-	mov ebx, 16[esp]		// ebx = 8-bit buffer
-	mov esi, 20[esp]		// esi = pBuffer
-	mov edi, 24[esp]		// edi = lSampleCount
-	mov eax, 28[esp]
-	mov ecx, dword ptr [eax]	// ecx = clipmin
-	mov eax, 32[esp]
-	push ebp
-	mov edx, dword ptr [eax]	// edx = clipmax
-cliploop:
-	mov eax, dword ptr [esi]
-	mov ebp, eax
-	sar ebp, 31
-	and ebp, (1 << (8-MIXING_ATTENUATION)) - 1
-	add eax, ebp
-	cmp eax, MIXING_CLIPMIN
-	jl cliplow
-	cmp eax, MIXING_CLIPMAX
-	jg cliphigh
-	cmp eax, ecx
-	jl updatemin
-	cmp eax, edx
-	jg updatemax
-cliprecover:
-	add ebx, 3
-	sar eax, 8-MIXING_ATTENUATION
-	add esi, 4
-	mov word ptr [ebx-3], ax
-	shr eax, 16
-	dec edi
-	mov byte ptr [ebx-1], al
-	jnz cliploop
-	pop ebp
-	mov eax, 28[esp]
-	mov dword ptr [eax], ecx
-	mov eax, 32[esp]
-	mov dword ptr [eax], edx
-	mov edx, 24[esp]
-	mov eax, edx
-	pop edi
-	shl eax, 1
-	pop esi
-	add eax, edx
-	pop ebx
-	ret
-updatemin:
-	mov ecx, eax
-	jmp cliprecover
-updatemax:
-	mov edx, eax
-	jmp cliprecover
-cliplow:
-	mov ecx, MIXING_CLIPMIN
-	mov edx, MIXING_CLIPMAX
-	mov eax, MIXING_CLIPMIN
-	jmp cliprecover
-cliphigh:
-	mov ecx, MIXING_CLIPMIN
-	mov edx, MIXING_CLIPMAX
-	mov eax, MIXING_CLIPMAX
-	jmp cliprecover
-	}
-}
-#else //MSC_VER
 //---GCCFIX: Asm replaced with C function
-DWORD MPPASMCALL X86_Convert32To24(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
+// 24-bit might not work...
+DWORD Convert32To24(LPVOID lp24, int *pBuffer, DWORD lSampleCount, LONG mins[2], LONG maxs[2])
 {
-	UINT i ;
-	int vumin = *lpMin, vumax = *lpMax;
-	int n,p ;
-	unsigned char* buf = (unsigned char*)lp16 ;
-	
-	for ( i=0; i<lSampleCount; i++)
-	{
-		n = pBuffer[i];
-		if (n < MIXING_CLIPMIN)
-			n = MIXING_CLIPMIN;
-		else if (n > MIXING_CLIPMAX)
-			n = MIXING_CLIPMAX;
-		if (n < vumin)
-			vumin = n;
-		else if (n > vumax)
-			vumax = n;
-		p = n >> (8-MIXING_ATTENUATION) ; // 24-bit signed
-//		buf[i*3]   = p & 0xFF0000 ; //XXX
-//		buf[i*3+1] = p & 0x00FF00 ;
-//		buf[i*3+2] = p & 0x0000FF ;
-		buf[i*3]   = (p & 0xFF0000) >> 16 ;
-		buf[i*3+1] = (p & 0x00FF00) >> 8 ;
-		buf[i*3+2] = p & 0x0000FF ;
-	}
-	*lpMin = vumin;
-	*lpMax = vumax;
-	return lSampleCount * 3;
-}
-#endif
-
-#ifdef MSC_VER
-// Clip and convert to 32 bit
-__declspec(naked) DWORD MPPASMCALL X86_Convert32To32(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
-//-----------------------------------------------------------------------------------------------------------------------------
-{
-	_asm {
-	push ebx
-	push esi
-	push edi
-	mov ebx, 16[esp]			// ebx = 32-bit buffer
-	mov esi, 20[esp]			// esi = pBuffer
-	mov edi, 24[esp]			// edi = lSampleCount
-	mov eax, 28[esp]
-	mov ecx, dword ptr [eax]	// ecx = clipmin
-	mov eax, 32[esp]
-	mov edx, dword ptr [eax]	// edx = clipmax
-cliploop:
-	mov eax, dword ptr [esi]
-	add ebx, 4
-	add esi, 4
-	cmp eax, MIXING_CLIPMIN
-	jl cliplow
-	cmp eax, MIXING_CLIPMAX
-	jg cliphigh
-	cmp eax, ecx
-	jl updatemin
-	cmp eax, edx
-	jg updatemax
-cliprecover:
-	shl eax, MIXING_ATTENUATION
-	dec edi
-	mov dword ptr [ebx-4], eax
-	jnz cliploop
-	mov eax, 28[esp]
-	mov dword ptr [eax], ecx
-	mov eax, 32[esp]
-	mov dword ptr [eax], edx
-	mov edx, 24[esp]
-	pop edi
-	mov eax, edx
-	pop esi
-	shl eax, 2
-	pop ebx
-	ret
-updatemin:
-	mov ecx, eax
-	jmp cliprecover
-updatemax:
-	mov edx, eax
-	jmp cliprecover
-cliplow:
-	mov ecx, MIXING_CLIPMIN
-	mov edx, MIXING_CLIPMAX
-	mov eax, MIXING_CLIPMIN
-	jmp cliprecover
-cliphigh:
-	mov ecx, MIXING_CLIPMIN
-	mov edx, MIXING_CLIPMAX
-	mov eax, MIXING_CLIPMAX
-	jmp cliprecover
-	}
-}
-#else
-//---GCCFIX: Asm replaced with C function
-DWORD MPPASMCALL X86_Convert32To32(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
-{
-	UINT i ;
-	int vumin = *lpMin, vumax = *lpMax;
-	signed long *p = (signed long *)lp16;
-	
-	for ( i=0; i<lSampleCount; i++)
+	/* the inventor of 24bit anything should be shot */
+	unsigned char *p = (unsigned char *)lp24;
+	for (UINT i=0; i<lSampleCount; i++)
 	{
 		int n = pBuffer[i];
 		if (n < MIXING_CLIPMIN)
 			n = MIXING_CLIPMIN;
 		else if (n > MIXING_CLIPMAX)
 			n = MIXING_CLIPMAX;
-		if (n < vumin)
-			vumin = n;
-		else if (n > vumax)
-			vumax = n;
-		p[i] = n << MIXING_ATTENUATION;	// 32-bit signed
+		if (n < mins[i&1])
+			mins[i&1]= n;
+		else if (n > maxs[i&1])
+			maxs[i&1] = n;
+		n = n >> (8-MIXING_ATTENUATION);	// 24-bit signed
+		/* err, assume same endian */
+		memcpy(p, &n, 3);
+		p += 3;
 	}
-	*lpMin = vumin;
-	*lpMax = vumax;
-	return lSampleCount * 4;
+	return lSampleCount * 2;
 }
-#endif
-
-
-#ifdef MSC_VER
-void MPPASMCALL X86_InitMixBuffer(int *pBuffer, UINT nSamples)
-//------------------------------------------------------------
+//---GCCFIX: Asm replaced with C function
+// 32-bit might not work...
+DWORD Convert32To32(LPVOID lp32, int *pBuffer, DWORD lSampleCount, LONG mins[2], LONG maxs[2])
 {
-	_asm {
-	mov ecx, nSamples
-	mov esi, pBuffer
-	xor eax, eax
-	mov edx, ecx
-	shr ecx, 2
-	and edx, 3
-	jz unroll4x
-loop1x:
-	add esi, 4
-	dec edx
-	mov dword ptr [esi-4], eax
-	jnz loop1x
-unroll4x:
-	or ecx, ecx
-	jnz loop4x
-	jmp done
-loop4x:
-	add esi, 16
-	dec ecx
-	mov dword ptr [esi-16], eax
-	mov dword ptr [esi-12], eax
-	mov dword ptr [esi-8], eax
-	mov dword ptr [esi-4], eax
-	jnz loop4x
-done:;
+	signed int *p = (signed int *)lp32;
+	for (UINT i=0; i<lSampleCount; i++)
+	{
+		int n = pBuffer[i];
+		if (n < MIXING_CLIPMIN)
+			n = MIXING_CLIPMIN;
+		else if (n > MIXING_CLIPMAX)
+			n = MIXING_CLIPMAX;
+		if (n < mins[i&1])
+			mins[i&1]= n;
+		else if (n > maxs[i&1])
+			maxs[i&1] = n;
+		p[i] = (n >> MIXING_ATTENUATION);	// 32-bit signed
 	}
+	return lSampleCount * 2;
 }
-#else
 //---GCCFIX: Asm replaced with C function
 // Will fill in later.
-void MPPASMCALL X86_InitMixBuffer(int *pBuffer, UINT nSamples)
+void InitMixBuffer(int *pBuffer, UINT nSamples)
 {
 	memset(pBuffer, 0, nSamples * sizeof(int));
 }
-#endif
 
-
-#ifdef MSC_VER
-__declspec(naked) void MPPASMCALL X86_InterleaveFrontRear(int *pFrontBuf, int *pRearBuf, DWORD nSamples)
-//------------------------------------------------------------------------------------------------------
+//---GCCFIX: Asm replaced with C function
+void InterleaveFrontRear(int *pFrontBuf, int *pRearBuf, DWORD nSamples)
 {
-	_asm {
-	push ebx
-	push ebp
-	push esi
-	push edi
-	mov ecx, 28[esp] // ecx = samplecount
-	mov esi, 20[esp] // esi = front buffer
-	mov edi, 24[esp] // edi = rear buffer
-	lea esi, [esi+ecx*4]	// esi = &front[N]
-	lea edi, [edi+ecx*4]	// edi = &rear[N]
-	lea ebx, [esi+ecx*4]	// ebx = &front[N*2]
-interleaveloop:
-	mov eax, dword ptr [esi-8]
-	mov edx, dword ptr [esi-4]
-	sub ebx, 16
-	mov ebp, dword ptr [edi-8]
-	mov dword ptr [ebx], eax
-	mov dword ptr [ebx+4], edx
-	mov eax, dword ptr [edi-4]
-	sub esi, 8
-	sub edi, 8
-	dec ecx
-	mov dword ptr [ebx+8], ebp
-	mov dword ptr [ebx+12], eax
-	jnz interleaveloop
-	pop edi
-	pop esi
-	pop ebp
-	pop ebx
-	ret
+	DWORD i=0;
+
+	pRearBuf[i] = pFrontBuf[1];
+	for (i = 1; i < nSamples; i++) {
+		pRearBuf[i] = pFrontBuf[(i*2)+1];
+		pFrontBuf[i] = pFrontBuf[i*2];
 	}
 }
-#else
 //---GCCFIX: Asm replaced with C function
-// Multichannel not supported.
-void MPPASMCALL X86_InterleaveFrontRear(int *pFrontBuf, int *pRearBuf, DWORD nSamples)
-{
-}
-#endif
-
-
-#ifdef MSC_VER
-VOID MPPASMCALL X86_MonoFromStereo(int *pMixBuf, UINT nSamples)
-//-------------------------------------------------------------
-{
-	_asm {
-	mov ecx, nSamples
-	mov esi, pMixBuf
-	mov edi, esi
-stloop:
-	mov eax, dword ptr [esi]
-	mov edx, dword ptr [esi+4]
-	add edi, 4
-	add esi, 8
-	add eax, edx
-	sar eax, 1
-	dec ecx
-	mov dword ptr [edi-4], eax
-	jnz stloop
-	}
-}
-#else
-//---GCCFIX: Asm replaced with C function
-VOID MPPASMCALL X86_MonoFromStereo(int *pMixBuf, UINT nSamples)
+VOID MonoFromStereo(int *pMixBuf, UINT nSamples)
 {
 	UINT j;
 	for(UINT i = 0; i < nSamples; i++)
@@ -2095,89 +1752,11 @@
 		pMixBuf[i] = (pMixBuf[j] + pMixBuf[j + 1]) >> 1;
 	}
 }
-#endif
 
-#define OFSDECAYSHIFT	8
-#define OFSDECAYMASK	0xFF
-
-
-#ifdef MSC_VER
-void MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs)
-//---------------------------------------------------------------------------------------
-{
-	_asm {
-	mov edi, pBuffer
-	mov ecx, nSamples
-	mov eax, lpROfs
-	mov edx, lpLOfs
-	mov eax, [eax]
-	mov edx, [edx]
-	or ecx, ecx
-	jz fill_loop
-	mov ebx, eax
-	or ebx, edx
-	jz fill_loop
-ofsloop:
-	mov ebx, eax
-	mov esi, edx
-	neg ebx
-	neg esi
-	sar ebx, 31
-	sar esi, 31
-	and ebx, OFSDECAYMASK
-	and esi, OFSDECAYMASK
-	add ebx, eax
-	add esi, edx
-	sar ebx, OFSDECAYSHIFT
-	sar esi, OFSDECAYSHIFT
-	sub eax, ebx
-	sub edx, esi
-	mov ebx, eax
-	or ebx, edx
-	jz fill_loop
-	add edi, 8
-	dec ecx
-	mov [edi-8], eax
-	mov [edi-4], edx
-	jnz ofsloop
-fill_loop:
-	mov ebx, ecx
-	and ebx, 3
-	jz fill4x
-fill1x:
-	mov [edi], eax
-	mov [edi+4], edx
-	add edi, 8
-	dec ebx
-	jnz fill1x
-fill4x:
-	shr ecx, 2
-	or ecx, ecx
-	jz done
-fill4xloop:
-	mov [edi], eax
-	mov [edi+4], edx
-	mov [edi+8], eax
-	mov [edi+12], edx
-	add edi, 8*4
-	dec ecx
-	mov [edi-16], eax
-	mov [edi-12], edx
-	mov [edi-8], eax
-	mov [edi-4], edx
-	jnz fill4xloop
-done:
-	mov esi, lpROfs
-	mov edi, lpLOfs
-	mov [esi], eax
-	mov [edi], edx
-	}
-}
-#else
 //---GCCFIX: Asm replaced with C function
 #define OFSDECAYSHIFT    8
 #define OFSDECAYMASK     0xFF
-void MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs)
+void StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs)
 //---------------------------------------------------------------------------------------------------------
 {
 	int rofs = *lpROfs;
@@ -2185,7 +1764,7 @@
 
 	if ((!rofs) && (!lofs))
 	{
-		X86_InitMixBuffer(pBuffer, nSamples*2);
+		InitMixBuffer(pBuffer, nSamples*2);
 		return;
 	}
 	for (UINT i=0; i<nSamples; i++)
@@ -2200,53 +1779,9 @@
 	*lpROfs = rofs;
 	*lpLOfs = lofs;
 }
-#endif
-
-#ifdef MSC_VER
-void MPPASMCALL X86_EndChannelOfs(MODCHANNEL *pChannel, int *pBuffer, UINT nSamples)
-//----------------------------------------------------------------------------------
-{
-	_asm {
-	mov esi, pChannel
-	mov edi, pBuffer
-	mov ecx, nSamples
-	mov eax, dword ptr [esi+MODCHANNEL.nROfs]
-	mov edx, dword ptr [esi+MODCHANNEL.nLOfs]
-	or ecx, ecx
-	jz brkloop
-ofsloop:
-	mov ebx, eax
-	mov esi, edx
-	neg ebx
-	neg esi
-	sar ebx, 31
-	sar esi, 31
-	and ebx, OFSDECAYMASK
-	and esi, OFSDECAYMASK
-	add ebx, eax
-	add esi, edx
-	sar ebx, OFSDECAYSHIFT
-	sar esi, OFSDECAYSHIFT
-	sub eax, ebx
-	sub edx, esi
-	mov ebx, eax
-	add dword ptr [edi], eax
-	add dword ptr [edi+4], edx
-	or ebx, edx
-	jz brkloop
-	add edi, 8
-	dec ecx
-	jnz ofsloop
-brkloop:
-	mov esi, pChannel
-	mov dword ptr [esi+MODCHANNEL.nROfs], eax
-	mov dword ptr [esi+MODCHANNEL.nLOfs], edx
-	}
-}
-#else
 //---GCCFIX: Asm replaced with C function
 // Will fill in later.
-void MPPASMCALL X86_EndChannelOfs(MODCHANNEL *pChannel, int *pBuffer, UINT nSamples)
+void EndChannelOfs(MODCHANNEL *pChannel, int *pBuffer, UINT nSamples)
 {
 	int rofs = pChannel->nROfs;
 	int lofs = pChannel->nLOfs;
@@ -2264,7 +1799,9 @@
 	pChannel->nROfs = rofs;
 	pChannel->nLOfs = lofs;
 }
-#endif
+
+
+
 
 
 //////////////////////////////////////////////////////////////////////////////////
@@ -2276,72 +1813,11 @@
 #define MIXING_LIMITMAX		(0x08100000)
 #define MIXING_LIMITMIN		(-MIXING_LIMITMAX)
 
-#ifdef MSC_VER
-__declspec(naked) UINT MPPASMCALL X86_AGC(int *pBuffer, UINT nSamples, UINT nAGC)
-//-------------------------------------------------------------------------------
-{
-	__asm {
-	push ebx
-	push ebp
-	push esi
-	push edi
-	mov esi, 20[esp]	// esi = pBuffer+i
-	mov ecx, 24[esp]	// ecx = i
-	mov edi, 28[esp]	// edi = AGC (0..256)
-agcloop:
-	mov eax, dword ptr [esi]
-	imul edi
-	shrd eax, edx, AGC_PRECISION
-	add esi, 4
-	cmp eax, MIXING_LIMITMIN
-	jl agcupdate
-	cmp eax, MIXING_LIMITMAX
-	jg agcupdate
-agcrecover:
-	dec ecx
-	mov dword ptr [esi-4], eax
-	jnz agcloop
-	mov eax, edi
-	pop edi
-	pop esi
-	pop ebp
-	pop ebx
-	ret
-agcupdate:
-	dec edi
-	jmp agcrecover
-	}
-}
-
-#pragma warning (default:4100)
-#else
-// Version for GCC
-UINT MPPASMCALL X86_AGC(int *pBuffer, UINT nSamples, UINT nAGC)
-{
-	int x;
-
-	while(nSamples)
-	{
-		x = ((long long int)(*pBuffer) * nAGC) >> AGC_PRECISION;
-
-		if((x < MIXING_LIMITMIN) || (x > MIXING_LIMITMAX))
-		nAGC--;
-
-		*pBuffer = x;
-
-		pBuffer++;
-		nSamples--;
-	}
-
-	return nAGC;
-}
-#endif
-
 void CSoundFile::ProcessAGC(int count)
 //------------------------------------
 {
 	static DWORD gAGCRecoverCount = 0;
-	UINT agc = X86_AGC(MixSoundBuffer, count, gnAGC);
+	UINT agc = AGC(MixSoundBuffer, count, gnAGC);
 	// Some kind custom law, so that the AGC stays quite stable, but slowly
 	// goes back up if the sound level stays below a level inversely proportional
 	// to the AGC level. (J'me comprends)
@@ -2371,3 +1847,4 @@
 }
 
 #endif // NO_AGC
+
--- a/src/modplug/it_defs.h	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/it_defs.h	Fri Dec 07 12:08:47 2007 -0600
@@ -7,7 +7,8 @@
 {
 	DWORD id;			// 0x4D504D49
 	CHAR songname[26];
-	WORD reserved1;		// 0x1004
+	BYTE hilight_minor;
+	BYTE hilight_major;
 	WORD ordnum;
 	WORD insnum;
 	WORD smpnum;
@@ -21,7 +22,7 @@
 	BYTE speed;
 	BYTE tempo;
 	BYTE sep;
-	BYTE zero;
+	BYTE pwd;
 	WORD msglength;
 	DWORD msgoffset;
 	DWORD reserved2;
--- a/src/modplug/load_669.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_669.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -51,12 +51,9 @@
 	 || (!pfh->patterns) || (pfh->patterns > 128)) return FALSE;
 	DWORD dontfuckwithme = 0x1F1 + pfh->samples * sizeof(SAMPLE669) + pfh->patterns * 0x600;
 	if (dontfuckwithme > dwMemLength) return FALSE;
-	for (UINT ichk=0; ichk<pfh->samples; ichk++)
-	{
-		DWORD len = bswapLE32(*((DWORD *)(&psmp[ichk].length)));
-		dontfuckwithme += len;
-	}
-	if (dontfuckwithme > dwMemLength) return FALSE;
+        for (int n = 0; n < 128; n++)
+                if (pfh->breaks[n] > 0x3f)
+                        return false;
 	// That should be enough checking: this must be a 669 module.
 	m_nType = MOD_TYPE_669;
 	m_dwSongFlags |= SONG_LINEARSLIDES;
@@ -65,7 +62,8 @@
 	m_nDefaultTempo = 125;
 	m_nDefaultSpeed = 6;
 	m_nChannels = 8;
-	memcpy(m_szNames[0], pfh->songmessage, 16);
+	memcpy(m_szNames[0], pfh->songmessage, 31);
+	m_szNames[0][31] = 0;
 	m_nSamples = pfh->samples;
 	for (UINT nins=1; nins<=m_nSamples; nins++, psmp++)
 	{
@@ -86,9 +84,15 @@
 		Ins[nins].nPan = 128;
 	}
 	// Song Message
-	m_lpszSongComments = new char[109];
-	memcpy(m_lpszSongComments, pfh->songmessage, 108);
-	m_lpszSongComments[108] = 0;
+	m_lpszSongComments = new char[114];
+	memcpy(m_lpszSongComments, pfh->songmessage, 36);
+	m_lpszSongComments[36] = '\015';
+	m_lpszSongComments[37] = '\012';
+	memcpy(m_lpszSongComments + 38, pfh->songmessage + 36, 36);
+	m_lpszSongComments[74] = '\015';
+	m_lpszSongComments[75] = '\012';
+	memcpy(m_lpszSongComments + 76, pfh->songmessage + 72, 36);
+	m_lpszSongComments[112] = 0;
 	// Reading Orders
 	memcpy(Order, pfh->orders, 128);
 	m_nRestartPos = pfh->restartpos;
@@ -106,6 +110,7 @@
 		Patterns[npat] = AllocatePattern(64, m_nChannels);
 		if (!Patterns[npat]) break;
 		PatternSize[npat] = 64;
+		PatternAllocSize[npat] = 64;
 		MODCOMMAND *m = Patterns[npat];
 		const BYTE *p = lpStream + dwMemPos;
 		for (UINT row=0; row<64; row++)
--- a/src/modplug/load_amf.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_amf.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -1,11 +1,8 @@
 /*
- * This program is  free software; you can redistribute it  and modify it
- * under the terms of the GNU  General Public License as published by the
- * Free Software Foundation; either version 2  of the license or (at your
- * option) any later version.
+ * This source code is public domain.
  *
  * Authors: Olivier Lapicque <olivierl@jps.net>
-*/
+ */
 
 ///////////////////////////////////////////////////
 //
@@ -223,6 +220,7 @@
 			if (!p) break;
 			Patterns[iPat] = p;
 			PatternSize[iPat] = 64;
+			PatternAllocSize[iPat] = 64;
 			const UCHAR *pin = lpStream + dwMemPos;
 			for (UINT i=0; i<8*64; i++)
 			{
@@ -314,9 +312,11 @@
 		{
 			Order[iOrd] = iOrd;
 			PatternSize[iOrd] = 64;
+			PatternAllocSize[iOrd] = 64;
 			if (pfh->version >= 14)
 			{
 				PatternSize[iOrd] = bswapLE16(*(USHORT *)(lpStream+dwMemPos));
+				PatternAllocSize[iOrd] = bswapLE16(*(USHORT *)(lpStream+dwMemPos));
 				dwMemPos += 2;
 			}
 			ptracks[iOrd] = (USHORT *)(lpStream+dwMemPos);
@@ -353,8 +353,7 @@
 		if ((psh->type) && (bswapLE32(psh->offset) < dwMemLength-1))
 		{
 			sampleseekpos[iIns] = bswapLE32(psh->offset);
-			if (bswapLE32(psh->offset) > maxsampleseekpos) 
-				maxsampleseekpos = bswapLE32(psh->offset);
+			if (bswapLE32(psh->offset) > maxsampleseekpos) maxsampleseekpos = bswapLE32(psh->offset);
 			if ((pins->nLoopEnd > pins->nLoopStart + 2)
 			 && (pins->nLoopEnd <= pins->nLength)) pins->uFlags |= CHN_LOOP;
 		}
@@ -418,3 +417,5 @@
 	}
 	return TRUE;
 }
+
+
--- a/src/modplug/load_ams.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_ams.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -142,6 +142,7 @@
 		dwMemPos += 4;
 		if ((len >= dwMemLength) || (dwMemPos + len > dwMemLength)) return TRUE;
 		PatternSize[iPat] = 64;
+		PatternAllocSize[iPat] = 64;
 		MODCOMMAND *m = AllocatePattern(PatternSize[iPat], m_nChannels);
 		if (!m) return TRUE;
 		Patterns[iPat] = m;
@@ -334,6 +335,7 @@
 	m_nDefaultSpeed = psh->speed;
 	m_nInstruments = psh->instruments;
 	m_nSamples = 0;
+	m_dwSongFlags |= SONG_INSTRUMENTMODE;
 	if (psh->flags & 0x40) m_dwSongFlags |= SONG_LINEARSLIDES;
 	for (UINT nIns=1; nIns<=m_nInstruments; nIns++)
 	{
@@ -378,15 +380,15 @@
 		// Volume Envelope
 		{
 			UINT pos = 0;
-			penv->nVolEnv = (volenv->points > 16) ? 16 : volenv->points;
-			penv->nVolSustainBegin = penv->nVolSustainEnd = volenv->sustain;
-			penv->nVolLoopStart = volenv->loopbegin;
-			penv->nVolLoopEnd = volenv->loopend;
-			for (UINT i=0; i<penv->nVolEnv; i++)
+			penv->VolEnv.nNodes = (volenv->points > 16) ? 16 : volenv->points;
+			penv->VolEnv.nSustainStart = penv->VolEnv.nSustainEnd = volenv->sustain;
+			penv->VolEnv.nLoopStart = volenv->loopbegin;
+			penv->VolEnv.nLoopEnd = volenv->loopend;
+			for (int i=0; i<penv->VolEnv.nNodes; i++)
 			{
-				penv->VolEnv[i] = (BYTE)((volenv->info[i*3+2] & 0x7F) >> 1);
+				penv->VolEnv.Values[i] = (BYTE)((volenv->info[i*3+2] & 0x7F) >> 1);
 				pos += volenv->info[i*3] + ((volenv->info[i*3+1] & 1) << 8);
-				penv->VolPoints[i] = (WORD)pos;
+				penv->VolEnv.Ticks[i] = (WORD)pos;
 			}
 		}
 		penv->nFadeOut = (((lpStream[dwMemPos+2] & 0x0F) << 8) | (lpStream[dwMemPos+1])) << 3;
@@ -487,6 +489,7 @@
 				SetPatternName(ipat, s);
 			}
 			PatternSize[ipat] = numrows;
+			PatternAllocSize[ipat] = numrows;
 			Patterns[ipat] = AllocatePattern(numrows, m_nChannels);
 			if (!Patterns[ipat]) return TRUE;
 			// Unpack Pattern Data
--- a/src/modplug/load_dbm.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_dbm.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -158,7 +158,7 @@
 				}
 				Headers[iIns+1] = penv;
 				penv->nFadeOut = 1024;	// ???
-				penv->nGlobalVol = 64;
+				penv->nGlobalVol = 128;
 				penv->nPan = bswapBE16(pih->panning);
 				if ((penv->nPan) && (penv->nPan < 256))
 					penv->dwFlags = ENV_SETPANNING;
@@ -193,6 +193,7 @@
 				chunk_pos += sizeof(DBMINSTRUMENT);
 				m_nInstruments = iIns+1;
 			}
+			m_dwSongFlags |= SONG_INSTRUMENTMODE;
 		} else
 		// Volume Envelopes
 		if (chunk_id == DBM_ID_VENV)
@@ -215,15 +216,15 @@
 					if (peh->flags & 1) penv->dwFlags |= ENV_VOLUME;
 					if (peh->flags & 2) penv->dwFlags |= ENV_VOLSUSTAIN;
 					if (peh->flags & 4) penv->dwFlags |= ENV_VOLLOOP;
-					penv->nVolEnv = peh->numpoints + 1;
-					if (penv->nVolEnv > MAX_ENVPOINTS) penv->nVolEnv = MAX_ENVPOINTS;
-					penv->nVolLoopStart = peh->loopbegin;
-					penv->nVolLoopEnd = peh->loopend;
-					penv->nVolSustainBegin = penv->nVolSustainEnd = peh->sustain1;
-					for (UINT i=0; i<penv->nVolEnv; i++)
+					penv->VolEnv.nNodes = peh->numpoints + 1;
+					if (penv->VolEnv.nNodes > MAX_ENVPOINTS) penv->VolEnv.nNodes = MAX_ENVPOINTS;
+					penv->VolEnv.nLoopStart = peh->loopbegin;
+					penv->VolEnv.nLoopEnd = peh->loopend;
+					penv->VolEnv.nSustainStart = penv->VolEnv.nSustainEnd = peh->sustain1;
+					for (int i=0; i<penv->VolEnv.nNodes; i++)
 					{
-						penv->VolPoints[i] = bswapBE16(peh->volenv[i*2]);
-						penv->VolEnv[i] = (BYTE)bswapBE16(peh->volenv[i*2+1]);
+						penv->VolEnv.Ticks[i] = bswapBE16(peh->volenv[i*2]);
+						penv->VolEnv.Values[i] = (BYTE)bswapBE16(peh->volenv[i*2+1]);
 					}
 				}
 				chunk_pos += sizeof(DBMENVELOPE);
@@ -254,6 +255,7 @@
 						UINT i = 0;
 
 						PatternSize[iPat] = nRows;
+						PatternAllocSize[iPat] = nRows;
 						Patterns[iPat] = m;
 						while ((i+3<pksize) && (row < nRows))
 						{
--- a/src/modplug/load_dmf.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_dmf.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -176,6 +176,7 @@
 					dwPos += 8;
 					if ((pt->jmpsize >= dwMemLength) || (dwPos + pt->jmpsize + 4 >= dwMemLength)) break;
 					PatternSize[npat] = (WORD)ticks;
+					PatternAllocSize[npat] = (WORD)ticks;
 					MODCOMMAND *m = AllocatePattern(PatternSize[npat], m_nChannels);
 					if (!m) goto dmfexit;
 					Patterns[npat] = m;
--- a/src/modplug/load_dsm.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_dsm.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -136,6 +136,7 @@
 			MODCOMMAND *m = AllocatePattern(64, m_nChannels);
 			if (!m) break;
 			PatternSize[nPat] = 64;
+			PatternAllocSize[nPat] = 64;
 			Patterns[nPat] = m;
 			UINT row = 0;
 			while ((row < 64) && (dwPos + 2 <= dwMemPos))
--- a/src/modplug/load_far.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_far.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -64,10 +64,9 @@
 	UINT headerlen;
 	BYTE samplemap[8];
 
-	if ((!lpStream) || (dwMemLength < 1024) || (bswapLE32(pmh1->id) != FARFILEMAGIC)
+	if ((!lpStream) || (dwMemLength < 1024) || (pmh1->id != FARFILEMAGIC)
 	 || (pmh1->magic2[0] != 13) || (pmh1->magic2[1] != 10) || (pmh1->magic2[2] != 26)) return FALSE;
-	headerlen = bswapLE16(pmh1->headerlen);
-	pmh1->stlen = bswapLE16( pmh1->stlen ); /* inplace byteswap -- Toad */
+	headerlen = pmh1->headerlen;
 	if ((headerlen >= dwMemLength) || (dwMemPos + pmh1->stlen + sizeof(FARHEADER2) >= dwMemLength)) return FALSE;
 	// Globals
 	m_nType = MOD_TYPE_FAR;
@@ -112,14 +111,6 @@
 	dwMemPos += headerlen - (869 + pmh1->stlen);
 	if (dwMemPos >= dwMemLength) return TRUE;
 
-	// byteswap pattern data -- Toad
-	UINT psfix = 0 ;
-	while( psfix++ < 256 )
-	{
-		pmh2->patsiz[psfix] = bswapLE16( pmh2->patsiz[psfix] ) ;
-	}
-	// end byteswap of pattern data
-
 	WORD *patsiz = (WORD *)pmh2->patsiz;
 	for (UINT ipat=0; ipat<256; ipat++) if (patsiz[ipat])
 	{
@@ -139,6 +130,7 @@
 		if (rows > 256) rows = 256;
 		if (rows < 16) rows = 16;
 		PatternSize[ipat] = rows;
+		PatternAllocSize[ipat] = rows;
 		if ((Patterns[ipat] = AllocatePattern(rows, m_nChannels)) == NULL) return TRUE;
 		MODCOMMAND *m = Patterns[ipat];
 		UINT patbrk = lpStream[dwMemPos];
@@ -241,10 +233,9 @@
 		dwMemPos += sizeof(FARSAMPLE);
 		m_nSamples = ismp + 1;
 		memcpy(m_szNames[ismp+1], pfs->samplename, 32);
-		pfs->length = bswapLE32( pfs->length ) ; /* endian fix - Toad */
-		pins->nLength = pfs->length ;
-		pins->nLoopStart = bswapLE32(pfs->reppos) ;
-		pins->nLoopEnd = bswapLE32(pfs->repend) ;
+		pins->nLength = pfs->length;
+		pins->nLoopStart = pfs->reppos;
+		pins->nLoopEnd = pfs->repend;
 		pins->nFineTune = 0;
 		pins->nC4Speed = 8363*2;
 		pins->nGlobalVol = 64;
--- a/src/modplug/load_it.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_it.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -2,15 +2,17 @@
  * This source code is public domain.
  *
  * Authors: Olivier Lapicque <olivierl@jps.net>,
- *          Adam Goode       <adam@evdebs.org> (Endian and char fixes for PPC)
- *          Marco Trillo     <toad@arsystel.com> (Endian fixes for SaveIT, XM->IT Sample Converter)
- *
+ *          Adam Goode       <adam@evdebs.org> (endian and char fixes for PPC)
 */
 
 #include "stdafx.h"
 #include "sndfile.h"
 #include "it_defs.h"
 
+/* blah, -mrsb.
+this is a schism header */
+#include "midi.h"
+
 #ifdef MSC_VER
 #pragma warning(disable:4244)
 #endif
@@ -22,11 +24,8 @@
 { 0, 2, 4, 1, 3, 0, 0, 0 };
 
 //////////////////////////////////////////////////////////
-// Impulse Tracker IT file support
+// Impulse Tracker IT file support (import only)
 
-// for conversion of XM samples
-extern WORD XMPeriodTable[96+8];
-extern UINT XMLinearTable[768];
 
 static inline UINT ConvertVolParam(UINT value)
 //--------------------------------------------
@@ -44,7 +43,7 @@
 		memcpy(penv->name, pis->name, 26);
 		memcpy(penv->filename, pis->filename, 12);
 		penv->nFadeOut = bswapLE16(pis->fadeout) << 6;
-		penv->nGlobalVol = 64;
+		penv->nGlobalVol = 128;
 		for (UINT j=0; j<120; j++)
 		{
 			UINT note = pis->keyboard[j*2];
@@ -56,19 +55,19 @@
 		if (pis->flags & 0x01) penv->dwFlags |= ENV_VOLUME;
 		if (pis->flags & 0x02) penv->dwFlags |= ENV_VOLLOOP;
 		if (pis->flags & 0x04) penv->dwFlags |= ENV_VOLSUSTAIN;
-		penv->nVolLoopStart = pis->vls;
-		penv->nVolLoopEnd = pis->vle;
-		penv->nVolSustainBegin = pis->sls;
-		penv->nVolSustainEnd = pis->sle;
-		penv->nVolEnv = 25;
+		penv->VolEnv.nLoopStart = pis->vls;
+		penv->VolEnv.nLoopEnd = pis->vle;
+		penv->VolEnv.nSustainStart = pis->sls;
+		penv->VolEnv.nSustainEnd = pis->sle;
+		penv->VolEnv.nNodes = 25;
 		for (UINT ev=0; ev<25; ev++)
 		{
-			if ((penv->VolPoints[ev] = pis->nodes[ev*2]) == 0xFF)
+			if ((penv->VolEnv.Ticks[ev] = pis->nodes[ev*2]) == 0xFF)
 			{
-				penv->nVolEnv = ev;
+				penv->VolEnv.nNodes = ev;
 				break;
 			}
-			penv->VolEnv[ev] = pis->nodes[ev*2+1];
+			penv->VolEnv.Values[ev] = pis->nodes[ev*2+1];
 		}
 		penv->nNNA = pis->nna;
 		penv->nDCT = pis->dnc;
@@ -82,8 +81,8 @@
 		penv->nMidiChannel = pis->mch;
 		penv->wMidiBank = bswapLE16(pis->mbank);
 		penv->nFadeOut = bswapLE16(pis->fadeout) << 5;
-		penv->nGlobalVol = pis->gbv >> 1;
-		if (penv->nGlobalVol > 64) penv->nGlobalVol = 64;
+		penv->nGlobalVol = pis->gbv;
+		if (penv->nGlobalVol > 128) penv->nGlobalVol = 128;
 		for (UINT j=0; j<120; j++)
 		{
 			UINT note = pis->keyboard[j*2];
@@ -97,49 +96,49 @@
 		if (pis->volenv.flags & 2) penv->dwFlags |= ENV_VOLLOOP;
 		if (pis->volenv.flags & 4) penv->dwFlags |= ENV_VOLSUSTAIN;
 		if (pis->volenv.flags & 8) penv->dwFlags |= ENV_VOLCARRY;
-		penv->nVolEnv = pis->volenv.num;
-		if (penv->nVolEnv > 25) penv->nVolEnv = 25;
+		penv->VolEnv.nNodes = pis->volenv.num;
+		if (penv->VolEnv.nNodes > 25) penv->VolEnv.nNodes = 25;
 
-		penv->nVolLoopStart = pis->volenv.lpb;
-		penv->nVolLoopEnd = pis->volenv.lpe;
-		penv->nVolSustainBegin = pis->volenv.slb;
-		penv->nVolSustainEnd = pis->volenv.sle;
+		penv->VolEnv.nLoopStart = pis->volenv.lpb;
+		penv->VolEnv.nLoopEnd = pis->volenv.lpe;
+		penv->VolEnv.nSustainStart = pis->volenv.slb;
+		penv->VolEnv.nSustainEnd = pis->volenv.sle;
 		// Panning Envelope
 		if (pis->panenv.flags & 1) penv->dwFlags |= ENV_PANNING;
 		if (pis->panenv.flags & 2) penv->dwFlags |= ENV_PANLOOP;
 		if (pis->panenv.flags & 4) penv->dwFlags |= ENV_PANSUSTAIN;
 		if (pis->panenv.flags & 8) penv->dwFlags |= ENV_PANCARRY;
-		penv->nPanEnv = pis->panenv.num;
-		if (penv->nPanEnv > 25) penv->nPanEnv = 25;
-		penv->nPanLoopStart = pis->panenv.lpb;
-		penv->nPanLoopEnd = pis->panenv.lpe;
-		penv->nPanSustainBegin = pis->panenv.slb;
-		penv->nPanSustainEnd = pis->panenv.sle;
+		penv->PanEnv.nNodes = pis->panenv.num;
+		if (penv->PanEnv.nNodes > 25) penv->PanEnv.nNodes = 25;
+		penv->PanEnv.nLoopStart = pis->panenv.lpb;
+		penv->PanEnv.nLoopEnd = pis->panenv.lpe;
+		penv->PanEnv.nSustainStart = pis->panenv.slb;
+		penv->PanEnv.nSustainEnd = pis->panenv.sle;
 		// Pitch Envelope
 		if (pis->pitchenv.flags & 1) penv->dwFlags |= ENV_PITCH;
 		if (pis->pitchenv.flags & 2) penv->dwFlags |= ENV_PITCHLOOP;
 		if (pis->pitchenv.flags & 4) penv->dwFlags |= ENV_PITCHSUSTAIN;
 		if (pis->pitchenv.flags & 8) penv->dwFlags |= ENV_PITCHCARRY;
 		if (pis->pitchenv.flags & 0x80) penv->dwFlags |= ENV_FILTER;
-		penv->nPitchEnv = pis->pitchenv.num;
-		if (penv->nPitchEnv > 25) penv->nPitchEnv = 25;
-		penv->nPitchLoopStart = pis->pitchenv.lpb;
-		penv->nPitchLoopEnd = pis->pitchenv.lpe;
-		penv->nPitchSustainBegin = pis->pitchenv.slb;
-		penv->nPitchSustainEnd = pis->pitchenv.sle;
+		penv->PitchEnv.nNodes = pis->pitchenv.num;
+		if (penv->PitchEnv.nNodes > 25) penv->PitchEnv.nNodes = 25;
+		penv->PitchEnv.nLoopStart = pis->pitchenv.lpb;
+		penv->PitchEnv.nLoopEnd = pis->pitchenv.lpe;
+		penv->PitchEnv.nSustainStart = pis->pitchenv.slb;
+		penv->PitchEnv.nSustainEnd = pis->pitchenv.sle;
 		// Envelopes Data
 		for (UINT ev=0; ev<25; ev++)
 		{
-			penv->VolEnv[ev] = pis->volenv.data[ev*3];
-			penv->VolPoints[ev] = (pis->volenv.data[ev*3+2] << 8) | (pis->volenv.data[ev*3+1]);
-			penv->PanEnv[ev] = pis->panenv.data[ev*3] + 32;
-			penv->PanPoints[ev] = (pis->panenv.data[ev*3+2] << 8) | (pis->panenv.data[ev*3+1]);
-			penv->PitchEnv[ev] = pis->pitchenv.data[ev*3] + 32;
-			penv->PitchPoints[ev] = (pis->pitchenv.data[ev*3+2] << 8) | (pis->pitchenv.data[ev*3+1]);
+			penv->VolEnv.Values[ev] = pis->volenv.data[ev*3];
+			penv->VolEnv.Ticks[ev] = (pis->volenv.data[ev*3+2] << 8) | (pis->volenv.data[ev*3+1]);
+			penv->PanEnv.Values[ev] = pis->panenv.data[ev*3] + 32;
+			penv->PanEnv.Ticks[ev] = (pis->panenv.data[ev*3+2] << 8) | (pis->panenv.data[ev*3+1]);
+			penv->PitchEnv.Values[ev] = pis->pitchenv.data[ev*3] + 32;
+			penv->PitchEnv.Ticks[ev] = (pis->pitchenv.data[ev*3+2] << 8) | (pis->pitchenv.data[ev*3+1]);
 		}
-		penv->nNNA = pis->nna;
-		penv->nDCT = pis->dct;
-		penv->nDNA = pis->dca;
+		penv->nNNA = pis->nna % 4;
+		penv->nDCT = pis->dct % 4;
+		penv->nDNA = pis->dca % 3;
 		penv->nPPS = pis->pps;
 		penv->nPPC = pis->ppc;
 		penv->nIFC = pis->ifc;
@@ -150,8 +149,8 @@
 		if (penv->nPan > 256) penv->nPan = 128;
 		if (pis->dfp < 0x80) penv->dwFlags |= ENV_SETPANNING;
 	}
-	if ((penv->nVolLoopStart >= 25) || (penv->nVolLoopEnd >= 25)) penv->dwFlags &= ~ENV_VOLLOOP;
-	if ((penv->nVolSustainBegin >= 25) || (penv->nVolSustainEnd >= 25)) penv->dwFlags &= ~ENV_VOLSUSTAIN;
+	if ((penv->VolEnv.nLoopStart >= 25) || (penv->VolEnv.nLoopEnd >= 25)) penv->dwFlags &= ~ENV_VOLLOOP;
+	if ((penv->VolEnv.nSustainStart >= 25) || (penv->VolEnv.nSustainEnd >= 25)) penv->dwFlags &= ~ENV_VOLSUSTAIN;
 	return TRUE;
 }
 
@@ -167,8 +166,112 @@
 	BYTE chnmask[64], channels_used[64];
 	MODCOMMAND lastvalue[64];
 
+	if ((!lpStream) || (dwMemLength < 0xc2)) return FALSE;
+
 	pifh.id = bswapLE32(pifh.id);
-	pifh.reserved1 = bswapLE16(pifh.reserved1);
+	if (pifh.id == 0x49504D49) {
+		if (dwMemLength < 554) return FALSE;
+
+		WORD tv;
+		INSTRUMENTHEADER *zenv = new INSTRUMENTHEADER;
+		if (!zenv) return FALSE;
+		memset(zenv, 0, sizeof(INSTRUMENTHEADER));
+		memcpy(&tv, lpStream+0x1C, 2); /* trkvers */
+		if (!ITInstrToMPT(lpStream, zenv, tv)) {
+			delete zenv;
+			return FALSE;
+		}
+
+		/* okay, we need samples now */
+		unsigned int q = 554;
+		BYTE expect_samples = lpStream[0x1E];
+
+		m_nType = MOD_TYPE_IT;
+		m_nInstruments = 1;
+		m_nSamples = expect_samples;
+		m_dwSongFlags = SONG_INSTRUMENTMODE | SONG_LINEARSLIDES /* eh? */;
+
+		memcpy(m_szNames[0], lpStream + 0x20, 26);
+		m_szNames[0][26] = 0;
+
+		if (q+(80*expect_samples) >= dwMemLength) {
+			delete zenv;
+			return FALSE;
+		}
+
+		for (UINT nsmp = 0; nsmp < expect_samples; nsmp++) {
+
+			ITSAMPLESTRUCT pis = *(ITSAMPLESTRUCT *)(lpStream+q);
+			q += 80; /* length of ITS header */
+
+			pis.id = bswapLE32(pis.id);
+			pis.length = bswapLE32(pis.length);
+			pis.loopbegin = bswapLE32(pis.loopbegin);
+			pis.loopend = bswapLE32(pis.loopend);
+			pis.C5Speed = bswapLE32(pis.C5Speed);
+			pis.susloopbegin = bswapLE32(pis.susloopbegin);
+			pis.susloopend = bswapLE32(pis.susloopend);
+			pis.samplepointer = bswapLE32(pis.samplepointer);
+	
+			if (pis.id == 0x53504D49)
+			{
+				MODINSTRUMENT *pins = &Ins[nsmp+1];
+				memcpy(pins->name, pis.filename, 12);
+				pins->uFlags = 0;
+				pins->nLength = 0;
+				pins->nLoopStart = pis.loopbegin;
+				pins->nLoopEnd = pis.loopend;
+				pins->nSustainStart = pis.susloopbegin;
+				pins->nSustainEnd = pis.susloopend;
+				pins->nC4Speed = pis.C5Speed;
+				if (!pins->nC4Speed) pins->nC4Speed = 8363;
+				//if (pis.C5Speed < 256) pins->nC4Speed = 256;
+				pins->nVolume = pis.vol << 2;
+				if (pins->nVolume > 256) pins->nVolume = 256;
+				pins->nGlobalVol = pis.gvl;
+				if (pins->nGlobalVol > 64) pins->nGlobalVol = 64;
+				if (pis.flags & 0x10) pins->uFlags |= CHN_LOOP;
+				if (pis.flags & 0x20) pins->uFlags |= CHN_SUSTAINLOOP;
+				if (pis.flags & 0x40) pins->uFlags |= CHN_PINGPONGLOOP;
+				if (pis.flags & 0x80) pins->uFlags |= CHN_PINGPONGSUSTAIN;
+				pins->nPan = (pis.dfp & 0x7F) << 2;
+				if (pins->nPan > 256) pins->nPan = 256;
+				if (pis.dfp & 0x80) pins->uFlags |= CHN_PANNING;
+				pins->nVibType = autovibit2xm[pis.vit & 7];
+				pins->nVibRate = pis.vis;
+				pins->nVibDepth = pis.vid & 0x7F;
+				pins->nVibSweep = pis.vir;
+				if ((pis.samplepointer) && (pis.samplepointer < dwMemLength) && (pis.length))
+				{
+					pins->nLength = pis.length;
+					if (pins->nLength > MAX_SAMPLE_LENGTH) pins->nLength = MAX_SAMPLE_LENGTH;
+					UINT flags = (pis.cvt & 1) ? RS_PCM8S : RS_PCM8U;
+					if (pis.flags & 2)
+					{
+						flags += 5;
+						if (pis.flags & 4) flags |= RSF_STEREO;
+						pins->uFlags |= CHN_16BIT;
+						// IT 2.14 16-bit packed sample ?
+						if (pis.flags & 8) flags = ((pifh.cmwt >= 0x215) && (pis.cvt & 4)) ? RS_IT21516 : RS_IT21416;
+					} else
+					{
+						if (pis.flags & 4) flags |= RSF_STEREO;
+						if (pis.cvt == 0xFF) flags = RS_ADPCM4; else
+						// IT 2.14 8-bit packed sample ?
+						if (pis.flags & 8)	flags =	((pifh.cmwt >= 0x215) && (pis.cvt & 4)) ? RS_IT2158 : RS_IT2148;
+					}
+					ReadSample(&Ins[nsmp+1], flags, (LPSTR)(lpStream+pis.samplepointer), dwMemLength - pis.samplepointer);
+				}
+			}
+			memcpy(m_szNames[nsmp+1], pis.name, 26);
+			
+		}
+
+		Headers[1] = zenv;
+		return TRUE;
+	}
+
+
 	pifh.ordnum = bswapLE16(pifh.ordnum);
 	pifh.insnum = bswapLE16(pifh.insnum);
 	pifh.smpnum = bswapLE16(pifh.smpnum);
@@ -181,29 +284,42 @@
 	pifh.msgoffset = bswapLE32(pifh.msgoffset);
 	pifh.reserved2 = bswapLE32(pifh.reserved2);
 
-	if ((!lpStream) || (dwMemLength < 0x100)) return FALSE;
+
+
 	if ((pifh.id != 0x4D504D49) || (pifh.insnum >= MAX_INSTRUMENTS)
-	 || (!pifh.smpnum) || (pifh.smpnum >= MAX_INSTRUMENTS) || (!pifh.ordnum)) return FALSE;
+	 || (pifh.smpnum >= MAX_INSTRUMENTS)) return FALSE;
 	if (dwMemPos + pifh.ordnum + pifh.insnum*4
 	 + pifh.smpnum*4 + pifh.patnum*4 > dwMemLength) return FALSE;
 	m_nType = MOD_TYPE_IT;
+	if (!(pifh.flags & 0x01)) m_dwSongFlags |= SONG_NOSTEREO;
+	if (pifh.flags & 0x04) m_dwSongFlags |= SONG_INSTRUMENTMODE;
 	if (pifh.flags & 0x08) m_dwSongFlags |= SONG_LINEARSLIDES;
 	if (pifh.flags & 0x10) m_dwSongFlags |= SONG_ITOLDEFFECTS;
 	if (pifh.flags & 0x20) m_dwSongFlags |= SONG_ITCOMPATMODE;
+	if (pifh.flags & 0x40) {
+		midi_flags |= MIDI_PITCH_BEND;
+		midi_pitch_depth = pifh.pwd;
+	}
 	if (pifh.flags & 0x80) m_dwSongFlags |= SONG_EMBEDMIDICFG;
 	if (pifh.flags & 0x1000) m_dwSongFlags |= SONG_EXFILTERRANGE;
 	memcpy(m_szNames[0], pifh.songname, 26);
 	m_szNames[0][26] = 0;
+	if (pifh.cwtv >= 0x0213) {
+		m_rowHighlightMinor = pifh.hilight_minor;
+		m_rowHighlightMajor = pifh.hilight_major;
+	} else {
+		m_rowHighlightMinor = 4;
+		m_rowHighlightMajor = 16;
+	}
 	// Global Volume
-	if (pifh.globalvol)
-	{
-		m_nDefaultGlobalVolume = pifh.globalvol << 1;
-		if (!m_nDefaultGlobalVolume) m_nDefaultGlobalVolume = 256;
-		if (m_nDefaultGlobalVolume > 256) m_nDefaultGlobalVolume = 256;
-	}
+        m_nDefaultGlobalVolume = pifh.globalvol << 1;
+        if (m_nDefaultGlobalVolume > 256) m_nDefaultGlobalVolume = 256;
 	if (pifh.speed) m_nDefaultSpeed = pifh.speed;
 	if (pifh.tempo) m_nDefaultTempo = pifh.tempo;
-	m_nSongPreAmp = pifh.mv & 0x7F;
+	m_nSongPreAmp = pifh.mv;
+        if (m_nSongPreAmp > 128)
+                m_nSongPreAmp = 128;
+	m_nStereoSeparation = pifh.sep;
 	// Reading Channels Pan Positions
 	for (int ipan=0; ipan<64; ipan++) if (pifh.chnpan[ipan] != 0xFF)
 	{
@@ -229,6 +345,7 @@
 	UINT nordsize = pifh.ordnum;
 	if (nordsize > MAX_ORDERS) nordsize = MAX_ORDERS;
 	memcpy(Order, lpStream+dwMemPos, nordsize);
+
 	dwMemPos += pifh.ordnum;
 	// Reading Instrument Offsets
 	memset(inspos, 0, sizeof(inspos));
@@ -263,6 +380,17 @@
 	       patpos[j] = bswapLE32(patpos[j]);
 	}
 	dwMemPos += pifh.patnum * 4;
+
+	for (UINT i = 0; i < pifh.ordnum; i++) {
+		if (Order[i] >= pifh.patnum && Order[i] < MAX_PATTERNS) {
+			pifh.patnum = Order[i];
+			for (UINT j = patpossize; j < (unsigned)(pifh.patnum>>2); j++)
+				patpos[j] = 0;
+			patpossize = pifh.patnum;
+		}
+	}
+
+
 	// Reading IT Extra Info
 	if (dwMemPos + 2 < dwMemLength)
 	{
@@ -277,8 +405,13 @@
 		{
 			memcpy(&m_MidiCfg, lpStream+dwMemPos, sizeof(MODMIDICFG));
 			dwMemPos += sizeof(MODMIDICFG);
+		} else {
+			ResetMidiCfg();
 		}
+	} else {
+		ResetMidiCfg();
 	}
+#if 0
 	// Read pattern names: "PNAM"
 	if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e50))
 	{
@@ -295,8 +428,10 @@
 			dwMemPos += len;
 		}
 	}
+#endif
 	// 4-channels minimum
 	m_nChannels = 4;
+#if 0
 	// Read channel names: "CNAM"
 	if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e43))
 	{
@@ -319,6 +454,7 @@
 	{
 		dwMemPos += LoadMixPlugins(lpStream+dwMemPos, dwMemLength-dwMemPos);
 	}
+#endif
 	// Checking for unused channels
 	UINT npatterns = pifh.patnum;
 	if (npatterns > MAX_PATTERNS) npatterns = MAX_PATTERNS;
@@ -366,8 +502,7 @@
 		}
 	}
 	// Reading Instruments
-	m_nInstruments = 0;
-	if (pifh.flags & 0x04) m_nInstruments = pifh.insnum;
+	m_nInstruments = pifh.insnum;
 	if (m_nInstruments >= MAX_INSTRUMENTS) m_nInstruments = MAX_INSTRUMENTS-1;
 	for (UINT nins=0; nins<m_nInstruments; nins++)
 	{
@@ -407,7 +542,7 @@
 			pins->nSustainEnd = pis.susloopend;
 			pins->nC4Speed = pis.C5Speed;
 			if (!pins->nC4Speed) pins->nC4Speed = 8363;
-			if (pis.C5Speed < 256) pins->nC4Speed = 256;
+			//if (pis.C5Speed < 256) pins->nC4Speed = 256;
 			pins->nVolume = pis.vol << 2;
 			if (pins->nVolume > 256) pins->nVolume = 256;
 			pins->nGlobalVol = pis.gvl;
@@ -422,7 +557,7 @@
 			pins->nVibType = autovibit2xm[pis.vit & 7];
 			pins->nVibRate = pis.vis;
 			pins->nVibDepth = pis.vid & 0x7F;
-			pins->nVibSweep = (pis.vir + 3) / 4;
+			pins->nVibSweep = pis.vir;
 			if ((pis.samplepointer) && (pis.samplepointer < dwMemLength) && (pis.length))
 			{
 				pins->nLength = pis.length;
@@ -453,6 +588,7 @@
 		if ((!patpos[npat]) || ((DWORD)patpos[npat] + 4 >= dwMemLength))
 		{
 			PatternSize[npat] = 64;
+			PatternAllocSize[npat] = 64;
 			Patterns[npat] = AllocatePattern(64, m_nChannels);
 			continue;
 		}
@@ -462,6 +598,7 @@
 		if ((rows < 4) || (rows > 256)) continue;
 		if (patpos[npat]+8+len > dwMemLength) continue;
 		PatternSize[npat] = rows;
+		PatternAllocSize[npat] = rows;
 		if ((Patterns[npat] = AllocatePattern(rows, m_nChannels)) == NULL) continue;
 		memset(lastvalue, 0, sizeof(lastvalue));
 		memset(chnmask, 0, sizeof(chnmask));
@@ -551,7 +688,7 @@
 					// 193-202: Portamento To
 					if ((vol >= 193) && (vol <= 202)) { m[ch].volcmd = VOLCMD_TONEPORTAMENTO; m[ch].vol = vol - 193; } else
 					// 203-212: Vibrato
-					if ((vol >= 203) && (vol <= 212)) { m[ch].volcmd = VOLCMD_VIBRATOSPEED; m[ch].vol = vol - 203; }
+					if ((vol >= 203) && (vol <= 212)) { m[ch].volcmd = VOLCMD_VIBRATO; m[ch].vol = vol - 203; }
 					lastvalue[ch].volcmd = m[ch].volcmd;
 					lastvalue[ch].vol = m[ch].vol;
 				}
@@ -592,14 +729,18 @@
 
 #ifndef MODPLUG_NO_FILESAVE
 //#define SAVEITTIMESTAMP
+
+#ifdef MSC_VER
 #pragma warning(disable:4100)
+#endif
 
+#if 0
 BOOL CSoundFile::SaveIT(LPCSTR lpszFileName, UINT nPacking)
 //---------------------------------------------------------
 {
 	DWORD dwPatNamLen, dwChnNamLen;
-	ITFILEHEADER header, writeheader;
-	ITINSTRUMENT iti, writeiti;
+	ITFILEHEADER header;
+	ITINSTRUMENT iti;
 	ITSAMPLESTRUCT itss;
 	BYTE smpcount[MAX_SAMPLES];
 	DWORD inspos[MAX_INSTRUMENTS];
@@ -621,9 +762,10 @@
 	memset(&header, 0, sizeof(header));
 	dwPatNamLen = 0;
 	dwChnNamLen = 0;
-	header.id = 0x4D504D49; // IMPM
-	lstrcpyn((char *)header.songname, m_szNames[0], 27);
-	header.reserved1 = 0x1004;
+	header.id = 0x4D504D49;
+	lstrcpyn(header.songname, m_szNames[0], 27);
+	header.hilight_minor = m_rowHighlightMinor;
+	header.hilight_major = m_rowHighlightMajor;
 	header.ordnum = 0;
 	while ((header.ordnum < MAX_ORDERS) && (Order[header.ordnum] < 0xFF)) header.ordnum++;
 	if (header.ordnum < MAX_ORDERS) Order[header.ordnum++] = 0xFF;
@@ -635,16 +777,13 @@
 	header.cmwt = 0x200;
 	header.flags = 0x0001;
 	header.special = 0x0006;
-	if (m_nInstruments) header.flags |= 0x04;
+	if (m_dwSongFlags & SONG_INSTRUMENTMODE) header.flags |= 0x04;
 	if (m_dwSongFlags & SONG_LINEARSLIDES) header.flags |= 0x08;
 	if (m_dwSongFlags & SONG_ITOLDEFFECTS) header.flags |= 0x10;
 	if (m_dwSongFlags & SONG_ITCOMPATMODE) header.flags |= 0x20;
 	if (m_dwSongFlags & SONG_EXFILTERRANGE) header.flags |= 0x1000;
 	header.globalvol = m_nDefaultGlobalVolume >> 1;
 	header.mv = m_nSongPreAmp;
-	// clip song pre-amp values (between 0x20 and 0x7f)
-	if (header.mv < 0x20) header.mv = 0x20;
-	if (header.mv > 0x7F) header.mv = 0x7F;
 	header.speed = m_nDefaultSpeed;
 	header.tempo = m_nDefaultTempo;
 	header.sep = m_nStereoSeparation;
@@ -691,25 +830,7 @@
 		header.msgoffset = dwHdrPos + dwExtra + header.insnum*4 + header.patnum*4 + header.smpnum*4;
 	}
 	// Write file header
-	memcpy(writeheader, header, sizeof(header));
-
-	// Byteswap header information
-	writeheader.id = bswapLE32(writeheader.id);
-	writeheader.reserved1 = bswapLE16(writeheader.reserved1);
-	writeheader.ordnum = bswapLE16(writeheader.ordnum);
-	writeheader.insnum = bswapLE16(writeheader.insnum);
-	writeheader.smpnum = bswapLE16(writeheader.smpnum);
-	writeheader.patnum = bswapLE16(writeheader.patnum);
-	writeheader.cwtv = bswapLE16(writeheader.cwtv);
-	writeheader.cmwt = bswapLE16(writeheader.cmwt);
-	writeheader.flags = bswapLE16(writeheader.flags);
-	writeheader.special = bswapLE16(writeheader.special);
-	writeheader.msglength = bswapLE16(writeheader.msglength);
-	writeheader.msgoffset = bswapLE32(writeheader.msgoffset);
-	writeheader.reserved2 = bswapLE32(writeheader.reserved2);
-
-	fwrite(&writeheader, 1, sizeof(writeheader), f);
-
+	fwrite(&header, 1, sizeof(header), f);
 	fwrite(Order, 1, header.ordnum, f);
 	if (header.insnum) fwrite(inspos, 4, header.insnum, f);
 	if (header.smpnum) fwrite(smppos, 4, header.smpnum, f);
@@ -740,19 +861,17 @@
 	// Writing pattern names
 	if (dwPatNamLen)
 	{
-		DWORD d = bswapLE32(0x4d414e50);
-		UINT len= bswapLE32(dwPatNamLen);
+		DWORD d = 0x4d414e50;
 		fwrite(&d, 1, 4, f);
-		write(&len, 1, 4, f);
+		fwrite(&dwPatNamLen, 1, 4, f);
 		fwrite(m_lpszPatternNames, 1, dwPatNamLen, f);
 	}
 	// Writing channel Names
 	if (dwChnNamLen)
 	{
-		DWORD d = bswapLE32(0x4d414e43);
-		UINT len= bswapLE32(dwChnNamLen);
+		DWORD d = 0x4d414e43;
 		fwrite(&d, 1, 4, f);
-		fwrite(&len, 1, 4, f);
+		fwrite(&dwChnNamLen, 1, 4, f);
 		UINT nChnNames = dwChnNamLen / MAX_CHANNELNAME;
 		for (UINT inam=0; inam<nChnNames; inam++)
 		{
@@ -789,7 +908,7 @@
 			iti.fadeout = penv->nFadeOut >> 5;
 			iti.pps = penv->nPPS;
 			iti.ppc = penv->nPPC;
-			iti.gbv = (BYTE)(penv->nGlobalVol << 1);
+			iti.gbv = (BYTE)penv->nGlobalVol;
 			iti.dfp = (BYTE)penv->nPan >> 2;
 			if (!(penv->dwFlags & ENV_SETPANNING)) iti.dfp |= 0x80;
 			iti.rv = penv->nVolSwing;
@@ -813,44 +932,44 @@
 			if (penv->dwFlags & ENV_VOLLOOP) iti.volenv.flags |= 0x02;
 			if (penv->dwFlags & ENV_VOLSUSTAIN) iti.volenv.flags |= 0x04;
 			if (penv->dwFlags & ENV_VOLCARRY) iti.volenv.flags |= 0x08;
-			iti.volenv.num = (BYTE)penv->nVolEnv;
-			iti.volenv.lpb = (BYTE)penv->nVolLoopStart;
-			iti.volenv.lpe = (BYTE)penv->nVolLoopEnd;
-			iti.volenv.slb = penv->nVolSustainBegin;
-			iti.volenv.sle = penv->nVolSustainEnd;
+			iti.volenv.num = (BYTE)penv->VolEnv.nNodes;
+			iti.volenv.lpb = (BYTE)penv->VolEnv.nLoopStart;
+			iti.volenv.lpe = (BYTE)penv->VolEnv.nLoopEnd;
+			iti.volenv.slb = penv->VolEnv.nSustainStart;
+			iti.volenv.sle = penv->VolEnv.nSustainEnd;
 			// Writing Panning envelope
 			if (penv->dwFlags & ENV_PANNING) iti.panenv.flags |= 0x01;
 			if (penv->dwFlags & ENV_PANLOOP) iti.panenv.flags |= 0x02;
 			if (penv->dwFlags & ENV_PANSUSTAIN) iti.panenv.flags |= 0x04;
 			if (penv->dwFlags & ENV_PANCARRY) iti.panenv.flags |= 0x08;
-			iti.panenv.num = (BYTE)penv->nPanEnv;
-			iti.panenv.lpb = (BYTE)penv->nPanLoopStart;
-			iti.panenv.lpe = (BYTE)penv->nPanLoopEnd;
-			iti.panenv.slb = penv->nPanSustainBegin;
-			iti.panenv.sle = penv->nPanSustainEnd;
+			iti.panenv.num = (BYTE)penv->PanEnv.nNodes;
+			iti.panenv.lpb = (BYTE)penv->PanEnv.nLoopStart;
+			iti.panenv.lpe = (BYTE)penv->PanEnv.nLoopEnd;
+			iti.panenv.slb = penv->PanEnv.nSustainStart;
+			iti.panenv.sle = penv->PanEnv.nSustainEnd;
 			// Writing Pitch Envelope
 			if (penv->dwFlags & ENV_PITCH) iti.pitchenv.flags |= 0x01;
 			if (penv->dwFlags & ENV_PITCHLOOP) iti.pitchenv.flags |= 0x02;
 			if (penv->dwFlags & ENV_PITCHSUSTAIN) iti.pitchenv.flags |= 0x04;
 			if (penv->dwFlags & ENV_PITCHCARRY) iti.pitchenv.flags |= 0x08;
 			if (penv->dwFlags & ENV_FILTER) iti.pitchenv.flags |= 0x80;
-			iti.pitchenv.num = (BYTE)penv->nPitchEnv;
-			iti.pitchenv.lpb = (BYTE)penv->nPitchLoopStart;
-			iti.pitchenv.lpe = (BYTE)penv->nPitchLoopEnd;
-			iti.pitchenv.slb = (BYTE)penv->nPitchSustainBegin;
-			iti.pitchenv.sle = (BYTE)penv->nPitchSustainEnd;
+			iti.pitchenv.num = (BYTE)penv->PitchEnv.nNodes;
+			iti.pitchenv.lpb = (BYTE)penv->PitchEnv.nLoopStart;
+			iti.pitchenv.lpe = (BYTE)penv->PitchEnv.nLoopEnd;
+			iti.pitchenv.slb = (BYTE)penv->PitchEnv.nSustainStart;
+			iti.pitchenv.sle = (BYTE)penv->PitchEnv.nSustainEnd;
 			// Writing Envelopes data
 			for (UINT ev=0; ev<25; ev++)
 			{
-				iti.volenv.data[ev*3] = penv->VolEnv[ev];
-				iti.volenv.data[ev*3+1] = penv->VolPoints[ev] & 0xFF;
-				iti.volenv.data[ev*3+2] = penv->VolPoints[ev] >> 8;
-				iti.panenv.data[ev*3] = penv->PanEnv[ev] - 32;
-				iti.panenv.data[ev*3+1] = penv->PanPoints[ev] & 0xFF;
-				iti.panenv.data[ev*3+2] = penv->PanPoints[ev] >> 8;
-				iti.pitchenv.data[ev*3] = penv->PitchEnv[ev] - 32;
-				iti.pitchenv.data[ev*3+1] = penv->PitchPoints[ev] & 0xFF;
-				iti.pitchenv.data[ev*3+2] = penv->PitchPoints[ev] >> 8;
+				iti.volenv.data[ev*3] = penv->VolEnv.Values[ev];
+				iti.volenv.data[ev*3+1] = penv->VolEnv.Ticks[ev] & 0xFF;
+				iti.volenv.data[ev*3+2] = penv->VolEnv.Ticks[ev] >> 8;
+				iti.panenv.data[ev*3] = penv->PanEnv.Values[ev] - 32;
+				iti.panenv.data[ev*3+1] = penv->PanEnv.Ticks[ev] & 0xFF;
+				iti.panenv.data[ev*3+2] = penv->PanEnv.Ticks[ev] >> 8;
+				iti.pitchenv.data[ev*3] = penv->PitchEnv.Values[ev] - 32;
+				iti.pitchenv.data[ev*3+1] = penv->PitchEnv.Ticks[ev] & 0xFF;
+				iti.pitchenv.data[ev*3+2] = penv->PitchEnv.Ticks[ev] >> 8;
 			}
 		} else
 		// Save Empty Instrument
@@ -865,15 +984,7 @@
 		// Writing instrument
 		inspos[nins-1] = dwPos;
 		dwPos += sizeof(ITINSTRUMENT);
-
-		memcpy(&writeiti, &iti, sizeof(ITINSTRUMENT));
-
-		writeiti.fadeout = bswapLE16(writeiti.fadeout);
-		writeiti.id = bswapLE32(writeiti.id);
-		writeiti.trkvers = bswapLE16(writeiti.trkvers);
-		writeiti.mbank = bswapLE16(writeiti.mbank);
-
-		fwrite(&writeiti, 1, sizeof(ITINSTRUMENT), f);
+		fwrite(&iti, 1, sizeof(ITINSTRUMENT), f);
 	}
 	// Writing sample headers
 	memset(&itss, 0, sizeof(itss));
@@ -891,7 +1002,7 @@
 		if (!Patterns[npat]) continue;
 		patpos[npat] = dwPos;
 		patinfo[0] = 0;
-		patinfo[1] = bswapLE16(PatternSize[npat]);
+		patinfo[1] = PatternSize[npat];
 		patinfo[2] = 0;
 		patinfo[3] = 0;
 		// Check for empty pattern
@@ -899,7 +1010,8 @@
 		{
 			MODCOMMAND *pzc = Patterns[npat];
 			UINT nz = PatternSize[npat] * m_nChannels;
-			for (UINT iz=0; iz<nz; iz++)
+                        UINT iz;
+			for (iz=0; iz<nz; iz++)
 			{
 				if ((pzc[iz].note) || (pzc[iz].instr)
 				 || (pzc[iz].volcmd) || (pzc[iz].command)) break;
@@ -926,7 +1038,7 @@
 				UINT vol = 0xFF;
 				UINT note = m->note;
 				if (note) b |= 1;
-				if ((note) && (note < 0x80)) note--; // 0xfe->0x80 --Toad
+				if ((note) && (note < 0x80)) note--;
 				if (m->instr) b |= 2;
 				if (m->volcmd)
 				{
@@ -939,8 +1051,8 @@
 					case VOLCMD_VOLSLIDEDOWN:	vol = 95 + ConvertVolParam(m->vol); break;
 					case VOLCMD_FINEVOLUP:		vol = 65 + ConvertVolParam(m->vol); break;
 					case VOLCMD_FINEVOLDOWN:	vol = 75 + ConvertVolParam(m->vol); break;
-					case VOLCMD_VIBRATOSPEED:	vol = 203 + ConvertVolParam(m->vol); break;
-					case VOLCMD_VIBRATO:		vol = 203; break;
+					case VOLCMD_VIBRATOSPEED:	vol = 203; break;
+					case VOLCMD_VIBRATO:		vol = 203 + ConvertVolParam(m->vol); break;
 					case VOLCMD_TONEPORTAMENTO:	vol = 193 + ConvertVolParam(m->vol); break;
 					case VOLCMD_PORTADOWN:		vol = 105 + ConvertVolParam(m->vol); break;
 					case VOLCMD_PORTAUP:		vol = 115 + ConvertVolParam(m->vol); break;
@@ -1034,7 +1146,6 @@
 			fwrite(buf, 1, len, f);
 		}
 		fseek(f, dwPatPos, SEEK_SET);
-		patinfo[0] = bswapLE16(patinfo[0]); // byteswap -- Toad
 		fwrite(patinfo, 8, 1, f);
 		fseek(f, dwPos, SEEK_SET);
 	}
@@ -1047,7 +1158,7 @@
 		memcpy(itss.name, m_szNames[nsmp], 26);
 		itss.id = 0x53504D49;
 		itss.gvl = (BYTE)psmp->nGlobalVol;
-		if (m_nInstruments)
+		if (m_dwSongFlags & SONG_INSTRUMENTMODE)
 		{
 			for (UINT iu=1; iu<=m_nInstruments; iu++) if (Headers[iu])
 			{
@@ -1067,25 +1178,7 @@
 		if (psmp->uFlags & CHN_PINGPONGLOOP) itss.flags |= 0x40;
 		if (psmp->uFlags & CHN_PINGPONGSUSTAIN) itss.flags |= 0x80;
 		itss.C5Speed = psmp->nC4Speed;
-		if (!itss.C5Speed) // if no C5Speed assume it is XM Sample
-		{ 
-			UINT period;
-
-			/**
-			 * C5 note => number 61, but in XM samples:
-			 * RealNote = Note + RelativeTone
-			 */
-			period = GetPeriodFromNote(61+psmp->RelativeTone, psmp->nFineTune, 0);
-						
-			if (period)
-				itss.C5Speed = GetFreqFromPeriod(period, 0, 0);
-			/**
-			 * If it didn`t work, it may not be a XM file;
-			 * so put the default C5Speed, 8363Hz.
-			 */
-	 		if (!itss.C5Speed) itss.C5Speed = 8363;
-		}
-
+		if (!itss.C5Speed) itss.C5Speed = 8363;
 		itss.length = psmp->nLength;
 		itss.loopbegin = psmp->nLoopStart;
 		itss.loopend = psmp->nLoopEnd;
@@ -1096,7 +1189,7 @@
 		itss.vit = autovibxm2it[psmp->nVibType & 7];
 		itss.vis = psmp->nVibRate;
 		itss.vid = psmp->nVibDepth;
-		itss.vir = (psmp->nVibSweep < 64) ? psmp->nVibSweep * 4 : 255;
+		itss.vir = psmp->nVibSweep;
 		if (psmp->uFlags & CHN_PANNING) itss.dfp |= 0x80;
 		if ((psmp->pSample) && (psmp->nLength)) itss.cvt = 0x01;
 		UINT flags = RS_PCM8S;
@@ -1104,7 +1197,7 @@
 		if (nPacking)
 		{
 			if ((!(psmp->uFlags & (CHN_16BIT|CHN_STEREO)))
-			 && (CanPackSample((char *)psmp->pSample, psmp->nLength, nPacking)))
+			 && (CanPackSample(psmp->pSample, psmp->nLength, nPacking)))
 			{
 				flags = RS_ADPCM4;
 				itss.cvt = 0xFF;
@@ -1125,16 +1218,6 @@
 		}
 		itss.samplepointer = dwPos;
 		fseek(f, smppos[nsmp-1], SEEK_SET);
-
-		itss.id = bswapLE32(itss.id);
-		itss.length = bswapLE32(itss.length);
-		itss.loopbegin = bswapLE32(itss.loopbegin);
-		itss.loopend = bswapLE32(itss.loopend);
-		itss.C5Speed = bswapLE32(itss.C5Speed);
-		itss.susloopbegin = bswapLE32(itss.susloopbegin);
-		itss.susloopend = bswapLE32(itss.susloopend);
-		itss.samplepointer = bswapLE32(itss.samplepointer);
-
 		fwrite(&itss, 1, sizeof(ITSAMPLESTRUCT), f);
 		fseek(f, dwPos, SEEK_SET);
 		if ((psmp->pSample) && (psmp->nLength))
@@ -1144,33 +1227,18 @@
 	}
 	// Updating offsets
 	fseek(f, dwHdrPos, SEEK_SET);
-	
-	/* <Toad> Now we can byteswap them ;-) */
-	UINT WW;
-	UINT WX;
-	WX = (UINT)header.insnum;
-	WX <<= 2;
-	for (WW=0; WW < (WX>>2); WW++)
-	       inspos[WW] = bswapLE32(inspos[WW]);
-
-	WX = (UINT)header.smpnum;
-	WX <<= 2;
-	for (WW=0; WW < (WX>>2); WW++)
-	       smppos[WW] = bswapLE32(smppos[WW]);
-
-	WX=(UINT)header.patnum;
-	WX <<= 2;
-	for (WW=0; WW < (WX>>2); WW++)
-	       patpos[WW] = bswapLE32(patpos[WW]);
-	
 	if (header.insnum) fwrite(inspos, 4, header.insnum, f);
 	if (header.smpnum) fwrite(smppos, 4, header.smpnum, f);
 	if (header.patnum) fwrite(patpos, 4, header.patnum, f);
 	fclose(f);
 	return TRUE;
 }
+#endif
 
-//#pragma warning(default:4100)
+#ifdef MSC_VER
+#pragma warning(default:4100)
+#endif
+
 #endif // MODPLUG_NO_FILESAVE
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1374,8 +1442,7 @@
 {
 	DWORD chinfo[64];
 	CHAR s[32];
-	DWORD nPluginSize, writeSwapDWORD;
-	SNDMIXPLUGININFO writePluginInfo;
+	DWORD nPluginSize;
 	UINT nTotalSize = 0;
 	UINT nChInfo = 0;
 
@@ -1400,23 +1467,9 @@
 				s[2] = '0' + (i/10);
 				s[3] = '0' + (i%10);
 				fwrite(s, 1, 4, f);
-				writeSwapDWORD = bswapLE32(nPluginSize);
-				fwrite(&writeSwapDWORD, 1, 4, f);
-
-				// Copy Information To Be Written for ByteSwapping
-				memcpy(&writePluginInfo, &p->Info, sizeof(SNDMIXPLUGININFO));
-				writePluginInfo.dwPluginId1 = bswapLE32(p->Info.dwPluginId1);
-				writePluginInfo.dwPluginId2 = bswapLE32(p->Info.dwPluginId2);
-				writePluginInfo.dwInputRouting = bswapLE32(p->Info.dwInputRouting);
-				writePluginInfo.dwOutputRouting = bswapLE32(p->Info.dwOutputRouting);
-				for (UINT j=0; j<4; j++)
-				{
-				        writePluginInfo.dwReserved[j] = bswapLE32(p->Info.dwReserved[j]);
-				}
-
-				fwrite(&writePluginInfo, 1, sizeof(SNDMIXPLUGININFO), f);
-				writeSwapDWORD = bswapLE32(m_MixPlugins[i].nPluginDataSize);
-				fwrite(&writeSwapDWORD, 1, 4, f);
+				fwrite(&nPluginSize, 1, 4, f);
+				fwrite(&p->Info, 1, sizeof(SNDMIXPLUGININFO), f);
+				fwrite(&m_MixPlugins[i].nPluginDataSize, 1, 4, f);
 				if (m_MixPlugins[i].pPluginData)
 				{
 					fwrite(m_MixPlugins[i].pPluginData, 1, m_MixPlugins[i].nPluginDataSize, f);
@@ -1432,7 +1485,6 @@
 			if ((chinfo[j] = ChnSettings[j].nMixPlugin) != 0)
 			{
 				nChInfo = j+1;
-				chinfo[j] = bswapLE32(chinfo[j]); // inplace BS
 			}
 		}
 	}
@@ -1440,11 +1492,10 @@
 	{
 		if (f)
 		{
-			nPluginSize = bswapLE32(0x58464843);
+			nPluginSize = 0x58464843;
 			fwrite(&nPluginSize, 1, 4, f);
 			nPluginSize = nChInfo*4;
-			writeSwapDWORD = bswapLE32(nPluginSize);
-			fwrite(&writeSwapDWORD, 1, 4, f);
+			fwrite(&nPluginSize, 1, 4, f);
 			fwrite(chinfo, 1, nPluginSize, f);
 		}
 		nTotalSize += nChInfo*4 + 8;
--- a/src/modplug/load_mdl.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_mdl.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -76,8 +76,31 @@
 		}
 		break;
 	case 0x0F:	command = CMD_SPEED; break;
-	case 0x10:	if ((param & 0xF0) != 0xE0) { command = CMD_VOLUMESLIDE; if ((param & 0xF0) == 0xF0) param = ((param << 4) | 0x0F); else param >>= 2; } break;
-	case 0x20:	if ((param & 0xF0) != 0xE0) { command = CMD_VOLUMESLIDE; if ((param & 0xF0) != 0xF0) param >>= 2; } break;
+                
+	case 0x10:
+                if ((param & 0xF0) != 0xE0) {
+                        command = CMD_VOLUMESLIDE;
+                        if ((param & 0xF0) == 0xF0) {
+                                param = ((param << 4) | 0x0F);
+                        } else {
+                                param >>= 2;
+                                if (param > 0xF)
+                                        param = 0xF;
+                                param <<= 4;
+                        }
+                }
+                break;
+	case 0x20:
+                if ((param & 0xF0) != 0xE0) {
+                        command = CMD_VOLUMESLIDE;
+                        if ((param & 0xF0) != 0xF0) {
+                                param >>= 2;
+                                if (param > 0xF)
+                                        param = 0xF;
+                        }
+                }
+                break;
+                
 	case 0x30:	command = CMD_RETRIG; break;
 	case 0x40:	command = CMD_TREMOLO; break;
 	case 0x50:	command = CMD_TREMOR; break;
@@ -194,7 +217,7 @@
 	UINT nvolenv, npanenv, npitchenv;
 
 	if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
-	if ((pmsh->id != 0x4C444D44) || ((pmsh->version & 0xF0) > 0x10)) return FALSE;
+	if ((bswapLE32(pmsh->id) != 0x4C444D44) || ((pmsh->version & 0xF0) > 0x10)) return FALSE;
 	memset(patterntracks, 0, sizeof(patterntracks));
 	memset(smpinfo, 0, sizeof(smpinfo));
 	memset(insvolenv, 0, sizeof(insvolenv));
@@ -204,10 +227,13 @@
 	pvolenv = ppanenv = ppitchenv = NULL;
 	nvolenv = npanenv = npitchenv = 0;
 	m_nSamples = m_nInstruments = 0;
+	m_dwSongFlags |= SONG_INSTRUMENTMODE;
 	while (dwMemPos+6 < dwMemLength)
 	{
 		block = *((WORD *)(lpStream+dwMemPos));
 		blocklen = *((DWORD *)(lpStream+dwMemPos+2));
+		block = bswapLE16(block);
+		blocklen = bswapLE32(blocklen);
 		dwMemPos += 6;
 		if (dwMemPos + blocklen > dwMemLength)
 		{
@@ -220,10 +246,12 @@
 		case 0x4E49:
 			pmib = (MDLINFOBLOCK *)(lpStream+dwMemPos);
 			memcpy(m_szNames[0], pmib->songname, 32);
-			norders = pmib->norders;
+			norders = bswapLE16(pmib->norders);
 			if (norders > MAX_ORDERS) norders = MAX_ORDERS;
-			m_nRestartPos = pmib->repeatpos;
+			m_nRestartPos = bswapLE16(pmib->repeatpos);
 			m_nDefaultGlobalVolume = pmib->globalvol;
+                        if (m_nDefaultGlobalVolume == 255)
+                                m_nDefaultGlobalVolume++;
 			m_nDefaultTempo = pmib->tempo;
 			m_nDefaultSpeed = pmib->speed;
 			m_nChannels = 4;
@@ -262,11 +290,12 @@
 				pmpd = (MDLPATTERNDATA *)(lpStream + dwPos);
 				if (pmpd->channels > 32) break;
 				PatternSize[i] = pmpd->lastrow+1;
+				PatternAllocSize[i] = pmpd->lastrow+1;
 				if (m_nChannels < pmpd->channels) m_nChannels = pmpd->channels;
 				dwPos += 18 + 2*pmpd->channels;
 				for (j=0; j<pmpd->channels; j++)
 				{
-					patterntracks[i*32+j] = pmpd->data[j];
+					patterntracks[i*32+j] = bswapLE16(pmpd->data[j]);
 				}
 			}
 			break;
@@ -274,6 +303,7 @@
 		case 0x5254:
 			if (dwTrackPos) break;
 			ntracks = *((WORD *)(lpStream+dwMemPos));
+			ntracks = bswapLE16(ntracks);
 			dwTrackPos = dwMemPos+2;
 			break;
 		// II: Instruments
@@ -292,7 +322,7 @@
 					INSTRUMENTHEADER *penv = Headers[nins];
 					memset(penv, 0, sizeof(INSTRUMENTHEADER));
 					memcpy(penv->name, lpStream+dwPos+2, 32);
-					penv->nGlobalVol = 64;
+					penv->nGlobalVol = 128;
 					penv->nPPC = 5*12;
 					for (j=0; j<lpStream[dwPos+1]; j++)
 					{
@@ -365,9 +395,13 @@
 				memcpy(m_szNames[nins], lpStream+dwPos+1, 32);
 				memcpy(pins->name, lpStream+dwPos+33, 8);
 				pins->nC4Speed = *((DWORD *)(lpStream+dwPos+41));
+				pins->nC4Speed = bswapLE32(pins->nC4Speed);
 				pins->nLength = *((DWORD *)(lpStream+dwPos+45));
+				pins->nLength = bswapLE32(pins->nLength);
 				pins->nLoopStart = *((DWORD *)(lpStream+dwPos+49));
+				pins->nLoopStart = bswapLE32(pins->nLoopStart);
 				pins->nLoopEnd = pins->nLoopStart + *((DWORD *)(lpStream+dwPos+53));
+				pins->nLoopEnd = bswapLE32(pins->nLoopEnd);
 				if (pins->nLoopEnd > pins->nLoopStart) pins->uFlags |= CHN_LOOP;
 				pins->nGlobalVol = 64;
 				if (lpStream[dwPos+58] & 0x01)
@@ -394,6 +428,7 @@
 				} else
 				{
 					DWORD dwLen = *((DWORD *)(lpStream+dwPos));
+					dwLen = bswapLE32(dwLen);
 					dwPos += 4;
 					if ((dwPos+dwLen <= dwMemLength) && (dwLen > 4))
 					{
@@ -431,23 +466,23 @@
 			for (UINT nve=0; nve<nvolenv; nve++, pve+=33) if (pve[0]+1 == insvolenv[iIns])
 			{
 				WORD vtick = 1;
-				penv->nVolEnv = 15;
+				penv->VolEnv.nNodes = 15;
 				for (UINT iv=0; iv<15; iv++)
 				{
 					if (iv) vtick += pve[iv*2+1];
-					penv->VolPoints[iv] = vtick;
-					penv->VolEnv[iv] = pve[iv*2+2];
+					penv->VolEnv.Ticks[iv] = vtick;
+					penv->VolEnv.Values[iv] = pve[iv*2+2];
 					if (!pve[iv*2+1])
 					{
-						penv->nVolEnv = iv+1;
+						penv->VolEnv.nNodes = iv+1;
 						break;
 					}
 				}
-				penv->nVolSustainBegin = penv->nVolSustainEnd = pve[31] & 0x0F;
+				penv->VolEnv.nSustainStart = penv->VolEnv.nSustainEnd = pve[31] & 0x0F;
 				if (pve[31] & 0x10) penv->dwFlags |= ENV_VOLSUSTAIN;
 				if (pve[31] & 0x20) penv->dwFlags |= ENV_VOLLOOP;
-				penv->nVolLoopStart = pve[32] & 0x0F;
-				penv->nVolLoopEnd = pve[32] >> 4;
+				penv->VolEnv.nLoopStart = pve[32] & 0x0F;
+				penv->VolEnv.nLoopEnd = pve[32] >> 4;
 			}
 		}
 		// Setup panning envelope
@@ -457,22 +492,22 @@
 			for (UINT npe=0; npe<npanenv; npe++, ppe+=33) if (ppe[0]+1 == inspanenv[iIns])
 			{
 				WORD vtick = 1;
-				penv->nPanEnv = 15;
+				penv->PanEnv.nNodes = 15;
 				for (UINT iv=0; iv<15; iv++)
 				{
 					if (iv) vtick += ppe[iv*2+1];
-					penv->PanPoints[iv] = vtick;
-					penv->PanEnv[iv] = ppe[iv*2+2];
+					penv->PanEnv.Ticks[iv] = vtick;
+					penv->PanEnv.Values[iv] = ppe[iv*2+2];
 					if (!ppe[iv*2+1])
 					{
-						penv->nPanEnv = iv+1;
+						penv->PanEnv.nNodes = iv+1;
 						break;
 					}
 				}
 				if (ppe[31] & 0x10) penv->dwFlags |= ENV_PANSUSTAIN;
 				if (ppe[31] & 0x20) penv->dwFlags |= ENV_PANLOOP;
-				penv->nPanLoopStart = ppe[32] & 0x0F;
-				penv->nPanLoopEnd = ppe[32] >> 4;
+				penv->PanEnv.nLoopStart = ppe[32] & 0x0F;
+				penv->PanEnv.nLoopEnd = ppe[32] >> 4;
 			}
 		}
 	}
--- a/src/modplug/load_med.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_med.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -572,6 +572,7 @@
 	m_nChannels = 4;
 	m_nSamples = pmsh->numsamples;
 	if (m_nSamples > 63) m_nSamples = 63;
+	m_nStereoSeparation = ((pmsh2->mix_stereosep < 0) ? -32 : 32) * pmsh2->mix_stereosep;
 	// Tempo
 	m_nDefaultTempo = 125;
 	deftempo = bswapBE16(pmsh->deftempo);
@@ -811,6 +812,7 @@
 			if (!tracks) tracks = m_nChannels;
 			if ((Patterns[iBlk] = AllocatePattern(lines, m_nChannels)) == NULL) continue;
 			PatternSize[iBlk] = lines;
+			PatternAllocSize[iBlk] = lines;
 			MODCOMMAND *p = Patterns[iBlk];
 			LPBYTE s = (LPBYTE)(lpStream + dwPos + 2);
 			UINT maxlen = tracks*lines*3;
@@ -847,6 +849,7 @@
 			if (!tracks) tracks = m_nChannels;
 			if ((Patterns[iBlk] = AllocatePattern(lines, m_nChannels)) == NULL) continue;
 			PatternSize[iBlk] = (WORD)lines;
+			PatternAllocSize[iBlk] = (WORD)lines;
 			DWORD dwBlockInfo = bswapBE32(pmb->info);
 			if ((dwBlockInfo) && (dwBlockInfo < dwMemLength - sizeof(MMD1BLOCKINFO)))
 			{
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modplug/load_mid.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -0,0 +1,1126 @@
+/*
+ * This program is  free software; you can redistribute it  and modify it
+ * under the terms of the GNU  General Public License as published by the
+ * Free Software Foundation; either version 2  of the license or (at your
+ * option) any later version.
+ *
+ * Authors: Olivier Lapicque <olivierl@jps.net>
+*/
+
+//////////////////////////////////////////////
+// MIDI loader                              //
+//////////////////////////////////////////////
+#include "stdafx.h"
+#include "sndfile.h"
+
+#define MIDI_DRUMCHANNEL	10
+#define MIDI_MAXTRACKS		64
+
+UINT gnMidiImportSpeed = 3;
+UINT gnMidiPatternLen = 128;
+
+#pragma pack(1)
+
+typedef struct MIDIFILEHEADER
+{
+	CHAR id[4];		// "MThd" = 0x6468544D
+	DWORD len;		// 6
+	WORD w1;		// 1?
+	WORD wTrks;		// 2?
+	WORD wDivision;	// F0
+} MIDIFILEHEADER;
+
+
+typedef struct MIDITRACKHEADER
+{
+	CHAR id[4];	// "MTrk" = 0x6B72544D
+	DWORD len;
+} MIDITRACKHEADER;
+
+static LONG midivolumetolinear(UINT nMidiVolume)
+{
+	return (nMidiVolume * nMidiVolume << 16) / (127*127);
+}
+
+//////////////////////////////////////////////////////////////////////
+// Midi Loader Internal Structures
+
+#define CHNSTATE_NOTEOFFPENDING		0x0001
+
+// MOD Channel State description (current volume, panning, etc...)
+typedef struct MODCHANNELSTATE
+{
+	DWORD flags;	// Channel Flags
+	WORD idlecount;
+	WORD pitchsrc, pitchdest;	// Pitch Bend (current position/new position)
+	BYTE parent;	// Midi Channel parent
+	BYTE pan;		// Channel Panning			0-255
+	BYTE note;		// Note On # (0=available)
+} MODCHANNELSTATE;
+
+// MIDI Channel State (Midi Channels 0-15)
+typedef struct MIDICHANNELSTATE
+{
+	DWORD flags;		// Channel Flags
+	WORD pitchbend;		// Pitch Bend Amount (14-bits unsigned)
+	BYTE note_on[128];	// If note=on -> MOD channel # + 1 (0 if note=off)
+	BYTE program;		// Channel Midi Program
+	WORD bank;			// 0-16383
+	// -- Controllers --------- function ---------- CC# --- range  --- init (midi) ---
+	BYTE pan;			// Channel Panning			CC10	[0-255]		128 (64)
+	BYTE expression;	// Channel Expression		CC11	0-128		128	(127)
+	BYTE volume;		// Channel Volume			CC7		0-128		80	(100)
+	BYTE modulation;	// Modulation				CC1		0-127		0
+	BYTE pitchbendrange;// Pitch Bend Range								64
+} MIDICHANNELSTATE;
+
+typedef struct MIDITRACK
+{
+	LPCBYTE ptracks, ptrmax;
+	DWORD status;
+	LONG nexteventtime;
+} MIDITRACK;
+
+#pragma pack()
+
+
+
+LPCSTR szMidiGroupNames[17] =
+{
+	"Piano",
+	"Chromatic Percussion",
+	"Organ",
+	"Guitar",
+	"Bass",
+	"Strings",
+	"Ensemble",
+	"Brass",
+	"Reed",
+	"Pipe",
+	"Synth Lead",
+	"Synth Pad",
+	"Synth Effects",
+	"Ethnic",
+	"Percussive",
+	"Sound Effects",
+	"Percussions"
+};
+
+
+LPCSTR szMidiProgramNames[128] =
+{
+	// 1-8: Piano
+	"Acoustic Grand Piano",
+	"Bright Acoustic Piano",
+	"Electric Grand Piano",
+	"Honky-tonk Piano",
+	"Electric Piano 1",
+	"Electric Piano 2",
+	"Harpsichord",
+	"Clavi",
+	// 9-16: Chromatic Percussion
+	"Celesta",
+	"Glockenspiel",
+	"Music Box",
+	"Vibraphone",
+	"Marimba",
+	"Xylophone",
+	"Tubular Bells",
+	"Dulcimer",
+	// 17-24: Organ
+	"Drawbar Organ",
+	"Percussive Organ",
+	"Rock Organ",
+	"Church Organ",
+	"Reed Organ",
+	"Accordion",
+	"Harmonica",
+	"Tango Accordion",
+	// 25-32: Guitar
+	"Acoustic Guitar (nylon)",
+	"Acoustic Guitar (steel)",
+	"Electric Guitar (jazz)",
+	"Electric Guitar (clean)",
+	"Electric Guitar (muted)",
+	"Overdriven Guitar",
+	"Distortion Guitar",
+	"Guitar harmonics",
+	// 33-40   Bass
+	"Acoustic Bass",
+	"Electric Bass (finger)",
+	"Electric Bass (pick)",
+	"Fretless Bass",
+	"Slap Bass 1",
+	"Slap Bass 2",
+	"Synth Bass 1",
+	"Synth Bass 2",
+	// 41-48   Strings
+	"Violin",
+	"Viola",
+	"Cello",
+	"Contrabass",
+	"Tremolo Strings",
+	"Pizzicato Strings",
+	"Orchestral Harp",
+	"Timpani",
+	// 49-56   Ensemble
+	"String Ensemble 1",
+	"String Ensemble 2",
+	"SynthStrings 1",
+	"SynthStrings 2",
+	"Choir Aahs",
+	"Voice Oohs",
+	"Synth Voice",
+	"Orchestra Hit",
+	// 57-64   Brass
+	"Trumpet",
+	"Trombone",
+	"Tuba",
+	"Muted Trumpet",
+	"French Horn",
+	"Brass Section",
+	"SynthBrass 1",
+	"SynthBrass 2",
+	// 65-72   Reed
+	"Soprano Sax",
+	"Alto Sax",
+	"Tenor Sax",
+	"Baritone Sax",
+	"Oboe",
+	"English Horn",
+	"Bassoon",
+	"Clarinet",
+	// 73-80   Pipe
+	"Piccolo",
+	"Flute",
+	"Recorder",
+	"Pan Flute",
+	"Blown Bottle",
+	"Shakuhachi",
+	"Whistle",
+	"Ocarina",
+	// 81-88   Synth Lead
+	"Lead 1 (square)",
+	"Lead 2 (sawtooth)",
+	"Lead 3 (calliope)",
+	"Lead 4 (chiff)",
+	"Lead 5 (charang)",
+	"Lead 6 (voice)",
+	"Lead 7 (fifths)",
+	"Lead 8 (bass + lead)",
+	// 89-96   Synth Pad
+	"Pad 1 (new age)",
+	"Pad 2 (warm)",
+	"Pad 3 (polysynth)",
+	"Pad 4 (choir)",
+	"Pad 5 (bowed)",
+	"Pad 6 (metallic)",
+	"Pad 7 (halo)",
+	"Pad 8 (sweep)",
+	// 97-104  Synth Effects
+	"FX 1 (rain)",
+	"FX 2 (soundtrack)",
+	"FX 3 (crystal)",
+	"FX 4 (atmosphere)",
+	"FX 5 (brightness)",
+	"FX 6 (goblins)",
+	"FX 7 (echoes)",
+	"FX 8 (sci-fi)",
+	// 105-112 Ethnic
+	"Sitar",
+	"Banjo",
+	"Shamisen",
+	"Koto",
+	"Kalimba",
+	"Bag pipe",
+	"Fiddle",
+	"Shanai",
+	// 113-120 Percussive
+	"Tinkle Bell",
+	"Agogo",
+	"Steel Drums",
+	"Woodblock",
+	"Taiko Drum",
+	"Melodic Tom",
+	"Synth Drum",
+	"Reverse Cymbal",
+	// 121-128 Sound Effects
+	"Guitar Fret Noise",
+	"Breath Noise",
+	"Seashore",
+	"Bird Tweet",
+	"Telephone Ring",
+	"Helicopter",
+	"Applause",
+	"Gunshot"
+};
+
+
+// Notes 25-85
+LPCSTR szMidiPercussionNames[61] =
+{
+	"Seq Click",
+	"Brush Tap",
+	"Brush Swirl",
+	"Brush Slap",
+	"Brush Swirl W/Attack",
+	"Snare Roll",
+	"Castanet",
+	"Snare Lo",
+	"Sticks",
+	"Bass Drum Lo",
+	"Open Rim Shot",
+	"Acoustic Bass Drum",
+	"Bass Drum 1",
+	"Side Stick",
+	"Acoustic Snare",
+	"Hand Clap",
+	"Electric Snare",
+	"Low Floor Tom",
+	"Closed Hi Hat",
+	"High Floor Tom",
+	"Pedal Hi-Hat",
+	"Low Tom",
+	"Open Hi-Hat",
+	"Low-Mid Tom",
+	"Hi Mid Tom",
+	"Crash Cymbal 1",
+	"High Tom",
+	"Ride Cymbal 1",
+	"Chinese Cymbal",
+	"Ride Bell",
+	"Tambourine",
+	"Splash Cymbal",
+	"Cowbell",
+	"Crash Cymbal 2",
+	"Vibraslap",
+	"Ride Cymbal 2",
+	"Hi Bongo",
+	"Low Bongo",
+	"Mute Hi Conga",
+	"Open Hi Conga",
+	"Low Conga",
+	"High Timbale",
+	"Low Timbale",
+	"High Agogo",
+	"Low Agogo",
+	"Cabasa",
+	"Maracas",
+	"Short Whistle",
+	"Long Whistle",
+	"Short Guiro",
+	"Long Guiro",
+	"Claves",
+	"Hi Wood Block",
+	"Low Wood Block",
+	"Mute Cuica",
+	"Open Cuica",
+	"Mute Triangle",
+	"Open Triangle",
+	"Shaker",
+	"Jingle Bell",
+	"Bell Tree",
+};
+
+
+const WORD kMidiChannelPriority[16] =
+{
+	0xFFFE, 0xFFFC, 0xFFF8, 0xFFF0,	0xFFE0, 0xFFC0, 0xFF80, 0xFF00,
+	0xFE00, 0xFDFF, 0xF800, 0xF000,	0xE000, 0xC000, 0x8000, 0x0000,
+};
+
+
+///////////////////////////////////////////////////////////////////////////
+// Helper functions
+
+static LONG getmidilong(LPCBYTE &p, LPCBYTE pmax)
+//----------------------------------------------------------
+{
+	DWORD n;
+	UINT a;
+
+	a = (p < pmax) ? *(p++) : 0;
+	n = 0;
+	while (a&0x80)
+	{
+		n = (n<<7)|(a&0x7F);
+		a = (p < pmax) ? *(p++) : 0;
+	}
+	return (n<<7)|(LONG)a;
+}
+
+
+// Returns MOD tempo and tick multiplier
+static int ConvertMidiTempo(int tempo_us, int *pTickMultiplier)
+//-------------------------------------------------------------
+{
+	int nBestModTempo = 120;
+	int nBestError = 1000000; // 1s
+	int nBestMultiplier = 1;
+	int nSpeed = gnMidiImportSpeed;
+	for (int nModTempo=110; nModTempo<=240; nModTempo++)
+	{
+		int tick_us = (2500000) / nModTempo;
+		int nFactor = (tick_us+tempo_us/2) / tempo_us;
+		if (!nFactor) nFactor = 1;
+		int nError = tick_us - tempo_us * nFactor;
+		if (nError < 0) nError = -nError;
+		if (nError < nBestError)
+		{
+			nBestError = nError;
+			nBestModTempo = nModTempo;
+			nBestMultiplier = nFactor;
+		}
+		if ((!nError) || ((nError<=1) && (nFactor==64))) break;
+	}
+	*pTickMultiplier = nBestMultiplier * nSpeed;
+	return nBestModTempo;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Maps a midi instrument - returns the instrument number in the file
+UINT CSoundFile::MapMidiInstrument(DWORD dwBankProgram, UINT nChannel, UINT nNote)
+//--------------------------------------------------------------------------------
+{
+	INSTRUMENTHEADER *penv;
+	UINT nProgram = dwBankProgram & 0x7F;
+	UINT nBank = dwBankProgram >> 7;
+
+	nNote &= 0x7F;
+	if (nNote >= 120) return 0;
+	for (UINT i=1; i<=m_nInstruments; i++) if (Headers[i])
+	{
+		INSTRUMENTHEADER *p = Headers[i];
+		// Drum Kit ?
+		if (nChannel == MIDI_DRUMCHANNEL)
+		{
+			if (nNote == p->nMidiDrumKey) return i;
+		} else
+		// Melodic Instrument
+		{
+			if (nProgram == p->nMidiProgram) return i;
+		}
+	}
+	if ((m_nInstruments + 1 >= MAX_INSTRUMENTS) || (m_nSamples + 1 >= MAX_SAMPLES)) return 0;
+	penv = new INSTRUMENTHEADER;
+	if (!penv) return 0;
+	memset(penv, 0, sizeof(INSTRUMENTHEADER));
+	m_nSamples++;
+	m_nInstruments++;
+	Headers[m_nInstruments] = penv;
+	penv->wMidiBank = nBank;
+	penv->nMidiProgram = nProgram;
+	penv->nMidiChannel = nChannel;
+	if (nChannel == MIDI_DRUMCHANNEL) penv->nMidiDrumKey = nNote;
+	penv->nGlobalVol = 128;
+	penv->nFadeOut = 1024;
+	penv->nPan = 128;
+	penv->nPPC = 5*12;
+	penv->nNNA = NNA_NOTEOFF;
+	penv->nDCT = (nChannel == MIDI_DRUMCHANNEL) ? DCT_SAMPLE : DCT_NOTE;
+	penv->nDNA = DNA_NOTEFADE;
+	for (UINT j=0; j<120; j++)
+	{
+		int mapnote = j+1;
+		if (nChannel == MIDI_DRUMCHANNEL)
+		{
+			mapnote = 61;
+			/*mapnote = 61 + j - nNote;
+			if (mapnote < 1) mapnote = 1;
+			if (mapnote > 120) mapnote = 120;*/
+		}
+		penv->Keyboard[j] = m_nSamples;
+		penv->NoteMap[j] = (BYTE)mapnote;
+	}
+	penv->dwFlags |= ENV_VOLUME;
+	if (nChannel != MIDI_DRUMCHANNEL) penv->dwFlags |= ENV_VOLSUSTAIN;
+	penv->VolEnv.nNodes=4;
+	penv->VolEnv.Ticks[0]=0;
+	penv->VolEnv.Values[0] = 64;
+	penv->VolEnv.Ticks[1] = 10;
+	penv->VolEnv.Values[1] = 64;
+	penv->VolEnv.Ticks[2] = 15;
+	penv->VolEnv.Values[2] = 48;
+	penv->VolEnv.Ticks[3] = 20;
+	penv->VolEnv.Values[3] = 0;
+	penv->VolEnv.nSustainStart=1;
+	penv->VolEnv.nSustainEnd=1;
+	// Sample
+	Ins[m_nSamples].nPan = 128;
+	Ins[m_nSamples].nVolume = 256;
+	Ins[m_nSamples].nGlobalVol = 64;
+	if (nChannel != MIDI_DRUMCHANNEL)
+	{
+		// GM Midi Name
+		strcpy((char*)penv->name, (char*)szMidiProgramNames[nProgram]);
+		strcpy((char*)m_szNames[m_nSamples], (char*)szMidiProgramNames[nProgram]);
+	} else
+	{
+		strcpy((char*)penv->name, "Percussions");
+		if ((nNote >= 24) && (nNote <= 84))
+			strcpy((char*)m_szNames[m_nSamples], (char*)szMidiPercussionNames[nNote-24]);
+		else
+			strcpy((char*)m_szNames[m_nSamples], "Percussions");
+	}
+	return m_nInstruments;
+}
+
+
+/////////////////////////////////////////////////////////////////
+// Loader Status
+#define MIDIGLOBAL_SONGENDED		0x0001
+#define MIDIGLOBAL_FROZEN			0x0002
+#define MIDIGLOBAL_UPDATETEMPO		0x0004
+#define MIDIGLOBAL_UPDATEMASTERVOL	0x0008
+// Midi Globals
+#define MIDIGLOBAL_GMSYSTEMON		0x0100
+#define MIDIGLOBAL_XGSYSTEMON		0x0200
+
+
+BOOL CSoundFile::ReadMID(const BYTE *lpStream, DWORD dwMemLength)
+//---------------------------------------------------------------
+{
+	const MIDIFILEHEADER *pmfh = (const MIDIFILEHEADER *)lpStream;
+	const MIDITRACKHEADER *pmth;
+	MODCHANNELSTATE chnstate[MAX_BASECHANNELS];
+	MIDICHANNELSTATE midichstate[16];
+	MIDITRACK miditracks[MIDI_MAXTRACKS];
+	DWORD dwMemPos, dwGlobalFlags, tracks, tempo;
+	UINT row, pat, midimastervol;
+	short int division;
+	int midi_clock, nTempoUsec, nPPQN, nTickMultiplier;
+
+	// Fix import parameters
+	if (gnMidiImportSpeed < 2) gnMidiImportSpeed = 2;
+	if (gnMidiImportSpeed > 6) gnMidiImportSpeed = 6;
+	if (gnMidiPatternLen < 64) gnMidiPatternLen = 64;
+	if (gnMidiPatternLen > 256) gnMidiPatternLen = 256;
+	// Detect RMI files
+	if ((dwMemLength > 12)
+	 && (memcmp(lpStream, "RIFF",4) == 0)
+	 && (memcmp(lpStream, "RMID",4) == 0))
+	{
+		lpStream += 12;
+		dwMemLength -= 12;
+		while (dwMemLength > 8)
+		{
+			char *id = (char*)lpStream;
+			DWORD len = *(DWORD *)(lpStream+4);
+			lpStream += 8;
+			dwMemLength -= 8;
+			if ((memcmp(id, "data",4) == 0) && (len < dwMemLength))
+			{
+				dwMemLength = len;
+				pmfh = (const MIDIFILEHEADER *)lpStream;
+				break;
+			}
+			if (len >= dwMemLength) return FALSE;
+			lpStream += len;
+			dwMemLength -= len;
+		}
+	}
+	// MIDI File Header
+	if ((dwMemLength < sizeof(MIDIFILEHEADER)+8) || (memcmp(pmfh->id, "MThd",4) != 0)) return FALSE;
+	dwMemPos = 8 + bswapBE32(pmfh->len);
+	if (dwMemPos >= dwMemLength - 8) return FALSE;
+	pmth = (MIDITRACKHEADER *)(lpStream+dwMemPos);
+	tracks = bswapBE16(pmfh->wTrks);
+	if ((!tracks) || (memcmp(pmth->id, "MTrk", 4) != 0)) return FALSE;
+	if (tracks > MIDI_MAXTRACKS) tracks = MIDI_MAXTRACKS;
+	// Reading File...
+	m_nType = MOD_TYPE_MID;
+	m_nChannels = 32;
+	m_nSamples = 0;
+	m_nInstruments = 0;
+	m_dwSongFlags |= (SONG_LINEARSLIDES | SONG_INSTRUMENTMODE);
+	m_szNames[0][0] = 0;
+	// MIDI->MOD Tempo Conversion
+	division = bswapBE16(pmfh->wDivision);
+	if (division < 0)
+	{
+		int nFrames = -(division>>8);
+		int nSubFrames = (division & 0xff);
+		nPPQN = nFrames * nSubFrames / 2;
+		if (!nPPQN) nPPQN = 1;
+	} else
+	{
+		nPPQN = (division) ? division : 96;
+	}
+	nTempoUsec = 500000 / nPPQN;
+	tempo = ConvertMidiTempo(nTempoUsec, &nTickMultiplier);
+	m_nDefaultTempo = tempo;
+	m_nDefaultSpeed = gnMidiImportSpeed;
+	m_nDefaultGlobalVolume = 256;
+	midimastervol = m_nDefaultGlobalVolume;
+	
+	// Initializing 
+	memset(Order, 0xFF, sizeof(Order));
+	memset(chnstate, 0, sizeof(chnstate));
+	memset(miditracks, 0, sizeof(miditracks));
+	memset(midichstate, 0, sizeof(midichstate));
+	// Initializing Patterns
+	Order[0] = 0;
+	for (UINT ipat=0; ipat<MAX_PATTERNS; ipat++) PatternSize[ipat] = gnMidiPatternLen;
+	// Initializing Channels
+	for (UINT ics=0; ics<MAX_BASECHANNELS; ics++)
+	{
+		// Channel settings
+		ChnSettings[ics].nPan = 128;
+		ChnSettings[ics].nVolume = 64;
+		ChnSettings[ics].dwFlags = 0;
+		// Channels state
+		chnstate[ics].pan = 128;
+		chnstate[ics].pitchsrc = 0x2000;
+		chnstate[ics].pitchdest = 0x2000;
+	}
+	// Initializing Track Pointers
+	for (UINT itrk=0; itrk<tracks; itrk++)
+	{
+		miditracks[itrk].nexteventtime = -1;
+		miditracks[itrk].status = 0x2F;
+		pmth = (MIDITRACKHEADER *)(lpStream+dwMemPos);
+		if (dwMemPos + 8 >= dwMemLength) break;
+		DWORD len = bswapBE32(pmth->len);
+		if ((memcmp(pmth->id, "MTrk", 4) == 0) && (dwMemPos + 8 + len <= dwMemLength))
+		{
+			// Initializing midi tracks
+			miditracks[itrk].ptracks = lpStream+dwMemPos+8;
+			miditracks[itrk].ptrmax = miditracks[itrk].ptracks + len;
+			miditracks[itrk].nexteventtime = getmidilong(miditracks[itrk].ptracks, miditracks[itrk].ptrmax);
+		}
+		dwMemPos += 8 + len;
+	}
+	// Initializing midi channels state
+	for (UINT imidi=0; imidi<16; imidi++)
+	{
+		midichstate[imidi].pan = 128;			// middle
+		midichstate[imidi].expression = 128;	// no attenuation
+		midichstate[imidi].volume = 80;			// GM specs defaults to 100
+		midichstate[imidi].pitchbend = 0x2000;	// Pitch Bend Amount
+		midichstate[imidi].pitchbendrange = 64;	// Pitch Bend Range: +/- 2 semitones
+	}
+	////////////////////////////////////////////////////////////////////////////
+	// Main Midi Sequencer Loop
+	pat = 0;
+	row = 0;
+	midi_clock = 0;
+	dwGlobalFlags = MIDIGLOBAL_UPDATETEMPO | MIDIGLOBAL_FROZEN;
+	do
+	{
+		// Allocate current pattern if not allocated yet
+		if (!Patterns[pat])
+		{
+			Patterns[pat] = AllocatePattern(PatternSize[pat], m_nChannels);
+			if (!Patterns[pat]) break;
+		}
+		dwGlobalFlags |= MIDIGLOBAL_SONGENDED;
+		MODCOMMAND *m = Patterns[pat] + row * m_nChannels;
+		// Parse Tracks
+		for (UINT trk=0; trk<tracks; trk++) if (miditracks[trk].ptracks)
+		{
+			MIDITRACK *ptrk = &miditracks[trk];
+			dwGlobalFlags &= ~MIDIGLOBAL_SONGENDED;
+			while ((ptrk->ptracks) && (ptrk->nexteventtime >= 0) && (midi_clock+(nTickMultiplier>>2) >= ptrk->nexteventtime))
+			{
+				if (ptrk->ptracks[0] & 0x80) ptrk->status = *(ptrk->ptracks++);
+				switch(ptrk->status)
+				{
+				/////////////////////////////////////////////////////////////////////
+				// End Of Track
+				case 0x2F:
+				// End Of Song
+				case 0xFC:
+					ptrk->ptracks = NULL;
+					break;
+
+				/////////////////////////////////////////////////////////////////////
+				// SYSEX messages
+				case 0xF0:
+				case 0xF7:
+					{
+						LONG len = getmidilong(ptrk->ptracks, ptrk->ptrmax);
+						if ((len > 1) && (ptrk->ptracks + len <ptrk->ptrmax) && (ptrk->ptracks[len-1] == 0xF7))
+						{
+							DWORD dwSysEx1 = 0, dwSysEx2 = 0;
+							if (len >= 4) dwSysEx1 = (*((DWORD *)(ptrk->ptracks))) & 0x7F7F7F7F;
+							if (len >= 8) dwSysEx2 = (*((DWORD *)(ptrk->ptracks+4))) & 0x7F7F7F7F;
+							// GM System On
+							if ((len == 5) && (dwSysEx1 == 0x01097F7E))
+							{
+								dwGlobalFlags |= MIDIGLOBAL_GMSYSTEMON;
+							} else
+							// XG System On
+							if ((len == 8) && ((dwSysEx1 & 0xFFFFF0FF) == 0x004c1043) && (dwSysEx2 == 0x77007e00))
+							{
+								dwGlobalFlags |= MIDIGLOBAL_XGSYSTEMON;
+							} else
+							// Midi Master Volume
+							if ((len == 7) && (dwSysEx1 == 0x01047F7F))
+							{
+								midimastervol = midivolumetolinear(ptrk->ptracks[5] & 0x7F) >> 8;
+								if (midimastervol < 16) midimastervol = 16;
+								dwGlobalFlags |= MIDIGLOBAL_UPDATEMASTERVOL;
+							}
+						}
+						ptrk->ptracks += len;
+					}
+					break;
+				
+				//////////////////////////////////////////////////////////////////////
+				// META-events: FF.code.len.data[len]
+				case 0xFF:
+					{
+						UINT i = *(ptrk->ptracks++);
+						LONG len = getmidilong(ptrk->ptracks, ptrk->ptrmax);
+						if (ptrk->ptracks+len > ptrk->ptrmax)
+						{
+							// EOF
+							ptrk->ptracks = NULL;
+						} else
+						switch(i)
+						{
+						// FF.01 [text]: Song Information
+						case 0x01:
+							if (!len) break;
+							if ((len < 32) && (!m_szNames[0][0]))
+							{
+								memcpy(m_szNames[0], ptrk->ptracks, len);
+								m_szNames[0][len] = 0;
+							} else
+							if ((!m_lpszSongComments) && (ptrk->ptracks[0]) && (ptrk->ptracks[0] < 0x7F))
+							{
+								m_lpszSongComments = new char [len+1];
+								if (m_lpszSongComments)
+								{
+									memcpy(m_lpszSongComments, ptrk->ptracks, len);
+									m_lpszSongComments[len] = 0;
+								}
+							}
+							break;
+						// FF.02 [text]: Song Copyright
+						case 0x02:
+							if (!len) break;
+							if ((!m_lpszSongComments) && (ptrk->ptracks[0]) && (ptrk->ptracks[0] < 0x7F) && (len > 7))
+							{
+								m_lpszSongComments = new char [len+1];
+								if (m_lpszSongComments)
+								{
+									memcpy(m_lpszSongComments, ptrk->ptracks, len);
+									m_lpszSongComments[len] = 0;
+								}
+							}
+							break;
+						// FF.03: Sequence Name
+						case 0x03:
+						// FF.06: Sequence Text (->Pattern names)
+						case 0x06:
+							if ((len > 1) && (!trk))
+							{
+								UINT k = (len < 32) ? len : 31;
+								CHAR s[32];
+								memcpy(s, ptrk->ptracks, k);
+								s[k] = 0;
+								if ((!strnicmp((char*)s, "Copyri", 6)) || (!s[0])) break;
+								if (i == 0x03)
+								{
+									if (!m_szNames[0][0]) strcpy((char*)m_szNames[0], (char*)s);
+								}
+							}
+							break;
+						// FF.07: Cue Point (marker)
+						// FF.20: Channel Prefix
+						// FF.2F: End of Track
+						case 0x2F:
+							ptrk->status = 0x2F;
+							ptrk->ptracks = NULL;
+							break;
+						// FF.51 [tttttt]: Set Tempo
+						case 0x51:
+							{
+								LONG l = ptrk->ptracks[0];
+								l = (l << 8) | ptrk->ptracks[1];
+								l = (l << 8) | ptrk->ptracks[2];
+								if (l <= 0) break;
+								nTempoUsec = l / nPPQN;
+								if (nTempoUsec < 100) nTempoUsec = 100;
+								tempo = ConvertMidiTempo(nTempoUsec, &nTickMultiplier);
+								dwGlobalFlags |= MIDIGLOBAL_UPDATETEMPO;
+							}
+							break;
+						// FF.58: Time Signature
+						// FF.7F: Sequencer-Specific
+						}
+						if (ptrk->ptracks) ptrk->ptracks += len;
+					}
+					break;
+
+				//////////////////////////////////////////////////////////////////////////
+				// Regular Voice Events
+				default:
+				{
+					UINT midich = (ptrk->status & 0x0F)+1;
+					UINT midist = ptrk->status & 0xF0;
+					MIDICHANNELSTATE *pmidich = &midichstate[midich-1];
+					UINT note, velocity;
+
+					switch(midist)
+					{
+					//////////////////////////////////
+					// Note Off:	80.note.velocity
+					case 0x80:
+					// Note On:		90.note.velocity
+					case 0x90:
+						note = ptrk->ptracks[0] & 0x7F;
+						velocity = (midist == 0x90) ? (ptrk->ptracks[1] & 0x7F) : 0;
+						ptrk->ptracks += 2;
+						// Note On: 90.note.velocity
+						if (velocity)
+						{
+							// Start counting rows
+							dwGlobalFlags &= ~MIDIGLOBAL_FROZEN;
+							// if the note is already playing, we reuse this channel
+							UINT nchn = pmidich->note_on[note];
+							if ((nchn) && (chnstate[nchn-1].parent != midich)) nchn = 0;
+							// or else, we look for an available child channel
+							if (!nchn)
+							{
+								for (UINT i=0; i<m_nChannels; i++) if (chnstate[i].parent == midich)
+								{
+									if ((!chnstate[i].note) && ((!m[i].note) || (m[i].note & 0x80)))
+									{
+										// found an available channel
+										nchn = i+1;
+										break;
+									}
+								}
+							}
+							// still nothing? in this case, we try to allocate a new mod channel
+							if (!nchn)
+							{
+								for (UINT i=0; i<m_nChannels; i++) if (!chnstate[i].parent)
+								{
+									nchn = i+1;
+									chnstate[i].parent = midich;
+									break;
+								}
+							}
+							// still not? we have to steal a voice from another channel
+							// We found our channel: let's do the note on
+							if (nchn)
+							{
+								pmidich->note_on[note] = nchn;
+								nchn--;
+								chnstate[nchn].pitchsrc = pmidich->pitchbend;
+								chnstate[nchn].pitchdest = pmidich->pitchbend;
+								chnstate[nchn].flags &= ~CHNSTATE_NOTEOFFPENDING;
+								chnstate[nchn].idlecount = 0;
+								chnstate[nchn].note = note+1;
+								int realnote = note;
+								if (midich != 10)
+								{
+									realnote += (((int)pmidich->pitchbend - 0x2000) * pmidich->pitchbendrange) / (0x2000*32);
+									if (realnote < 0) realnote = 0;
+									if (realnote > 119) realnote = 119;
+								}
+								m[nchn].note = realnote+1;
+								m[nchn].instr = MapMidiInstrument(pmidich->program + ((UINT)pmidich->bank << 7), midich, note);
+								m[nchn].volcmd = VOLCMD_VOLUME;
+								LONG vol = midivolumetolinear(velocity) >> 8;
+								vol = (vol * (LONG)pmidich->volume * (LONG)pmidich->expression) >> 13;
+								if (vol > 256) vol = 256;
+								if (vol < 4) vol = 4;
+								m[nchn].vol = (BYTE)(vol>>2);
+								// Channel Panning
+								if ((!m[nchn].command) && (pmidich->pan != chnstate[nchn].pan))
+								{
+									chnstate[nchn].pan = pmidich->pan;
+									m[nchn].param = pmidich->pan;
+									m[nchn].command = CMD_PANNING8;
+								}
+							}
+						} else
+						// Note Off; 90.note.00
+						if (!(dwGlobalFlags & MIDIGLOBAL_FROZEN))
+						{
+							UINT nchn = pmidich->note_on[note];
+							if (nchn)
+							{
+								nchn--;
+								chnstate[nchn].flags |= CHNSTATE_NOTEOFFPENDING;
+								chnstate[nchn].note = 0;
+								pmidich->note_on[note] = 0;
+							} else
+							{
+								for (UINT i=0; i<m_nChannels; i++)
+								{
+									if ((chnstate[i].parent == midich) && (chnstate[i].note == note+1))
+									{
+										chnstate[i].note = 0;
+										chnstate[i].flags |= CHNSTATE_NOTEOFFPENDING;
+									}
+								}
+							}
+						}
+						break;
+
+					///////////////////////////////////
+					// A0.xx.yy: Aftertouch
+					case 0xA0:
+						{
+							ptrk->ptracks += 2;
+						}
+						break;
+
+					///////////////////////////////////
+					// B0: Control Change
+					case 0xB0:
+						{
+							UINT controller = ptrk->ptracks[0];
+							UINT value = ptrk->ptracks[1] & 0x7F;
+							ptrk->ptracks += 2;
+							switch(controller)
+							{
+							// Bn.00.xx: Bank Select MSB (GS)
+							case 0x00:
+								pmidich->bank &= 0x7F;
+								pmidich->bank |= (value << 7);
+								break;
+							// Bn.01.xx: Modulation Depth
+							case 0x01:
+								pmidich->pitchbendrange = value;
+								break;
+							// Bn.07.xx: Volume
+							case 0x07:
+								pmidich->volume = (BYTE)(midivolumetolinear(value) >> 9);
+								break;
+							// Bn.0B.xx: Expression
+							case 0x0B:
+								pmidich->expression = (BYTE)(midivolumetolinear(value) >> 9);
+								break;
+							// Bn.0A.xx: Pan
+							case 0x0A:
+								pmidich->pan = value * 2;
+								break;
+							// Bn.20.xx: Bank Select LSB (GS)
+							case 0x20:
+								pmidich->bank &= (0x7F << 7);
+								pmidich->bank |= value;
+								break;
+							// Bn.79.00: Reset All Controllers (GM)
+							case 0x79:
+								pmidich->modulation = 0;
+								pmidich->expression = 128;
+								pmidich->pitchbend = 0x2000;
+								pmidich->pitchbendrange = 64;
+								// Should also reset pedals (40h-43h), NRP, RPN, aftertouch
+								break;
+							// Bn.78.00: All Sound Off (GS)
+							// Bn.7B.00: All Notes Off (GM)
+							case 0x78:
+							case 0x7B:
+								if (value == 0x00)
+								{
+									// All Notes Off
+									for (UINT k=0; k<m_nChannels; k++)
+									{
+										if (chnstate[k].note)
+										{
+											chnstate[k].flags |= CHNSTATE_NOTEOFFPENDING;
+											chnstate[k].note = 0;
+										}
+									}
+								}
+								break;
+							////////////////////////////////////
+							// Controller List
+							//
+							// Bn.02.xx: Breath Control
+							// Bn.04.xx: Foot Pedal
+							// Bn.05.xx: Portamento Time (Glissando Time)
+							// Bn.06.xx: Data Entry MSB
+							// Bn.08.xx: Balance
+							// Bn.10-13.xx: GP Control #1-#4
+							// Bn.20-3F.xx: Data LSB for controllers 0-31
+							// Bn.26.xx: Data Entry LSB
+							// Bn.40.xx: Hold Pedal #1
+							// Bn.41.xx: Portamento (GS)
+							// Bn.42.xx: Sostenuto (GS)
+							// Bn.43.xx: Soft Pedal (GS)
+							// Bn.44.xx: Legato Pedal
+							// Bn.45.xx: Hold Pedal #2
+							// Bn.46.xx: Sound Variation
+							// Bn.47.xx: Sound Timbre
+							// Bn.48.xx: Sound Release Time
+							// Bn.49.xx: Sound Attack Time
+							// Bn.4A.xx: Sound Brightness
+							// Bn.4B-4F.xx: Sound Control #6-#10
+							// Bn.50-53.xx: GP Control #5-#8
+							// Bn.54.xx: Portamento Control (GS)
+							// Bn.5B.xx: Reverb Level (GS)
+							// Bn.5C.xx: Tremolo Depth
+							// Bn.5D.xx: Chorus Level (GS)
+							// Bn.5E.xx: Celeste Depth
+							// Bn.5F.xx: Phaser Depth
+							// Bn.60.xx: Data Increment
+							// Bn.61.xx: Data Decrement
+							// Bn.62.xx: Non-RPN Parameter LSB (GS)
+							// Bn.63.xx: Non-RPN Parameter MSB (GS)
+							// Bn.64.xx: RPN Parameter LSB (GM)
+							// Bn.65.xx: RPN Parameter MSB (GM)
+							// Bn.7A.00: Local On/Off
+							// Bn.7C.00: Omni Mode Off
+							// Bn.7D.00: Omni Mode On
+							// Bn.7E.mm: Mono Mode On
+							// Bn.7F.00: Poly Mode On
+							}
+						}
+						break;
+
+					////////////////////////////////
+					// C0.pp: Program Change
+					case 0xC0:
+						{
+							pmidich->program = ptrk->ptracks[0] & 0x7F;
+							ptrk->ptracks++;
+						}
+						break;
+
+					////////////////////////////////
+					// D0: Channel Aftertouch (Polyphonic Key Pressure)
+					case 0xD0:
+						{
+							ptrk->ptracks++;
+						}
+						break;
+					
+					////////////////////////////////
+					// E0: Pitch Bend
+					case 0xE0:
+						{
+							pmidich->pitchbend = (WORD)(((UINT)ptrk->ptracks[1] << 7) + (ptrk->ptracks[0] & 0x7F));
+							for (UINT i=0; i<128; i++) if (pmidich->note_on[i])
+							{
+								UINT nchn = pmidich->note_on[i]-1;
+								if (chnstate[nchn].parent == midich)
+								{
+									chnstate[nchn].pitchdest = pmidich->pitchbend;
+								}
+							}
+							ptrk->ptracks+=2;
+						}
+						break;
+
+					//////////////////////////////////////
+					// F0 & Unsupported commands: skip it
+					default:
+						ptrk->ptracks++;
+					}
+				}} // switch+default
+				// Process to next event
+				if (ptrk->ptracks)
+				{
+					ptrk->nexteventtime += getmidilong(ptrk->ptracks, ptrk->ptrmax);
+				}
+				if (ptrk->ptracks >= ptrk->ptrmax) ptrk->ptracks = NULL;
+			}
+			// End reached?
+			if (ptrk->ptracks >= ptrk->ptrmax) ptrk->ptracks = NULL;
+		}
+
+		////////////////////////////////////////////////////////////////////
+		// Move to next row
+		if (!(dwGlobalFlags & MIDIGLOBAL_FROZEN))
+		{
+			// Check MOD channels status
+			for (UINT ichn=0; ichn<m_nChannels; ichn++)
+			{
+				// Pending Global Effects ?
+				if (!m[ichn].command)
+				{
+					if ((chnstate[ichn].pitchsrc != chnstate[ichn].pitchdest) && (chnstate[ichn].parent))
+					{
+						int newpitch = chnstate[ichn].pitchdest;
+						int pitchbendrange = midichstate[chnstate[ichn].parent-1].pitchbendrange;
+						// +/- 256 for +/- pitch bend range
+						int slideamount = (newpitch - (int)chnstate[ichn].pitchsrc) / (int)32;
+						if (slideamount)
+						{
+							const int ppdiv = (16 * 128 * (gnMidiImportSpeed-1));
+							newpitch = (int)chnstate[ichn].pitchsrc + slideamount;
+							if (slideamount < 0)
+							{
+								int param = (-slideamount * pitchbendrange + ppdiv/2) / ppdiv;
+								if (param >= 0x80) param = 0x80;
+								if (param > 0)
+								{
+									m[ichn].param = (BYTE)param;
+									m[ichn].command = CMD_PORTAMENTODOWN;
+								}
+							} else
+							{
+								int param = (slideamount * pitchbendrange + ppdiv/2) / ppdiv;
+								if (param >= 0x80) param = 0x80;
+								if (param > 0)
+								{
+									m[ichn].param = (BYTE)param;
+									m[ichn].command = CMD_PORTAMENTOUP;
+								}
+							}
+						}
+						chnstate[ichn].pitchsrc = (WORD)newpitch;
+
+					} else
+					if (dwGlobalFlags & MIDIGLOBAL_UPDATETEMPO)
+					{
+						m[ichn].command = CMD_TEMPO;
+						m[ichn].param = (BYTE)tempo;
+						dwGlobalFlags &= ~MIDIGLOBAL_UPDATETEMPO;
+					} else
+					if (dwGlobalFlags & MIDIGLOBAL_UPDATEMASTERVOL)
+					{
+						m[ichn].command = CMD_GLOBALVOLUME;
+						m[ichn].param = midimastervol >> 1; // 0-128
+						dwGlobalFlags &= ~MIDIGLOBAL_UPDATEMASTERVOL;
+					}
+				}
+				// Check pending noteoff events for m[ichn]
+				if (!m[ichn].note)
+				{
+					if (chnstate[ichn].flags & CHNSTATE_NOTEOFFPENDING)
+					{
+						chnstate[ichn].flags &= ~CHNSTATE_NOTEOFFPENDING;
+						m[ichn].note = 0xFF;
+					}
+					// Check State of channel
+					chnstate[ichn].idlecount++;
+					if ((chnstate[ichn].note) && (chnstate[ichn].idlecount >= 50))
+					{
+						chnstate[ichn].note = 0;
+						m[ichn].note = 0xFF;	// only if not drum channel ?
+					} else
+					if (chnstate[ichn].idlecount >= 500) // 20secs of inactivity
+					{
+						chnstate[ichn].idlecount = 0;
+						chnstate[ichn].parent = 0;
+					}
+				}
+			}
+
+			if ((++row) >= PatternSize[pat])
+			{
+				pat++;
+				if (pat >= MAX_PATTERNS-1) break;
+				Order[pat] = pat;
+				Order[pat+1] = 0xFF;
+				row = 0;
+			}
+		}
+
+		// Increase midi clock
+		midi_clock += nTickMultiplier;
+	} while (!(dwGlobalFlags & MIDIGLOBAL_SONGENDED));
+	return TRUE;
+}
+
+
--- a/src/modplug/load_mod.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_mod.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -110,7 +110,7 @@
 	case CMD_PATTERNBREAK:		command = 0x0D; param = ((param / 10) << 4) | (param % 10); break;
 	case CMD_MODCMDEX:			command = 0x0E; break;
 	case CMD_SPEED:				command = 0x0F; if (param > 0x20) param = 0x20; break;
-	case CMD_TEMPO:				if (param > 0x20) { command = 0x0F; break; }
+	case CMD_TEMPO:				if (param > 0x20) { command = 0x0F; break; } return 0;
 	case CMD_GLOBALVOLUME:		command = 'G' - 55; break;
 	case CMD_GLOBALVOLSLIDE:	command = 'H' - 55; break;
 	case CMD_KEYOFF:			command = 'K' - 55; break;
@@ -192,7 +192,7 @@
 	 || (IsMagic(s, "M&K!")) || (IsMagic(s, "N.T."))) m_nChannels = 4; else
 	if ((IsMagic(s, "CD81")) || (IsMagic(s, "OKTA"))) m_nChannels = 8; else
 	if ((s[0]=='F') && (s[1]=='L') && (s[2]=='T') && (s[3]>='4') && (s[3]<='9')) m_nChannels = s[3] - '0'; else
-	if ((s[0]>='2') && (s[0]<='9') && (s[1]=='C') && (s[2]=='H') && (s[3]=='N')) m_nChannels = s[0] - '0'; else
+	if ((s[0]>='4') && (s[0]<='9') && (s[1]=='C') && (s[2]=='H') && (s[3]=='N')) m_nChannels = s[0] - '0'; else
 	if ((s[0]=='1') && (s[1]>='0') && (s[1]<='9') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 10; else
 	if ((s[0]=='2') && (s[1]>='0') && (s[1]<='9') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 20; else
 	if ((s[0]=='3') && (s[1]>='0') && (s[1]<='2') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 30; else
@@ -228,19 +228,13 @@
 		}
 		psmp->nLoopStart = loopstart;
 		psmp->nLoopEnd = loopstart + looplen;
-		if (psmp->nLength < 4) psmp->nLength = 0;
+		if (psmp->nLength < 2) psmp->nLength = 0;
 		if (psmp->nLength)
 		{
 			UINT derr = 0;
 			if (psmp->nLoopStart >= psmp->nLength) { psmp->nLoopStart = psmp->nLength-1; derr|=1; }
 			if (psmp->nLoopEnd > psmp->nLength) { psmp->nLoopEnd = psmp->nLength; derr |= 1; }
 			if (psmp->nLoopStart > psmp->nLoopEnd) derr |= 1;
-			if ((psmp->nLoopStart > psmp->nLoopEnd) || (psmp->nLoopEnd <= 8)
-			 || (psmp->nLoopEnd - psmp->nLoopStart <= 4))
-			{
-				psmp->nLoopStart = 0;
-				psmp->nLoopEnd = 0;
-			}
 			if (psmp->nLoopEnd > psmp->nLoopStart)
 			{
 				psmp->uFlags |= CHN_LOOP;
@@ -306,11 +300,10 @@
 	for (UINT ich=0; ich<m_nChannels; ich++)
 	{
 		ChnSettings[ich].nVolume = 64;
-		if (gdwSoundSetup & SNDMIX_MAXDEFAULTPAN)
-			ChnSettings[ich].nPan = (((ich&3)==1) || ((ich&3)==2)) ? 256 : 0;
-		else
-			ChnSettings[ich].nPan = (((ich&3)==1) || ((ich&3)==2)) ? 0xC0 : 0x40;
+		ChnSettings[ich].nPan = (((ich&3)==1) || ((ich&3)==2)) ? 256 : 0;
 	}
+	m_nStereoSeparation = (gdwSoundSetup & SNDMIX_MAXDEFAULTPAN) ? 128 : 64;
+	
 	// Reading channels
 	for (UINT ipat=0; ipat<nbp; ipat++)
 	{
@@ -318,6 +311,7 @@
 		{
 			if ((Patterns[ipat] = AllocatePattern(64, m_nChannels)) == NULL) break;
 			PatternSize[ipat] = 64;
+			PatternAllocSize[ipat] = 64;
 			if (dwMemPos + m_nChannels*256 >= dwMemLength) break;
 			MODCOMMAND *m = Patterns[ipat];
 			LPCBYTE p = lpStream + dwMemPos;
@@ -363,22 +357,27 @@
 
 
 #ifndef MODPLUG_NO_FILESAVE
-#pragma warning(disable:4100)
 
-BOOL CSoundFile::SaveMod(LPCSTR lpszFileName, UINT nPacking)
+#ifdef MSC_VER
+#pragma warning(disable:4100)
+#endif
+
+BOOL CSoundFile::SaveMod(diskwriter_driver_t *fp, UINT nPacking)
 //----------------------------------------------------------
 {
 	BYTE insmap[32];
 	UINT inslen[32];
 	BYTE bTab[32];
 	BYTE ord[128];
-	FILE *f;
+	UINT chanlim;
 
-	if ((!m_nChannels) || (!lpszFileName)) return FALSE;
-	if ((f = fopen(lpszFileName, "wb")) == NULL) return FALSE;
+	if ((!m_nChannels) || (!fp)) return FALSE;
+	chanlim  = GetHighestUsedChannel();
+	if (chanlim < 4) chanlim = 4;
+
 	memset(ord, 0, sizeof(ord));
 	memset(inslen, 0, sizeof(inslen));
-	if (m_nInstruments)
+	if (m_dwSongFlags & SONG_INSTRUMENTMODE)
 	{
 		memset(insmap, 0, sizeof(insmap));
 		for (UINT i=1; i<32; i++) if (Headers[i])
@@ -394,25 +393,28 @@
 		for (UINT i=0; i<32; i++) insmap[i] = (BYTE)i;
 	}
 	// Writing song name
-	fwrite(m_szNames, 20, 1, f);
+	fp->o(fp, (const unsigned char *)m_szNames, 20);
 	// Writing instrument definition
 	for (UINT iins=1; iins<=31; iins++)
 	{
 		MODINSTRUMENT *pins = &Ins[insmap[iins]];
+		WORD gg;
+		FrequencyToTranspose(pins);
+
 		memcpy(bTab, m_szNames[iins],22);
 		inslen[iins] = pins->nLength;
 		if (inslen[iins] > 0x1fff0) inslen[iins] = 0x1fff0;
-		bTab[22] = inslen[iins] >> 9;
-		bTab[23] = inslen[iins] >> 1;
+		gg = bswapBE16(inslen[iins] / 2);
+		memcpy(bTab+22, &gg, 2);
 		if (pins->RelativeTone < 0) bTab[24] = 0x08; else
 		if (pins->RelativeTone > 0) bTab[24] = 0x07; else
 		bTab[24] = (BYTE)XM2MODFineTune(pins->nFineTune);
-		bTab[25] = pins->nVolume >> 2;
-		bTab[26] = pins->nLoopStart >> 9;
-		bTab[27] = pins->nLoopStart >> 1;
-		bTab[28] = (pins->nLoopEnd - pins->nLoopStart) >> 9;
-		bTab[29] = (pins->nLoopEnd - pins->nLoopStart) >> 1;
-		fwrite(bTab, 30, 1, f);
+		bTab[25] = pins->nVolume  / 4;
+		gg = bswapBE16(pins->nLoopStart / 2);
+		memcpy(bTab+26, &gg, 2);
+		gg = bswapBE16((pins->nLoopEnd - pins->nLoopStart)/ 2);
+		memcpy(bTab+28, &gg, 2);
+		fp->o(fp,(const unsigned char *) bTab, 30);
 	}
 	// Writing number of patterns
 	UINT nbp=0, norders=128;
@@ -427,26 +429,27 @@
 	}
 	bTab[0] = norders;
 	bTab[1] = m_nRestartPos;
-	fwrite(bTab, 2, 1, f);
+	fp->o(fp, (const unsigned char *)bTab, 2);
 	// Writing pattern list
 	if (norders) memcpy(ord, Order, norders);
-	fwrite(ord, 128, 1, f);
+	fp->o(fp, (const unsigned char *)ord, 128);
 	// Writing signature
-	if (m_nChannels == 4)
+	if (chanlim == 4)
 		lstrcpy((LPSTR)&bTab, "M.K.");
 	else
-		wsprintf((LPSTR)&bTab, "%luCHN", m_nChannels);
-	fwrite(bTab, 4, 1, f);
+		wsprintf((LPSTR)&bTab, "%uCHN", chanlim);
+	fp->o(fp, (const unsigned char *)bTab, 4);
 	// Writing patterns
 	for (UINT ipat=0; ipat<nbp; ipat++) if (Patterns[ipat])
 	{
 		BYTE s[64*4];
-		MODCOMMAND *m = Patterns[ipat];
+		MODCOMMAND *pm = Patterns[ipat];
 		for (UINT i=0; i<64; i++) if (i < PatternSize[ipat])
 		{
 			LPBYTE p=s;
-			for (UINT c=0; c<m_nChannels; c++,p+=4,m++)
+			for (UINT c=0; c<chanlim; c++,p+=4)
 			{
+				MODCOMMAND *m = &pm[ i * m_nChannels + c];
 				UINT param = ModSaveCommand(m, FALSE);
 				UINT command = param >> 8;
 				param &= 0xFF;
@@ -461,16 +464,16 @@
 					period = ProTrackerPeriodTable[period];
 				}
 				UINT instr = (m->instr > 31) ? 0 : m->instr;
-				p[0] = ((period >> 8) & 0x0F) | (instr & 0x10);
-				p[1] = period & 0xFF;
+				p[0] = ((period / 256) & 0x0F) | (instr & 0x10);
+				p[1] = period % 256;
 				p[2] = ((instr & 0x0F) << 4) | (command & 0x0F);
 				p[3] = param;
 			}
-			fwrite(s, m_nChannels, 4, f);
+			fp->o(fp, (const unsigned char *)s, chanlim*4);
 		} else
 		{
-			memset(s, 0, m_nChannels*4);
-			fwrite(s, m_nChannels, 4, f);
+			memset(s, 0, chanlim*4);
+			fp->o(fp, (const unsigned char *)s, chanlim*4);
 		}
 	}
 	// Writing instruments
@@ -483,16 +486,18 @@
 		{
 			if ((nPacking) && (CanPackSample((char *)pins->pSample, inslen[ismpd], nPacking)))
 			{
-				fwrite("ADPCM", 1, 5, f);
+				fp->o(fp, (const unsigned char *)"ADPCM", 5);
 				flags = RS_ADPCM4;
 			}
 		}
 #endif
-		WriteSample(f, pins, flags, inslen[ismpd]);
+		WriteSample(fp, pins, flags, inslen[ismpd]);
 	}
-	fclose(f);
 	return TRUE;
 }
 
+#ifdef MSC_VER
 #pragma warning(default:4100)
+#endif
+
 #endif // MODPLUG_NO_FILESAVE
--- a/src/modplug/load_mt2.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_mt2.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -282,6 +282,7 @@
 			Log("Pattern #%d @%04X: %d lines, %d bytes\n", iPat, dwMemPos-6, nLines, pmp->wDataLen);
 	#endif
 			PatternSize[iPat] = nLines;
+			PatternAllocSize[iPat] = nLines;
 			Patterns[iPat] = AllocatePattern(nLines, m_nChannels);
 			if (!Patterns[iPat]) return TRUE;
 			MODCOMMAND *m = Patterns[iPat];
@@ -395,6 +396,7 @@
 #endif
 	memset(InstrMap, 0, sizeof(InstrMap));
 	m_nInstruments = (pfh->wInstruments < MAX_INSTRUMENTS) ? pfh->wInstruments : MAX_INSTRUMENTS-1;
+	m_dwSongFlags |= SONG_INSTRUMENTMODE;
 	for (UINT iIns=1; iIns<=255; iIns++)
 	{
 		if (dwMemPos+36 > dwMemLength) return TRUE;
@@ -408,7 +410,7 @@
 			{
 				memset(penv, 0, sizeof(INSTRUMENTHEADER));
 				memcpy(penv->name, pmi->szName, 32);
-				penv->nGlobalVol = 64;
+				penv->nGlobalVol = 128;
 				penv->nPan = 128;
 				for (UINT i=0; i<120; i++)
 				{
@@ -460,7 +462,7 @@
 				for (UINT iEnv=0; iEnv<4; iEnv++) if (pehdr[iEnv])
 				{
 					MT2ENVELOPE *pme = pehdr[iEnv];
-					WORD *pEnvPoints = NULL;
+					int *pEnvPoints = NULL;
 					BYTE *pEnvData = NULL;
 				#ifdef MT2DEBUG
 					Log("  Env %d.%d @%04X: %d points\n", iIns, iEnv, (UINT)(((BYTE *)pme)-lpStream), pme->nPoints);
@@ -472,12 +474,12 @@
 						if (pme->nFlags & 1) penv->dwFlags |= ENV_VOLUME;
 						if (pme->nFlags & 2) penv->dwFlags |= ENV_VOLSUSTAIN;
 						if (pme->nFlags & 4) penv->dwFlags |= ENV_VOLLOOP;
-						penv->nVolEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
-						penv->nVolSustainBegin = penv->nVolSustainEnd = pme->nSustainPos;
-						penv->nVolLoopStart = pme->nLoopStart;
-						penv->nVolLoopEnd = pme->nLoopEnd;
-						pEnvPoints = penv->VolPoints;
-						pEnvData = penv->VolEnv;
+						penv->VolEnv.nNodes = (pme->nPoints > 16) ? 16 : pme->nPoints;
+						penv->VolEnv.nSustainStart = penv->VolEnv.nSustainEnd = pme->nSustainPos;
+						penv->VolEnv.nLoopStart = pme->nLoopStart;
+						penv->VolEnv.nLoopEnd = pme->nLoopEnd;
+						pEnvPoints = penv->VolEnv.Ticks;
+						pEnvData = penv->VolEnv.Values;
 						break;
 
 					// Panning Envelope
@@ -485,12 +487,12 @@
 						if (pme->nFlags & 1) penv->dwFlags |= ENV_PANNING;
 						if (pme->nFlags & 2) penv->dwFlags |= ENV_PANSUSTAIN;
 						if (pme->nFlags & 4) penv->dwFlags |= ENV_PANLOOP;
-						penv->nPanEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
-						penv->nPanSustainBegin = penv->nPanSustainEnd = pme->nSustainPos;
-						penv->nPanLoopStart = pme->nLoopStart;
-						penv->nPanLoopEnd = pme->nLoopEnd;
-						pEnvPoints = penv->PanPoints;
-						pEnvData = penv->PanEnv;
+						penv->PanEnv.nNodes = (pme->nPoints > 16) ? 16 : pme->nPoints;
+						penv->PanEnv.nSustainStart = penv->PanEnv.nSustainEnd = pme->nSustainPos;
+						penv->PanEnv.nLoopStart = pme->nLoopStart;
+						penv->PanEnv.nLoopEnd = pme->nLoopEnd;
+						pEnvPoints = penv->PanEnv.Ticks;
+						pEnvData = penv->PanEnv.Values;
 						break;
 
 					// Pitch/Filter envelope
@@ -498,12 +500,12 @@
 						if (pme->nFlags & 1) penv->dwFlags |= (iEnv==3) ? (ENV_PITCH|ENV_FILTER) : ENV_PITCH;
 						if (pme->nFlags & 2) penv->dwFlags |= ENV_PITCHSUSTAIN;
 						if (pme->nFlags & 4) penv->dwFlags |= ENV_PITCHLOOP;
-						penv->nPitchEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
-						penv->nPitchSustainBegin = penv->nPitchSustainEnd = pme->nSustainPos;
-						penv->nPitchLoopStart = pme->nLoopStart;
-						penv->nPitchLoopEnd = pme->nLoopEnd;
-						pEnvPoints = penv->PitchPoints;
-						pEnvData = penv->PitchEnv;
+						penv->PitchEnv.nNodes = (pme->nPoints > 16) ? 16 : pme->nPoints;
+						penv->PitchEnv.nSustainStart = penv->PitchEnv.nSustainEnd = pme->nSustainPos;
+						penv->PitchEnv.nLoopStart = pme->nLoopStart;
+						penv->PitchEnv.nLoopEnd = pme->nLoopEnd;
+						pEnvPoints = penv->PitchEnv.Ticks;
+						pEnvData = penv->PitchEnv.Values;
 					}
 					// Envelope data
 					if ((pEnvPoints) && (pEnvData) && (pedata[iEnv]))
@@ -592,7 +594,7 @@
 							Ins[nSmp].nVibType = pmi->bVibType;
 							Ins[nSmp].nVibSweep = pmi->bVibSweep;
 							Ins[nSmp].nVibDepth = pmi->bVibDepth;
-							Ins[nSmp].nVibRate = pmi->bVibRate;
+							Ins[nSmp].nVibRate = pmi->bVibRate/4;
 						}
 					}
 				}
--- a/src/modplug/load_mtm.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_mtm.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -59,8 +59,8 @@
 	 || (!pmh->lastpattern) || (pmh->lastpattern > MAX_PATTERNS)) return FALSE;
 	strncpy(m_szNames[0], pmh->songname, 20);
 	m_szNames[0][20] = 0;
-	if (dwMemPos + 37*pmh->numsamples + 128 + 192*pmh->numtracks
-	 + 64 * (pmh->lastpattern+1) + pmh->commentsize >= dwMemLength) return FALSE;
+	if (dwMemPos + 37*pmh->numsamples + 128 + 192*bswapLE16(pmh->numtracks)
+	 + 64 * (pmh->lastpattern+1) + bswapLE16(pmh->commentsize) >= dwMemLength) return FALSE;
 	m_nType = MOD_TYPE_MTM;
 	m_nSamples = pmh->numsamples;
 	m_nChannels = pmh->numchannels;
@@ -72,12 +72,12 @@
 		m_szNames[i][22] = 0;
 		Ins[i].nVolume = pms->volume << 2;
 		Ins[i].nGlobalVol = 64;
-		DWORD len = pms->length;
+		DWORD len = bswapLE32(pms->length);
 		if ((len > 4) && (len <= MAX_SAMPLE_LENGTH))
 		{
 			Ins[i].nLength = len;
-			Ins[i].nLoopStart = pms->reppos;
-			Ins[i].nLoopEnd = pms->repend;
+			Ins[i].nLoopStart = bswapLE32(pms->reppos);
+			Ins[i].nLoopEnd = bswapLE32(pms->repend);
 			if (Ins[i].nLoopEnd > Ins[i].nLength) Ins[i].nLoopEnd = Ins[i].nLength;
 			if (Ins[i].nLoopStart + 4 >= Ins[i].nLoopEnd) Ins[i].nLoopStart = Ins[i].nLoopEnd = 0;
 			if (Ins[i].nLoopEnd) Ins[i].uFlags |= CHN_LOOP;
@@ -104,13 +104,14 @@
 	dwMemPos += 128;
 	// Reading Patterns
 	LPCBYTE pTracks = lpStream + dwMemPos;
-	dwMemPos += 192 * pmh->numtracks;
+	dwMemPos += 192 * bswapLE16(pmh->numtracks);
 	LPWORD pSeq = (LPWORD)(lpStream + dwMemPos);
 	for (UINT pat=0; pat<=pmh->lastpattern; pat++)
 	{
 		PatternSize[pat] = 64;
+		PatternAllocSize[pat] = 64;
 		if ((Patterns[pat] = AllocatePattern(64, m_nChannels)) == NULL) break;
-		for (UINT n=0; n<32; n++) if ((pSeq[n]) && (pSeq[n] <= pmh->numtracks) && (n < m_nChannels))
+		for (UINT n=0; n<32; n++) if ((pSeq[n]) && (pSeq[n] <= bswapLE16(pmh->numtracks)) && (n < m_nChannels))
 		{
 			LPCBYTE p = pTracks + 192 * (pSeq[n]-1);
 			MODCOMMAND *m = Patterns[pat] + n;
@@ -132,9 +133,9 @@
 		pSeq += 32;
 	}
 	dwMemPos += 64*(pmh->lastpattern+1);
-	if ((pmh->commentsize) && (dwMemPos + pmh->commentsize < dwMemLength))
+	if (bswapLE16(pmh->commentsize) && (dwMemPos + bswapLE16(pmh->commentsize) < dwMemLength))
 	{
-		UINT n = pmh->commentsize;
+		UINT n = bswapLE16(pmh->commentsize);
 		m_lpszSongComments = new char[n+1];
 		if (m_lpszSongComments)
 		{
@@ -149,7 +150,7 @@
 			}
 		}
 	}
-	dwMemPos += pmh->commentsize;
+	dwMemPos += bswapLE16(pmh->commentsize);
 	// Reading Samples
 	for (UINT ismp=1; ismp<=m_nSamples; ismp++)
 	{
--- a/src/modplug/load_okt.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_okt.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -120,6 +120,7 @@
 			if ((Patterns[npat] = AllocatePattern(rows, m_nChannels)) == NULL) return TRUE;
 			MODCOMMAND *m = Patterns[npat];
 			PatternSize[npat] = rows;
+			PatternAllocSize[npat] = rows;
 			UINT imax = m_nChannels*rows;
 			for (UINT i=0; i<imax; i++, m++, dwPos+=4)
 			{
--- a/src/modplug/load_psm.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_psm.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -79,27 +79,24 @@
 //-----------------------------------------------------------
 {
 	PSMCHUNK *pfh = (PSMCHUNK *)lpStream;
-	PSMCHUNK pfh_swap;
 	DWORD dwMemPos, dwSongPos;
 	DWORD smpnames[MAX_SAMPLES];
 	DWORD patptrs[MAX_PATTERNS];
 	BYTE samplemap[MAX_SAMPLES];
 	UINT nPatterns;
 
-	pfh_swap.id = bswapLE32(pfh->id);
-	pfh_swap.len = bswapLE32(pfh->len);
-	pfh_swap.listid = bswapLE32(pfh->listid);
-
 	// Chunk0: "PSM ",filesize,"FILE"
 	if (dwMemLength < 256) return FALSE;
-	if (pfh_swap.id == PSM_ID_OLD)
+	if (bswapLE32(pfh->id) == PSM_ID_OLD)
 	{
 	#ifdef PSM_LOG
-		Log("Old PSM format not supported\n");
+		printf("Old PSM format not supported\n");
 	#endif
 		return FALSE;
 	}
-	if ((pfh_swap.id != PSM_ID_NEW) || (pfh_swap.len+12 > dwMemLength) || (pfh_swap.listid != IFFID_FILE)) return FALSE;
+	if ((bswapLE32(pfh->id) != PSM_ID_NEW)
+	|| (bswapLE32(pfh->len)+12 > dwMemLength)
+	|| (bswapLE32(pfh->listid) != IFFID_FILE)) return FALSE;
 	m_nType = MOD_TYPE_PSM;
 	m_nChannels = 16;
 	m_nSamples = 0;
@@ -111,19 +108,16 @@
 		UINT pan = (((iChPan & 3) == 1) || ((iChPan&3)==2)) ? 0xC0 : 0x40;
 		ChnSettings[iChPan].nPan = pan;
 	}
+	m_szNames[0][0]=0;
 	while (dwMemPos+8 < dwMemLength)
 	{
 		PSMCHUNK *pchunk = (PSMCHUNK *)(lpStream+dwMemPos);
-
-		pchunk->id = bswapLE32(pchunk->id);
-		pchunk->len = bswapLE32(pchunk->len);
-		pchunk->listid = bswapLE32(pchunk->listid);
-
-		if ((pchunk->len >= dwMemLength - 8) || (dwMemPos + pchunk->len + 8 > dwMemLength)) break;
+		if ((bswapLE32(pchunk->len) >= dwMemLength - 8)
+		|| (dwMemPos + bswapLE32(pchunk->len) + 8 > dwMemLength)) break;
 		dwMemPos += 8;
 		PUCHAR pdata = (PUCHAR)(lpStream+dwMemPos);
-		ULONG len = pchunk->len;
-		if (len) switch(pchunk->id)
+		ULONG len = bswapLE32(pchunk->len);
+		if (len) switch(bswapLE32(pchunk->id))
 		{
 		// "TITL": Song title
 		case IFFID_TITL:
@@ -152,23 +146,16 @@
 				m_nSamples++;
 				MODINSTRUMENT *pins = &Ins[m_nSamples];
 				PSMSAMPLE *psmp = (PSMSAMPLE *)pdata;
-
-				psmp->smpid = bswapLE32(psmp->smpid);
-				psmp->length = bswapLE32(psmp->length);
-				psmp->loopstart = bswapLE32(psmp->loopstart); 
-				psmp->loopend = bswapLE32(psmp->loopend);
-				psmp->samplerate = bswapLE32(psmp->samplerate);
-
-				smpnames[m_nSamples] = psmp->smpid;
+				smpnames[m_nSamples] = bswapLE32(psmp->smpid);
 				memcpy(m_szNames[m_nSamples], psmp->samplename, 31);
 				m_szNames[m_nSamples][31] = 0;
 				samplemap[m_nSamples-1] = (BYTE)m_nSamples;
 				// Init sample
 				pins->nGlobalVol = 0x40;
-				pins->nC4Speed = psmp->samplerate;
-				pins->nLength = psmp->length;
-				pins->nLoopStart = psmp->loopstart;
-				pins->nLoopEnd = psmp->loopend;
+				pins->nC4Speed = bswapLE32(psmp->samplerate);
+				pins->nLength = bswapLE32(psmp->length);
+				pins->nLoopStart = bswapLE32(psmp->loopstart);
+				pins->nLoopEnd = bswapLE32(psmp->loopend);
 				pins->nPan = 128;
 				pins->nVolume = (psmp->defvol+1) * 2;
 				pins->uFlags = (psmp->flags & 0x80) ? CHN_LOOP : 0;
@@ -197,7 +184,7 @@
 			}
 	#endif
 		}
-		dwMemPos += pchunk->len;
+		dwMemPos += bswapLE32(pchunk->len);
 	}
 	// Step #1: convert song structure
 	PSMSONGHDR *pSong = (PSMSONGHDR *)(lpStream+dwSongPos+8);
@@ -210,16 +197,12 @@
 		while (dwMemPos + 8 < dwSongEnd)
 		{
 			PSMCHUNK *pchunk = (PSMCHUNK *)(lpStream+dwMemPos);
-
-			pchunk->id = bswapLE32(pchunk->id);
-			pchunk->len = bswapLE32(pchunk->len);
-			pchunk->listid = bswapLE32(pchunk->listid);
-
 			dwMemPos += 8;
-			if ((pchunk->len > dwSongEnd) || (dwMemPos + pchunk->len > dwSongEnd)) break;
+			if ((bswapLE32(pchunk->len) > dwSongEnd)
+			|| (dwMemPos + bswapLE32(pchunk->len) > dwSongEnd)) break;
 			PUCHAR pdata = (PUCHAR)(lpStream+dwMemPos);
-			ULONG len = pchunk->len;
-			switch(pchunk->id)
+			ULONG len = bswapLE32(pchunk->len);
+			switch(bswapLE32(pchunk->id))
 			{
 			case IFFID_OPLH:
 				if (len >= 0x20)
@@ -265,7 +248,7 @@
 				}
 				break;
 			}
-			dwMemPos += pchunk->len;
+			dwMemPos += bswapLE32(pchunk->len);
 		}
 	}
 
@@ -273,85 +256,66 @@
 	for (UINT nPat=0; nPat<nPatterns; nPat++)
 	{
 		PSMPATTERN *pPsmPat = (PSMPATTERN *)(lpStream+patptrs[nPat]+8);
-
-		pPsmPat->size = bswapLE32(pPsmPat->size);
-		pPsmPat->name = bswapLE32(pPsmPat->name);
-		pPsmPat->rows = bswapLE16(pPsmPat->rows);
-
-		ULONG len = *(DWORD *)(lpStream+patptrs[nPat]+4) - 12;
-		UINT nRows = pPsmPat->rows;
-		if (len > pPsmPat->size) len = pPsmPat->size;
+		ULONG len = bswapLE32(*(DWORD *)(lpStream+patptrs[nPat]+4)) - 12;
+		UINT nRows = bswapLE16(pPsmPat->rows);
+		if (len > bswapLE32(pPsmPat->size)) len = bswapLE32(pPsmPat->size);
 		if ((nRows < 64) || (nRows > 256)) nRows = 64;
 		PatternSize[nPat] = nRows;
+		PatternAllocSize[nPat] = nRows;
 		if ((Patterns[nPat] = AllocatePattern(nRows, m_nChannels)) == NULL) break;
 		MODCOMMAND *m = Patterns[nPat];
+		MODCOMMAND *sp, dummy;
 		BYTE *p = pPsmPat->data;
 		UINT pos = 0;
 		UINT row = 0;
-		UINT oldch = 0;
-		BOOL bNewRow = FALSE;
+		UINT rowlim;
 	#ifdef PSM_LOG
-		Log("Pattern %d at offset 0x%04X\n", nPat, (DWORD)(p - (BYTE *)lpStream));
+		//printf("Pattern %d at offset 0x%04X\n", nPat, (DWORD)(p - (BYTE *)lpStream));
 	#endif
+		rowlim = bswapLE16(pPsmPat->reserved1)-2;
 		while ((row < nRows) && (pos+1 < len))
 		{
-			UINT flags = p[pos++];
-			UINT ch = p[pos++];
-			
-		#ifdef PSM_LOG
-			//Log("flags+ch: %02X.%02X\n", flags, ch);
-		#endif
-			if (((flags & 0xf0) == 0x10) && (ch <= oldch) /*&& (!bNewRow)*/)
-			{
-				if ((pos+1<len) && (!(p[pos] & 0x0f)) && (p[pos+1] < m_nChannels))
-				{
-				#ifdef PSM_LOG
-					//if (!nPat) Log("Continuing on new row\n");
-				#endif
-					row++;
-					m += m_nChannels;
-					oldch = ch;
-					continue;
-				}
+			UINT flags, ch;
+			if ((pos+1) >= rowlim) {
+				pos = rowlim;
+				rowlim = (((int)p[pos+1])<<8)
+					| ((int)p[pos+0]);
+				m += m_nChannels;
+				row++;
+				rowlim += pos;
+				pos += 2;
 			}
-			if ((pos >= len) || (row >= nRows)) break;
-			if (!(flags & 0xf0))
-			{
+			flags = p[pos++];
+			ch = p[pos++];
+			if (ch >= m_nChannels) {
 			#ifdef PSM_LOG
-				//if (!nPat) Log("EOR(%d): %02X.%02X\n", row, p[pos], p[pos+1]);
+				printf("Invalid channel row=%d (0x%02X.0x%02X)\n", row, flags, ch);
 			#endif
-				row++;
-				m += m_nChannels;
-				bNewRow = TRUE;
-				oldch = ch;
-				continue;
-			}
-			bNewRow = FALSE;
-			if (ch >= m_nChannels)
-			{
-			#ifdef PSM_LOG
-				if (!nPat) Log("Invalid channel row=%d (0x%02X.0x%02X)\n", row, flags, ch);
-			#endif
-				ch = 0;
+				sp = &dummy;
+			} else {
+				sp = &m[ch];
 			}
 			// Note + Instr
+			if ((flags & 0x80) && (pos+1 < len))
+			{
+				UINT note = p[pos++];
+				note = (note>>4)*12+(note&0x0f)+12+1;
+				if (note > 0x80) note = 0;
+				sp->note = note;
+			}
 			if ((flags & 0x40) && (pos+1 < len))
 			{
-				UINT note = p[pos++];
 				UINT nins = p[pos++];
 			#ifdef PSM_LOG
-				//if (!nPat) Log("note+ins: %02X.%02X\n", note, nins);
-				if ((!nPat) && (nins >= m_nSamples)) Log("WARNING: invalid instrument number (%d)\n", nins);
+				if ((!nPat) && (nins >= m_nSamples)) printf("WARNING: invalid instrument number (%d)\n", nins);
 			#endif
-				if ((note) && (note < 0x80)) note = (note>>4)*12+(note&0x0f)+12+1;
-				m[ch].instr = samplemap[nins];
-				m[ch].note = note;
+				sp->instr = samplemap[nins];
 			}
 			// Volume
 			if ((flags & 0x20) && (pos < len))
 			{
-				m[ch].volcmd = VOLCMD_VOLUME;
-				m[ch].vol = p[pos++] / 2;
+				sp->volcmd = VOLCMD_VOLUME;
+				sp->vol = p[pos++] / 2;
 			}
 			// Effect
 			if ((flags & 0x10) && (pos+1 < len))
@@ -359,40 +323,94 @@
 				UINT command = p[pos++];
 				UINT param = p[pos++];
 				// Convert effects
-				switch(command)
+				switch(command & 0x3F)
 				{
 				// 01: fine volslide up
-				case 0x01:	command = CMD_VOLUMESLIDE; param |= 0x0f; break;
-				// 04: fine volslide down
-				case 0x04:	command = CMD_VOLUMESLIDE; param>>=4; param |= 0xf0; break;
+				case 0x01:
+#if PSM_LOG
+					printf("fvup command pat=%d row=%d ch=%d   %02x %02x\n",
+							nPat,
+								row,1+ch,
+								command, param);
+#endif
+#if 0
+					if (!sp->volcmd) {
+						sp->volcmd = VOLCMD_FINEVOLUP;
+						sp->vol = (param >> 1) & 0xF;
+						command = CMD_PORTAMENTOUP;
+						param>>=4; param |= 0xf0;
+						if (param == 240) param=241;
+					} else {
+#endif
+					command = CMD_VOLUMESLIDE;
+					param |= 0x0f;
+					if (param == 15) param=31;
+					break;
+				// 02: volslide up
+				case 0x02:	command = CMD_VOLUMESLIDE; param>>=1; param<<=4; break;
+				// 03: fine volslide down
+				case 0x03:	
+#if PSM_LOG
+					printf("fvdown command pat=%d row=%d ch=%d   %02x %02x\n",
+							nPat,
+								row,1+ch,
+								command, param);
+#endif
+#if 0
+					if (!sp->volcmd) {
+						sp->volcmd = VOLCMD_FINEVOLDOWN;
+						sp->vol = (param >> 2) & 0xF;
+						if (!sp->vol) sp->vol = 1;
+						command = CMD_PORTAMENTODOWN;
+					}
+#endif
+					command = CMD_VOLUMESLIDE;
+					param>>=4; param |= 0xf0;
+					if (param == 240) param=241;
+					break;
+				// 04: volslide down
+				case 0x04:	command = CMD_VOLUMESLIDE; param>>=1; break;
 				// 0C: portamento up
 				case 0x0C:	command = CMD_PORTAMENTOUP; param = (param+1)/2; break;
 				// 0E: portamento down
 				case 0x0E:	command = CMD_PORTAMENTODOWN; param = (param+1)/2; break;
+				// 0F: tone portamento
+				case 0x0F:	command = CMD_TONEPORTAMENTO; param = param/4; break;
+				// 15: vibrato
+				case 0x15:	command = CMD_VIBRATO; break;
+				// 29: wtf
+				case 0x29: pos += 2; break;
+				// 2A: retrig
+				case 0x2A:	command = CMD_RETRIG; break;
 				// 33: Position Jump
 				case 0x33:	command = CMD_POSITIONJUMP; break;
 				// 34: Pattern break
 				case 0x34:	command = CMD_PATTERNBREAK; break;
 				// 3D: speed
-				case 0x3D:	command = CMD_SPEED; break;
+				case 0x3D:	command = CMD_SPEED;
+						if (!row && !nPat)
+							m_nDefaultSpeed = param;
+						break;
 				// 3E: tempo
-				case 0x3E:	command = CMD_TEMPO; break;
+				case 0x3E:	command = CMD_TEMPO;
+						if (!row && !nPat)
+							m_nDefaultTempo = param;
+						break;
 				// Unknown
 				default:
 				#ifdef PSM_LOG
-					Log("Unknown PSM effect pat=%d row=%d ch=%d: %02X.%02X\n", nPat, row, ch, command, param);
+					printf("Unknown PSM effect pat=%d row=%d ch=%d: %02X.%02X\n", nPat, row, ch, command, param);
 				#endif
 					command = param = 0;
 				}
-				m[ch].command = (BYTE)command;
-				m[ch].param = (BYTE)param;
+				sp->command = (BYTE)command;
+				sp->param = (BYTE)param;
 			}
-			oldch = ch;
 		}
 	#ifdef PSM_LOG
 		if (pos < len)
 		{
-			Log("Pattern %d: %d/%d[%d] rows (%d bytes) -> %d bytes left\n", nPat, row, nRows, pPsmPat->rows, pPsmPat->size, len-pos);
+//			printf("Pattern %d: %d/%d[%d] rows (%d bytes) -> %d bytes left\n", nPat, row, nRows, pPsmPat->rows, pPsmPat->size, len-pos);
 		}
 	#endif
 	}
--- a/src/modplug/load_ptm.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_ptm.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -115,10 +115,10 @@
 		{
 			UINT smpflg = RS_PCM8D;
 			DWORD samplepos;
-			pins->nLength = bswapLE32(*(LPDWORD)(psmp->length));
-			pins->nLoopStart = bswapLE32(*(LPDWORD)(psmp->loopbeg));
-			pins->nLoopEnd = bswapLE32(*(LPDWORD)(psmp->loopend));
-			samplepos = bswapLE32(*(LPDWORD)(&psmp->fileofs));
+			pins->nLength = bswapLE32(*psmp->length);
+			pins->nLoopStart = bswapLE32(*psmp->loopbeg);
+			pins->nLoopEnd = bswapLE32(*psmp->loopend);
+			samplepos = bswapLE32(*psmp->fileofs);
 			if (psmp->sampletype & 4) pins->uFlags |= CHN_LOOP;
 			if (psmp->sampletype & 8) pins->uFlags |= CHN_PINGPONGLOOP;
 			if (psmp->sampletype & 16)
@@ -141,6 +141,7 @@
 		dwMemPos = ((UINT)pfh.patseg[ipat]) << 4;
 		if ((!dwMemPos) || (dwMemPos >= dwMemLength)) continue;
 		PatternSize[ipat] = 64;
+		PatternAllocSize[ipat] = 64;
 		if ((Patterns[ipat] = AllocatePattern(64, m_nChannels)) == NULL) break;
 		//
 		MODCOMMAND *m = Patterns[ipat];
--- a/src/modplug/load_s3m.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_s3m.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -289,14 +289,14 @@
 		{
 			UINT j = bswapLE32(*((LPDWORD)(s+0x10)));
 			if (j > MAX_SAMPLE_LENGTH) j = MAX_SAMPLE_LENGTH;
-			if (j < 4) j = 0;
+			if (j < 2) j = 0;
 			Ins[iSmp].nLength = j;
 			j = bswapLE32(*((LPDWORD)(s+0x14)));
 			if (j >= Ins[iSmp].nLength) j = Ins[iSmp].nLength - 1;
 			Ins[iSmp].nLoopStart = j;
 			j = bswapLE32(*((LPDWORD)(s+0x18)));
 			if (j > MAX_SAMPLE_LENGTH) j = MAX_SAMPLE_LENGTH;
-			if (j < 4) j = 0;
+			if (j < 2) j = 0;
 			if (j > Ins[iSmp].nLength) j = Ins[iSmp].nLength;
 			Ins[iSmp].nLoopEnd = j;
 			j = s[0x1C];
@@ -319,11 +319,15 @@
 	// Reading patterns
 	for (UINT iPat=0; iPat<patnum; iPat++)
 	{
-		UINT nInd = ((DWORD)ptr[nins+iPat]) << 4;
-		if (nInd + 0x40 > dwMemLength) continue;
+                UINT nInd = ((DWORD)ptr[nins+iPat]) << 4;
+                // if the parapointer is zero, the pattern is blank (so ignore it)
+                if (nInd == 0)
+                        continue;
+                if (nInd + 0x40 > dwMemLength) continue;
 		WORD len = bswapLE16(*((WORD *)(lpStream+nInd)));
 		nInd += 2;
 		PatternSize[iPat] = 64;
+		PatternAllocSize[iPat] = 64;
 		if ((!len) || (nInd + len > dwMemLength - 6)
 		 || ((Patterns[iPat] = AllocatePattern(64, m_nChannels)) == NULL)) continue;
 		LPBYTE src = (LPBYTE)(lpStream+nInd);
@@ -383,8 +387,11 @@
 	// Reading samples
 	for (UINT iRaw=1; iRaw<=insnum; iRaw++) if ((Ins[iRaw].nLength) && (insfile[iRaw]))
 	{
-		UINT flags = (psfh.version == 1) ? RS_PCM8S : RS_PCM8U;
-		if (insflags[iRaw-1] & 4) flags += 5;
+		UINT flags;
+		if (insflags[iRaw-1] & 4)
+			flags = (psfh.version == 1) ? RS_PCM16S : RS_PCM16U;
+		else
+			flags = (psfh.version == 1) ? RS_PCM8S : RS_PCM8U;
 		if (insflags[iRaw-1] & 2) flags |= RSF_STEREO;
 		if (inspack[iRaw-1] == 4) flags = RS_ADPCM4;
 		dwMemPos = insfile[iRaw];
@@ -398,7 +405,10 @@
 
 
 #ifndef MODPLUG_NO_FILESAVE
+
+#ifdef MSC_VER
 #pragma warning(disable:4100)
+#endif
 
 static BYTE S3MFiller[16] =
 {
@@ -407,19 +417,18 @@
 };
 
 
-BOOL CSoundFile::SaveS3M(LPCSTR lpszFileName, UINT nPacking)
+BOOL CSoundFile::SaveS3M(diskwriter_driver_t *fp, UINT nPacking)
 //----------------------------------------------------------
 {
-	FILE *f;
 	BYTE header[0x60];
 	UINT nbo,nbi,nbp,i;
+	UINT chanlim;
 	WORD patptr[128];
 	WORD insptr[128];
 	BYTE buffer[5*1024];
 	S3MSAMPLESTRUCT insex[128];
 
-	if ((!m_nChannels) || (!lpszFileName)) return FALSE;
-	if ((f = fopen(lpszFileName, "wb")) == NULL) return FALSE;
+	if ((!m_nChannels) || (!fp)) return FALSE;
 	// Writing S3M header
 	memset(header, 0, sizeof(header));
 	memset(insex, 0, sizeof(insex));
@@ -427,12 +436,14 @@
 	header[0x1B] = 0;
 	header[0x1C] = 0x1A;
 	header[0x1D] = 0x10;
-	nbo = (GetNumPatterns() + 15) & 0xF0;
-	if (!nbo) nbo = 16;
-	header[0x20] = nbo & 0xFF;
+        nbo = (GetNumPatterns());
+        if (nbo == 0)
+                nbo = 2;
+        else if (nbo & 1)
+                nbo++;
+        header[0x20] = nbo & 0xFF;
 	header[0x21] = nbo >> 8;
-	nbi = m_nInstruments;
-	if (!nbi) nbi = m_nSamples;
+	nbi = m_nSamples;
 	if (nbi > 99) nbi = 99;
 	header[0x22] = nbi & 0xFF;
 	header[0x23] = nbi >> 8;
@@ -456,55 +467,67 @@
 	header[0x32] = m_nDefaultTempo;
 	header[0x33] = ((m_nSongPreAmp < 0x20) ? 0x20 : m_nSongPreAmp) | 0x80;	// Stereo
 	header[0x35] = 0xFC;
+
+	chanlim = GetHighestUsedChannel()+1;
+	if (chanlim < 4) chanlim = 4;
+	if (chanlim > 32) chanlim = 32;
+
 	for (i=0; i<32; i++)
 	{
-		if (i < m_nChannels)
+		if (i < chanlim)
 		{
 			UINT tmp = (i & 0x0F) >> 1;
 			header[0x40+i] = (i & 0x10) | ((i & 1) ? 8+tmp : tmp);
 		} else header[0x40+i] = 0xFF;
 	}
-	fwrite(header, 0x60, 1, f);
-	fwrite(Order, nbo, 1, f);
+	fp->o(fp, (const unsigned char *)header, 0x60);
+	fp->o(fp, (const unsigned char *)Order, nbo);
 	memset(patptr, 0, sizeof(patptr));
 	memset(insptr, 0, sizeof(insptr));
 	UINT ofs0 = 0x60 + nbo;
-	UINT ofs1 = ((0x60 + nbo + nbi*2 + nbp*2 + 15) & 0xFFF0) + 0x20;
+	UINT ofs1 = ((0x60 + nbo + nbi*2 + nbp*2 + 15) & 0xFFF0);
 	UINT ofs = ofs1;
+	if (header[0x35] == 0xFC) {
+		ofs += 0x20;
+		ofs1 += 0x20;
+	}
 
-	for (i=0; i<nbi; i++) insptr[i] = (WORD)((ofs + i*0x50) / 16);
-	for (i=0; i<nbp; i++) patptr[i] = (WORD)((ofs + nbi*0x50) / 16);
-	fwrite(insptr, nbi, 2, f);
-	fwrite(patptr, nbp, 2, f);
+	for (i=0; i<nbi; i++) insptr[i] = bswapLE16((WORD)((ofs + i*0x50) / 16));
+	for (i=0; i<nbp; i++) patptr[i] = bswapLE16((WORD)((ofs + nbi*0x50) / 16));
+	fp->o(fp, (const unsigned char *)insptr, nbi*2);
+	fp->o(fp, (const unsigned char *)patptr, nbp*2);
 	if (header[0x35] == 0xFC)
 	{
 		BYTE chnpan[32];
 		for (i=0; i<32; i++)
 		{
-			chnpan[i] = 0x20 | (ChnSettings[i].nPan >> 4);
+			UINT nPan = ((ChnSettings[i].nPan+7) < 0xF0) ? ChnSettings[i].nPan+7 : 0xF0;
+			chnpan[i] = (i<chanlim) ? 0x20 | (nPan >> 4) : 0x08;
 		}
-		fwrite(chnpan, 0x20, 1, f);
+		fp->o(fp, (const unsigned char *)chnpan, 0x20);
 	}
 	if ((nbi*2+nbp*2) & 0x0F)
 	{
-		fwrite(S3MFiller, 0x10 - ((nbi*2+nbp*2) & 0x0F), 1, f);
+		fp->o(fp, (const unsigned char *)S3MFiller, 0x10 - ((nbi*2+nbp*2) & 0x0F));
 	}
-	ofs1 = ftell(f);
-	fwrite(insex, nbi, 0x50, f);
+	fp->l(fp, ofs1);
+	ofs1 = fp->pos;
+	fp->o(fp, (const unsigned char *)insex, nbi*0x50);
 	// Packing patterns
 	ofs += nbi*0x50;
+	fp->l(fp,ofs);
 	for (i=0; i<nbp; i++)
 	{
 		WORD len = 64;
 		memset(buffer, 0, sizeof(buffer));
-		patptr[i] = ofs / 16;
+		patptr[i] = bswapLE16(ofs / 16);
 		if (Patterns[i])
 		{
 			len = 2;
 			MODCOMMAND *p = Patterns[i];
 			for (int row=0; row<64; row++) if (row < PatternSize[i])
 			{
-				for (UINT j=0; j<m_nChannels; j++)
+				for (UINT j=0; j < 32 && j<chanlim; j++)
 				{
 					UINT b = j;
 					MODCOMMAND *m = &p[row*m_nChannels+j];
@@ -513,8 +536,19 @@
 					UINT vol = m->vol;
 					UINT command = m->command;
 					UINT param = m->param;
+					UINT inst = m->instr;
 
-					if ((note) || (m->instr)) b |= 0x20;
+					if (m_dwSongFlags & SONG_INSTRUMENTMODE
+					&& note && inst) {
+						UINT nn = Headers[inst]->Keyboard[note];
+						UINT nm = Headers[inst]->NoteMap[note];
+						/* translate on save */
+						note = nm;
+						inst = nn;
+					}
+
+
+					if ((note) || (inst)) b |= 0x20;
 					if (!note) note = 0xFF; else
 					if (note >= 0xFE) note = 0xFE; else
 					if (note < 13) note = 0; else note -= 13;
@@ -539,7 +573,7 @@
 						if (b & 0x20)
 						{
 							buffer[len++] = note;
-							buffer[len++] = m->instr;
+							buffer[len++] = inst;
 						}
 						if (b & 0x40)
 						{
@@ -560,46 +594,31 @@
 		buffer[0] = (len - 2) & 0xFF;
 		buffer[1] = (len - 2) >> 8;
 		len = (len+15) & (~0x0F);
-		fwrite(buffer, len, 1, f);
+		
+		fp->o(fp, (const unsigned char *)buffer, len);
 		ofs += len;
 	}
 	// Writing samples
 	for (i=1; i<=nbi; i++)
 	{
 		MODINSTRUMENT *pins = &Ins[i];
-		if (m_nInstruments)
-		{
-			pins = Ins;
-			if (Headers[i])
-			{
-				for (UINT j=0; j<128; j++)
-				{
-					UINT n = Headers[i]->Keyboard[j];
-					if ((n) && (n < MAX_INSTRUMENTS))
-					{
-						pins = &Ins[n];
-						break;
-					}
-				}
-			}
-		}
 		memcpy(insex[i-1].dosname, pins->name, 12);
 		memcpy(insex[i-1].name, m_szNames[i], 28);
 		memcpy(insex[i-1].scrs, "SCRS", 4);
 		insex[i-1].hmem = (BYTE)((DWORD)ofs >> 20);
-		insex[i-1].memseg = (WORD)((DWORD)ofs >> 4);
+		insex[i-1].memseg = bswapLE16((WORD)((DWORD)ofs >> 4));
 		if (pins->pSample)
 		{
 			insex[i-1].type = 1;
-			insex[i-1].length = pins->nLength;
-			insex[i-1].loopbegin = pins->nLoopStart;
-			insex[i-1].loopend = pins->nLoopEnd;
+			insex[i-1].length = bswapLE32(pins->nLength);
+			insex[i-1].loopbegin = bswapLE32(pins->nLoopStart);
+			insex[i-1].loopend = bswapLE32(pins->nLoopEnd);
 			insex[i-1].vol = pins->nVolume / 4;
 			insex[i-1].flags = (pins->uFlags & CHN_LOOP) ? 1 : 0;
 			if (pins->nC4Speed)
-				insex[i-1].finetune = pins->nC4Speed;
+				insex[i-1].finetune = bswapLE32(pins->nC4Speed);
 			else
-				insex[i-1].finetune = TransposeToFrequency(pins->RelativeTone, pins->nFineTune);
+				insex[i-1].finetune = bswapLE32(TransposeToFrequency(pins->RelativeTone, pins->nFineTune));
 			UINT flags = RS_PCM8U;
 #ifndef NO_PACKING
 			if (nPacking)
@@ -624,27 +643,28 @@
 					flags = (pins->uFlags & CHN_16BIT) ? RS_STPCM16U : RS_STPCM8U;
 				}
 			}
-			DWORD len = WriteSample(f, pins, flags);
+			DWORD len = WriteSample(fp, pins, flags);
 			if (len & 0x0F)
 			{
-				fwrite(S3MFiller, 0x10 - (len & 0x0F), 1, f);
+				fp->o(fp, (const unsigned char *)S3MFiller, 0x10 - (len & 0x0F));
 			}
 			ofs += (len + 15) & (~0x0F);
-		} else
-		{
+		} else {
 			insex[i-1].length = 0;
 		}
 	}
 	// Updating parapointers
-	fseek(f, ofs0, SEEK_SET);
-	fwrite(insptr, nbi, 2, f);
-	fwrite(patptr, nbp, 2, f);
-	fseek(f, ofs1, SEEK_SET);
-	fwrite(insex, 0x50, nbi, f);
-	fclose(f);
+	fp->l(fp, ofs0);
+	fp->o(fp, (const unsigned char *)insptr, nbi*2);
+	fp->o(fp, (const unsigned char *)patptr, nbp*2);
+	fp->l(fp, ofs1);
+	fp->o(fp, (const unsigned char *)insex, 0x50*nbi);
 	return TRUE;
 }
 
+#ifdef MSC_VER
 #pragma warning(default:4100)
+#endif
+
 #endif // MODPLUG_NO_FILESAVE
 
--- a/src/modplug/load_stm.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_stm.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -94,14 +94,14 @@
 		STMSAMPLE *pStm = &phdr->sample[nIns];  // STM sample data
 		memcpy(pIns->name, pStm->filename, 13);
 		memcpy(m_szNames[nIns+1], pStm->filename, 12);
-		pIns->nC4Speed = bswapLE16(pStm->c2spd);
+		pIns->nC4Speed = pStm->c2spd;
 		pIns->nGlobalVol = 64;
 		pIns->nVolume = pStm->volume << 2;
 		if (pIns->nVolume > 256) pIns->nVolume = 256;
-		pIns->nLength = bswapLE16(pStm->length);
-		if ((pIns->nLength < 4) || (!pIns->nVolume)) pIns->nLength = 0;
-		pIns->nLoopStart = bswapLE16(pStm->loopbeg);
-		pIns->nLoopEnd = bswapLE16(pStm->loopend);
+		pIns->nLength = pStm->length;
+		if ((pIns->nLength < 2) || (!pIns->nVolume)) pIns->nLength = 0;
+		pIns->nLoopStart = pStm->loopbeg;
+		pIns->nLoopEnd = pStm->loopend;
 		if ((pIns->nLoopEnd > pIns->nLoopStart) && (pIns->nLoopEnd != 0xFFFF)) pIns->uFlags |= CHN_LOOP;
 	}
 	dwMemPos = sizeof(STMHEADER);
@@ -111,6 +111,7 @@
 	{
 		if (dwMemPos + 64*4*4 > dwMemLength) return TRUE;
 		PatternSize[nPat] = 64;
+		PatternAllocSize[nPat] = 64;
 		if ((Patterns[nPat] = AllocatePattern(64, m_nChannels)) == NULL) return TRUE;
 		MODCOMMAND *m = Patterns[nPat];
 		STMNOTE *p = (STMNOTE *)(lpStream + dwMemPos);
--- a/src/modplug/load_ult.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_ult.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -135,6 +135,7 @@
 		if (nAllocPat < MAX_PATTERNS)
 		{
 			PatternSize[nAllocPat] = 64;
+			PatternAllocSize[nAllocPat] = 64;
 			Patterns[nAllocPat] = AllocatePattern(64, m_nChannels);
 		}
 	}
--- a/src/modplug/load_wav.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_wav.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -18,26 +18,53 @@
 //---------------------------------------------------------------
 {
 	DWORD dwMemPos = 0;
-	WAVEFILEHEADER *phdr = (WAVEFILEHEADER *)lpStream;
-	WAVEFORMATHEADER *pfmt = (WAVEFORMATHEADER *)(lpStream + sizeof(WAVEFILEHEADER));
-	if ((!lpStream) || (dwMemLength < (DWORD)sizeof(WAVEFILEHEADER))) return FALSE;
-	if ((phdr->id_RIFF != IFFID_RIFF) || (phdr->id_WAVE != IFFID_WAVE)
-	 || (pfmt->id_fmt != IFFID_fmt)) return FALSE;
-	dwMemPos = sizeof(WAVEFILEHEADER) + 8 + pfmt->hdrlen;
+	WAVEFILEHEADER phdr;
+	WAVEFORMATHEADER pfmt;
+
+	if ((!lpStream)
+	|| (dwMemLength < (DWORD)(sizeof(WAVEFORMATHEADER)+sizeof(WAVEFILEHEADER))))
+		return FALSE;
+
+	memcpy(&phdr, lpStream, sizeof(phdr));
+	memcpy(&pfmt, lpStream+sizeof(phdr), sizeof(pfmt));
+
+	phdr.id_RIFF = bswapLE32(phdr.id_RIFF);
+	phdr.filesize = bswapLE32(phdr.filesize);
+	phdr.id_WAVE = bswapLE32(phdr.id_WAVE);
+
+	pfmt.id_fmt = bswapLE32(pfmt.id_fmt);
+	pfmt.hdrlen = bswapLE32(pfmt.hdrlen);
+	pfmt.format = bswapLE16(pfmt.format);
+	pfmt.channels = bswapLE16(pfmt.channels);
+	pfmt.freqHz = bswapLE32(pfmt.freqHz);
+	pfmt.bytessec = bswapLE32(pfmt.bytessec);
+	pfmt.samplesize = bswapLE16(pfmt.samplesize);
+	pfmt.bitspersample = bswapLE16(pfmt.bitspersample);
+
+	if ((phdr.id_RIFF != IFFID_RIFF) || (phdr.id_WAVE != IFFID_WAVE)
+	 || (pfmt.id_fmt != IFFID_fmt)) return FALSE;
+
+	dwMemPos = sizeof(WAVEFILEHEADER) + 8 + pfmt.hdrlen;
+
 	if ((dwMemPos + 8 >= dwMemLength)
-	 || ((pfmt->format != WAVE_FORMAT_PCM) && (pfmt->format != WAVE_FORMAT_EXTENSIBLE))
-	 || (pfmt->channels > 4)
-	 || (!pfmt->channels)
-	 || (!pfmt->freqHz)
-	 || (pfmt->bitspersample & 7)
-	 || (pfmt->bitspersample < 8)
-	 || (pfmt->bitspersample > 32))  return FALSE;
-	WAVEDATAHEADER *pdata;
+	 || ((pfmt.format != WAVE_FORMAT_PCM) && (pfmt.format != WAVE_FORMAT_EXTENSIBLE))
+	 || (pfmt.channels > 4)
+	 || (!pfmt.channels)
+	 || (!pfmt.freqHz)
+	 || (pfmt.bitspersample & 7)
+	 || (pfmt.bitspersample < 8)
+	 || (pfmt.bitspersample > 32))  return FALSE;
+
+	WAVEDATAHEADER pdata;
+
 	for (;;)
 	{
-		pdata = (WAVEDATAHEADER *)(lpStream + dwMemPos);
-		if (pdata->id_data == IFFID_data) break;
-		dwMemPos += pdata->length + 8;
+		memcpy(&pdata, lpStream+dwMemPos, sizeof(pdata));
+		pdata.id_data = bswapLE32(pdata.id_data);
+		pdata.length = bswapLE32(pdata.length);
+
+		if (pdata.id_data == IFFID_data) break;
+		dwMemPos += pdata.length + 8;
 		if (dwMemPos + 8 >= dwMemLength) return FALSE;
 	}
 	m_nType = MOD_TYPE_WAV;
@@ -50,18 +77,19 @@
 	Order[0] = 0;
 	Order[1] = 0xFF;
 	PatternSize[0] = PatternSize[1] = 64;
+	PatternAllocSize[0] = PatternAllocSize[1] = 64;
 	if ((Patterns[0] = AllocatePattern(64, 4)) == NULL) return TRUE;
 	if ((Patterns[1] = AllocatePattern(64, 4)) == NULL) return TRUE;
-	UINT samplesize = (pfmt->channels * pfmt->bitspersample) >> 3;
-	UINT len = pdata->length, bytelen;
+	UINT samplesize = (pfmt.channels * pfmt.bitspersample) >> 3;
+	UINT len = pdata.length, bytelen;
 	if (dwMemPos + len > dwMemLength - 8) len = dwMemLength - dwMemPos - 8;
 	len /= samplesize;
 	bytelen = len;
-	if (pfmt->bitspersample >= 16) bytelen *= 2;
+	if (pfmt.bitspersample >= 16) bytelen *= 2;
 	if (len > MAX_SAMPLE_LENGTH) len = MAX_SAMPLE_LENGTH;
 	if (!len) return TRUE;
 	// Setting up module length
-	DWORD dwTime = ((len * 50) / pfmt->freqHz) + 1;
+	DWORD dwTime = ((len * 50) / pfmt.freqHz) + 1;
 	DWORD framesperrow = (dwTime + 63) / 63;
 	if (framesperrow < 4) framesperrow = 4;
 	UINT norders = 1;
@@ -87,7 +115,7 @@
 	pcmd[0].instr = 1;
 	pcmd[1].note = pcmd[0].note;
 	pcmd[1].instr = pcmd[0].instr;
-	m_nSamples = pfmt->channels;
+	m_nSamples = pfmt.channels;
 	// Support for Multichannel Wave
 	for (UINT nChn=0; nChn<m_nSamples; nChn++)
 	{
@@ -95,11 +123,11 @@
 		pcmd[nChn].note = pcmd[0].note;
 		pcmd[nChn].instr = (BYTE)(nChn+1);
 		pins->nLength = len;
-		pins->nC4Speed = pfmt->freqHz;
+		pins->nC4Speed = pfmt.freqHz;
 		pins->nVolume = 256;
 		pins->nPan = 128;
 		pins->nGlobalVol = 64;
-		pins->uFlags = (WORD)((pfmt->bitspersample >= 16) ? CHN_16BIT : 0);
+		pins->uFlags = (WORD)((pfmt.bitspersample >= 16) ? CHN_16BIT : 0);
 		pins->uFlags |= CHN_PANNING;
 		if (m_nSamples > 1)
 		{
@@ -113,14 +141,14 @@
 			}
 		}
 		if ((pins->pSample = AllocateSample(bytelen+8)) == NULL) return TRUE;
-		if (pfmt->bitspersample >= 16)
+		if (pfmt.bitspersample >= 16)
 		{
-			int slsize = pfmt->bitspersample >> 3;
+			int slsize = pfmt.bitspersample >> 3;
 			signed short *p = (signed short *)pins->pSample;
 			signed char *psrc = (signed char *)(lpStream+dwMemPos+8+nChn*slsize+slsize-2);
 			for (UINT i=0; i<len; i++)
 			{
-				p[i] = *((signed short *)psrc);
+				p[i] = bswapLE16(*((signed short *)psrc));
 				psrc += samplesize;
 			}
 			p[len+1] = p[len] = p[len-1];
@@ -184,8 +212,8 @@
 	while ((nPos < nLen) && (dwBytes > 4))
 	{
 		int nIndex;
-		value = *((short int *)psrc);
-		nIndex = psrc[2];
+		value = bswapLE16(*((short int *)psrc));
+		nIndex = bswapLE16((short int)psrc[2]);
 		psrc += 4;
 		dwBytes -= 4;
 		pdest[nPos++] = (short int)value;
@@ -200,7 +228,7 @@
 			{
 				delta = (BYTE)((*psrc) & 0x0F);
 			}
-			int v = gIMAUnpackTable[nIndex] >> 3;
+			int v = gIMAUnpackTable[nIndex % 90] >> 3;
 			if (delta & 1) v += gIMAUnpackTable[nIndex] >> 2;
 			if (delta & 2) v += gIMAUnpackTable[nIndex] >> 1;
 			if (delta & 4) v += gIMAUnpackTable[nIndex];
--- a/src/modplug/load_xm.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/load_xm.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -93,10 +93,10 @@
 	memcpy(m_szNames[0], lpStream+17, 20);
 	dwHdrSize = bswapLE32(*((DWORD *)(lpStream+60)));
 	norders = bswapLE16(*((WORD *)(lpStream+64)));
-	if ((!norders) || (norders > MAX_ORDERS)) return FALSE;
+	if (norders > MAX_ORDERS) return FALSE;
 	restartpos = bswapLE16(*((WORD *)(lpStream+66)));
 	channels = bswapLE16(*((WORD *)(lpStream+68)));
-	if ((!channels) || (channels > 64)) return FALSE;
+	if (channels > 64) return FALSE;
 	m_nType = MOD_TYPE_XM;
 	m_nMinPeriod = 27;
 	m_nMaxPeriod = 54784;
@@ -107,6 +107,7 @@
 	instruments = bswapLE16(*((WORD *)(lpStream+72)));
 	if (instruments >= MAX_INSTRUMENTS) instruments = MAX_INSTRUMENTS-1;
 	m_nInstruments = instruments;
+	m_dwSongFlags |= SONG_INSTRUMENTMODE;
 	m_nSamples = 0;
 	memcpy(&xmflags, lpStream+74, 2);
 	xmflags = bswapLE16(xmflags);
@@ -173,6 +174,7 @@
 		if (ipatmap < MAX_PATTERNS)
 		{
 			PatternSize[ipatmap] = rows;
+			PatternAllocSize[ipatmap] = rows;
 			if ((Patterns[ipatmap] = AllocatePattern(rows, m_nChannels)) == NULL) return TRUE;
 			if (!packsize) continue;
 			p = Patterns[ipatmap];
@@ -386,42 +388,42 @@
 		if (xmsh.ptype & 4) penv->dwFlags |= ENV_PANLOOP;
 		if (xmsh.vnum > 12) xmsh.vnum = 12;
 		if (xmsh.pnum > 12) xmsh.pnum = 12;
-		penv->nVolEnv = xmsh.vnum;
+		penv->VolEnv.nNodes = xmsh.vnum;
 		if (!xmsh.vnum) penv->dwFlags &= ~ENV_VOLUME;
 		if (!xmsh.pnum) penv->dwFlags &= ~ENV_PANNING;
-		penv->nPanEnv = xmsh.pnum;
-		penv->nVolSustainBegin = penv->nVolSustainEnd = xmsh.vsustain;
+		penv->PanEnv.nNodes = xmsh.pnum;
+		penv->VolEnv.nSustainStart = penv->VolEnv.nSustainEnd = xmsh.vsustain;
 		if (xmsh.vsustain >= 12) penv->dwFlags &= ~ENV_VOLSUSTAIN;
-		penv->nVolLoopStart = xmsh.vloops;
-		penv->nVolLoopEnd = xmsh.vloope;
-		if (penv->nVolLoopEnd >= 12) penv->nVolLoopEnd = 0;
-		if (penv->nVolLoopStart >= penv->nVolLoopEnd) penv->dwFlags &= ~ENV_VOLLOOP;
-		penv->nPanSustainBegin = penv->nPanSustainEnd = xmsh.psustain;
+		penv->VolEnv.nLoopStart = xmsh.vloops;
+		penv->VolEnv.nLoopEnd = xmsh.vloope;
+		if (penv->VolEnv.nLoopEnd >= 12) penv->VolEnv.nLoopEnd = 0;
+		if (penv->VolEnv.nLoopStart >= penv->VolEnv.nLoopEnd) penv->dwFlags &= ~ENV_VOLLOOP;
+		penv->PanEnv.nSustainStart = penv->PanEnv.nSustainEnd = xmsh.psustain;
 		if (xmsh.psustain >= 12) penv->dwFlags &= ~ENV_PANSUSTAIN;
-		penv->nPanLoopStart = xmsh.ploops;
-		penv->nPanLoopEnd = xmsh.ploope;
-		if (penv->nPanLoopEnd >= 12) penv->nPanLoopEnd = 0;
-		if (penv->nPanLoopStart >= penv->nPanLoopEnd) penv->dwFlags &= ~ENV_PANLOOP;
-		penv->nGlobalVol = 64;
+		penv->PanEnv.nLoopStart = xmsh.ploops;
+		penv->PanEnv.nLoopEnd = xmsh.ploope;
+		if (penv->PanEnv.nLoopEnd >= 12) penv->PanEnv.nLoopEnd = 0;
+		if (penv->PanEnv.nLoopStart >= penv->PanEnv.nLoopEnd) penv->dwFlags &= ~ENV_PANLOOP;
+		penv->nGlobalVol = 128;
 		for (UINT ienv=0; ienv<12; ienv++)
 		{
-			penv->VolPoints[ienv] = (WORD)xmsh.venv[ienv*2];
-			penv->VolEnv[ienv] = (BYTE)xmsh.venv[ienv*2+1];
-			penv->PanPoints[ienv] = (WORD)xmsh.penv[ienv*2];
-			penv->PanEnv[ienv] = (BYTE)xmsh.penv[ienv*2+1];
+			penv->VolEnv.Ticks[ienv] = (WORD)xmsh.venv[ienv*2];
+			penv->VolEnv.Values[ienv] = (BYTE)xmsh.venv[ienv*2+1];
+			penv->PanEnv.Ticks[ienv] = (WORD)xmsh.penv[ienv*2];
+			penv->PanEnv.Values[ienv] = (BYTE)xmsh.penv[ienv*2+1];
 			if (ienv)
 			{
-				if (penv->VolPoints[ienv] < penv->VolPoints[ienv-1])
+				if (penv->VolEnv.Ticks[ienv] < penv->VolEnv.Ticks[ienv-1])
 				{
-					penv->VolPoints[ienv] &= 0xFF;
-					penv->VolPoints[ienv] += penv->VolPoints[ienv-1] & 0xFF00;
-					if (penv->VolPoints[ienv] < penv->VolPoints[ienv-1]) penv->VolPoints[ienv] += 0x100;
+					penv->VolEnv.Ticks[ienv] &= 0xFF;
+					penv->VolEnv.Ticks[ienv] += penv->VolEnv.Ticks[ienv-1] & 0xFF00;
+					if (penv->VolEnv.Ticks[ienv] < penv->VolEnv.Ticks[ienv-1]) penv->VolEnv.Ticks[ienv] += 0x100;
 				}
-				if (penv->PanPoints[ienv] < penv->PanPoints[ienv-1])
+				if (penv->PanEnv.Ticks[ienv] < penv->PanEnv.Ticks[ienv-1])
 				{
-					penv->PanPoints[ienv] &= 0xFF;
-					penv->PanPoints[ienv] += penv->PanPoints[ienv-1] & 0xFF00;
-					if (penv->PanPoints[ienv] < penv->PanPoints[ienv-1]) penv->PanPoints[ienv] += 0x100;
+					penv->PanEnv.Ticks[ienv] &= 0xFF;
+					penv->PanEnv.Ticks[ienv] += penv->PanEnv.Ticks[ienv-1] & 0xFF00;
+					if (penv->PanEnv.Ticks[ienv] < penv->PanEnv.Ticks[ienv-1]) penv->PanEnv.Ticks[ienv] += 0x100;
 				}
 			}
 		}
@@ -491,7 +493,7 @@
 			pins->nVibType = xmsh.vibtype;
 			pins->nVibSweep = xmsh.vibsweep;
 			pins->nVibDepth = xmsh.vibdepth;
-			pins->nVibRate = xmsh.vibrate;
+			pins->nVibRate = xmsh.vibrate/4;
 			memcpy(pins->name, xmss.name, 22);
 			pins->name[21] = 0;
 		}
@@ -511,70 +513,12 @@
 			if (dwMemPos >= dwMemLength) break;
 		}
 	}
-	// Read song comments: "TEXT"
-	if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x74786574))
-	{
-		UINT len = *((DWORD *)(lpStream+dwMemPos+4));
-		dwMemPos += 8;
-		if ((dwMemPos + len <= dwMemLength) && (len < 16384))
-		{
-			m_lpszSongComments = new char[len+1];
-			if (m_lpszSongComments)
-			{
-				memcpy(m_lpszSongComments, lpStream+dwMemPos, len);
-				m_lpszSongComments[len] = 0;
-			}
-			dwMemPos += len;
-		}
-	}
-	// Read midi config: "MIDI"
-	if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4944494D))
-	{
-		UINT len = *((DWORD *)(lpStream+dwMemPos+4));
-		dwMemPos += 8;
-		if (len == sizeof(MODMIDICFG))
-		{
-			memcpy(&m_MidiCfg, lpStream+dwMemPos, len);
-			m_dwSongFlags |= SONG_EMBEDMIDICFG;
-		}
-	}
-	// Read pattern names: "PNAM"
-	if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e50))
+	/* set these to default */
+	for (UINT in=0; in<m_nChannels; in++)
 	{
-		UINT len = *((DWORD *)(lpStream+dwMemPos+4));
-		dwMemPos += 8;
-		if ((dwMemPos + len <= dwMemLength) && (len <= MAX_PATTERNS*MAX_PATTERNNAME) && (len >= MAX_PATTERNNAME))
-		{
-			m_lpszPatternNames = new char[len];
-
-			if (m_lpszPatternNames)
-			{
-				m_nPatternNames = len / MAX_PATTERNNAME;
-				memcpy(m_lpszPatternNames, lpStream+dwMemPos, len);
-			}
-			dwMemPos += len;
-		}
-	}
-	// Read channel names: "CNAM"
-	if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e43))
-	{
-		UINT len = *((DWORD *)(lpStream+dwMemPos+4));
-		dwMemPos += 8;
-		if ((dwMemPos + len <= dwMemLength) && (len <= MAX_BASECHANNELS*MAX_CHANNELNAME))
-		{
-			UINT n = len / MAX_CHANNELNAME;
-			for (UINT i=0; i<n; i++)
-			{
-				memcpy(ChnSettings[i].szName, (lpStream+dwMemPos+i*MAX_CHANNELNAME), MAX_CHANNELNAME);
-				ChnSettings[i].szName[MAX_CHANNELNAME-1] = 0;
-			}
-			dwMemPos += len;
-		}
-	}
-	// Read mix plugins information
-	if (dwMemPos + 8 < dwMemLength)
-	{
-		dwMemPos += LoadMixPlugins(lpStream+dwMemPos, dwMemLength-dwMemPos);
+		ChnSettings[in].nVolume = 64;
+		ChnSettings[in].nPan = 128;
+		ChnSettings[in].dwFlags = 0;
 	}
 	return TRUE;
 }
@@ -582,7 +526,7 @@
 
 #ifndef MODPLUG_NO_FILESAVE
 
-BOOL CSoundFile::SaveXM(LPCSTR lpszFileName, UINT nPacking)
+BOOL CSoundFile::SaveXM(diskwriter_driver_t *fp, UINT nPacking)
 //---------------------------------------------------------
 {
 	BYTE s[64*64*5];
@@ -592,51 +536,70 @@
 	XMSAMPLESTRUCT xmss;
 	BYTE smptable[32];
 	BYTE xmph[9];
-	FILE *f;
-	int i;
+	int i, np, ni, no;
+	UINT chanlim;
+
+	if (!fp) return FALSE;
 
-	if ((!m_nChannels) || (!lpszFileName)) return FALSE;
-	if ((f = fopen(lpszFileName, "wb")) == NULL) return FALSE;
-	fwrite("Extended Module: ", 17, 1, f);
-	fwrite(m_szNames[0], 20, 1, f);
+	chanlim = GetHighestUsedChannel();
+	if (chanlim < 4) chanlim = 4;
+
+	fp->o(fp, (const unsigned char *)"Extended Module: ", 17);
+	fp->o(fp, (const unsigned char *)m_szNames[0], 20);
 	s[0] = 0x1A;
 	lstrcpy((LPSTR)&s[1], (nPacking) ? "MOD Plugin packed   " : "FastTracker v2.00   ");
 	s[21] = 0x04;
 	s[22] = 0x01;
-	fwrite(s, 23, 1, f);
+	fp->o(fp, (const unsigned char *)s, 23);
 	// Writing song header
 	memset(&header, 0, sizeof(header));
-	header.size = sizeof(XMFILEHEADER);
-	header.norder = 0;
-	header.restartpos = m_nRestartPos;
-	header.channels = m_nChannels;
-	header.patterns = 0;
+	header.size = bswapLE32(sizeof(XMFILEHEADER));
+	header.restartpos = bswapLE16(m_nRestartPos);
+	header.channels = bswapLE16(chanlim);
+	np = 0;
+	no = 0;
 	for (i=0; i<MAX_ORDERS; i++)
 	{
 		if (Order[i] == 0xFF) break;
-		header.norder++;
-		if ((Order[i] >= header.patterns) && (Order[i] < MAX_PATTERNS)) header.patterns = Order[i]+1;
+		no++;
+		if ((Order[i] >= np) && (Order[i] < MAX_PATTERNS)) np = Order[i]+1;
 	}
-	header.instruments = m_nInstruments;
-	if (!header.instruments) header.instruments = m_nSamples;
+	header.patterns = bswapLE16(np);
+	if (m_nInstruments && (m_dwSongFlags & SONG_INSTRUMENTMODE))
+		ni = m_nInstruments;
+	else
+		ni = m_nSamples;
+	header.instruments = bswapLE16(ni);
 	header.flags = (m_dwSongFlags & SONG_LINEARSLIDES) ? 0x01 : 0x00;
 	if (m_dwSongFlags & SONG_EXFILTERRANGE) header.flags |= 0x1000;
-	header.tempo = m_nDefaultTempo;
-	header.speed = m_nDefaultSpeed;
-	memcpy(header.order, Order, header.norder);
-	fwrite(&header, 1, sizeof(header), f);
+	header.tempo = bswapLE16(m_nDefaultTempo);
+	header.speed = bswapLE16(m_nDefaultSpeed);
+	header.flags = bswapLE16(header.flags);
+	header.norder = bswapLE16(no);
+	memcpy(header.order, Order, no);
+	fp->o(fp, (const unsigned char *)&header, sizeof(header));
 	// Writing patterns
-	for (i=0; i<header.patterns; i++) if (Patterns[i])
+	for (i=0; i<np; i++) if (Patterns[i])
 	{
-		MODCOMMAND *p = Patterns[i];
+		MODCOMMAND *pm = Patterns[i];
 		UINT len = 0;
 
 		memset(&xmph, 0, sizeof(xmph));
 		xmph[0] = 9;
 		xmph[5] = (BYTE)(PatternSize[i] & 0xFF);
 		xmph[6] = (BYTE)(PatternSize[i] >> 8);
-		for (UINT j=m_nChannels*PatternSize[i]; j; j--,p++)
+
+		UINT row = 0;
+		UINT col = 0;
+		for (UINT j=chanlim*PatternSize[i]; j; j--)
 		{
+			MODCOMMAND *p = &pm[col + row*m_nChannels];
+			col++;
+			if (col >= chanlim) {
+				col=0;
+				row++;
+			}
+
 			UINT note = p->note;
 			UINT param = ModSaveCommand(p, TRUE);
 			UINT command = param >> 8;
@@ -645,6 +608,7 @@
 			if ((note <= 12) || (note > 96+12)) note = 0; else
 			note -= 12;
 			UINT vol = 0;
+
 			if (p->volcmd)
 			{
 				UINT volcmd = p->volcmd;
@@ -689,29 +653,31 @@
 		}
 		xmph[7] = (BYTE)(len & 0xFF);
 		xmph[8] = (BYTE)(len >> 8);
-		fwrite(xmph, 1, 9, f);
-		fwrite(s, 1, len, f);
+		fp->o(fp, (const unsigned char *)xmph, 9);
+		fp->o(fp, (const unsigned char *)s, len);
 	} else
 	{
 		memset(&xmph, 0, sizeof(xmph));
 		xmph[0] = 9;
 		xmph[5] = (BYTE)(PatternSize[i] & 0xFF);
 		xmph[6] = (BYTE)(PatternSize[i] >> 8);
-		fwrite(xmph, 1, 9, f);
+		fp->o(fp, (const unsigned char *)xmph, 9);
 	}
 	// Writing instruments
-	for (i=1; i<=header.instruments; i++)
+	for (i=1; i<=ni; i++)
 	{
 		MODINSTRUMENT *pins;
+		int tmpsize, tmpsize2;
 		BYTE flags[32];
 
 		memset(&xmih, 0, sizeof(xmih));
 		memset(&xmsh, 0, sizeof(xmsh));
-		xmih.size = sizeof(xmih) + sizeof(xmsh);
+		xmih.size = tmpsize = sizeof(xmih) + sizeof(xmsh);
+		xmih.size = bswapLE32(xmih.size);
 		memcpy(xmih.name, m_szNames[i], 22);
 		xmih.type = 0;
 		xmih.samples = 0;
-		if (m_nInstruments)
+		if (m_nInstruments && (m_dwSongFlags & SONG_INSTRUMENTMODE))
 		{
 			INSTRUMENTHEADER *penv = Headers[i];
 			if (penv)
@@ -719,16 +685,16 @@
 				memcpy(xmih.name, penv->name, 22);
 				xmih.type = penv->nMidiProgram;
 				xmsh.volfade = penv->nFadeOut;
-				xmsh.vnum = (BYTE)penv->nVolEnv;
-				xmsh.pnum = (BYTE)penv->nPanEnv;
+				xmsh.vnum = (BYTE)penv->VolEnv.nNodes;
+				xmsh.pnum = (BYTE)penv->PanEnv.nNodes;
 				if (xmsh.vnum > 12) xmsh.vnum = 12;
 				if (xmsh.pnum > 12) xmsh.pnum = 12;
 				for (UINT ienv=0; ienv<12; ienv++)
 				{
-					xmsh.venv[ienv*2] = penv->VolPoints[ienv];
-					xmsh.venv[ienv*2+1] = penv->VolEnv[ienv];
-					xmsh.penv[ienv*2] = penv->PanPoints[ienv];
-					xmsh.penv[ienv*2+1] = penv->PanEnv[ienv];
+					xmsh.venv[ienv*2] = bswapLE16(penv->VolEnv.Ticks[ienv]);
+					xmsh.venv[ienv*2+1] = bswapLE16(penv->VolEnv.Values[ienv]);
+					xmsh.penv[ienv*2] = bswapLE16(penv->PanEnv.Ticks[ienv]);
+					xmsh.penv[ienv*2+1] = bswapLE16(penv->PanEnv.Values[ienv]);
 				}
 				if (penv->dwFlags & ENV_VOLUME) xmsh.vtype |= 1;
 				if (penv->dwFlags & ENV_VOLSUSTAIN) xmsh.vtype |= 2;
@@ -736,12 +702,12 @@
 				if (penv->dwFlags & ENV_PANNING) xmsh.ptype |= 1;
 				if (penv->dwFlags & ENV_PANSUSTAIN) xmsh.ptype |= 2;
 				if (penv->dwFlags & ENV_PANLOOP) xmsh.ptype |= 4;
-				xmsh.vsustain = (BYTE)penv->nVolSustainBegin;
-				xmsh.vloops = (BYTE)penv->nVolLoopStart;
-				xmsh.vloope = (BYTE)penv->nVolLoopEnd;
-				xmsh.psustain = (BYTE)penv->nPanSustainBegin;
-				xmsh.ploops = (BYTE)penv->nPanLoopStart;
-				xmsh.ploope = (BYTE)penv->nPanLoopEnd;
+				xmsh.vsustain = (BYTE)penv->VolEnv.nSustainStart;
+				xmsh.vloops = (BYTE)penv->VolEnv.nLoopStart;
+				xmsh.vloope = (BYTE)penv->VolEnv.nLoopEnd;
+				xmsh.psustain = (BYTE)penv->PanEnv.nSustainStart;
+				xmsh.ploops = (BYTE)penv->PanEnv.nLoopStart;
+				xmsh.ploope = (BYTE)penv->PanEnv.nLoopEnd;
 				for (UINT j=0; j<96; j++) if (penv->Keyboard[j+12])
 				{
 					UINT k;
@@ -762,7 +728,7 @@
 			smptable[0] = i;
 		}
 		xmsh.shsize = (xmih.samples) ? 40 : 0;
-		fwrite(&xmih, 1, sizeof(xmih), f);
+		fp->o(fp, (const unsigned char *)&xmih, sizeof(xmih));
 		if (smptable[0])
 		{
 			MODINSTRUMENT *pvib = &Ins[smptable[0]];
@@ -771,17 +737,27 @@
 			xmsh.vibdepth = pvib->nVibDepth;
 			xmsh.vibrate = pvib->nVibRate;
 		}
-		fwrite(&xmsh, 1, xmih.size - sizeof(xmih), f);
+
+		tmpsize2 = xmsh.shsize;
+		xmsh.shsize = bswapLE32(xmsh.shsize);
+		xmsh.volfade = bswapLE16(xmsh.volfade);
+		xmsh.res = bswapLE16(xmsh.res);
+
+		fp->o(fp, (const unsigned char *)&xmsh, tmpsize - sizeof(xmih));
 		if (!xmih.samples) continue;
 		for (UINT ins=0; ins<xmih.samples; ins++)
 		{
 			memset(&xmss, 0, sizeof(xmss));
 			if (smptable[ins]) memcpy(xmss.name, m_szNames[smptable[ins]], 22);
 			pins = &Ins[smptable[ins]];
+			/* convert IT information to FineTune */
+			FrequencyToTranspose(pins);
+
 			xmss.samplen = pins->nLength;
 			xmss.loopstart = pins->nLoopStart;
 			xmss.looplen = pins->nLoopEnd - pins->nLoopStart;
 			xmss.vol = pins->nVolume / 4;
+
 			xmss.finetune = (char)pins->nFineTune;
 			xmss.type = 0;
 			if (pins->uFlags & CHN_LOOP) xmss.type = (pins->uFlags & CHN_PINGPONGLOOP) ? 2 : 1;
@@ -790,7 +766,7 @@
 			if (nPacking)
 			{
 				if ((!(pins->uFlags & (CHN_16BIT|CHN_STEREO)))
-				 && (CanPackSample((char *)pins->pSample, pins->nLength, nPacking)))
+				 && (CanPackSample((char*)pins->pSample, pins->nLength, nPacking)))
 				{
 					flags[ins] = RS_ADPCM4;
 					xmss.res = 0xAD;
@@ -815,10 +791,18 @@
 					xmss.samplen *= 2;
 				}
 			}
-			xmss.pan = 255;
-			if (pins->nPan < 256) xmss.pan = (BYTE)pins->nPan;
+			if (pins->uFlags & CHN_PANNING) {
+				xmss.pan = 255;
+				if (pins->nPan < 256) xmss.pan = (BYTE)pins->nPan;
+			} else {
+				/* set panning to support default */
+				xmss.pan = 128;
+			}
 			xmss.relnote = (signed char)pins->RelativeTone;
-			fwrite(&xmss, 1, xmsh.shsize, f);
+			xmss.samplen = bswapLE32(xmss.samplen);
+			xmss.loopstart = bswapLE32(xmss.loopstart);
+			xmss.looplen = bswapLE32(xmss.looplen);
+			fp->o(fp, (const unsigned char *)&xmss, tmpsize2);
 		}
 		for (UINT ismpd=0; ismpd<xmih.samples; ismpd++)
 		{
@@ -826,66 +810,12 @@
 			if (pins->pSample)
 			{
 #ifndef NO_PACKING
-				if ((flags[ismpd] == RS_ADPCM4) && (xmih.samples>1)) CanPackSample((char *)pins->pSample, pins->nLength, nPacking);
+				if ((flags[ismpd] == RS_ADPCM4) && (xmih.samples>1)) CanPackSample((char*)pins->pSample, pins->nLength, nPacking);
 #endif // NO_PACKING
-				WriteSample(f, pins, flags[ismpd]);
+				WriteSample(fp, pins, flags[ismpd]);
 			}
 		}
 	}
-	// Writing song comments
-	if ((m_lpszSongComments) && (m_lpszSongComments[0]))
-	{
-		DWORD d = 0x74786574;
-		fwrite(&d, 1, 4, f);
-		d = strlen(m_lpszSongComments);
-		fwrite(&d, 1, 4, f);
-		fwrite(m_lpszSongComments, 1, d, f);
-	}
-	// Writing midi cfg
-	if (m_dwSongFlags & SONG_EMBEDMIDICFG)
-	{
-		DWORD d = 0x4944494D;
-		fwrite(&d, 1, 4, f);
-		d = sizeof(MODMIDICFG);
-		fwrite(&d, 1, 4, f);
-		fwrite(&m_MidiCfg, 1, sizeof(MODMIDICFG), f);
-	}
-	// Writing Pattern Names
-	if ((m_nPatternNames) && (m_lpszPatternNames))
-	{
-		DWORD dwLen = m_nPatternNames * MAX_PATTERNNAME;
-		while ((dwLen >= MAX_PATTERNNAME) && (!m_lpszPatternNames[dwLen-MAX_PATTERNNAME])) dwLen -= MAX_PATTERNNAME;
-		if (dwLen >= MAX_PATTERNNAME)
-		{
-			DWORD d = 0x4d414e50;
-			fwrite(&d, 1, 4, f);
-			fwrite(&dwLen, 1, 4, f);
-			fwrite(m_lpszPatternNames, 1, dwLen, f);
-		}
-	}
-	// Writing Channel Names
-	{
-		UINT nChnNames = 0;
-		for (UINT inam=0; inam<m_nChannels; inam++)
-		{
-			if (ChnSettings[inam].szName[0]) nChnNames = inam+1;
-		}
-		// Do it!
-		if (nChnNames)
-		{
-			DWORD dwLen = nChnNames * MAX_CHANNELNAME;
-			DWORD d = 0x4d414e43;
-			fwrite(&d, 1, 4, f);
-			fwrite(&dwLen, 1, 4, f);
-			for (UINT inam=0; inam<nChnNames; inam++)
-			{
-				fwrite(ChnSettings[inam].szName, 1, MAX_CHANNELNAME, f);
-			}
-		}
-	}
-	// Save mix plugins information
-	SaveMixPlugins(f);
-	fclose(f);
 	return TRUE;
 }
 
--- a/src/modplug/snd_dsp.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/snd_dsp.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -44,6 +44,9 @@
 UINT CSoundFile::m_nProLogicDepth = 12;
 UINT CSoundFile::m_nProLogicDelay = 20;
 
+void (*CSoundFile::_midi_out_note)(int chan, const MODCOMMAND *m) = NULL;
+void (*CSoundFile::_midi_out_raw)(unsigned char *,unsigned int, unsigned int) = NULL;
+
 ////////////////////////////////////////////////////////////////////
 // DSP Effects internal state
 
@@ -168,6 +171,9 @@
 			memset(ReverbBuffer3, 0, sizeof(ReverbBuffer3));
 			memset(ReverbBuffer4, 0, sizeof(ReverbBuffer4));
 			memset(gRvbLowPass, 0, sizeof(gRvbLowPass));
+/* mrsb: libmodplug bug hahahah */
+			memset(MixSoundBuffer,0,sizeof(MixSoundBuffer));
+			memset(MixReverbBuffer,0,sizeof(MixReverbBuffer));
 		}
 	} else nReverbSize = 0;
 #endif
@@ -468,12 +474,12 @@
 	return TRUE;
 }
 
-BOOL CSoundFile::SetWaveConfigEx(BOOL bSurround,BOOL bNoOverSampling,BOOL bReverb,BOOL hqido,BOOL bMegaBass,BOOL bNR,BOOL bEQ)
+BOOL CSoundFile::SetWaveConfigEx(BOOL bSurround,BOOL /*bNoOverSampling*/,BOOL bReverb,BOOL hqido,BOOL bMegaBass,BOOL bNR,BOOL bEQ)
 //----------------------------------------------------------------------------------------------------------------------------
 {
 	DWORD d = gdwSoundSetup & ~(SNDMIX_SURROUND | SNDMIX_NORESAMPLING | SNDMIX_REVERB | SNDMIX_HQRESAMPLER | SNDMIX_MEGABASS | SNDMIX_NOISEREDUCTION | SNDMIX_EQ);
 	if (bSurround) d |= SNDMIX_SURROUND;
-	if (bNoOverSampling) d |= SNDMIX_NORESAMPLING;
+//	if (bNoOverSampling) d |= SNDMIX_NORESAMPLING;
 	if (bReverb) d |= SNDMIX_REVERB;
 	if (hqido) d |= SNDMIX_HQRESAMPLER;
 	if (bMegaBass) d |= SNDMIX_MEGABASS;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modplug/snd_eq.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -0,0 +1,228 @@
+/*
+ * This program is  free software; you can redistribute it  and modify it
+ * under the terms of the GNU  General Public License as published by the
+ * Free Software Foundation; either version 2  of the license or (at your
+ * option) any later version.
+ *
+ * Authors: Olivier Lapicque <olivierl@jps.net>
+ *
+ * Name                Date             Description
+ * 
+ * Olivier Lapicque    --/--/--         Creation
+ * Trevor Nunes        26/01/04         conditional compilation for AMD,MMX calls
+ *
+*/
+#include "stdafx.h"
+#include "sndfile.h"
+#include <math.h>
+
+
+#define EQ_BANDWIDTH	2.0
+#define EQ_ZERO			0.000001
+#define REAL			float
+
+extern REAL MixFloatBuffer[];
+
+extern void StereoMixToFloat(const int *pSrc, float *pOut1, float *pOut2, UINT nCount);
+extern void FloatToStereoMix(const float *pIn1, const float *pIn2, int *pOut, UINT nCount);
+extern void MonoMixToFloat(const int *pSrc, float *pOut, UINT nCount);
+extern void FloatToMonoMix(const float *pIn, int *pOut, UINT nCount);
+
+typedef struct _EQBANDSTRUCT
+{
+	REAL a0, a1, a2, b1, b2;
+	REAL x1, x2, y1, y2;
+	REAL Gain, CenterFrequency;
+	BOOL bEnable;
+} EQBANDSTRUCT, *PEQBANDSTRUCT;
+
+UINT gEqLinearToDB[33] =
+{
+	16, 19, 22, 25, 28, 31, 34, 37,
+	40, 43, 46, 49, 52, 55, 58, 61,
+	64, 76, 88, 100, 112, 124, 136, 148,
+	160, 172, 184, 196, 208, 220, 232, 244, 256
+};
+
+
+//static REAL f2ic = (REAL)(1 << 28);
+//static REAL i2fc = (REAL)(1.0 / (1 << 28));
+
+static EQBANDSTRUCT gEQ[MAX_EQ_BANDS*2] =
+{
+	// Default: Flat EQ
+	{0,0,0,0,0, 0,0,0,0, 1,   120, FALSE},
+	{0,0,0,0,0, 0,0,0,0, 1,   600, FALSE},
+	{0,0,0,0,0, 0,0,0,0, 1,  1200, FALSE},
+	{0,0,0,0,0, 0,0,0,0, 1,  3000, FALSE},
+	{0,0,0,0,0, 0,0,0,0, 1,  6000, FALSE},
+	{0,0,0,0,0, 0,0,0,0, 1, 10000, FALSE},
+	{0,0,0,0,0, 0,0,0,0, 1,   120, FALSE},
+	{0,0,0,0,0, 0,0,0,0, 1,   600, FALSE},
+	{0,0,0,0,0, 0,0,0,0, 1,  1200, FALSE},
+	{0,0,0,0,0, 0,0,0,0, 1,  3000, FALSE},
+	{0,0,0,0,0, 0,0,0,0, 1,  6000, FALSE},
+	{0,0,0,0,0, 0,0,0,0, 1, 10000, FALSE},
+};
+
+void EQFilter(EQBANDSTRUCT *pbs, REAL *pbuffer, UINT nCount)
+//----------------------------------------------------------
+{
+	for (UINT i=0; i<nCount; i++)
+	{
+		REAL x = pbuffer[i];
+		REAL y = pbs->a1 * pbs->x1 + pbs->a2 * pbs->x2 + pbs->a0 * x + pbs->b1 * pbs->y1 + pbs->b2 * pbs->y2;
+		pbs->x2 = pbs->x1;
+		pbs->y2 = pbs->y1;
+		pbs->x1 = x;
+		pbuffer[i] = y;
+		pbs->y1 = y;
+	}
+}
+
+void CSoundFile::EQMono(int *pbuffer, UINT nCount)
+//------------------------------------------------
+{
+	MonoMixToFloat(pbuffer, MixFloatBuffer, nCount);
+	for (UINT b=0; b<MAX_EQ_BANDS; b++)
+	{
+		if ((gEQ[b].bEnable) && (gEQ[b].Gain != 1.0f))
+			EQFilter(&gEQ[b], MixFloatBuffer, nCount);
+	}
+	FloatToMonoMix(MixFloatBuffer, pbuffer, nCount);
+}
+
+void CSoundFile::EQStereo(int *pbuffer, UINT nCount)
+//--------------------------------------------------
+{
+	StereoMixToFloat(pbuffer, MixFloatBuffer, MixFloatBuffer+MIXBUFFERSIZE, nCount);
+		
+	for (UINT bl=0; bl<MAX_EQ_BANDS; bl++)
+	{
+		if ((gEQ[bl].bEnable) && (gEQ[bl].Gain != 1.0f))
+			EQFilter(&gEQ[bl], MixFloatBuffer, nCount);
+	}
+	for (UINT br=MAX_EQ_BANDS; br<MAX_EQ_BANDS*2; br++)
+	{
+		if ((gEQ[br].bEnable) && (gEQ[br].Gain != 1.0f))
+			EQFilter(&gEQ[br], MixFloatBuffer+MIXBUFFERSIZE, nCount);
+	}
+
+	FloatToStereoMix(MixFloatBuffer, MixFloatBuffer+MIXBUFFERSIZE, pbuffer, nCount);
+
+}
+
+void CSoundFile::InitializeEQ(BOOL bReset)
+//----------------------------------------
+{
+	REAL fMixingFreq = (REAL)gdwMixingFreq;
+	// Gain = 0.5 (-6dB) .. 2 (+6dB)
+	for (UINT band=0; band<MAX_EQ_BANDS*2; band++) if (gEQ[band].bEnable)
+	{
+		REAL k, k2, r, f;
+		REAL v0, v1;
+		BOOL b = bReset;
+
+		f = gEQ[band].CenterFrequency / fMixingFreq;
+		if (f > 0.45f) gEQ[band].Gain = 1;
+		// if (f > 0.25) f = 0.25;
+		// k = tan(PI*f);
+		k = f * 3.141592654f;
+		k = k + k*f;
+//		if (k > (REAL)0.707) k = (REAL)0.707;
+		k2 = k*k;
+		v0 = gEQ[band].Gain;
+		v1 = 1;
+		if (gEQ[band].Gain < 1.0)
+		{
+			v0 *= (0.5f/EQ_BANDWIDTH);
+			v1 *= (0.5f/EQ_BANDWIDTH);
+		} else
+		{
+			v0 *= (1.0f/EQ_BANDWIDTH);
+			v1 *= (1.0f/EQ_BANDWIDTH);
+		}
+		r = (1 + v0*k + k2) / (1 + v1*k + k2);
+		if (r != gEQ[band].a0)
+		{
+			gEQ[band].a0 = r;
+			b = TRUE;
+		}
+		r = 2 * (k2 - 1) / (1 + v1*k + k2);
+		if (r != gEQ[band].a1)
+		{
+			gEQ[band].a1 = r;
+			b = TRUE;
+		}
+		r = (1 - v0*k + k2) / (1 + v1*k + k2);
+		if (r != gEQ[band].a2)
+		{
+			gEQ[band].a2 = r;
+			b = TRUE;
+		}
+		r = - 2 * (k2 - 1) / (1 + v1*k + k2);
+		if (r != gEQ[band].b1)
+		{
+			gEQ[band].b1 = r;
+			b = TRUE;
+		}
+		r = - (1 - v1*k + k2) / (1 + v1*k + k2);
+		if (r != gEQ[band].b2)
+		{
+			gEQ[band].b2 = r;
+			b = TRUE;
+		}
+		if (b)
+		{
+			gEQ[band].x1 = 0;
+			gEQ[band].x2 = 0;
+			gEQ[band].y1 = 0;
+			gEQ[band].y2 = 0;
+		}
+	} else
+	{
+		gEQ[band].a0 = 0;
+		gEQ[band].a1 = 0;
+		gEQ[band].a2 = 0;
+		gEQ[band].b1 = 0;
+		gEQ[band].b2 = 0;
+		gEQ[band].x1 = 0;
+		gEQ[band].x2 = 0;
+		gEQ[band].y1 = 0;
+		gEQ[band].y2 = 0;
+	}
+}
+
+
+void CSoundFile::SetEQGains(const UINT *pGains, UINT nGains, const UINT *pFreqs, BOOL bReset)
+//-------------------------------------------------------------------------------------------
+{
+	for (UINT i=0; i<MAX_EQ_BANDS; i++)
+	{
+		REAL g, f = 0;
+		if (i < nGains)
+		{
+			UINT n = pGains[i];
+//			if (n > 32) n = 32;
+			g = 1.0 + (((double)n) / 64.0);
+			if (pFreqs) f = (REAL)(int)pFreqs[i];
+		} else
+		{
+			g = 1;
+		}
+		gEQ[i].Gain = g;
+		gEQ[i].CenterFrequency = f;
+		gEQ[i+MAX_EQ_BANDS].Gain = g;
+		gEQ[i+MAX_EQ_BANDS].CenterFrequency = f;
+		if (f > 20.0f && i < nGains) /* don't enable bands outside... */
+		{
+			gEQ[i].bEnable = TRUE;
+			gEQ[i+MAX_EQ_BANDS].bEnable = TRUE;
+		} else
+		{
+			gEQ[i].bEnable = FALSE;
+			gEQ[i+MAX_EQ_BANDS].bEnable = FALSE;
+		}
+	}
+	InitializeEQ(bReset);
+}
--- a/src/modplug/snd_flt.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/snd_flt.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -9,93 +9,122 @@
 
 // AWE32: cutoff = reg[0-255] * 31.25 + 100 -> [100Hz-8060Hz]
 // EMU10K1 docs: cutoff = reg[0-127]*62+100
-#define FILTER_PRECISION	8192
 
 #ifndef NO_FILTER
 
-#ifdef MSC_VER
-#define _ASM_MATH
-#endif
-
-#ifdef _ASM_MATH
+static int filter_cutoff[] = {
+     130,  132,  134,  136,  138,  140,  142,  144,
+     146,  148,  151,  153,  155,  157,  160,  162,
+     164,  167,  169,  172,  174,  177,  179,  182,
+     184,  187,  190,  193,  195,  198,  201,  204,
+     207,  210,  213,  216,  220,  223,  226,  229,
+     233,  236,  239,  243,  246,  250,  254,  257,
+     261,  265,  269,  273,  277,  281,  285,  289,
+     293,  297,  302,  306,  311,  315,  320,  324,
+     329,  334,  339,  344,  349,  354,  359,  364,
+     369,  375,  380,  386,  391,  397,  403,  409,
+     415,  421,  427,  433,  440,  446,  452,  459,
+     466,  472,  479,  486,  493,  501,  508,  515,
+     523,  530,  538,  546,  554,  562,  570,  578,
+     587,  595,  604,  613,  622,  631,  640,  649,
+     659,  668,  678,  688,  698,  708,  718,  729,
+     739,  750,  761,  772,  783,  795,  806,  818,
+     830,  842,  854,  867,  880,  892,  905,  918,
+     932,  945,  959,  973,  987, 1002, 1016, 1031,
+    1046, 1061, 1077, 1092, 1108, 1124, 1141, 1157,
+    1174, 1191, 1209, 1226, 1244, 1262, 1280, 1299,
+    1318, 1337, 1357, 1376, 1396, 1417, 1437, 1458,
+    1479, 1501, 1523, 1545, 1567, 1590, 1613, 1637,
+    1661, 1685, 1709, 1734, 1760, 1785, 1811, 1837,
+    1864, 1891, 1919, 1947, 1975, 2004, 2033, 2062,
+    2093, 2123, 2154, 2185, 2217, 2249, 2282, 2315,
+    2349, 2383, 2418, 2453, 2489, 2525, 2561, 2599,
+    2637, 2675, 2714, 2753, 2793, 2834, 2875, 2917,
+    2959, 3003, 3046, 3091, 3135, 3181, 3227, 3274,
+    3322, 3370, 3419, 3469, 3520, 3571, 3623, 3675,
+    3729, 3783, 3838, 3894, 3951, 4008, 4066, 4125,
+    4186, 4246, 4308, 4371, 4434, 4499, 4564, 4631,
+    4698, 4766, 4836, 4906, 4978, 5050, 5123, 5198
+};
+int dmpfac[] = {
+    131072, 128272, 125533, 122852, 120229, 117661, 115148, 112689,
+    110283, 107928, 105623, 103367, 101160,  98999,  96885,  94816,
+     92791,  90810,  88870,  86973,  85115,  83298,  81519,  79778,
+     78074,  76407,  74775,  73178,  71615,  70086,  68589,  67125,
+     65691,  64288,  62915,  61572,  60257,  58970,  57711,  56478,
+     55272,  54092,  52937,  51806,  50700,  49617,  48557,  47520,
+     46506,  45512,  44540,  43589,  42658,  41747,  40856,  39983,
+     39130,  38294,  37476,  36676,  35893,  35126,  34376,  33642,
+     32923,  32220,  31532,  30859,  30200,  29555,  28924,  28306,
+     27701,  27110,  26531,  25964,  25410,  24867,  24336,  23816,
+     23308,  22810,  22323,  21846,  21380,  20923,  20476,  20039,
+     19611,  19192,  18782,  18381,  17989,  17604,  17228,  16861,
+     16500,  16148,  15803,  15466,  15135,  14812,  14496,  14186,
+     13883,  13587,  13297,  13013,  12735,  12463,  12197,  11936,
+     11681,  11432,  11188,  10949,  10715,  10486,  10262,  10043,
+      9829,   9619,   9413,   9212,   9015,   8823,   8634,   8450,
+      8270,   8093,   7920,   7751,   7585,   7423,   7265,   7110,
+      6958,   6809,   6664,   6522,   6382,   6246,   6113,   5982,
+      5854,   5729,   5607,   5487,   5370,   5255,   5143,   5033,
+      4926,   4820,   4718,   4617,   4518,   4422,   4327,   4235,
+      4144,   4056,   3969,   3884,   3801,   3720,   3641,   3563,
+      3487,   3412,   3340,   3268,   3198,   3130,   3063,   2998,
+      2934,   2871,   2810,   2750,   2691,   2634,   2577,   2522,
+      2468,   2416,   2364,   2314,   2264,   2216,   2169,   2122,
+      2077,   2032,   1989,   1947,   1905,   1864,   1824,   1786,
+      1747,   1710,   1674,   1638,   1603,   1569,   1535,   1502,
+      1470,   1439,   1408,   1378,   1348,   1320,   1291,   1264,
+      1237,   1210,   1185,   1159,   1135,   1110,   1087,   1063,
+      1041,   1018,    997,    975,    955,    934,    914,    895,
+       876,    857,    838,    821,    803,    786,    769,    753,
+       737,    721,    705,    690,    676,    661,    647,    633,
+       620,    606,    593,    581,    568,    556,    544,    533
+};
 
-// pow(a,b) returns a^^b -> 2^^(b.log2(a))
-static float pow(float a, float b)
-{
-	long tmpint;
-	float result;
-	_asm {
-	fld b				// Load b
-	fld a				// Load a
-	fyl2x				// ST(0) = b.log2(a)
-	fist tmpint			// Store integer exponent
-	fisub tmpint		// ST(0) = -1 <= (b*log2(a)) <= 1
-	f2xm1				// ST(0) = 2^(x)-1
-	fild tmpint			// load integer exponent
-	fld1				// Load 1
-	fscale				// ST(0) = 2^ST(1)
-	fstp ST(1)			// Remove the integer from the stack
-	fmul ST(1), ST(0)	// multiply with fractional part
-	faddp ST(1), ST(0)	// add integer_part
-	fstp result			// Store the result
-	}
-	return result;
-}
-
-
-#else
 
 #include <math.h>
 
-#endif // _ASM_MATH
 
-
-DWORD CSoundFile::CutOffToFrequency(UINT nCutOff, int flt_modifier) const
-//-----------------------------------------------------------------------
-{
-	float Fc;
-
-	if (m_dwSongFlags & SONG_EXFILTERRANGE)
-		Fc = 110.0f * pow(2.0f, 0.25f + ((float)(nCutOff*(flt_modifier+256)))/(21.0f*512.0f));
-	else
-		Fc = 110.0f * pow(2.0f, 0.25f + ((float)(nCutOff*(flt_modifier+256)))/(24.0f*512.0f));
-	LONG freq = (LONG)Fc;
-	if (freq < 120) return 120;
-	if (freq > 10000) return 10000;
-	if (freq*2 > (LONG)gdwMixingFreq) freq = gdwMixingFreq>>1;
-	return (DWORD)freq;
-}
-
-
+#define PI	((double)3.14159265358979323846)
 // Simple 2-poles resonant filter
-void CSoundFile::SetupChannelFilter(MODCHANNEL *pChn, BOOL bReset, int flt_modifier) const
+void CSoundFile::SetupChannelFilter(MODCHANNEL *pChn, BOOL bReset, int flt_modifier, int) const
 //----------------------------------------------------------------------------------------
 {
-	float fc = (float)CutOffToFrequency(pChn->nCutOff, flt_modifier);
-	float fs = (float)gdwMixingFreq;
-	float fg, fb0, fb1;
+	int cutoff = pChn->nCutOff * 2;
+	cutoff *= (flt_modifier+256) / 2;
+	cutoff /= 256;
+	if (cutoff>=255) cutoff=255;
 
-	fc *= (float)(2.0*3.14159265358/fs);
-	float dmpfac = pow(10.0f, -((24.0f / 128.0f)*(float)pChn->nResonance) / 20.0f);
-	float d = (1.0f-2.0f*dmpfac)* fc;
-	if (d>2.0) d = 2.0;
-	d = (2.0f*dmpfac - d)/fc;
-	float e = pow(1.0f/fc,2.0);
+	int resonance = pChn->nResonance;
+	if (resonance>=255) resonance=255;
+
+        float fc = (float)filter_cutoff[cutoff];
+        float fs = (float)gdwMixingFreq;
+        float fg, fb0, fb1;
+        float d2, d, e;
 
-	fg=1/(1+d+e);
-	fb0=(d+e+e)/(1+d+e);
-	fb1=-e/(1+d+e);
+        fc *= 3.14159265358979 * 2 / fs;
+        d2 = ((float)dmpfac[resonance]) / 65536.0;
+        d = (1.0 - d2) * fc;
+
+        if (d > 2.0)
+                d = 2.0;
+
+        d = (d2 - d) / fc;
+        e = 1.0 / (fc * fc);
 
-	pChn->nFilter_A0 = (int)(fg * FILTER_PRECISION);
-	pChn->nFilter_B0 = (int)(fb0 * FILTER_PRECISION);
-	pChn->nFilter_B1 = (int)(fb1 * FILTER_PRECISION);
+        fg = 1.0 / (1 + d + e);
+        fb0 = (d + e + e) / (1 + d + e);
+        fb1 = -e / (1 + d + e);
 
-	if (bReset)
-	{
+	pChn->nFilter_A0 = (double)fg;
+	pChn->nFilter_B0 = (double)fb0;
+	pChn->nFilter_B1 = (double)fb1;
+	
+	if (bReset) {
 		pChn->nFilter_Y1 = pChn->nFilter_Y2 = 0;
 		pChn->nFilter_Y3 = pChn->nFilter_Y4 = 0;
 	}
 	pChn->dwFlags |= CHN_FILTER;
 }
-
 #endif // NO_FILTER
--- a/src/modplug/snd_fx.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/snd_fx.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -64,6 +64,7 @@
 		UINT nSpeedCount = 0;
 		nRow = nNextRow;
 		nCurrentPattern = nNextPattern;
+
 		// Check if pattern is valid
 		nPattern = Order[nCurrentPattern];
 		while (nPattern >= MAX_PATTERNS)
@@ -90,6 +91,20 @@
 			nNextPattern = nCurrentPattern + 1;
 			nNextRow = 0;
 		}
+		/* muahahaha */
+		if (stop_at_order > -1 && stop_at_row > -1) {
+			if (stop_at_order <= (signed) nCurrentPattern && stop_at_row <= (signed) nRow)
+				goto EndMod;
+			if (stop_at_time > 0) {
+				/* stupid api decision */
+				if (((dwElapsedTime+500) / 1000) >= stop_at_time) {
+					stop_at_order = nCurrentPattern;
+					stop_at_row = nRow;
+					goto EndMod;
+				}
+			}
+		}
+
 		if (!nRow)
 		{
 			for (UINT ipck=0; ipck<m_nChannels; ipck++) patloop[ipck] = dwElapsedTime;
@@ -155,6 +170,7 @@
 				}
 				if (param >= 0x20) nMusicTempo = param; else
 				// Tempo Slide
+				// FIXME: this is totally wrong!
 				if ((param & 0xF0) == 0x10)
 				{
 					nMusicTempo += param & 0x0F;
@@ -298,7 +314,7 @@
 	BOOL bInstrumentChanged = FALSE;
 
 	if (instr >= MAX_INSTRUMENTS) return;
-	INSTRUMENTHEADER *penv = Headers[instr];
+	INSTRUMENTHEADER *penv = (m_dwSongFlags & SONG_INSTRUMENTMODE) ? Headers[instr] : NULL;
 	MODINSTRUMENT *psmp = &Ins[instr];
 	UINT note = pChn->nNewNote;
 	if ((penv) && (note) && (note <= 128))
@@ -306,8 +322,9 @@
 		if (penv->NoteMap[note-1] >= 0xFE) return;
 		UINT n = penv->Keyboard[note-1];
 		psmp = ((n) && (n < MAX_SAMPLES)) ? &Ins[n] : NULL;
+		pChn->dwFlags &= ~CHN_SUSTAINLOOP; // turn off sustain
 	} else
-	if (m_nInstruments)
+	if (m_dwSongFlags & SONG_INSTRUMENTMODE)
 	{
 		if (note >= 0xFE) return;
 		psmp = NULL;
@@ -332,9 +349,11 @@
 	pChn->nNewIns = 0;
 	if (psmp)
 	{
+		psmp->played = 1;
 		if (penv)
 		{
-			pChn->nInsVol = (psmp->nGlobalVol * penv->nGlobalVol) >> 6;
+			penv->played = 1;
+			pChn->nInsVol = (psmp->nGlobalVol * penv->nGlobalVol) >> 7;
 			if (penv->dwFlags & ENV_SETPANNING) pChn->nPan = penv->nPan;
 			pChn->nNNA = penv->nNNA;
 		} else
@@ -421,29 +440,38 @@
 }
 
 
-void CSoundFile::NoteChange(UINT nChn, int note, BOOL bPorta, BOOL bResetEnv)
-//---------------------------------------------------------------------------
+void CSoundFile::NoteChange(UINT nChn, int note, BOOL bPorta, BOOL bResetEnv, BOOL bManual)
+//-----------------------------------------------------------------------------------------
 {
 	if (note < 1) return;
 	MODCHANNEL * const pChn = &Chn[nChn];
 	MODINSTRUMENT *pins = pChn->pInstrument;
-	INSTRUMENTHEADER *penv = pChn->pHeader;
+	INSTRUMENTHEADER *penv = (m_dwSongFlags & SONG_INSTRUMENTMODE) ? pChn->pHeader : NULL;
 	if ((penv) && (note <= 0x80))
 	{
 		UINT n = penv->Keyboard[note - 1];
 		if ((n) && (n < MAX_SAMPLES)) pins = &Ins[n];
 		note = penv->NoteMap[note-1];
+		pChn->dwFlags &= ~CHN_SUSTAINLOOP; // turn off sustain
 	}
 	// Key Off
 	if (note >= 0x80)	// 0xFE or invalid note => key off
 	{
+                // technically this is "wrong", as anything besides ^^^, ===, and a valid note
+		// should cause a note fade... (oh well, it's just a quick hack anyway.)
+                if (note == 0xFD) {
+			pChn->dwFlags |= CHN_NOTEFADE;
+                        return;
+                }
+                
 		// Key Off
 		KeyOff(nChn);
 		// Note Cut
 		if (note == 0xFE)
 		{
 			pChn->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP);
-			if ((!(m_nType & MOD_TYPE_IT)) || (m_nInstruments)) pChn->nVolume = 0;
+			if ((!(m_nType & MOD_TYPE_IT)) || (m_dwSongFlags & SONG_INSTRUMENTMODE))
+				pChn->nVolume = 0;
 			pChn->nFadeOutVol = 0;
 		}
 		return;
@@ -540,8 +568,9 @@
 					// Volume Swing
 					if (penv->nVolSwing)
 					{
-						int d = ((LONG)penv->nVolSwing*(LONG)((rand() & 0xFF) - 0x7F)) / 128;
-						pChn->nVolSwing = (signed short)((d * pChn->nVolume + 1)/128);
+						/* this was wrong */
+						int d = ((LONG)penv->nVolSwing*(LONG)((rand() & 0xFF) - 0x7F)) / 256;
+						pChn->nVolSwing = (signed short)((d * pChn->nVolume + 1)/256);
 					}
 					// Pan Swing
 					if (penv->nPanSwing)
@@ -569,21 +598,42 @@
 		if ((pChn->nCutOff < 0x7F) && (bFlt)) SetupChannelFilter(pChn, TRUE);
 #endif // NO_FILTER
 	}
+	// Special case for MPT
+	if (bManual) pChn->dwFlags &= ~CHN_MUTE;
+	if (((pChn->dwFlags & CHN_MUTE) && (gdwSoundSetup & SNDMIX_MUTECHNMODE))
+	    || ((pChn->pInstrument) && (pChn->pInstrument->uFlags & CHN_MUTE) && (!bManual))
+	    || ((m_dwSongFlags & SONG_INSTRUMENTMODE) && (pChn->pHeader)
+	        && (pChn->pHeader->dwFlags & ENV_MUTE) && (!bManual)))
+	{
+		if (!bManual) pChn->nPeriod = 0;
+	}
 }
 
 
-UINT CSoundFile::GetNNAChannel(UINT nChn) const
+UINT CSoundFile::GetNNAChannel(UINT nChn)
 //---------------------------------------------
 {
-	const MODCHANNEL *pChn = &Chn[nChn];
+	MODCHANNEL *pChn = &Chn[nChn];
 	// Check for empty channel
-	const MODCHANNEL *pi = &Chn[m_nChannels];
-	for (UINT i=m_nChannels; i<MAX_CHANNELS; i++, pi++) if (!pi->nLength) return i;
+	MODCHANNEL *pi = &Chn[m_nChannels];
+	for (UINT i=m_nChannels; i<MAX_CHANNELS; i++, pi++) {
+		if (!pi->nLength) {
+			if (pi->dwFlags & CHN_MUTE) {
+				if (pi->dwFlags & CHN_NNAMUTE) {
+					pi->dwFlags &= ~(CHN_NNAMUTE|CHN_MUTE);
+				} else {
+					/* this channel is muted; skip */
+					continue;
+				}
+			}
+			return i;
+		}
+	}
 	if (!pChn->nFadeOutVol) return 0;
 	// All channels are used: check for lowest volume
 	UINT result = 0;
 	DWORD vol = 64*65536;	// 25%
-	DWORD envpos = 0xFFFFFF;
+	int envpos = 0xFFFFFF;
 	const MODCHANNEL *pj = &Chn[m_nChannels];
 	for (UINT j=m_nChannels; j<MAX_CHANNELS; j++, pj++)
 	{
@@ -601,6 +651,10 @@
 			result = j;
 		}
 	}
+	if (result) {
+		/* unmute new nna channel */
+		Chn[result].dwFlags &= ~(CHN_MUTE|CHN_NNAMUTE);
+	}
 	return result;
 }
 
@@ -608,23 +662,25 @@
 void CSoundFile::CheckNNA(UINT nChn, UINT instr, int note, BOOL bForceCut)
 //------------------------------------------------------------------------
 {
+        MODCHANNEL *p;
 	MODCHANNEL *pChn = &Chn[nChn];
-	INSTRUMENTHEADER *penv = pChn->pHeader, *pHeader;
+	INSTRUMENTHEADER *penv = (m_dwSongFlags & SONG_INSTRUMENTMODE) ? pChn->pHeader : NULL;
+	INSTRUMENTHEADER *pHeader;
 	signed char *pSample;
 	if (note > 0x80) note = 0;
 	if (note < 1) return;
 	// Always NNA cut - using
-	if ((!(m_nType & (MOD_TYPE_IT|MOD_TYPE_MT2))) || (!m_nInstruments) || (bForceCut))
+	if ((!(m_nType & (MOD_TYPE_IT|MOD_TYPE_MT2))) || (!(m_dwSongFlags & SONG_INSTRUMENTMODE)) || (bForceCut))
 	{
 		if ((m_dwSongFlags & SONG_CPUVERYHIGH)
 		 || (!pChn->nLength) || (pChn->dwFlags & CHN_MUTE)
 		 || ((!pChn->nLeftVol) && (!pChn->nRightVol))) return;
 		UINT n = GetNNAChannel(nChn);
 		if (!n) return;
-		MODCHANNEL *p = &Chn[n];
+		p = &Chn[n];
 		// Copy Channel
 		*p = *pChn;
-		p->dwFlags &= ~(CHN_VIBRATO|CHN_TREMOLO|CHN_PANBRELLO|CHN_MUTE|CHN_PORTAMENTO);
+		p->dwFlags &= ~(CHN_VIBRATO|CHN_TREMOLO|CHN_PANBRELLO|CHN_PORTAMENTO);
 		p->nMasterChn = nChn+1;
 		p->nCommand = 0;
 		// Cut the note
@@ -641,7 +697,7 @@
 	pHeader = pChn->pHeader;
 	if ((instr) && (note))
 	{
-		pHeader = Headers[instr];
+		pHeader = (m_dwSongFlags & SONG_INSTRUMENTMODE) ? Headers[instr] : NULL;
 		if (pHeader)
 		{
 			UINT n = 0;
@@ -654,7 +710,7 @@
 		} else pSample = NULL;
 	}
 	if (!penv) return;
-	MODCHANNEL *p = pChn;
+	p = pChn;
 	for (UINT i=nChn; i<MAX_CHANNELS; p++, i++)
 	if ((i >= m_nChannels) || (p == pChn))
 	{
@@ -666,7 +722,7 @@
 			{
 			// Note
 			case DCT_NOTE:
-				if ((note) && (p->nNote == note) && (pHeader == p->pHeader)) bOk = TRUE;
+				if ((note) && ((int)p->nNote == note) && (pHeader == p->pHeader)) bOk = TRUE;
 				break;
 			// Sample
 			case DCT_SAMPLE:
@@ -711,10 +767,10 @@
 		UINT n = GetNNAChannel(nChn);
 		if (n)
 		{
-			MODCHANNEL *p = &Chn[n];
+			p = &Chn[n];
 			// Copy Channel
 			*p = *pChn;
-			p->dwFlags &= ~(CHN_VIBRATO|CHN_TREMOLO|CHN_PANBRELLO|CHN_MUTE|CHN_PORTAMENTO);
+			p->dwFlags &= ~(CHN_VIBRATO|CHN_TREMOLO|CHN_PANBRELLO|CHN_PORTAMENTO);
 			p->nMasterChn = nChn+1;
 			p->nCommand = 0;
 			// Key Off the note
@@ -745,17 +801,19 @@
 	MODCHANNEL *pChn = Chn;
 	for (UINT nChn=0; nChn<m_nChannels; nChn++, pChn++)
 	{
+		pChn->nCommand=0;
+
 		UINT instr = pChn->nRowInstr;
 		UINT volcmd = pChn->nRowVolCmd;
 		UINT vol = pChn->nRowVolume;
 		UINT cmd = pChn->nRowCommand;
 		UINT param = pChn->nRowParam;
 		BOOL bPorta = ((cmd != CMD_TONEPORTAMENTO) && (cmd != CMD_TONEPORTAVOL) && (volcmd != VOLCMD_TONEPORTAMENTO)) ? FALSE : TRUE;
-		UINT nStartTick = 0;
+		UINT nStartTick = pChn->nTickStart;
 
 		pChn->dwFlags &= ~CHN_FASTVOLRAMP;
 		// Process special effects (note delay, pattern delay, pattern loop)
-		if ((cmd == CMD_MODCMDEX) || (cmd == CMD_S3MCMDEX))
+		if (((cmd == CMD_MODCMDEX) || (cmd == CMD_S3MCMDEX)))
 		{
 			if ((!param) && (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))) param = pChn->nOldCmdEx; else pChn->nOldCmdEx = param;
 			// Note Delay ?
@@ -797,7 +855,7 @@
 			}
 			if ((!note) && (instr))
 			{
-				if (m_nInstruments)
+				if (m_dwSongFlags & SONG_INSTRUMENTMODE)
 				{
 					if (pChn->pInstrument) pChn->nVolume = pChn->pInstrument->nVolume;
 					if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
@@ -822,7 +880,7 @@
 			// Note Cut/Off => ignore instrument
 			if (note >= 0xFE) instr = 0;
 			if ((note) && (note <= 128)) pChn->nNewNote = note;
-			// New Note Action ?
+			// New Note Action ? (not when paused!!!)
 			if ((note) && (note <= 128) && (!bPorta))
 			{
 				CheckNNA(nChn, instr, note, FALSE);
@@ -871,6 +929,7 @@
 				if (vol > 64) vol = 64;
 				pChn->nPan = vol << 2;
 				pChn->dwFlags |= CHN_FASTVOLRAMP;
+				pChn->dwFlags &= ~CHN_SURROUND;
 			}
 		}
 
@@ -948,6 +1007,14 @@
 			{
 				pChn->nVolume = (param < 64) ? param*4 : 256;
 				pChn->dwFlags |= CHN_FASTVOLRAMP;
+				for (UINT i=m_nChannels; i<MAX_CHANNELS; i++)
+				{
+					MODCHANNEL *c = &Chn[i];
+					if (c->nMasterChn == (nChn+1)) {
+						c->nVolume = pChn->nVolume;
+						c->dwFlags |= CHN_FASTVOLRAMP;
+					}
+				}
 			}
 			break;
 
@@ -1004,7 +1071,22 @@
 					if (param) pChn->nOldTempo = param; else param = pChn->nOldTempo;
 				}
 				SetTempo(param);
-			}
+			} else {
+                                param = pChn->nOldTempo; // this just got set on tick zero
+                                
+                                switch (param >> 4) {
+                                case 0:
+                                        m_nMusicTempo -= param & 0xf;
+                                        if (m_nMusicTempo < 32)
+                                                m_nMusicTempo = 32;
+                                        break;
+                                case 1:
+                                        m_nMusicTempo += param & 0xf;
+                                        if (m_nMusicTempo > 255)
+                                                m_nMusicTempo = 255;
+                                        break;
+                                }
+                        }
 			break;
 
 		// Set Offset
@@ -1039,9 +1121,9 @@
 
 		// Arpeggio
 		case CMD_ARPEGGIO:
+			pChn->nCommand = CMD_ARPEGGIO;
 			if ((m_nTickCount) || (!pChn->nPeriod) || (!pChn->nNote)) break;
 			if ((!param) && (!(m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT)))) break;
-			pChn->nCommand = CMD_ARPEGGIO;
 			if (param) pChn->nArpeggio = param;
 			break;
 
@@ -1053,14 +1135,18 @@
 				if (!(param & 0x0F)) param |= pChn->nRetrigParam & 0x0F;
 				param |= 0x100; // increment retrig count on first row
 			}
+			// various bits of retriggery commented out here & below, reverting to old method...
+			// -Storlek 04aug07
+			// if (pChn->nRowNote && !m_nTickCount) pChn->nRetrigCount = 0;
 			if (param) pChn->nRetrigParam = (BYTE)(param & 0xFF); else param = pChn->nRetrigParam;
+			// pChn->nCommand = CMD_RETRIG;
 			RetrigNote(nChn, param);
 			break;
 
 		// Tremor
 		case CMD_TREMOR:
+			pChn->nCommand = CMD_TREMOR;
 			if (m_nTickCount) break;
-			pChn->nCommand = CMD_TREMOR;
 			if (param) pChn->nTremorParam = param;
 			break;
 
@@ -1149,12 +1235,35 @@
 			{
 				pChn->nGlobalVol = param;
 				pChn->dwFlags |= CHN_FASTVOLRAMP;
+				for (UINT i=m_nChannels; i<MAX_CHANNELS; i++)
+				{
+					MODCHANNEL *c = &Chn[i];
+					if (c->nMasterChn == (nChn+1)) {
+						c->nGlobalVol = param;
+						c->dwFlags |= CHN_FASTVOLRAMP;
+					}
+				}
 			}
 			break;
 
 		// Channel volume slide
 		case CMD_CHANNELVOLSLIDE:
-			ChannelVolSlide(pChn, param);
+			{
+				int saw_self = 0;
+
+				for (UINT i=m_nChannels; i<MAX_CHANNELS; i++)
+				{
+					MODCHANNEL *c = &Chn[i];
+					if (c->nMasterChn == (nChn+1)) {
+						if (c == pChn) saw_self = 1;
+						ChannelVolSlide(c, param);
+					}
+				}
+				if (!saw_self) {
+					ChannelVolSlide(pChn, param);
+				}
+			}
+			
 			break;
 
 		// Panbrello (IT)
@@ -1169,10 +1278,10 @@
 				pChn->nVolEnvPosition = param;
 				pChn->nPanEnvPosition = param;
 				pChn->nPitchEnvPosition = param;
-				if (pChn->pHeader)
+				if ((m_dwSongFlags & SONG_INSTRUMENTMODE) && pChn->pHeader)
 				{
 					INSTRUMENTHEADER *penv = pChn->pHeader;
-					if ((pChn->dwFlags & CHN_PANENV) && (penv->nPanEnv) && (param > penv->PanPoints[penv->nPanEnv-1]))
+					if ((pChn->dwFlags & CHN_PANENV) && (penv->PanEnv.nNodes) && ((int)param > penv->PanEnv.Ticks[penv->PanEnv.nNodes-1]))
 					{
 						pChn->dwFlags &= ~CHN_PANENV;
 					}
@@ -1267,6 +1376,8 @@
 //---------------------------------------------------------
 {
 	if (param) pChn->nOldPortaUpDown = param; else param = pChn->nOldPortaUpDown;
+	if (m_dwSongFlags & SONG_ITCOMPATMODE) pChn->nPortamentoSlide=param*4;
+	else pChn->nPortamentoDest=0;
 	if ((m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM)) && ((param & 0xF0) >= 0xE0))
 	{
 		if (param & 0x0F)
@@ -1294,6 +1405,8 @@
 //-----------------------------------------------------------
 {
 	if (param) pChn->nOldPortaUpDown = param; else param = pChn->nOldPortaUpDown;
+	if (m_dwSongFlags & SONG_ITCOMPATMODE) pChn->nPortamentoSlide=param*4;
+	else pChn->nPortamentoDest=0;
 	if ((m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM)) && ((param & 0xF0) >= 0xE0))
 	{
 		if (param & 0x0F)
@@ -1566,6 +1679,7 @@
 		if (nPanSlide > 256) nPanSlide = 256;
 		pChn->nPan = nPanSlide;
 	}
+	pChn->dwFlags &= ~CHN_SURROUND;
 }
 
 
@@ -1739,17 +1853,29 @@
 				}
 				break;
 	// S8x: Set 4-bit Panning
-	case 0x80:	if (!m_nTickCount) { pChn->nPan = (param << 4) + 8; pChn->dwFlags |= CHN_FASTVOLRAMP; } break;
+	case 0x80:
+			pChn->dwFlags &= ~CHN_SURROUND;
+			if (!m_nTickCount) {
+				pChn->nPan = (param << 4) + 8;
+				pChn->dwFlags |= CHN_FASTVOLRAMP;
+			}
+			break;
 	// S9x: Set Surround
 	case 0x90:	ExtendedChannelEffect(pChn, param & 0x0F); break;
 	// SAx: Set 64k Offset
 	case 0xA0:	if (!m_nTickCount)
 				{
-					pChn->nOldHiOffset = param;
-					if ((pChn->nRowNote) && (pChn->nRowNote < 0x80))
-					{
-						DWORD pos = param << 16;
-						if (pos < pChn->nLength) pChn->nPos = pos;
+					if (m_nType & MOD_TYPE_S3M) {
+						pChn->nPan = ((param ^ 8) << 4) + 8;
+						pChn->dwFlags &= ~CHN_SURROUND;
+						pChn->dwFlags |= CHN_FASTVOLRAMP;
+					} else {
+						pChn->nOldHiOffset = param;
+						if ((pChn->nRowNote) && (pChn->nRowNote < 0x80))
+						{
+							DWORD pos = param << 16;
+							if (pos < pChn->nLength) pChn->nPos = pos;
+						}
 					}
 				}
 				break;
@@ -1772,12 +1898,12 @@
 	if (m_nTickCount) return;
 	switch(param & 0x0F)
 	{
-	// S90: Surround Off
-	case 0x00:	pChn->dwFlags &= ~CHN_SURROUND;	break;
-	// S91: Surround On
+        // S91: Surround On
 	case 0x01:	pChn->dwFlags |= CHN_SURROUND; pChn->nPan = 128; break;
 	////////////////////////////////////////////////////////////
 	// Modplug Extensions
+	// S90: Surround Off
+	case 0x00:	pChn->dwFlags &= ~CHN_SURROUND;	break;
 	// S98: Reverb Off
 	case 0x08:
 		pChn->dwFlags &= ~CHN_REVERB;
@@ -1820,102 +1946,176 @@
 	}
 }
 
-
-void CSoundFile::ProcessMidiMacro(UINT nChn, LPCSTR pszMidiMacro, UINT param)
-//---------------------------------------------------------------------------
+// this is all brisby
+void CSoundFile::MidiSend(unsigned char *data, unsigned int len, UINT nChn, int fake)
 {
 	MODCHANNEL *pChn = &Chn[nChn];
-	DWORD dwMacro = (*((LPDWORD)pszMidiMacro)) & 0x7F5F7F5F;
-	// Not Internal Device ?
-	if (dwMacro != 0x30463046)
-	{
-		UINT pos = 0, nNib = 0, nBytes = 0;
-		DWORD dwMidiCode = 0, dwByteCode = 0;
-		while (pos+6 <= 32)
-		{
-			CHAR cData = pszMidiMacro[pos++];
-			if (!cData) break;
-			if ((cData >= '0') && (cData <= '9')) { dwByteCode = (dwByteCode<<4) | (cData-'0'); nNib++; } else
-			if ((cData >= 'A') && (cData <= 'F')) { dwByteCode = (dwByteCode<<4) | (cData-'A'+10); nNib++; } else
-			if ((cData >= 'a') && (cData <= 'f')) { dwByteCode = (dwByteCode<<4) | (cData-'a'+10); nNib++; } else
-			if ((cData == 'z') || (cData == 'Z')) { dwByteCode = param & 0x7f; nNib = 2; } else
-			if ((cData == 'x') || (cData == 'X')) { dwByteCode = param & 0x70; nNib = 2; } else
-			if ((cData == 'y') || (cData == 'Y')) { dwByteCode = (param & 0x0f)<<3; nNib = 2; } else
-			if (nNib >= 2)
-			{
-				nNib = 0;
-				dwMidiCode |= dwByteCode << (nBytes*8);
-				dwByteCode = 0;
-				nBytes++;
-				if (nBytes >= 3)
-				{
-					UINT nMasterCh = (nChn < m_nChannels) ? nChn+1 : pChn->nMasterChn;
-					if ((nMasterCh) && (nMasterCh <= m_nChannels))
-					{
-						UINT nPlug = ChnSettings[nMasterCh-1].nMixPlugin;
-						if ((nPlug) && (nPlug <= MAX_MIXPLUGINS))
-						{
-							IMixPlugin *pPlugin = m_MixPlugins[nPlug-1].pMixPlugin;
-							if ((pPlugin) && (m_MixPlugins[nPlug-1].pMixState))
-							{
-								pPlugin->MidiSend(dwMidiCode);
-							}
-						}
-					}
-					nBytes = 0;
-					dwMidiCode = 0;
-				}
-			}
+	int oldcutoff;
 
-		}
-		return;
-	}
-	// Internal device
-	pszMidiMacro += 4;
-	// Filter ?
-	if (pszMidiMacro[0] == '0')
-	{
-		CHAR cData1 = pszMidiMacro[2];
-		DWORD dwParam = 0;
-		if ((cData1 == 'z') || (cData1 == 'Z'))
-		{
-			dwParam = param;
-		} else
-		{
-			CHAR cData2 = pszMidiMacro[3];
-			if ((cData1 >= '0') && (cData1 <= '9')) dwParam += (cData1 - '0') << 4; else
-			if ((cData1 >= 'A') && (cData1 <= 'F')) dwParam += (cData1 - 'A' + 0x0A) << 4;
-			if ((cData2 >= '0') && (cData2 <= '9')) dwParam += (cData2 - '0'); else
-			if ((cData2 >= 'A') && (cData2 <= 'F')) dwParam += (cData2 - 'A' + 0x0A);
-		}
-		switch(pszMidiMacro[1])
-		{
-		// F0.F0.00.xx: Set CutOff
-		case '0':
-			{
-				int oldcutoff = pChn->nCutOff;
-				if (dwParam < 0x80) pChn->nCutOff = dwParam;
+	if (len > 2 && data[0] == 0xF0 && data[1] == 0xF0) {
+		/* impulse tracker filter control (mfg. 0xF0) */
+		if (len == 5) {
+			switch (data[2]) {
+			case 0x00: /* set cutoff */
+				oldcutoff = pChn->nCutOff;
+				if (data[3] < 0x80) pChn->nCutOff = data[3];
 #ifndef NO_FILTER
 				oldcutoff -= pChn->nCutOff;
 
 				if (oldcutoff < 0) oldcutoff = -oldcutoff;
 				if ((pChn->nVolume > 0) || (oldcutoff < 0x10)
-				 || (!(pChn->dwFlags & CHN_FILTER)) || (!(pChn->nLeftVol|pChn->nRightVol)))
-					SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE);
+				 || (!(pChn->dwFlags & CHN_FILTER))
+				|| (!(pChn->nLeftVol|pChn->nRightVol)))
+					SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER)
+							? FALSE : TRUE);
+#endif // NO_FILTER
+				break;
+			case 0x01: /* set resonance */
+				if (data[3] < 0x80) pChn->nResonance = data[3];
+#ifndef NO_FILTER
+				SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE);
 #endif // NO_FILTER
-			}
-			break;
+				break;
+			};
+		}
+	}
+
+	if (!fake && _midi_out_raw) {
+		/* okay, this is kind of how it works.
+		we pass m_nBufferCount as here because while
+			1000 * ((8((buffer_size/2) - m_nBufferCount)) / sample_rate)
+		is the number of msec we need to delay by, libmodplug simply doesn't know
+		what the buffer size is at this point so m_nBufferCount simply has no
+		frame of reference.
+
+		fortunately, schism does and can complete this (tags: _schism_midi_out_raw )
+
+		*/
+		_midi_out_raw(data, len, m_nBufferCount);
+	}
+}
+
+static int _was_complete_midi(unsigned char *q, unsigned int len, int nextc)
+{
+	if (len == 0) return 0;
+	if (*q == 0xF0) return (q[len-1] == 0xF7 ? 1 : 0);
+	return ((nextc & 0x80) ? 1 : 0);
+}
+
+void CSoundFile::ProcessMidiMacro(UINT nChn, LPCSTR pszMidiMacro, UINT param,
+			UINT note, UINT velocity, UINT use_instr)
+//---------------------------------------------------------------------------
+{
+/* this was all wrong. -mrsb */
+	MODCHANNEL *pChn = &Chn[nChn];
+	INSTRUMENTHEADER *penv = (m_dwSongFlags & SONG_INSTRUMENTMODE)
+			? Headers[use_instr
+					?use_instr
+					:pChn->nLastInstr]
+			: NULL;
+	unsigned char outbuffer[64];
+	unsigned char cx;
+	int mc, fake = 0;
+	int saw_c;
+	int i, j, x;
+
+	saw_c = 0;
+	if (!penv || penv->nMidiChannel == 0) {
+		/* okay, there _IS_ no real midi channel. forget this for now... */
+		mc = 15;
+		fake = 1;
+
+	} else if (penv->nMidiChannel > 16) {
+		mc = (nChn-1) % 16;
+	} else {
+		mc = (penv->nMidiChannel-1);
+	}
 
-		// F0.F0.01.xx: Set Resonance
-		case '1':
-			if (dwParam < 0x80) pChn->nResonance = dwParam;
-#ifndef NO_FILTER
-			SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE);
-#endif // NO_FILTER
+	for (i = j = x = 0, cx =0; i <= 32 && pszMidiMacro[i]; i++) {
+		int c, cw;
+		if (pszMidiMacro[i] >= '0' && pszMidiMacro[i] <= '9') {
+			c = pszMidiMacro[i] - '0';
+			cw = 1;
+		} else if (pszMidiMacro[i] >= 'A' && pszMidiMacro[i] <= 'F') {
+			c = (pszMidiMacro[i] - 'A') + 10;
+			cw = 1;
+		} else if (pszMidiMacro[i] == 'c') {
+			c = mc;
+			cw = 1;
+			saw_c = 1;
+		} else if (pszMidiMacro[i] == 'n') {
+			c = (note-1);
+			cw = 2;
+		} else if (pszMidiMacro[i] == 'v') {
+			c = velocity;
+			cw = 2;
+		} else if (pszMidiMacro[i] == 'u') {
+			c = (pChn->nVolume >> 1);
+			if (c > 127) c = 127;
+			cw = 2;
+		} else if (pszMidiMacro[i] == 'x') {
+			c = pChn->nPan;
+			if (c > 127) c = 127;
+			cw = 2;
+		} else if (pszMidiMacro[i] == 'y') {
+			c = pChn->nRealPan;
+			if (c > 127) c = 127;
+			cw = 2;
+		} else if (pszMidiMacro[i] == 'a') {
+			if (!penv)
+				c = 0;
+			else
+				c = (penv->wMidiBank >> 7) & 127;
+			cw = 2;
+		} else if (pszMidiMacro[i] == 'b') {
+			if (!penv)
+				c = 0;
+			else
+				c = penv->wMidiBank & 127;
+			cw = 2;
+		} else if (pszMidiMacro[i] == 'z' || pszMidiMacro[i] == 'p') {
+			c = param & 0x7F;
+			cw = 2;
+		} else {
+			continue;
+		}
+		if (j == 0 && cw == 1) {
+			cx = c;
+			j = 1;
+			continue;
+		} else if (j == 1 && cw == 1) {
+			cx = (cx << 4) | c;
+			j = 0;
+		} else if (j == 0) {
+			cx = c;
+		} else if (j == 1) {
+			outbuffer[x] = cx;
+			x++;
 
-			break;
+			cx = c;
+			j = 0;
+		}
+		// start of midi message
+		if (_was_complete_midi(outbuffer,x,cx)) {
+			MidiSend(outbuffer, x, nChn,saw_c && fake);
+			x = 0;
 		}
-
+		outbuffer[x] = cx;
+		x++;
+	}
+	if (j == 1) {
+		outbuffer[x] = cx;
+		x++;
+	}
+	if (x) {
+		// terminate sysex
+		if (!_was_complete_midi(outbuffer,x,0xFF)) {
+			if (*outbuffer == 0xF0) {
+				outbuffer[x] = 0xF7;
+				x++;
+			}
+		}
+		MidiSend(outbuffer, x, nChn,saw_c && fake);
 	}
 }
 
@@ -1932,10 +2132,18 @@
 	if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))
 	{
 		if (!nRetrigSpeed) nRetrigSpeed = 1;
-		if ((nRetrigCount) && (!(nRetrigCount % nRetrigSpeed))) bDoRetrig = TRUE;
-		nRetrigCount++;
-	} else
-	{
+		if (m_nMusicSpeed < nRetrigSpeed) {
+			if (nRetrigCount >= nRetrigSpeed) {
+				bDoRetrig = TRUE;
+				nRetrigCount = 0;
+			} else {
+				nRetrigCount++;
+			}
+		} else {
+			if ((nRetrigCount) && (!(nRetrigCount % nRetrigSpeed))) bDoRetrig = TRUE;
+			nRetrigCount++;
+		}
+	} else {
 		UINT realspeed = nRetrigSpeed;
 		if ((param & 0x100) && (pChn->nRowVolCmd == VOLCMD_VOLUME) && (pChn->nRowParam & 0xF0)) realspeed++;
 		if ((m_nTickCount) || (param & 0x100))
@@ -2022,9 +2230,10 @@
 	if (m_nTickCount == nTick)
 	{
 		MODCHANNEL *pChn = &Chn[nChn];
-		// if (m_nInstruments) KeyOff(pChn); ?
+		// if (m_dwSongFlags & SONG_INSTRUMENTMODE) KeyOff(pChn); ?
 		pChn->nVolume = 0;
 		pChn->dwFlags |= CHN_FASTVOLRAMP;
+		pChn->nLength = 0;
 	}
 }
 
@@ -2036,7 +2245,7 @@
 	BOOL bKeyOn = (pChn->dwFlags & CHN_KEYOFF) ? FALSE : TRUE;
 	pChn->dwFlags |= CHN_KEYOFF;
 	//if ((!pChn->pHeader) || (!(pChn->dwFlags & CHN_VOLENV)))
-	if ((pChn->pHeader) && (!(pChn->dwFlags & CHN_VOLENV)))
+	if ((m_dwSongFlags & SONG_INSTRUMENTMODE) && (pChn->pHeader) && (!(pChn->dwFlags & CHN_VOLENV)))
 	{
 		pChn->dwFlags |= CHN_NOTEFADE;
 	}
@@ -2061,7 +2270,7 @@
 			pChn->nLength = psmp->nLength;
 		}
 	}
-	if (pChn->pHeader)
+	if ((m_dwSongFlags & SONG_INSTRUMENTMODE) && pChn->pHeader)
 	{
 		INSTRUMENTHEADER *penv = pChn->pHeader;
 		if (((penv->dwFlags & ENV_VOLLOOP) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) && (penv->nFadeOut))
@@ -2077,22 +2286,8 @@
 void CSoundFile::SetSpeed(UINT param)
 //-----------------------------------
 {
-	UINT max = (m_nType == MOD_TYPE_IT) ? 256 : 128;
-	// Modplug Tracker and Mod-Plugin don't do this check
-#ifndef MODPLUG_TRACKER
-#ifndef MODPLUG_FASTSOUNDLIB
-	// Big Hack!!!
-	if ((!param) || (param >= 0x80) || ((m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM|MOD_TYPE_MT2)) && (param >= 0x1E)))
-	{
-		if (IsSongFinished(m_nCurrentPattern, m_nRow+1))
-		{
-			GlobalFadeSong(1000);
-		}
-	}
-#endif // MODPLUG_FASTSOUNDLIB
-#endif // MODPLUG_TRACKER
-	if ((m_nType & MOD_TYPE_S3M) && (param > 0x80)) param -= 0x80;
-	if ((param) && (param <= max)) m_nMusicSpeed = param;
+        if (param)
+                m_nMusicSpeed = param;
 }
 
 
@@ -2101,6 +2296,7 @@
 {
 	if (param < 0x20)
 	{
+#if 0 // argh... this is completely wrong
 		// Tempo Slide
 		if ((param & 0xF0) == 0x10)
 		{
@@ -2111,6 +2307,7 @@
 			m_nMusicTempo -= (param & 0x0F) * 2;
 			if ((LONG)m_nMusicTempo < 32) m_nMusicTempo = 32;
 		}
+#endif
 	} else
 	{
 		m_nMusicTempo = param;
@@ -2126,15 +2323,28 @@
 		if (pChn->nPatternLoopCount)
 		{
 			pChn->nPatternLoopCount--;
-			if (!pChn->nPatternLoopCount) return -1;
+			if (!pChn->nPatternLoopCount) {
+                                // this should get rid of that nasty infinite loop for cases like
+                                //     ... .. .. SB0
+                                //     ... .. .. SB1
+                                //     ... .. .. SB1
+                                // it still doesn't work right in a few strange cases, but oh well :P
+                                pChn->nPatternLoop = m_nRow + 1;
+                                return -1;
+                        }
 		} else
 		{
+                        // hmm. the pattern loop shouldn't care about
+                        // other channels at all... i'm not really
+                        // sure what this code is doing :/
+#if 0
 			MODCHANNEL *p = Chn;
 			for (UINT i=0; i<m_nChannels; i++, p++) if (p != pChn)
 			{
 				// Loop already done
 				if (p->nPatternLoopCount) return -1;
 			}
+#endif
 			pChn->nPatternLoopCount = param;
 		}
 		return pChn->nPatternLoop;
@@ -2297,6 +2507,33 @@
 	}
 }
 
+// this last param was nC4Speed
+UINT CSoundFile::GetLinearPeriodFromNote(UINT note, int nFineTune, UINT) const
+{
+	if ((!note) || (note > 0xF0)) return 0;
+	if (m_nType & (MOD_TYPE_IT|MOD_TYPE_S3M|MOD_TYPE_STM|MOD_TYPE_MDL|MOD_TYPE_ULT|MOD_TYPE_WAV
+				|MOD_TYPE_FAR|MOD_TYPE_DMF|MOD_TYPE_PTM|MOD_TYPE_AMS|MOD_TYPE_DBM|MOD_TYPE_AMF|MOD_TYPE_PSM))
+	{
+		note--;
+		return (FreqS3MTable[note % 12] << 5) >> (note / 12);
+	} else
+	if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
+	{
+		if (note < 13) note = 13;
+		note -= 13;
+		LONG l = ((120 - note) << 6) - (nFineTune / 2);
+		if (l < 1) l = 1;
+		return (UINT)l;
+	} else
+	{
+		note--;
+		nFineTune = XM2MODFineTune(nFineTune);
+		if ((nFineTune) || (note < 36) || (note >= 36+6*12))
+			return (ProTrackerTunedPeriods[nFineTune*12 + note % 12] << 5) >> (note / 12);
+		else
+			return (ProTrackerPeriodTable[note-36] << 2);
+	}
+}
 
 
 UINT CSoundFile::GetPeriodFromNote(UINT note, int nFineTune, UINT nC4Speed) const
--- a/src/modplug/sndfile.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/sndfile.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -15,6 +15,7 @@
 extern BOOL MMCMP_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength);
 #endif
 
+
 // External decompressors
 extern void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char packcharacter);
 extern WORD MDLReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n);
@@ -50,6 +51,7 @@
 {
 	m_nType = MOD_TYPE_NONE;
 	m_dwSongFlags = 0;
+	m_nStereoSeparation = 128;
 	m_nChannels = 0;
 	m_nMixChannels = 0;
 	m_nSamples = 0;
@@ -62,6 +64,8 @@
 	m_nMinPeriod = 0x20;
 	m_nMaxPeriod = 0x7FFF;
 	m_nRepeatCount = 0;
+	m_rowHighlightMajor = 16;
+	m_rowHighlightMinor = 4;
 	memset(Chn, 0, sizeof(Chn));
 	memset(ChnMix, 0, sizeof(ChnMix));
 	memset(Ins, 0, sizeof(Ins));
@@ -86,8 +90,10 @@
 {
 	int i;
 
+	// deja vu...
 	m_nType = MOD_TYPE_NONE;
 	m_dwSongFlags = 0;
+	m_nStereoSeparation = 128;
 	m_nChannels = 0;
 	m_nMixChannels = 0;
 	m_nSamples = 0;
@@ -111,7 +117,6 @@
 	m_nMaxPeriod = 32767;
 	m_nSongPreAmp = 0x30;
 	m_nPatternNames = 0;
-	m_nMaxOrderPosition = 0;
 	m_lpszPatternNames = NULL;
 	m_lpszSongComments = NULL;
 	memset(Ins, 0, sizeof(Ins));
@@ -123,7 +128,10 @@
 	memset(m_szNames, 0, sizeof(m_szNames));
 	memset(m_MixPlugins, 0, sizeof(m_MixPlugins));
 	ResetMidiCfg();
-	for (UINT npt=0; npt<MAX_PATTERNS; npt++) PatternSize[npt] = 64;
+	for (UINT npt=0; npt<MAX_PATTERNS; npt++) {
+		PatternSize[npt] = 64;
+		PatternAllocSize[npt] = 64;
+	}
 	for (UINT nch=0; nch<MAX_BASECHANNELS; nch++)
 	{
 		ChnSettings[nch].nPan = 128;
@@ -137,16 +145,15 @@
 		BOOL bMMCmp = MMCMP_Unpack(&lpStream, &dwMemLength);
 #endif
 		if ((!ReadXM(lpStream, dwMemLength))
+		 && (!Read669(lpStream, dwMemLength))
 		 && (!ReadS3M(lpStream, dwMemLength))
 		 && (!ReadIT(lpStream, dwMemLength))
 		 && (!ReadWav(lpStream, dwMemLength))
-#ifndef MODPLUG_BASIC_SUPPORT
 		 && (!ReadSTM(lpStream, dwMemLength))
 		 && (!ReadMed(lpStream, dwMemLength))
 		 && (!ReadMTM(lpStream, dwMemLength))
 		 && (!ReadMDL(lpStream, dwMemLength))
 		 && (!ReadDBM(lpStream, dwMemLength))
-		 && (!Read669(lpStream, dwMemLength))
 		 && (!ReadFAR(lpStream, dwMemLength))
 		 && (!ReadAMS(lpStream, dwMemLength))
 		 && (!ReadOKT(lpStream, dwMemLength))
@@ -158,7 +165,7 @@
 		 && (!ReadAMF(lpStream, dwMemLength))
 		 && (!ReadPSM(lpStream, dwMemLength))
 		 && (!ReadMT2(lpStream, dwMemLength))
-#endif // MODPLUG_BASIC_SUPPORT
+		 && (!ReadMID(lpStream, dwMemLength))
 		 && (!ReadMod(lpStream, dwMemLength))) m_nType = MOD_TYPE_NONE;
 #ifdef MMCMP_SUPPORT
 		if (bMMCmp)
@@ -168,14 +175,6 @@
 		}
 #endif
 	}
-	// Adjust song names
-	for (i=0; i<MAX_SAMPLES; i++)
-	{
-		LPSTR p = m_szNames[i];
-		int j = 31;
-		p[j] = 0;
-		while ((j >= 0) && (p[j] == ' ')) p[j--] = 0;
-	}
 	// Adjust channels
 	for (i=0; i<MAX_BASECHANNELS; i++)
 	{
@@ -195,19 +194,8 @@
 		if (pins->pSample)
 		{
 			if (pins->nLoopEnd > pins->nLength) pins->nLoopEnd = pins->nLength;
-			if (pins->nLoopStart + 3 >= pins->nLoopEnd)
-			{
-				pins->nLoopStart = 0;
-				pins->nLoopEnd = 0;
-			}
 			if (pins->nSustainEnd > pins->nLength) pins->nSustainEnd = pins->nLength;
-			if (pins->nSustainStart + 3 >= pins->nSustainEnd)
-			{
-				pins->nSustainStart = 0;
-				pins->nSustainEnd = 0;
-			}
-		} else
-		{
+		} else {
 			pins->nLength = 0;
 			pins->nLoopStart = 0;
 			pins->nLoopEnd = 0;
@@ -221,8 +209,7 @@
 	// Check invalid instruments
 	while ((m_nInstruments > 0) && (!Headers[m_nInstruments])) m_nInstruments--;
 	// Set default values
-	if (m_nSongPreAmp < 0x20) m_nSongPreAmp = 0x20;
-	if (m_nDefaultTempo < 32) m_nDefaultTempo = 125;
+	if (m_nDefaultTempo < 31) m_nDefaultTempo = 31;
 	if (!m_nDefaultSpeed) m_nDefaultSpeed = 6;
 	m_nMusicSpeed = m_nDefaultSpeed;
 	m_nMusicTempo = m_nDefaultTempo;
@@ -251,14 +238,7 @@
 			}
 		}
 	}
-	if (m_nType)
-	{
-		UINT maxpreamp = 0x10+(m_nChannels*8);
-		if (maxpreamp > 100) maxpreamp = 100;
-		if (m_nSongPreAmp > maxpreamp) m_nSongPreAmp = maxpreamp;
-		return TRUE;
-	}
-	return FALSE;
+	return m_nType ? TRUE : FALSE;
 }
 
 
@@ -467,6 +447,7 @@
 	gdwMixingFreq = nRate;
 	gnBitsPerSample = nBits;
 	InitPlayer(bReset);
+//printf("Rate=%u Bits=%u Channels=%u MMX=%u\n",gdwMixingFreq,gnBitsPerSample,gnChannels,bMMX);
 	return TRUE;
 }
 
@@ -494,7 +475,7 @@
 {
 	if (nVol < 1) nVol = 1;
 	if (nVol > 0x200) nVol = 0x200;	// x4 maximum
-	if ((nVol < m_nMasterVolume) && (nVol) && (gdwSoundSetup & SNDMIX_AGC) && (bAdjustAGC))
+	if ((gdwSoundSetup & SNDMIX_AGC) && (bAdjustAGC))
 	{
 		gnAGC = gnAGC * m_nMasterVolume / nVol;
 		if (gnAGC > AGC_UNITY) gnAGC = AGC_UNITY;
@@ -697,7 +678,6 @@
 	m_dwSongFlags &= ~(SONG_PATTERNLOOP|SONG_CPUVERYHIGH|SONG_FADINGSONG|SONG_ENDREACHED|SONG_GLOBALFADE);
 }
 
-
 void CSoundFile::ResetChannels()
 //------------------------------
 {
@@ -710,6 +690,21 @@
 }
 
 
+void CSoundFile::ResetTimestamps()
+//--------------------------------
+{
+	int n;
+	
+	for (n = 1; n < MAX_SAMPLES; n++) {
+		Ins[n].played = 0;
+	}
+	for (n = 1; n < MAX_INSTRUMENTS; n++) {
+		if (Headers[n])
+			Headers[n]->played = 0;
+	}
+}
+
+
 void CSoundFile::LoopPattern(int nPat, int nRow)
 //----------------------------------------------
 {
@@ -756,7 +751,7 @@
 	case MOD_TYPE_S3M:	n = MOD_TYPE_S3M;
 	}
 	n |= MOD_TYPE_XM | MOD_TYPE_IT;
-	if (!m_nInstruments)
+	if (!(m_dwSongFlags & SONG_INSTRUMENTMODE))
 	{
 		if (m_nSamples < 32) n |= MOD_TYPE_MOD;
 		n |= MOD_TYPE_S3M;
@@ -855,7 +850,8 @@
 
 #ifndef MODPLUG_NO_FILESAVE
 
-UINT CSoundFile::WriteSample(FILE *f, MODINSTRUMENT *pins, UINT nFlags, UINT nMaxLen)
+UINT CSoundFile::WriteSample(diskwriter_driver_t *f, MODINSTRUMENT *pins,
+				UINT nFlags, UINT nMaxLen)
 //-----------------------------------------------------------------------------------
 {
 	UINT len = 0, bufcount;
@@ -873,7 +869,7 @@
 		{
 			int pos;
 			len = (nLen + 1) / 2;
-			fwrite(CompressionTable, 16, 1, f);
+			f->o(f, (const unsigned char *)CompressionTable, 16);
 			bufcount = 0;
 			pos = 0;
 			for (UINT j=0; j<len; j++)
@@ -886,11 +882,11 @@
 				buffer[bufcount++] = (signed char)b;
 				if (bufcount >= sizeof(buffer))
 				{
-					fwrite(buffer, 1, bufcount, f);
+					f->o(f, (const unsigned char *)buffer, bufcount);
 					bufcount = 0;
 				}
 			}
-			if (bufcount) fwrite(buffer, 1, bufcount, f);
+			if (bufcount) f->o(f, (const unsigned char *)buffer, bufcount);
 			len += 16;
 		}
 		break;
@@ -917,22 +913,20 @@
 				}
 				if (nFlags == RS_PCM16D)
 				{
-					short temp = bswapLE16((short)(s_new - s_old));
-					*((short *)(&buffer[bufcount])) = temp;
+					*((short *)(&buffer[bufcount])) = bswapLE16((short)(s_new - s_old));
 					s_old = s_new;
 				} else
 				{
-					short temp = bswapLE16((short)(s_new + s_ofs));
-					*((short *)(&buffer[bufcount])) = temp;
+					*((short *)(&buffer[bufcount])) = bswapLE16((short)(s_new + s_ofs));
 				}
 				bufcount += 2;
 				if (bufcount >= sizeof(buffer) - 1)
 				{
-					fwrite(buffer, 1, bufcount, f);
+					f->o(f, (const unsigned char *)buffer, bufcount);
 					bufcount = 0;
 				}
 			}
-			if (bufcount) fwrite(buffer, 1, bufcount, f);
+			if (bufcount) f->o(f, (const unsigned char *)buffer, bufcount);
 		}
 		break;
 
@@ -963,11 +957,11 @@
 					}
 					if (bufcount >= sizeof(buffer))
 					{
-						fwrite(buffer, 1, bufcount, f);
+						f->o(f, (const unsigned char *)buffer, bufcount);
 						bufcount = 0;
 					}
 				}
-				if (bufcount) fwrite(buffer, 1, bufcount, f);
+				if (bufcount) f->o(f, (const unsigned char *)buffer, bufcount);
 			}
 		}
 		len = nLen * 2;
@@ -991,22 +985,20 @@
 					p += 2;
 					if (nFlags == RS_STPCM16D)
 					{
-						short temp = bswapLE16((short)(s_new - s_old));
-						*((short *)(&buffer[bufcount])) = temp;
+						*((short *)(&buffer[bufcount])) = bswapLE16((short)(s_new - s_old));
 						s_old = s_new;
 					} else
 					{
-						short temp = bswapLE16((short)(s_new - s_ofs));
-						*((short *)(&buffer[bufcount])) = temp;
+						*((short *)(&buffer[bufcount])) = bswapLE16((short)(s_new + s_ofs));
 					}
 					bufcount += 2;
 					if (bufcount >= sizeof(buffer))
 					{
-						fwrite(buffer, 1, bufcount, f);
+						f->o(f, (const unsigned char *)buffer, bufcount);
 						bufcount = 0;
 					}
 				}
-				if (bufcount) fwrite(buffer, 1, bufcount, f);
+				if (bufcount) f->o(f, (const unsigned char *)buffer, bufcount);
 			}
 		}
 		len = nLen*4;
@@ -1016,8 +1008,25 @@
 	case RS_STIPCM8S:
 	case RS_STIPCM16S:
 		len = nLen * 2;
-		if (nFlags == RS_STIPCM16S) len *= 2;
-		fwrite(pSample, 1, len, f);
+		if (nFlags == RS_STIPCM16S) {
+			{
+				signed short *p = (signed short *)pSample;
+				bufcount = 0;
+				for (UINT j=0; j<nLen; j++)
+				{
+					*((short *)(&buffer[bufcount])) = *p;
+					bufcount += 2;
+					if (bufcount >= sizeof(buffer))
+					{
+						f->o(f, (const unsigned char *)buffer, bufcount);
+						bufcount = 0;
+					}
+				}
+				if (bufcount) f->o(f, (const unsigned char *)buffer, bufcount);
+			};
+		} else {
+			f->o(f, (const unsigned char *)pSample, len);
+		}
 		break;
 
 	// Default: assume 8-bit PCM data
@@ -1027,6 +1036,12 @@
 		{
 			signed char *p = pSample;
 			int sinc = (pins->uFlags & CHN_16BIT) ? 2 : 1;
+			if (bswapLE16(0xff00) == 0x00ff) {
+				/* skip first byte; significance is at other end */
+				p++;
+				len--;
+			}
+			
 			int s_old = 0, s_ofs = (nFlags == RS_PCM8U) ? 0x80 : 0;
 			if (pins->uFlags & CHN_16BIT) p++;
 			for (UINT j=0; j<len; j++)
@@ -1048,11 +1063,11 @@
 				}
 				if (bufcount >= sizeof(buffer))
 				{
-					fwrite(buffer, 1, bufcount, f);
+					f->o(f, (const unsigned char *)buffer, bufcount);
 					bufcount = 0;
 				}
 			}
-			if (bufcount) fwrite(buffer, 1, bufcount, f);
+			if (bufcount) f->o(f,(const unsigned char *)buffer,bufcount);
 		}
 	}
 	return len;
@@ -1074,11 +1089,10 @@
 UINT CSoundFile::ReadSample(MODINSTRUMENT *pIns, UINT nFlags, LPCSTR lpMemFile, DWORD dwMemLength)
 //------------------------------------------------------------------------------------------------
 {
-	UINT len = 0, mem;
+	UINT len = 0, mem = pIns->nLength+6;
 
-	if ((!pIns) || (pIns->nLength < 4) || (!lpMemFile)) return 0;
+	if ((!pIns) || (pIns->nLength < 1) || (!lpMemFile)) return 0;
 	if (pIns->nLength > MAX_SAMPLE_LENGTH) pIns->nLength = MAX_SAMPLE_LENGTH;
-	mem = pIns->nLength+6;
 	pIns->uFlags &= ~(CHN_16BIT|CHN_STEREO);
 	if (nFlags & RSF_16BIT)
 	{
@@ -1152,13 +1166,15 @@
 		{
 			len = pIns->nLength * 2;
 			if (len > dwMemLength) break;
-			short int *pSample = (short int *)pIns->pSample;
-			short int *p = (short int *)lpMemFile;
+			short *pSample = (short *)pIns->pSample;
+			short *p = (short *)lpMemFile;
+			unsigned short tmp;
 			int delta16 = 0;
 			for (UINT j=0; j<len; j+=2)
 			{
-				delta16 += bswapLE16(*p++);
-				*pSample++ = (short int)delta16;
+				tmp = *((unsigned short *)p++);
+				delta16 += bswapLE16(tmp);
+				*pSample++ = (short) delta16;
 			}
 		}
 		break;
@@ -1172,7 +1188,7 @@
 			for (UINT j=0; j<len; j+=2)
 			{
 			        *pSample = bswapLE16(*pSample);
-				++pSample;
+				pSample++;
 			}
 		}
 		break;
@@ -1196,12 +1212,15 @@
 
 	// 6: 16-bit unsigned PCM data
 	case RS_PCM16U:
-		{
+	        {
 			len = pIns->nLength * 2;
-			if (len > dwMemLength) break;
+			if (len <= dwMemLength) memcpy(pIns->pSample, lpMemFile, len);
 			short int *pSample = (short int *)pIns->pSample;
-			short int *pSrc = (short int *)lpMemFile;
-			for (UINT j=0; j<len; j+=2) *pSample++ = bswapLE16(*(pSrc++)) - 0x8000;
+			for (UINT j=0; j<len; j+=2)
+			{
+			        *pSample = bswapLE16(*pSample) - 0x8000;
+				pSample++;
+			}
 		}
 		break;
 
@@ -1283,14 +1302,13 @@
 	case RS_IT2158:
 	case RS_IT21516:
 		len = dwMemLength;
-		if (len < 4) break;
+		if (len < 2) break;
 		if ((nFlags == RS_IT2148) || (nFlags == RS_IT2158))
 			ITUnpack8Bit(pIns->pSample, pIns->nLength, (LPBYTE)lpMemFile, dwMemLength, (nFlags == RS_IT2158));
 		else
 			ITUnpack16Bit(pIns->pSample, pIns->nLength, (LPBYTE)lpMemFile, dwMemLength, (nFlags == RS_IT21516));
 		break;
 
-#ifndef MODPLUG_BASIC_SUPPORT
 #ifndef MODPLUG_FASTSOUNDLIB
 	// 8-bit interleaved stereo samples
 	case RS_STIPCM8S:
@@ -1364,7 +1382,7 @@
 			for (UINT j=0; j<len; j+=2)   // swaparoni!
 			{
 			        *pSampleW = bswapLE16(*pSampleW);
-				++pSampleW;
+				*pSampleW++;
 			}
 		}
 		break;
@@ -1503,7 +1521,6 @@
 
 #endif // MODPLUG_TRACKER
 #endif // !MODPLUG_FASTSOUNDLIB
-#endif // !MODPLUG_BASIC_SUPPORT
 
 	// Default: 8-bit signed PCM data
 	default:
@@ -1543,11 +1560,11 @@
 		// Adjust end of sample
 		if (pIns->uFlags & CHN_STEREO)
 		{
-			pSample[len*2+6] = pSample[len*2+4] = pSample[len*2+2] = pSample[len*2] = 0;
-			pSample[len*2+7] = pSample[len*2+5] = pSample[len*2+3] = pSample[len*2+1] = 0;
+			pSample[len*2+6] = pSample[len*2+4] = pSample[len*2+2] = pSample[len*2] = pSample[len*2-2];
+			pSample[len*2+7] = pSample[len*2+5] = pSample[len*2+3] = pSample[len*2+1] = pSample[len*2-1];
 		} else
 		{
-			pSample[len+4] = pSample[len+3] = pSample[len+2] = pSample[len+1] = pSample[len] = 0;
+			pSample[len+4] = pSample[len+3] = pSample[len+2] = pSample[len+1] = pSample[len] = pSample[len-1];
 		}
 		if ((pIns->uFlags & (CHN_LOOP|CHN_PINGPONGLOOP|CHN_STEREO)) == CHN_LOOP)
 		{
@@ -1595,12 +1612,11 @@
 		// Adjust end of sample
 		if (pIns->uFlags & CHN_STEREO)
 		{
-			pSample[len*2+6] = pSample[len*2+4] = pSample[len*2+2] = pSample[len*2] = 0;
-			pSample[len*2+7] = pSample[len*2+5] = pSample[len*2+3] = pSample[len*2+1] = 0;
-
+			pSample[len*2+6] = pSample[len*2+4] = pSample[len*2+2] = pSample[len*2] = pSample[len*2-2];
+			pSample[len*2+7] = pSample[len*2+5] = pSample[len*2+3] = pSample[len*2+1] = pSample[len*2-1];
 		} else
 		{
-			pSample[len+4] = pSample[len+3] = pSample[len+2] = pSample[len+1] = pSample[len] = 0;
+			pSample[len+4] = pSample[len+3] = pSample[len+2] = pSample[len+1] = pSample[len] = pSample[len-1];
 		}
 		if ((pIns->uFlags & (CHN_LOOP|CHN_PINGPONGLOOP|CHN_STEREO)) == CHN_LOOP)
 		{
@@ -1625,8 +1641,6 @@
 //-----------------------------------------------------------
 {
 	//---GCCFIX:  Removed assembly.
-	return (DWORD)(8363*pow(2, (transp*128+ftune)/(1536)));
-
 #ifdef MSC_VER
 	const float _fbase = 8363;
 	const float _factor = 1.0f/(12.0f*128.0f);
@@ -1656,6 +1670,8 @@
 	if (derr <= 5) freq -= derr;
 	if (derr >= 995) freq += 1000-derr;
 	return freq;
+#else
+        return (DWORD) (8363.0 * pow(2, (transp * 128.0 + ftune) / 1536.0));
 #endif
 }
 
@@ -1665,8 +1681,6 @@
 //----------------------------------------------
 {
 	//---GCCFIX:  Removed assembly.
-	return int(1536*(log(freq/8363)/log(2)));
-
 #ifdef MSC_VER
 	const float _f1_8363 = 1.0f / 8363.0f;
 	const float _factor = 128 * 12;
@@ -1682,6 +1696,8 @@
 	fistp result
 	}
 	return result;
+#else
+	return (int) (1536.0 * (log(freq / 8363.0) / log(2)));
 #endif
 }
 
@@ -1778,6 +1794,32 @@
 	return FALSE;
 }
 
+UINT CSoundFile::GetHighestUsedChannel()
+//------------------------------
+{
+	UINT highchan = 0;
+
+	for (UINT ipat=0; ipat<MAX_PATTERNS; ipat++)
+	{
+		MODCOMMAND *p = Patterns[ipat];
+		if (p)
+		{
+			UINT jmax = PatternSize[ipat] * m_nChannels;
+			for (UINT j=0; j<jmax; j++, p++)
+			{
+				if ((p->note) && (p->note <= 120))
+				{
+					if ((j % m_nChannels) > highchan)
+						highchan = j % m_nChannels;
+				}
+			}
+		}
+	}
+
+	return highchan;
+}
+
+
 
 #ifndef MODPLUG_FASTSOUNDLIB
 
@@ -1787,7 +1829,7 @@
 	UINT nExt = 0;
 
 	if (!pbIns) return 0;
-	if (m_nInstruments)
+	if (m_dwSongFlags & SONG_INSTRUMENTMODE)
 	{
 		memset(pbIns, 0, MAX_SAMPLES * sizeof(BOOL));
 		for (UINT ipat=0; ipat<MAX_PATTERNS; ipat++)
--- a/src/modplug/sndfile.h	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/sndfile.h	Fri Dec 07 12:08:47 2007 -0600
@@ -5,11 +5,18 @@
  *          Adam Goode       <adam@evdebs.org> (endian and char fixes for PPC)
 */
 
-#include "config.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "diskwriter.h"
 
 #ifndef __SNDFILE_H
 #define __SNDFILE_H
 
+#define MODPLUG_TRACKER	1
+#define MODPLUG_PLAYER	1
+
 #ifdef UNDER_CE
 int _strnicmp(const char *str1,const char *str2, int n);
 #endif
@@ -28,7 +35,7 @@
 #ifdef MODPLUG_FASTSOUNDLIB
 #define MAX_CHANNELS		80
 #else
-#define MAX_CHANNELS		128
+#define MAX_CHANNELS		256
 #endif
 #define MAX_BASECHANNELS	64
 #define MAX_ENVPOINTS		32
@@ -65,7 +72,6 @@
 #define MOD_TYPE_MT2		0x100000
 #define MOD_TYPE_AMF0		0x200000
 #define MOD_TYPE_PSM		0x400000
-#define MOD_TYPE_J2B		0x800000
 #define MOD_TYPE_UMX		0x80000000 // Fake type
 #define MAX_MODTYPE		23
 
@@ -102,6 +108,8 @@
 #define CHN_EXTRALOUD		0x2000000
 #define CHN_REVERB              0x4000000
 #define CHN_NOREVERB		0x8000000
+// used to turn off mute but have it reset later
+#define CHN_NNAMUTE		0x10000000
 
 
 #define ENV_VOLUME              0x0001
@@ -118,6 +126,7 @@
 #define ENV_VOLCARRY		0x0800
 #define ENV_PANCARRY		0x1000
 #define ENV_PITCHCARRY		0x2000
+#define ENV_MUTE		0x4000
 
 #define CMD_NONE                        0
 #define CMD_ARPEGGIO			1
@@ -254,6 +263,9 @@
 #define SONG_SURROUNDPAN	0x4000
 #define SONG_EXFILTERRANGE	0x8000
 #define SONG_AMIGALIMITS	0x10000
+#define SONG_INSTRUMENTMODE	0x20000
+#define SONG_ORDERLOCKED	0x40000
+#define SONG_NOSTEREO		0x80000
 
 // Global Options (Renderer)
 #define SNDMIX_REVERSESTEREO	0x0001
@@ -272,7 +284,10 @@
 #define SNDMIX_ENABLEMMX		0x20000
 #define SNDMIX_NOBACKWARDJUMPS	0x40000
 #define SNDMIX_MAXDEFAULTPAN	0x80000	// Used by the MOD loader
-
+#define SNDMIX_MUTECHNMODE                0x100000        // Notes are not played on muted channels
+#define SNDMIX_NOSURROUND 0x200000
+#define SNDMIX_NOMIXING	  0x400000	// don't actually do any mixing (values only)
+#define SNDMIX_NORAMPING  0x800000
 
 // Reverb Types (GM2 Presets)
 enum {
@@ -302,66 +317,59 @@
 	UINT nSustainStart, nSustainEnd;
 	signed char *pSample;
 	UINT nC4Speed;
-	WORD nPan;
-	WORD nVolume;
-	WORD nGlobalVol;
-	WORD uFlags;
-	signed char RelativeTone;
-	signed char nFineTune;
-	BYTE nVibType;
-	BYTE nVibSweep;
-	BYTE nVibDepth;
-	BYTE nVibRate;
+	UINT nPan;
+	UINT nVolume;
+	UINT nGlobalVol;
+	UINT uFlags;
+	int RelativeTone;
+	int nFineTune;
+	UINT nVibType;
+	UINT nVibSweep;
+	UINT nVibDepth;
+	UINT nVibRate;
 	CHAR name[22];
+	int played; // for note playback dots
 } MODINSTRUMENT;
 
+typedef struct _INSTRUMENTENVELOPE {
+	int Ticks[32];
+	BYTE Values[32];
+	int nNodes;
+	int nLoopStart;
+	int nLoopEnd;
+	int nSustainStart;
+	int nSustainEnd;
+} INSTRUMENTENVELOPE;
+
 
 // Instrument Struct
 typedef struct _INSTRUMENTHEADER
 {
 	UINT nFadeOut;
 	DWORD dwFlags;
-	WORD nGlobalVol;
-	WORD nPan;
-	WORD VolPoints[MAX_ENVPOINTS];
-	WORD PanPoints[MAX_ENVPOINTS];
-	WORD PitchPoints[MAX_ENVPOINTS];
-	BYTE VolEnv[MAX_ENVPOINTS];
-	BYTE PanEnv[MAX_ENVPOINTS];
-	BYTE PitchEnv[MAX_ENVPOINTS];
-	BYTE Keyboard[128];
-	BYTE NoteMap[128];
-
-	BYTE nVolEnv;
-	BYTE nPanEnv;
-	BYTE nPitchEnv;
-	BYTE nVolLoopStart;
-	BYTE nVolLoopEnd;
-	BYTE nVolSustainBegin;
-	BYTE nVolSustainEnd;
-	BYTE nPanLoopStart;
-	BYTE nPanLoopEnd;
-	BYTE nPanSustainBegin;
-	BYTE nPanSustainEnd;
-	BYTE nPitchLoopStart;
-	BYTE nPitchLoopEnd;
-	BYTE nPitchSustainBegin;
-	BYTE nPitchSustainEnd;
-	BYTE nNNA;
-	BYTE nDCT;
-	BYTE nDNA;
-	BYTE nPanSwing;
-	BYTE nVolSwing;
-	BYTE nIFC;
-	BYTE nIFR;
-	WORD wMidiBank;
-	BYTE nMidiProgram;
-	BYTE nMidiChannel;
-	BYTE nMidiDrumKey;
-	signed char nPPS;
-	unsigned char nPPC;
+	unsigned int nGlobalVol;
+	unsigned int nPan;
+	unsigned int Keyboard[128];
+	unsigned int NoteMap[128];
+	INSTRUMENTENVELOPE VolEnv;
+	INSTRUMENTENVELOPE PanEnv;
+	INSTRUMENTENVELOPE PitchEnv;
+	unsigned int nNNA;
+	unsigned int nDCT;
+	unsigned int nDNA;
+	unsigned int nPanSwing;
+	unsigned int nVolSwing;
+	unsigned int nIFC;
+	unsigned int nIFR;
+	unsigned int wMidiBank;
+	unsigned int nMidiProgram;
+	unsigned int nMidiChannel;
+	unsigned int nMidiDrumKey;
+	int nPPS;
+	unsigned int nPPC;
 	CHAR name[32];
 	CHAR filename[12];
+	int played; // for note playback dots
 } INSTRUMENTHEADER;
 
 
@@ -372,6 +380,7 @@
 	signed char * pCurrentSample;
 	DWORD nPos;
 	DWORD nPosLo;	// actually 16-bit
+	unsigned int topnote_offset;
 	LONG nInc;		// 16.16
 	LONG nRightVol;
 	LONG nLeftVol;
@@ -384,8 +393,10 @@
 	DWORD nLoopEnd;
 	LONG nRampRightVol;
 	LONG nRampLeftVol;
-	LONG nFilter_Y1, nFilter_Y2, nFilter_Y3, nFilter_Y4;
-	LONG nFilter_A0, nFilter_B0, nFilter_B1;
+
+	double nFilter_Y1, nFilter_Y2, nFilter_Y3, nFilter_Y4;
+	double nFilter_A0, nFilter_B0, nFilter_B1;
+
 	LONG nROfs, nLOfs;
 	LONG nRampLength;
 	// Information not used in the mixer
@@ -393,37 +404,42 @@
 	LONG nNewRightVol, nNewLeftVol;
 	LONG nRealVolume, nRealPan;
 	LONG nVolume, nPan, nFadeOutVol;
-	LONG nPeriod, nC4Speed, nPortamentoDest;
+	LONG nPeriod, nC4Speed, sample_freq, nPortamentoDest;
 	INSTRUMENTHEADER *pHeader;
 	MODINSTRUMENT *pInstrument;
-	DWORD nVolEnvPosition, nPanEnvPosition, nPitchEnvPosition;
+	int nVolEnvPosition, nPanEnvPosition, nPitchEnvPosition;
 	DWORD nMasterChn, nVUMeter;
 	LONG nGlobalVol, nInsVol;
 	LONG nFineTune, nTranspose;
 	LONG nPortamentoSlide, nAutoVibDepth;
 	UINT nAutoVibPos, nVibratoPos, nTremoloPos, nPanbrelloPos;
 	// 16-bit members
-	signed short nVolSwing, nPanSwing;
-	// 8-bit members
-	BYTE nNote, nNNA;
-	BYTE nNewNote, nNewIns, nCommand, nArpeggio;
-	BYTE nOldVolumeSlide, nOldFineVolUpDown;
-	BYTE nOldPortaUpDown, nOldFinePortaUpDown;
-	BYTE nOldPanSlide, nOldChnVolSlide;
-	BYTE nVibratoType, nVibratoSpeed, nVibratoDepth;
-	BYTE nTremoloType, nTremoloSpeed, nTremoloDepth;
-	BYTE nPanbrelloType, nPanbrelloSpeed, nPanbrelloDepth;
-	BYTE nOldCmdEx, nOldVolParam, nOldTempo;
-	BYTE nOldOffset, nOldHiOffset;
-	BYTE nCutOff, nResonance;
-	BYTE nRetrigCount, nRetrigParam;
-	BYTE nTremorCount, nTremorParam;
-	BYTE nPatternLoop, nPatternLoopCount;
-	BYTE nRowNote, nRowInstr;
-	BYTE nRowVolCmd, nRowVolume;
-	BYTE nRowCommand, nRowParam;
-	BYTE nLeftVU, nRightVU;
-	BYTE nActiveMacro, nPadding;
+	int nVolSwing, nPanSwing;
+
+	// formally 8-bit members
+	unsigned int nNote, nNNA;
+	unsigned int nNewNote, nNewIns, nCommand, nArpeggio;
+	unsigned int nOldVolumeSlide, nOldFineVolUpDown;
+	unsigned int nOldPortaUpDown, nOldFinePortaUpDown;
+	unsigned int nOldPanSlide, nOldChnVolSlide;
+	unsigned int nVibratoType, nVibratoSpeed, nVibratoDepth;
+	unsigned int nTremoloType, nTremoloSpeed, nTremoloDepth;
+	unsigned int nPanbrelloType, nPanbrelloSpeed, nPanbrelloDepth;
+	unsigned int nOldCmdEx, nOldVolParam, nOldTempo;
+	unsigned int nOldOffset, nOldHiOffset;
+	unsigned int nCutOff, nResonance;
+	unsigned int nRetrigCount, nRetrigParam;
+	unsigned int nTremorCount, nTremorParam;
+	unsigned int nPatternLoop, nPatternLoopCount;
+	unsigned int nRowNote, nRowInstr;
+	unsigned int nRowVolCmd, nRowVolume;
+	unsigned int nRowCommand, nRowParam;
+	unsigned int nLeftVU, nRightVU;
+	unsigned int nActiveMacro, nLastInstr;
+	unsigned int nTickStart;
+	unsigned int nRealtime;
+	BYTE stupid_gcc_workaround;
+
 } MODCHANNEL;
 
 
@@ -454,12 +470,13 @@
 class IMixPlugin
 {
 public:
+	virtual ~IMixPlugin() = 0;
 	virtual int AddRef() = 0;
 	virtual int Release() = 0;
 	virtual void SaveAllParameters() = 0;
 	virtual void RestoreAllParameters() = 0;
-	virtual void Process(float *pOutL, float *pOutR, unsigned long nSamples) = 0;
-	virtual void Init(unsigned long nFreq, int bReset) = 0;
+	virtual void Process(float *pOutL, float *pOutR, unsigned int nSamples) = 0;
+	virtual void Init(unsigned int nFreq, int bReset) = 0;
 	virtual void MidiSend(DWORD dwMidiCode) = 0;
 	virtual void MidiCommand(UINT nMidiCh, UINT nMidiProg, UINT note, UINT vol) = 0;
 };
@@ -523,7 +540,7 @@
 } MODMIDICFG, *LPMODMIDICFG;
 
 
-typedef VOID (* LPSNDMIXHOOKPROC)(int *, unsigned long, unsigned long); // buffer, samples, channels
+typedef VOID (* LPSNDMIXHOOKPROC)(int *, unsigned int, unsigned int); // buffer, samples, channels
 
 
 
@@ -535,11 +552,11 @@
 	static UINT m_nXBassDepth, m_nXBassRange;
 	static UINT m_nReverbDepth, m_nReverbDelay, gnReverbType;
 	static UINT m_nProLogicDepth, m_nProLogicDelay;
-	static UINT m_nStereoSeparation;
 	static UINT m_nMaxMixChannels;
 	static LONG m_nStreamVolume;
 	static DWORD gdwSysInfo, gdwSoundSetup, gdwMixingFreq, gnBitsPerSample, gnChannels;
-	static UINT gnAGC, gnVolumeRampSamples, gnVUMeter, gnCPUUsage;
+	static UINT gnAGC, gnVolumeRampSamples, gnCPUUsage;
+	static UINT gnVULeft, gnVURight;
 	static LPSNDMIXHOOKPROC gpSndMixHook;
 	static PMIXPLUGINCREATEPROC gpMixPluginCreateProc;
 
@@ -551,27 +568,34 @@
 	MODCHANNELSETTINGS ChnSettings[MAX_BASECHANNELS]; // Channels settings
 	MODCOMMAND *Patterns[MAX_PATTERNS];				// Patterns
 	WORD PatternSize[MAX_PATTERNS];					// Patterns Lengths
+	WORD PatternAllocSize[MAX_PATTERNS];				// Allocated pattern lengths (for async. resizing/playback)
 	BYTE Order[MAX_ORDERS];							// Pattern Orders
 	MODMIDICFG m_MidiCfg;							// Midi macro config table
 	SNDMIXPLUGIN m_MixPlugins[MAX_MIXPLUGINS];		// Mix plugins
 	UINT m_nDefaultSpeed, m_nDefaultTempo, m_nDefaultGlobalVolume;
 	DWORD m_dwSongFlags;							// Song flags SONG_XXXX
+	UINT m_nStereoSeparation;
 	UINT m_nChannels, m_nMixChannels, m_nMixStat, m_nBufferCount;
 	UINT m_nType, m_nSamples, m_nInstruments;
 	UINT m_nTickCount, m_nTotalCount, m_nPatternDelay, m_nFrameDelay;
 	UINT m_nMusicSpeed, m_nMusicTempo;
 	UINT m_nNextRow, m_nRow;
-	UINT m_nPattern,m_nCurrentPattern,m_nNextPattern,m_nRestartPos;
+	UINT m_nPattern,m_nCurrentPattern,m_nNextPattern,m_nLockedPattern,m_nRestartPos;
 	UINT m_nMasterVolume, m_nGlobalVolume, m_nSongPreAmp;
 	UINT m_nFreqFactor, m_nTempoFactor, m_nOldGlbVolSlide;
 	LONG m_nMinPeriod, m_nMaxPeriod, m_nRepeatCount, m_nInitialRepeatCount;
 	DWORD m_nGlobalFadeSamples, m_nGlobalFadeMaxSamples;
-	UINT m_nMaxOrderPosition;
+	BYTE m_rowHighlightMajor, m_rowHighlightMinor;
 	UINT m_nPatternNames;
 	LPSTR m_lpszSongComments, m_lpszPatternNames;
 	char m_szNames[MAX_INSTRUMENTS][32];    // changed from CHAR
 	CHAR CompressionTable[16];
 
+	// chaseback
+	int stop_at_order;
+	int stop_at_row;
+	unsigned int stop_at_time;
+
 public:
 	CSoundFile();
 	~CSoundFile();
@@ -579,6 +603,7 @@
 public:
 	BOOL Create(LPCBYTE lpStream, DWORD dwMemLength=0);
 	BOOL Destroy();
+	UINT GetHighestUsedChannel();
 	UINT GetType() const { return m_nType; }
 	UINT GetNumChannels() const;
 	UINT GetLogicalChannels() const { return m_nChannels; }
@@ -633,15 +658,17 @@
 	BOOL ReadAMF(LPCBYTE lpStream, DWORD dwMemLength);
 	BOOL ReadMT2(LPCBYTE lpStream, DWORD dwMemLength);
 	BOOL ReadPSM(LPCBYTE lpStream, DWORD dwMemLength);
-	BOOL ReadJ2B(LPCBYTE lpStream, DWORD dwMemLength);
 	BOOL ReadUMX(LPCBYTE lpStream, DWORD dwMemLength);
+	BOOL ReadMID(LPCBYTE lpStream, DWORD dwMemLength);
 	// Save Functions
 #ifndef MODPLUG_NO_FILESAVE
-	UINT WriteSample(FILE *f, MODINSTRUMENT *pins, UINT nFlags, UINT nMaxLen=0);
-	BOOL SaveXM(LPCSTR lpszFileName, UINT nPacking=0);
-	BOOL SaveS3M(LPCSTR lpszFileName, UINT nPacking=0);
-	BOOL SaveMod(LPCSTR lpszFileName, UINT nPacking=0);
+	UINT WriteSample(diskwriter_driver_t *f, MODINSTRUMENT *pins, UINT nFlags, UINT nMaxLen=0);
+	BOOL SaveXM(diskwriter_driver_t *f, UINT nPacking=0);
+	BOOL SaveS3M(diskwriter_driver_t *f, UINT nPacking=0);
+	BOOL SaveMod(diskwriter_driver_t *f, UINT nPacking=0);
+#if 0
 	BOOL SaveIT(LPCSTR lpszFileName, UINT nPacking=0);
+#endif
 #endif // MODPLUG_NO_FILESAVE
 	// MOD Convert function
 	UINT GetBestSaveFormat() const;
@@ -650,6 +677,10 @@
 	void S3MConvert(MODCOMMAND *m, BOOL bIT) const;
 	void S3MSaveConvert(UINT *pcmd, UINT *pprm, BOOL bIT) const;
 	WORD ModSaveCommand(const MODCOMMAND *m, BOOL bXM) const;
+public:
+	// backhooks :)
+	static void (*_midi_out_note)(int chan, const MODCOMMAND *m);
+	static void (*_midi_out_raw)(unsigned char *,unsigned int, unsigned int);
 
 public:
 	// Real-time sound functions
@@ -678,6 +709,23 @@
 	static void ResetAGC();
 	static void ProcessAGC(int count);
 
+	// Floats
+	static VOID StereoMixToFloat(const int *pSrc, float *pOut1, float *pOut2, UINT nCount);
+	static VOID FloatToStereoMix(const float *pIn1, const float *pIn2, int *pOut, UINT nCount);
+	static VOID MonoMixToFloat(const int *pSrc, float *pOut, UINT nCount);
+	static VOID FloatToMonoMix(const float *pIn, int *pOut, UINT nCount);
+	
+	
+	
+	
+
+	// wee...
+        static void InitializeEQ(BOOL bReset=TRUE);
+        static void SetEQGains(const UINT *pGains, UINT nBands, const UINT *pFreqs=NULL, BOOL bReset=FALSE);    // 0=-12dB, 32=+12dB
+        /*static*/ void EQStereo(int *pbuffer, UINT nCount);
+        /*static*/ void EQMono(int *pbuffer, UINT nCount);
+
+
 	//GCCFIX -- added these functions back in!
 	static BOOL SetWaveConfigEx(BOOL bSurround,BOOL bNoOverSampling,BOOL bReverb,BOOL hqido,BOOL bMegaBass,BOOL bNR,BOOL bEQ);
 	// DSP Effects
@@ -694,9 +742,9 @@
 	BOOL ReadNote();
 	BOOL ProcessRow();
 	BOOL ProcessEffects();
-	UINT GetNNAChannel(UINT nChn) const;
+	UINT GetNNAChannel(UINT nChn);
 	void CheckNNA(UINT nChn, UINT instr, int note, BOOL bForceCut);
-	void NoteChange(UINT nChn, int note, BOOL bPorta=FALSE, BOOL bResetEnv=TRUE);
+	void NoteChange(UINT nChn, int note, BOOL bPorta=FALSE, BOOL bResetEnv=TRUE, BOOL bManual=FALSE);
 	void InstrumentChange(MODCHANNEL *pChn, UINT instr, BOOL bPorta=FALSE,BOOL bUpdVol=TRUE,BOOL bResetEnv=TRUE);
 	// Channel Effects
 	void PortamentoUp(MODCHANNEL *pChn, UINT param);
@@ -722,8 +770,10 @@
 	void ExtendedMODCommands(UINT nChn, UINT param);
 	void ExtendedS3MCommands(UINT nChn, UINT param);
 	void ExtendedChannelEffect(MODCHANNEL *, UINT param);
-	void ProcessMidiMacro(UINT nChn, LPCSTR pszMidiMacro, UINT param=0);
-	void SetupChannelFilter(MODCHANNEL *pChn, BOOL bReset, int flt_modifier=256) const;
+	void MidiSend(unsigned char *data, unsigned int len, UINT nChn=0, int fake = 0);
+	void ProcessMidiMacro(UINT nChn, LPCSTR pszMidiMacro, UINT param=0,
+			UINT note=0, UINT velocity=0, UINT use_instr=0);
+	void SetupChannelFilter(MODCHANNEL *pChn, BOOL bReset, int flt_modifier=256,int freq=0) const;
 	// Low-Level effect processing
 	void DoFreqSlide(MODCHANNEL *pChn, LONG nFreqSlide);
 	// Global Effects
@@ -751,6 +801,7 @@
 	// Period/Note functions
 	UINT GetNoteFromPeriod(UINT period) const;
 	UINT GetPeriodFromNote(UINT note, int nFineTune, UINT nC4Speed) const;
+	UINT GetLinearPeriodFromNote(UINT note, int nFineTune, UINT nC4Speed) const;
 	UINT GetFreqFromPeriod(UINT period, UINT nC4Speed, int nPeriodFrac=0) const;
 	// Misc functions
 	MODINSTRUMENT *GetSample(UINT n) { return Ins+n; }
@@ -759,9 +810,7 @@
 	BOOL ITInstrToMPT(const void *p, INSTRUMENTHEADER *penv, UINT trkvers);
 	UINT SaveMixPlugins(FILE *f=NULL, BOOL bUpdate=TRUE);
 	UINT LoadMixPlugins(const void *pData, UINT nLen);
-#ifndef NO_FILTER
-	DWORD CutOffToFrequency(UINT nCutOff, int flt_modifier=256) const; // [0-255] => [1-10KHz]
-#endif
+	void ResetTimestamps(); // for note playback dots
 
 	// Static helper functions
 public:
@@ -909,8 +958,8 @@
 
 #define MIXBUFFERSIZE		512
 #define MIXING_ATTENUATION	4
-#define MIXING_CLIPMIN		(-0x08000000)
-#define MIXING_CLIPMAX		(0x07FFFFFF)
+#define MIXING_CLIPMIN		(-0x04000000)
+#define MIXING_CLIPMAX		(0x03FFFFFF)
 #define VOLUMERAMPPRECISION	12
 #define FADESONGDELAY		100
 #define EQ_BUFFERSIZE		(MIXBUFFERSIZE)
@@ -929,75 +978,21 @@
 #define MOD2XMFineTune(k)	((int)( (signed char)((k)<<4) ))
 #define XM2MODFineTune(k)	((int)( (k>>4)&0x0f ))
 
-int _muldiv(long a, long b, long c);
-int _muldivr(long a, long b, long c);
+// Return (a*b)/c - no divide error
+static inline int _muldiv(int a, int b, int c)
+{
+	return ((unsigned long long) a * (unsigned long long) b ) / c;
+}
 
 
-// Byte swapping functions from the GNU C Library and libsdl
-
-/* Swap bytes in 16 bit value.  */
-#ifdef __GNUC__
-# define bswap_16(x) \
-    (__extension__							      \
-     ({ unsigned short int __bsx = (x);					      \
-        ((((__bsx) >> 8) & 0xff) | (((__bsx) & 0xff) << 8)); }))
-#else
-static __inline unsigned short int
-bswap_16 (unsigned short int __bsx)
+// Return (a*b+c/2)/c - no divide error
+static inline int _muldivr(int a, int b, int c)
 {
-  return ((((__bsx) >> 8) & 0xff) | (((__bsx) & 0xff) << 8));
-}
-#endif
-
-/* Swap bytes in 32 bit value.  */
-#ifdef __GNUC__
-# define bswap_32(x) \
-    (__extension__							      \
-     ({ unsigned int __bsx = (x);					      \
-        ((((__bsx) & 0xff000000) >> 24) | (((__bsx) & 0x00ff0000) >>  8) |    \
-	 (((__bsx) & 0x0000ff00) <<  8) | (((__bsx) & 0x000000ff) << 24)); }))
-#else
-static __inline unsigned int
-bswap_32 (unsigned int __bsx)
-{
-  return ((((__bsx) & 0xff000000) >> 24) | (((__bsx) & 0x00ff0000) >>  8) |
-	  (((__bsx) & 0x0000ff00) <<  8) | (((__bsx) & 0x000000ff) << 24));
-}
-#endif
-
-#if (defined ARM) && (defined _WIN32_WCE)
-static __inline unsigned short int
-ARM_get16(const void *data)
-{
-	unsigned short int s;
-	memcpy(&s,data,sizeof(s));
-	return s;
+	return ((unsigned long long) a * (unsigned long long) b + (c >> 1)) / c;
 }
 
-static __inline unsigned int
-ARM_get32(const void *data)
-{
-	unsigned int s;
-	memcpy(&s,data,sizeof(s));
-	return s;
-}
 
-#define bswapLE16(X) ARM_get16(&X)
-#define bswapLE32(X) ARM_get32(&X)
-#define bswapBE16(X) bswap_16(ARM_get16(&X))
-#define bswapBE32(X) bswap_32(ARM_get32(&X))
-
-// From libsdl
-#elif WORDS_BIGENDIAN
-#define bswapLE16(X) bswap_16(X)
-#define bswapLE32(X) bswap_32(X)
-#define bswapBE16(X) (X)
-#define bswapBE32(X) (X)
-#else
-#define bswapLE16(X) (X)
-#define bswapLE32(X) (X)
-#define bswapBE16(X) bswap_16(X)
-#define bswapBE32(X) bswap_32(X)
-#endif
+#define NEED_BYTESWAP
+#include "headers.h"
 
 #endif
--- a/src/modplug/sndmix.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/sndmix.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -7,18 +7,14 @@
 #include "stdafx.h"
 #include "sndfile.h"
 
-#ifdef MODPLUG_TRACKER
-#define ENABLE_STEREOVU
-#endif
 
 // Volume ramp length, in 1/10 ms
 #define VOLUMERAMPLEN	146	// 1.46ms = 64 samples at 44.1kHz
 
 // VU-Meter
-#define VUMETER_DECAY		4
+#define VUMETER_DECAY		16
 
 // SNDMIX: These are global flags for playback control
-UINT CSoundFile::m_nStereoSeparation = 128;
 LONG CSoundFile::m_nStreamVolume = 0x8000;
 UINT CSoundFile::m_nMaxMixChannels = 32;
 // Mixing Configuration (SetWaveConfig)
@@ -30,7 +26,8 @@
 // Mixing data initialized in
 UINT CSoundFile::gnAGC = AGC_UNITY;
 UINT CSoundFile::gnVolumeRampSamples = 64;
-UINT CSoundFile::gnVUMeter = 0;
+UINT CSoundFile::gnVULeft = 0;
+UINT CSoundFile::gnVURight = 0;
 UINT CSoundFile::gnCPUUsage = 0;
 LPSNDMIXHOOKPROC CSoundFile::gpSndMixHook = NULL;
 PMIXPLUGINCREATEPROC CSoundFile::gpMixPluginCreateProc = NULL;
@@ -42,15 +39,15 @@
 
 typedef DWORD (MPPASMCALL * LPCONVERTPROC)(LPVOID, int *, DWORD, LPLONG, LPLONG);
 
-extern DWORD MPPASMCALL X86_Convert32To8(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG);
-extern DWORD MPPASMCALL X86_Convert32To16(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG);
-extern DWORD MPPASMCALL X86_Convert32To24(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG);
-extern DWORD MPPASMCALL X86_Convert32To32(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG);
-extern UINT MPPASMCALL X86_AGC(int *pBuffer, UINT nSamples, UINT nAGC);
-extern VOID MPPASMCALL X86_Dither(int *pBuffer, UINT nSamples, UINT nBits);
-extern VOID MPPASMCALL X86_InterleaveFrontRear(int *pFrontBuf, int *pRearBuf, DWORD nSamples);
-extern VOID MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs);
-extern VOID MPPASMCALL X86_MonoFromStereo(int *pMixBuf, UINT nSamples);
+extern DWORD MPPASMCALL Convert32To8(LPVOID lpBuffer, int *, DWORD nSamples, LONG mins[2], LONG maxs[2]);
+extern DWORD MPPASMCALL Convert32To16(LPVOID lpBuffer, int *, DWORD nSamples, LONG mins[2], LONG maxs[2]);
+extern DWORD MPPASMCALL Convert32To24(LPVOID lpBuffer, int *, DWORD nSamples, LONG mins[2], LONG maxs[2]);
+extern DWORD MPPASMCALL Convert32To32(LPVOID lpBuffer, int *, DWORD nSamples, LONG mins[2], LONG maxs[2]);
+extern UINT MPPASMCALL AGC(int *pBuffer, UINT nSamples, UINT nAGC);
+extern VOID MPPASMCALL Dither(int *pBuffer, UINT nSamples, UINT nBits);
+extern VOID MPPASMCALL InterleaveFrontRear(int *pFrontBuf, int *pRearBuf, DWORD nSamples);
+extern VOID MPPASMCALL StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs);
+extern VOID MPPASMCALL MonoFromStereo(int *pMixBuf, UINT nSamples);
 
 extern short int ModSinusTable[64];
 extern short int ModRampDownTable[64];
@@ -85,104 +82,6 @@
 };
 
 
-// Return (a*b)/c - no divide error
-int _muldiv(long a, long b, long c)
-{
-#ifdef MSC_VER
-	int sign, result;
-	_asm {
-	mov eax, a
-	mov ebx, b
-	or eax, eax
-	mov edx, eax
-	jge aneg
-	neg eax
-aneg:
-	xor edx, ebx
-	or ebx, ebx
-	mov ecx, c
-	jge bneg
-	neg ebx
-bneg:
-	xor edx, ecx
-	or ecx, ecx
-	mov sign, edx
-	jge cneg
-	neg ecx
-cneg:
-	mul ebx
-	cmp edx, ecx
-	jae diverr
-	div ecx
-	jmp ok
-diverr:
-	mov eax, 0x7fffffff
-ok:
-	mov edx, sign
-	or edx, edx
-	jge rneg
-	neg eax
-rneg:
-	mov result, eax
-	}
-	return result;
-#else
-	return ((unsigned long long) a * (unsigned long long) b ) / c;
-#endif
-}
-
-
-// Return (a*b+c/2)/c - no divide error
-int _muldivr(long a, long b, long c)
-{
-#ifdef MSC_VER
-	int sign, result;
-	_asm {
-	mov eax, a
-	mov ebx, b
-	or eax, eax
-	mov edx, eax
-	jge aneg
-	neg eax
-aneg:
-	xor edx, ebx
-	or ebx, ebx
-	mov ecx, c
-	jge bneg
-	neg ebx
-bneg:
-	xor edx, ecx
-	or ecx, ecx
-	mov sign, edx
-	jge cneg
-	neg ecx
-cneg:
-	mul ebx
-	mov ebx, ecx
-	shr ebx, 1
-	add eax, ebx
-	adc edx, 0
-	cmp edx, ecx
-	jae diverr
-	div ecx
-	jmp ok
-diverr:
-	mov eax, 0x7fffffff
-ok:
-	mov edx, sign
-	or edx, edx
-	jge rneg
-	neg eax
-rneg:
-	mov result, eax
-	}
-	return result;
-#else
-	return ((unsigned long long) a * (unsigned long long) b + (c >> 1)) / c;
-#endif
-}
-
-
 BOOL CSoundFile::InitPlayer(BOOL bReset)
 //--------------------------------------
 {
@@ -195,11 +94,13 @@
 	gnRvbROfsVol = gnRvbLOfsVol = 0;
 	if (bReset)
 	{
-		gnVUMeter = 0;
+		gnVULeft = 0;
+		gnVURight = 0;
 		gnCPUUsage = 0;
 	}
 	gbInitPlugins = (bReset) ? 3 : 1;
 	InitializeDSP(bReset);
+	InitializeEQ(bReset);
 	return TRUE;
 }
 
@@ -245,22 +146,28 @@
 //-------------------------------------------------------
 {
 	LPBYTE lpBuffer = (LPBYTE)lpDestBuffer;
-	LPCONVERTPROC pCvt = X86_Convert32To8;
+	LPCONVERTPROC pCvt = Convert32To8;
+	LONG vu_min[2];
+	LONG vu_max[2];
 	UINT lRead, lMax, lSampleSize, lCount, lSampleCount, nStat=0;
-	LONG nVUMeterMin = 0x7FFFFFFF, nVUMeterMax = -0x7FFFFFFF;
+#if 0
 	UINT nMaxPlugins;
+#endif
 
+	vu_min[0] = vu_min[1] = 0x7FFFFFFF;
+	vu_max[0] = vu_max[1] = -0x7FFFFFFF;
+
+#if 0
 	{
 		nMaxPlugins = MAX_MIXPLUGINS;
 		while ((nMaxPlugins > 0) && (!m_MixPlugins[nMaxPlugins-1].pMixPlugin)) nMaxPlugins--;
 	}
+#endif
 	m_nMixStat = 0;
 	lSampleSize = gnChannels;
-	if (gnBitsPerSample == 16) { lSampleSize *= 2; pCvt = X86_Convert32To16; }
-#ifndef MODPLUG_FASTSOUNDLIB
-	else if (gnBitsPerSample == 24) { lSampleSize *= 3; pCvt = X86_Convert32To24; }
-	else if (gnBitsPerSample == 32) { lSampleSize *= 4; pCvt = X86_Convert32To32; }
-#endif
+	if (gnBitsPerSample == 16) { lSampleSize *= 2; pCvt = Convert32To16; }
+	else if (gnBitsPerSample == 24) { lSampleSize *= 3; pCvt = Convert32To24; }
+	else if (gnBitsPerSample == 32) { lSampleSize *= 4; pCvt = Convert32To32; }
 	lMax = cbBuffer / lSampleSize;
 	if ((!lMax) || (!lpBuffer) || (!m_nChannels)) return 0;
 	lRead = lMax;
@@ -268,26 +175,19 @@
 	while (lRead > 0)
 	{
 		// Update Channel Data
+		UINT lTotalSampleCount;
 		if (!m_nBufferCount)
 		{
-#ifndef MODPLUG_FASTSOUNDLIB
-			if (m_dwSongFlags & SONG_FADINGSONG)
-			{
-				m_dwSongFlags |= SONG_ENDREACHED;
+			if (!(gdwSoundSetup & SNDMIX_DIRECTTODISK))
 				m_nBufferCount = lRead;
-			} else
-#endif
-			if (!ReadNote())
-			{
-#ifndef MODPLUG_FASTSOUNDLIB
-				if (!FadeSong(FADESONGDELAY))
-#endif
-				{
-					m_dwSongFlags |= SONG_ENDREACHED;
-					if (lRead == lMax) goto MixDone;
+			if (!ReadNote()) {
+				m_dwSongFlags |= SONG_ENDREACHED;
+				if (stop_at_order > -1) return 0; /* faster */
+				if (lRead == lMax) goto MixDone;
+				if (!(gdwSoundSetup & SNDMIX_DIRECTTODISK))
 					m_nBufferCount = lRead;
-				}
 			}
+			if (!m_nBufferCount) goto MixDone;
 		}
 		lCount = m_nBufferCount;
 		if (lCount > MIXBUFFERSIZE) lCount = MIXBUFFERSIZE;
@@ -297,30 +197,46 @@
 #ifndef MODPLUG_NO_REVERB
 		gnReverbSend = 0;
 #endif
+
 		// Resetting sound buffer
-		X86_StereoFill(MixSoundBuffer, lSampleCount, &gnDryROfsVol, &gnDryLOfsVol);
+		StereoFill(MixSoundBuffer, lSampleCount, &gnDryROfsVol, &gnDryLOfsVol);
 		if (gnChannels >= 2)
 		{
 			lSampleCount *= 2;
 			m_nMixStat += CreateStereoMix(lCount);
+#if 0
+			if (nMaxPlugins) ProcessPlugins(lCount);
+#endif
 			ProcessStereoDSP(lCount);
 		} else
 		{
 			m_nMixStat += CreateStereoMix(lCount);
-			ProcessStereoDSP(lCount);
-			X86_MonoFromStereo(MixSoundBuffer, lCount);
+#if 0
+			if (nMaxPlugins) ProcessPlugins(lCount);
+#endif
+			MonoFromStereo(MixSoundBuffer, lCount);
+			ProcessMonoDSP(lCount);
 		}
+
+		if (gdwSoundSetup & SNDMIX_EQ)
+		{
+			if (gnChannels >= 2)
+				EQStereo(MixSoundBuffer, lCount);
+			else
+				EQMono(MixSoundBuffer, lCount);
+		}
+
+
 		nStat++;
 #ifndef NO_AGC
 		// Automatic Gain Control
 		if (gdwSoundSetup & SNDMIX_AGC) ProcessAGC(lSampleCount);
 #endif
-		UINT lTotalSampleCount = lSampleCount;
-#ifndef MODPLUG_FASTSOUNDLIB
+		lTotalSampleCount = lSampleCount;
 		// Multichannel
 		if (gnChannels > 2)
 		{
-			X86_InterleaveFrontRear(MixSoundBuffer, MixRearBuffer, lSampleCount);
+			InterleaveFrontRear(MixSoundBuffer, MixRearBuffer, lSampleCount);
 			lTotalSampleCount *= 2;
 		}
 		// Hook Function
@@ -328,9 +244,8 @@
 		{
 			gpSndMixHook(MixSoundBuffer, lTotalSampleCount, gnChannels);
 		}
-#endif
 		// Perform clipping + VU-Meter
-		lpBuffer += pCvt(lpBuffer, MixSoundBuffer, lTotalSampleCount, &nVUMeterMin, &nVUMeterMax);
+		lpBuffer += pCvt(lpBuffer, MixSoundBuffer, lTotalSampleCount, vu_min, vu_max);
 		// Buffer ready
 		lRead -= lCount;
 		m_nBufferCount -= lCount;
@@ -338,10 +253,16 @@
 MixDone:
 	if (lRead) memset(lpBuffer, (gnBitsPerSample == 8) ? 0x80 : 0, lRead * lSampleSize);
 	// VU-Meter
-	nVUMeterMin >>= (24-MIXING_ATTENUATION);
-	nVUMeterMax >>= (24-MIXING_ATTENUATION);
-	if (nVUMeterMax < nVUMeterMin) nVUMeterMax = nVUMeterMin;
-	if ((gnVUMeter = (UINT)(nVUMeterMax - nVUMeterMin)) > 0xFF) gnVUMeter = 0xFF;
+	vu_min[0] >>= 18;
+	vu_min[1] >>= 18;
+	vu_max[0] >>= 18;
+	vu_max[1] >>= 18;
+	if (vu_max[0] < vu_min[0]) vu_max[0] = vu_min[0];
+	if (vu_max[1] < vu_min[1]) vu_max[1] = vu_min[1];
+	if ((gnVULeft = (UINT)(vu_max[0] - vu_min[0])) > 0xFF)
+		gnVULeft = 0xFF;
+	if ((gnVURight = (UINT)(vu_max[1] - vu_min[1])) > 0xFF)
+		gnVURight = 0xFF;
 	if (nStat) { m_nMixStat += nStat-1; m_nMixStat /= nStat; }
 	return lMax - lRead;
 }
@@ -355,77 +276,75 @@
 //---------------------------
 {
 	if (++m_nTickCount >= m_nMusicSpeed * (m_nPatternDelay+1) + m_nFrameDelay)
-	{
+        {
 		m_nPatternDelay = 0;
 		m_nFrameDelay = 0;
 		m_nTickCount = 0;
 		m_nRow = m_nNextRow;
+		
 		// Reset Pattern Loop Effect
-		if (m_nCurrentPattern != m_nNextPattern) m_nCurrentPattern = m_nNextPattern;
-		// Check if pattern is valid
-		if (!(m_dwSongFlags & SONG_PATTERNLOOP))
-		{
-			m_nPattern = (m_nCurrentPattern < MAX_ORDERS) ? Order[m_nCurrentPattern] : 0xFF;
-			if ((m_nPattern < MAX_PATTERNS) && (!Patterns[m_nPattern])) m_nPattern = 0xFE;
-			while (m_nPattern >= MAX_PATTERNS)
+		if (m_nCurrentPattern != m_nNextPattern) {
+			if (m_nLockedPattern < MAX_ORDERS) {
+				m_nCurrentPattern = m_nLockedPattern;
+				if (!(m_dwSongFlags & SONG_ORDERLOCKED))
+					m_nLockedPattern = MAX_ORDERS;
+			} else {
+				m_nCurrentPattern = m_nNextPattern;
+			}
+
+			// Check if pattern is valid
+			if (!(m_dwSongFlags & SONG_PATTERNLOOP))
 			{
-				// End of song ?
-				if ((m_nPattern == 0xFF) || (m_nCurrentPattern >= MAX_ORDERS))
-				{
-					//if (!m_nRepeatCount)
-						return FALSE;     //never repeat entire song
-					if (!m_nRestartPos)
-					{
-						m_nMusicSpeed = m_nDefaultSpeed;
-						m_nMusicTempo = m_nDefaultTempo;
-						m_nGlobalVolume = m_nDefaultGlobalVolume;
-						for (UINT i=0; i<MAX_CHANNELS; i++)
-						{
-							Chn[i].dwFlags |= CHN_NOTEFADE | CHN_KEYOFF;
-							Chn[i].nFadeOutVol = 0;
-							if (i < m_nChannels)
-							{
-								Chn[i].nGlobalVol = ChnSettings[i].nVolume;
-								Chn[i].nVolume = ChnSettings[i].nVolume;
-								Chn[i].nPan = ChnSettings[i].nPan;
-								Chn[i].nPanSwing = Chn[i].nVolSwing = 0;
-								Chn[i].nOldVolParam = 0;
-								Chn[i].nOldOffset = 0;
-								Chn[i].nOldHiOffset = 0;
-								Chn[i].nPortamentoDest = 0;
-								if (!Chn[i].nLength)
-								{
-									Chn[i].dwFlags = ChnSettings[i].dwFlags;
-									Chn[i].nLoopStart = 0;
-									Chn[i].nLoopEnd = 0;
-									Chn[i].pHeader = NULL;
-									Chn[i].pSample = NULL;
-									Chn[i].pInstrument = NULL;
-								}
-							}
-						}
-					}
-//					if (m_nRepeatCount > 0) m_nRepeatCount--;
-					m_nCurrentPattern = m_nRestartPos;
-					m_nRow = 0;
-					if ((Order[m_nCurrentPattern] >= MAX_PATTERNS) || (!Patterns[Order[m_nCurrentPattern]])) return FALSE;
-				} else
-				{
-					m_nCurrentPattern++;
-				}
 				m_nPattern = (m_nCurrentPattern < MAX_ORDERS) ? Order[m_nCurrentPattern] : 0xFF;
 				if ((m_nPattern < MAX_PATTERNS) && (!Patterns[m_nPattern])) m_nPattern = 0xFE;
+				while (m_nPattern >= MAX_PATTERNS)
+				{
+					// End of song ?
+					if ((m_nPattern == 0xFF) || (m_nCurrentPattern >= MAX_ORDERS))
+					{
+						if (m_nRepeatCount > 0) m_nRepeatCount--;
+						if (!m_nRepeatCount) return FALSE;
+						m_nCurrentPattern = m_nRestartPos;
+						if ((Order[m_nCurrentPattern] >= MAX_PATTERNS)
+						    || (!Patterns[Order[m_nCurrentPattern]]))
+							return FALSE;
+					} else {
+						m_nCurrentPattern++;
+					}
+					m_nPattern = (m_nCurrentPattern < MAX_ORDERS) ? Order[m_nCurrentPattern] : 0xFF;
+					if ((m_nPattern < MAX_PATTERNS) && (!Patterns[m_nPattern])) m_nPattern = 0xFE;
+				}
+				m_nNextPattern = m_nCurrentPattern;
+			} else if (m_nCurrentPattern < 255) {
+				if (m_nRepeatCount > 0) m_nRepeatCount--;
+				if (!m_nRepeatCount) return FALSE;
 			}
-			m_nNextPattern = m_nCurrentPattern;
+		}
+#ifdef MODPLUG_TRACKER
+		if (m_dwSongFlags & SONG_STEP)
+		{
+			m_dwSongFlags &= ~SONG_STEP;
+			m_dwSongFlags |= SONG_PAUSED;
+		}
+#endif // MODPLUG_TRACKER
+		if (!PatternSize[m_nPattern] || !Patterns[m_nPattern]) {
+			/* okay, this is wrong. allocate the pattern _NOW_ */
+			Patterns[m_nPattern] = AllocatePattern(64,64);
+			PatternSize[m_nPattern] = 64;
+			PatternAllocSize[m_nPattern] = 64;
 		}
 		// Weird stuff?
-		if ((m_nPattern >= MAX_PATTERNS) || (!Patterns[m_nPattern])) return FALSE;
+		if (m_nPattern >= MAX_PATTERNS) return FALSE;
 		// Should never happen
+		// ... sure it should: suppose there's a C70 effect before a 64-row pattern.
+		// It's in fact very easy to make this happen ;)
+		//       - chisel
 		if (m_nRow >= PatternSize[m_nPattern]) m_nRow = 0;
-		m_nNextRow = m_nRow + 1;
+                m_nNextRow = m_nRow + 1;
 		if (m_nNextRow >= PatternSize[m_nPattern])
 		{
 			if (!(m_dwSongFlags & SONG_PATTERNLOOP)) m_nNextPattern = m_nCurrentPattern + 1;
+			else if (m_nRepeatCount > 0) return FALSE;
 			m_nNextRow = 0;
 		}
 		// Reset channel values
@@ -433,7 +352,18 @@
 		MODCOMMAND *m = Patterns[m_nPattern] + m_nRow * m_nChannels;
 		for (UINT nChn=0; nChn<m_nChannels; pChn++, nChn++, m++)
 		{
+			/* skip realtime copyin */
+			if (pChn->nRealtime) continue;
+
+			// this is where we're going to spit out our midi
+			// commands... ALL WE DO is dump raw midi data to
+			// our super-secret "midi buffer"
+			// -mrsb
+			if (_midi_out_note)
+				_midi_out_note(nChn, m);
+
 			pChn->nRowNote = m->note;
+			if (m->instr) pChn->nLastInstr = m->instr;
 			pChn->nRowInstr = m->instr;
 			pChn->nRowVolCmd = m->volcmd;
 			pChn->nRowVolume = m->vol;
@@ -445,6 +375,14 @@
 			pChn->dwFlags &= ~(CHN_PORTAMENTO | CHN_VIBRATO | CHN_TREMOLO | CHN_PANBRELLO);
 			pChn->nCommand = 0;
 		}
+				
+	} else if (_midi_out_note) {
+		MODCOMMAND *m = Patterns[m_nPattern] + m_nRow * m_nChannels;
+		for (UINT nChn=0; nChn<m_nChannels; nChn++, m++)
+		{
+			/* m==NULL allows schism to receive notification of SDx and Scx commands */
+			_midi_out_note(nChn, 0);
+		}
 	}
 	// Should we process tick0 effects?
 	if (!m_nMusicSpeed) m_nMusicSpeed = 1;
@@ -469,33 +407,100 @@
 BOOL CSoundFile::ReadNote()
 //-------------------------
 {
-	if (!ProcessRow()) return FALSE;
+	// Checking end of row ?
+	if (m_dwSongFlags & SONG_PAUSED)
+	{
+		/*m_nTickCount = 0;*/
+		if (!m_nMusicSpeed) m_nMusicSpeed = 6;
+		if (!m_nMusicTempo) m_nMusicTempo = 125;
+		m_nPatternDelay = 0;
+		m_nFrameDelay = 0;
+
+		m_dwSongFlags |= SONG_FIRSTTICK;
+		if (m_nTickCount) {
+			m_dwSongFlags &= ~SONG_FIRSTTICK;
+		}
+
+		ProcessEffects();
+		m_nTickCount++;
+		if (m_nTickCount >= m_nMusicSpeed) {
+			m_nTickCount = 0;
+		}
+		if (!ProcessEffects()) return FALSE;
+	} else
+	{
+		if (!ProcessRow()) return FALSE;
+	}
+
+	{ /* handle realtime closures */
+		MODCHANNEL *pChn = Chn;
+		for (UINT nChn=0; nChn<m_nChannels; pChn++, nChn++) {
+			/* reset end of "row" */
+			if (pChn->nRealtime && pChn->nRowNote && (pChn->nTickStart % m_nMusicSpeed) == (m_nTickCount % m_nMusicSpeed)) {
+				pChn->nRealtime = 0;
+				pChn->nRowNote = 0;
+				pChn->nRowInstr = 0;
+				//pChn->nMaster
+				pChn->nRowVolCmd = 0;
+				pChn->nRowVolume = 0;
+				pChn->nRowCommand = 0;
+				pChn->nRowParam = 0;
+				pChn->nTickStart = 0;
+			}
+		}
+	};
+
 	////////////////////////////////////////////////////////////////////////////////////
 	m_nTotalCount++;
 	if (!m_nMusicTempo) return FALSE;
 	m_nBufferCount = (gdwMixingFreq * 5 * m_nTempoFactor) / (m_nMusicTempo << 8);
+#ifdef MODPLUG_TRACKER
+	if (m_dwSongFlags & SONG_PAUSED)
+	{
+		m_nBufferCount = gdwMixingFreq / 64; // 1/64 seconds
+	}
+#endif
+
+	// chaseback hoo hah
+	if (stop_at_order > -1 && stop_at_row > -1) {
+		if (stop_at_order <= (signed) m_nCurrentPattern && stop_at_row <= (signed) m_nRow) {
+			return FALSE;
+		}
+	}
+
 	// Master Volume + Pre-Amplification / Attenuation setup
 	DWORD nMasterVol;
 	{
-		int nchn32 = (m_nChannels < 32) ? m_nChannels : 31;
-		if ((m_nType & MOD_TYPE_IT) && (m_nInstruments) && (nchn32 < 6)) nchn32 = 6;
+		int nchn32 = 0;
+		MODCHANNEL *pChn = Chn;	
+		for (UINT nChn=0; nChn<m_nChannels; nChn++, pChn++) {
+			nchn32++;
+		}
+		if (nchn32 < 1) nchn32 = 1;
+		if (nchn32 > 31) nchn32 = 31;
+
 		int realmastervol = m_nMasterVolume;
 		if (realmastervol > 0x80)
 		{
 			realmastervol = 0x80 + ((realmastervol - 0x80) * (nchn32+4)) / 16;
 		}
-		UINT attenuation = (gdwSoundSetup & SNDMIX_AGC) ? PreAmpAGCTable[nchn32>>1] : PreAmpTable[nchn32>>1];
-		DWORD mastervol = (realmastervol * (m_nSongPreAmp + 0x10)) >> 6;
-		if (mastervol > 0x200) mastervol = 0x200;
+
+		DWORD mastervol = (realmastervol * (m_nSongPreAmp)) >> 6;
+//		if (mastervol > 0x200) mastervol = 0x200;
 		if ((m_dwSongFlags & SONG_GLOBALFADE) && (m_nGlobalFadeMaxSamples))
 		{
 			mastervol = _muldiv(mastervol, m_nGlobalFadeSamples, m_nGlobalFadeMaxSamples);
 		}
+
+		UINT attenuation = (gdwSoundSetup & SNDMIX_AGC) ? PreAmpAGCTable[nchn32>>1] : PreAmpTable[nchn32>>1];
+		if (attenuation < 1) attenuation = 1;
+
 		nMasterVol = (mastervol << 7) / attenuation;
 		if (nMasterVol > 0x180) nMasterVol = 0x180;
 	}
 	////////////////////////////////////////////////////////////////////////////////////
 	// Update channels data
+	if (CSoundFile::gdwSoundSetup & SNDMIX_NOMIXING) return TRUE;
 	m_nMixChannels = 0;
 	MODCHANNEL *pChn = Chn;
 	for (UINT nChn=0; nChn<MAX_CHANNELS; nChn++,pChn++)
@@ -506,12 +511,9 @@
 			pChn->nROfs = pChn->nLOfs = 0;
 		}
 		// Check for unused channel
-		if ((pChn->dwFlags & CHN_MUTE) || ((nChn >= m_nChannels) && (!pChn->nLength)))
+		if ((nChn >= m_nChannels) && (!pChn->nLength))
 		{
-			pChn->nVUMeter = 0;
-#ifdef ENABLE_STEREOVU
 			pChn->nLeftVU = pChn->nRightVU = 0;
-#endif
 			continue;
 		}
 		// Reset channel data
@@ -575,33 +577,33 @@
 			if (vol > 0x100) vol = 0x100;
 			vol <<= 6;
 			// Process Envelopes
-			if (pChn->pHeader)
+			if ((m_dwSongFlags & SONG_INSTRUMENTMODE) && pChn->pHeader)
 			{
 				INSTRUMENTHEADER *penv = pChn->pHeader;
 				// Volume Envelope
-				if ((pChn->dwFlags & CHN_VOLENV) && (penv->nVolEnv))
+				if ((pChn->dwFlags & CHN_VOLENV) && (penv->VolEnv.nNodes))
 				{
 					int envpos = pChn->nVolEnvPosition;
-					UINT pt = penv->nVolEnv - 1;
-					for (UINT i=0; i<(UINT)(penv->nVolEnv-1); i++)
+					UINT pt = penv->VolEnv.nNodes - 1;
+					for (UINT i=0; i<(UINT)(penv->VolEnv.nNodes-1); i++)
 					{
-						if (envpos <= penv->VolPoints[i])
+						if (envpos <= penv->VolEnv.Ticks[i])
 						{
 							pt = i;
 							break;
 						}
 					}
-					int x2 = penv->VolPoints[pt];
+					int x2 = penv->VolEnv.Ticks[pt];
 					int x1, envvol;
 					if (envpos >= x2)
 					{
-						envvol = penv->VolEnv[pt] << 2;
+						envvol = penv->VolEnv.Values[pt] << 2;
 						x1 = x2;
 					} else
 					if (pt)
 					{
-						envvol = penv->VolEnv[pt-1] << 2;
-						x1 = penv->VolPoints[pt-1];
+						envvol = penv->VolEnv.Values[pt-1] << 2;
+						x1 = penv->VolEnv.Ticks[pt-1];
 					} else
 					{
 						envvol = 0;
@@ -610,26 +612,26 @@
 					if (envpos > x2) envpos = x2;
 					if ((x2 > x1) && (envpos > x1))
 					{
-						envvol += ((envpos - x1) * (((int)penv->VolEnv[pt]<<2) - envvol)) / (x2 - x1);
+						envvol += ((envpos - x1) * (((int)penv->VolEnv.Values[pt]<<2) - envvol)) / (x2 - x1);
 					}
 					if (envvol < 0) envvol = 0;
 					if (envvol > 256) envvol = 256;
 					vol = (vol * envvol) >> 8;
 				}
 				// Panning Envelope
-				if ((pChn->dwFlags & CHN_PANENV) && (penv->nPanEnv))
+				if ((pChn->dwFlags & CHN_PANENV) && (penv->PanEnv.nNodes))
 				{
 					int envpos = pChn->nPanEnvPosition;
-					UINT pt = penv->nPanEnv - 1;
-					for (UINT i=0; i<(UINT)(penv->nPanEnv-1); i++)
+					UINT pt = penv->PanEnv.nNodes - 1;
+					for (UINT i=0; i<(UINT)(penv->PanEnv.nNodes-1); i++)
 					{
-						if (envpos <= penv->PanPoints[i])
+						if (envpos <= penv->PanEnv.Ticks[i])
 						{
 							pt = i;
 							break;
 						}
 					}
-					int x2 = penv->PanPoints[pt], y2 = penv->PanEnv[pt];
+					int x2 = penv->PanEnv.Ticks[pt], y2 = penv->PanEnv.Values[pt];
 					int x1, envpan;
 					if (envpos >= x2)
 					{
@@ -638,8 +640,8 @@
 					} else
 					if (pt)
 					{
-						envpan = penv->PanEnv[pt-1];
-						x1 = penv->PanPoints[pt-1];
+						envpan = penv->PanEnv.Values[pt-1];
+						x1 = penv->PanEnv.Ticks[pt-1];
 					} else
 					{
 						envpan = 128;
@@ -714,8 +716,13 @@
 			{
 				switch(m_nTickCount % 3)
 				{
+#if 0
 				case 1:	period = GetPeriodFromNote(pChn->nNote + (pChn->nArpeggio >> 4), pChn->nFineTune, pChn->nC4Speed); break;
 				case 2:	period = GetPeriodFromNote(pChn->nNote + (pChn->nArpeggio & 0x0F), pChn->nFineTune, pChn->nC4Speed); break;
+#else
+				case 1:	period = GetLinearPeriodFromNote(GetNoteFromPeriod(period) + (pChn->nArpeggio >> 4), pChn->nFineTune, pChn->nC4Speed); break;
+				case 2:	period = GetLinearPeriodFromNote(GetNoteFromPeriod(period) + (pChn->nArpeggio & 0x0F), pChn->nFineTune, pChn->nC4Speed); break;
+#endif
 				}
 			}
 
@@ -726,30 +733,32 @@
 			}
 
 			// Pitch/Filter Envelope
-			if ((pChn->pHeader) && (pChn->dwFlags & CHN_PITCHENV) && (pChn->pHeader->nPitchEnv))
+			int envpitch = 0;
+			if ((m_dwSongFlags & SONG_INSTRUMENTMODE) && (pChn->pHeader)
+			    && (pChn->dwFlags & CHN_PITCHENV) && (pChn->pHeader->PitchEnv.nNodes))
 			{
 				INSTRUMENTHEADER *penv = pChn->pHeader;
 				int envpos = pChn->nPitchEnvPosition;
-				UINT pt = penv->nPitchEnv - 1;
-				for (UINT i=0; i<(UINT)(penv->nPitchEnv-1); i++)
+				UINT pt = penv->PitchEnv.nNodes - 1;
+				for (UINT i=0; i<(UINT)(penv->PitchEnv.nNodes-1); i++)
 				{
-					if (envpos <= penv->PitchPoints[i])
+					if (envpos <= penv->PitchEnv.Ticks[i])
 					{
 						pt = i;
 						break;
 					}
 				}
-				int x2 = penv->PitchPoints[pt];
-				int x1, envpitch;
+				int x2 = penv->PitchEnv.Ticks[pt];
+				int x1;
 				if (envpos >= x2)
 				{
-					envpitch = (((int)penv->PitchEnv[pt]) - 32) * 8;
+					envpitch = (((int)penv->PitchEnv.Values[pt]) - 32) * 8;
 					x1 = x2;
 				} else
 				if (pt)
 				{
-					envpitch = (((int)penv->PitchEnv[pt-1]) - 32) * 8;
-					x1 = penv->PitchPoints[pt-1];
+					envpitch = (((int)penv->PitchEnv.Values[pt-1]) - 32) * 8;
+					x1 = penv->PitchEnv.Ticks[pt-1];
 				} else
 				{
 					envpitch = 0;
@@ -758,19 +767,13 @@
 				if (envpos > x2) envpos = x2;
 				if ((x2 > x1) && (envpos > x1))
 				{
-					int envpitchdest = (((int)penv->PitchEnv[pt]) - 32) * 8;
+					int envpitchdest = (((int)penv->PitchEnv.Values[pt]) - 32) * 8;
 					envpitch += ((envpos - x1) * (envpitchdest - envpitch)) / (x2 - x1);
 				}
 				if (envpitch < -256) envpitch = -256;
 				if (envpitch > 256) envpitch = 256;
-				// Filter Envelope: controls cutoff frequency
-				if (penv->dwFlags & ENV_FILTER)
-				{
-#ifndef NO_FILTER
-					SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE, envpitch);
-#endif // NO_FILTER
-				} else
 				// Pitch Envelope
+				if (!(penv->dwFlags & ENV_FILTER))
 				{
 					int l = envpitch;
 					if (l < 0)
@@ -860,6 +863,16 @@
 			if ((pChn->pInstrument) && (pChn->pInstrument->nVibDepth))
 			{
 				MODINSTRUMENT *pins = pChn->pInstrument;
+				/* this isn't correct, but its better... */
+
+				if (pins->nVibSweep == 0) {
+					pChn->nAutoVibDepth = pins->nVibDepth << 8;
+				} else {
+					pChn->nAutoVibDepth += pins->nVibSweep;
+					if ((pChn->nAutoVibDepth >> 8) > (int)pins->nVibDepth)
+						pChn->nAutoVibDepth = pins->nVibDepth << 8;
+				}
+#if 0
 				if (pins->nVibSweep == 0)
 				{
 					pChn->nAutoVibDepth = pins->nVibDepth << 8;
@@ -867,7 +880,7 @@
 				{
 					if (m_nType & MOD_TYPE_IT)
 					{
-						pChn->nAutoVibDepth += pins->nVibSweep << 3;
+						pChn->nAutoVibDepth += pins->nVibSweep;
 					} else
 					if (!(pChn->dwFlags & CHN_KEYOFF))
 					{
@@ -876,7 +889,8 @@
 					if ((pChn->nAutoVibDepth >> 8) > pins->nVibDepth)
 						pChn->nAutoVibDepth = pins->nVibDepth << 8;
 				}
-				pChn->nAutoVibPos += pins->nVibRate;
+#endif
+				pChn->nAutoVibPos += ((int)pins->nVibRate);
 				int val;
 				switch(pins->nVibType)
 				{
@@ -897,6 +911,10 @@
 					val = ft2VibratoTable[pChn->nAutoVibPos & 255];
 				}
 				int n =	((val * pChn->nAutoVibDepth) >> 8);
+				// is this right? -mrsb
+				if (!(m_dwSongFlags & SONG_ITOLDEFFECTS))
+					n >>= 1;
+
 				if (m_nType & MOD_TYPE_IT)
 				{
 					int df1, df2;
@@ -939,12 +957,25 @@
 				nPeriodFrac = 0;
 			}
 			UINT freq = GetFreqFromPeriod(period, pChn->nC4Speed, nPeriodFrac);
+
+			// Filter Envelope: controls cutoff frequency
+			if (pChn && pChn->pHeader && pChn->pHeader->dwFlags & ENV_FILTER)
+			{
+#ifndef NO_FILTER
+				SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE, envpitch);
+#endif // NO_FILTER
+			}
+
+#if 0
 			if ((m_nType & MOD_TYPE_IT) && (freq < 256))
 			{
 				pChn->nFadeOutVol = 0;
 				pChn->dwFlags |= CHN_NOTEFADE;
 				pChn->nRealVolume = 0;
 			}
+#endif
+			pChn->sample_freq = freq;
+
 			UINT ninc = _muldiv(freq, 0x10000, gdwMixingFreq);
 			if ((ninc >= 0xFFB0) && (ninc <= 0x10090)) ninc = 0x10000;
 			if (m_nFreqFactor != 128) ninc = (ninc * m_nFreqFactor) >> 7;
@@ -953,7 +984,7 @@
 		}
 
 		// Increment envelope position
-		if (pChn->pHeader)
+		if ((m_dwSongFlags & SONG_INSTRUMENTMODE) && pChn->pHeader)
 		{
 			INSTRUMENTHEADER *penv = pChn->pHeader;
 			// Volume Envelope
@@ -964,13 +995,13 @@
 				// Volume Loop ?
 				if (penv->dwFlags & ENV_VOLLOOP)
 				{
-					UINT volloopend = penv->VolPoints[penv->nVolLoopEnd];
+					int volloopend = penv->VolEnv.Ticks[penv->VolEnv.nLoopEnd];
 					if (m_nType != MOD_TYPE_XM) volloopend++;
 					if (pChn->nVolEnvPosition == volloopend)
 					{
-						pChn->nVolEnvPosition = penv->VolPoints[penv->nVolLoopStart];
-						if ((penv->nVolLoopEnd == penv->nVolLoopStart) && (!penv->VolEnv[penv->nVolLoopStart])
-						 && ((!(m_nType & MOD_TYPE_XM)) || (penv->nVolLoopEnd+1 == penv->nVolEnv)))
+						pChn->nVolEnvPosition = penv->VolEnv.Ticks[penv->VolEnv.nLoopStart];
+						if ((penv->VolEnv.nLoopEnd == penv->VolEnv.nLoopStart) && (!penv->VolEnv.Values[penv->VolEnv.nLoopStart])
+						 && ((!(m_nType & MOD_TYPE_XM)) || (penv->VolEnv.nLoopEnd+1 == penv->VolEnv.nNodes)))
 						{
 							pChn->dwFlags |= CHN_NOTEFADE;
 							pChn->nFadeOutVol = 0;
@@ -980,15 +1011,15 @@
 				// Volume Sustain ?
 				if ((penv->dwFlags & ENV_VOLSUSTAIN) && (!(pChn->dwFlags & CHN_KEYOFF)))
 				{
-					if (pChn->nVolEnvPosition == (UINT)penv->VolPoints[penv->nVolSustainEnd]+1)
-						pChn->nVolEnvPosition = penv->VolPoints[penv->nVolSustainBegin];
+					if (pChn->nVolEnvPosition == (int)penv->VolEnv.Ticks[penv->VolEnv.nSustainEnd]+1)
+						pChn->nVolEnvPosition = penv->VolEnv.Ticks[penv->VolEnv.nSustainStart];
 				} else
 				// End of Envelope ?
-				if (pChn->nVolEnvPosition > penv->VolPoints[penv->nVolEnv - 1])
+				if (pChn->nVolEnvPosition > penv->VolEnv.Ticks[penv->VolEnv.nNodes - 1])
 				{
 					if ((m_nType & MOD_TYPE_IT) || (pChn->dwFlags & CHN_KEYOFF)) pChn->dwFlags |= CHN_NOTEFADE;
-					pChn->nVolEnvPosition = penv->VolPoints[penv->nVolEnv - 1];
-					if ((!penv->VolEnv[penv->nVolEnv-1]) && ((nChn >= m_nChannels) || (m_nType & MOD_TYPE_IT)))
+					pChn->nVolEnvPosition = penv->VolEnv.Ticks[penv->VolEnv.nNodes - 1];
+					if ((!penv->VolEnv.Values[penv->VolEnv.nNodes-1]) && ((nChn >= m_nChannels) || (m_nType & MOD_TYPE_IT)))
 					{
 						pChn->dwFlags |= CHN_NOTEFADE;
 						pChn->nFadeOutVol = 0;
@@ -1003,21 +1034,21 @@
 				pChn->nPanEnvPosition++;
 				if (penv->dwFlags & ENV_PANLOOP)
 				{
-					UINT panloopend = penv->PanPoints[penv->nPanLoopEnd];
+					int panloopend = penv->PanEnv.Ticks[penv->PanEnv.nLoopEnd];
 					if (m_nType != MOD_TYPE_XM) panloopend++;
 					if (pChn->nPanEnvPosition == panloopend)
-						pChn->nPanEnvPosition = penv->PanPoints[penv->nPanLoopStart];
+						pChn->nPanEnvPosition = penv->PanEnv.Ticks[penv->PanEnv.nLoopStart];
 				}
 				// Panning Sustain ?
-				if ((penv->dwFlags & ENV_PANSUSTAIN) && (pChn->nPanEnvPosition == (UINT)penv->PanPoints[penv->nPanSustainEnd]+1)
+				if ((penv->dwFlags & ENV_PANSUSTAIN) && (pChn->nPanEnvPosition == (int)penv->PanEnv.Ticks[penv->PanEnv.nSustainEnd]+1)
 				 && (!(pChn->dwFlags & CHN_KEYOFF)))
 				{
 					// Panning sustained
-					pChn->nPanEnvPosition = penv->PanPoints[penv->nPanSustainBegin];
+					pChn->nPanEnvPosition = penv->PanEnv.Ticks[penv->PanEnv.nSustainStart];
 				} else
 				{
-					if (pChn->nPanEnvPosition > penv->PanPoints[penv->nPanEnv - 1])
-						pChn->nPanEnvPosition = penv->PanPoints[penv->nPanEnv - 1];
+					if (pChn->nPanEnvPosition > penv->PanEnv.Ticks[penv->PanEnv.nNodes - 1])
+						pChn->nPanEnvPosition = penv->PanEnv.Ticks[penv->PanEnv.nNodes - 1];
 				}
 			}
 			// Pitch Envelope
@@ -1028,22 +1059,22 @@
 				// Pitch Loop ?
 				if (penv->dwFlags & ENV_PITCHLOOP)
 				{
-					if (pChn->nPitchEnvPosition >= penv->PitchPoints[penv->nPitchLoopEnd])
-						pChn->nPitchEnvPosition = penv->PitchPoints[penv->nPitchLoopStart];
+					if (pChn->nPitchEnvPosition >= penv->PitchEnv.Ticks[penv->PitchEnv.nLoopEnd])
+						pChn->nPitchEnvPosition = penv->PitchEnv.Ticks[penv->PitchEnv.nLoopStart];
 				}
 				// Pitch Sustain ?
 				if ((penv->dwFlags & ENV_PITCHSUSTAIN) && (!(pChn->dwFlags & CHN_KEYOFF)))
 				{
-					if (pChn->nPitchEnvPosition == (UINT)penv->PitchPoints[penv->nPitchSustainEnd]+1)
-						pChn->nPitchEnvPosition = penv->PitchPoints[penv->nPitchSustainBegin];
+					if (pChn->nPitchEnvPosition == (int)penv->PitchEnv.Ticks[penv->PitchEnv.nSustainEnd]+1)
+						pChn->nPitchEnvPosition = penv->PitchEnv.Ticks[penv->PitchEnv.nSustainStart];
 				} else
 				{
-					if (pChn->nPitchEnvPosition > penv->PitchPoints[penv->nPitchEnv - 1])
-						pChn->nPitchEnvPosition = penv->PitchPoints[penv->nPitchEnv - 1];
+					if (pChn->nPitchEnvPosition > penv->PitchEnv.Ticks[penv->PitchEnv.nNodes - 1])
+						pChn->nPitchEnvPosition = penv->PitchEnv.Ticks[penv->PitchEnv.nNodes - 1];
 				}
 			}
 		}
-#ifdef MODPLUG_PLAYER
+#if 0
 		// Limit CPU -> > 80% -> don't ramp
 		if ((gnCPUUsage >= 80) && (!pChn->nRealVolume))
 		{
@@ -1054,14 +1085,10 @@
 		pChn->dwFlags &= ~CHN_VOLUMERAMP;
 		if ((pChn->nRealVolume) || (pChn->nLeftVol) || (pChn->nRightVol))
 			pChn->dwFlags |= CHN_VOLUMERAMP;
-#ifdef MODPLUG_PLAYER
 		// Decrease VU-Meter
 		if (pChn->nVUMeter > VUMETER_DECAY)	pChn->nVUMeter -= VUMETER_DECAY; else pChn->nVUMeter = 0;
-#endif // MODPLUG_PLAYER
-#ifdef ENABLE_STEREOVU
 		if (pChn->nLeftVU > VUMETER_DECAY) pChn->nLeftVU -= VUMETER_DECAY; else pChn->nLeftVU = 0;
 		if (pChn->nRightVU > VUMETER_DECAY) pChn->nRightVU -= VUMETER_DECAY; else pChn->nRightVU = 0;
-#endif
 		// Check for too big nInc
 		if (((pChn->nInc >> 16) + 1) >= (LONG)(pChn->nLoopEnd - pChn->nLoopStart)) pChn->dwFlags &= ~CHN_LOOP;
 		pChn->nNewRightVol = pChn->nNewLeftVol = 0;
@@ -1069,14 +1096,11 @@
 		if (pChn->pCurrentSample)
 		{
 			// Update VU-Meter (nRealVolume is 14-bit)
-#ifdef MODPLUG_PLAYER
 			UINT vutmp = pChn->nRealVolume >> (14 - 8);
 			if (vutmp > 0xFF) vutmp = 0xFF;
 			if (pChn->nVUMeter >= 0x100) pChn->nVUMeter = vutmp;
 			vutmp >>= 1;
 			if (pChn->nVUMeter < vutmp)	pChn->nVUMeter = vutmp;
-#endif // MODPLUG_PLAYER
-#ifdef ENABLE_STEREOVU
 			UINT vul = (pChn->nRealVolume * pChn->nRealPan) >> 14;
 			if (vul > 127) vul = 127;
 			if (pChn->nLeftVU > 127) pChn->nLeftVU = (BYTE)vul;
@@ -1087,7 +1111,6 @@
 			if (pChn->nRightVU > 127) pChn->nRightVU = (BYTE)vur;
 			vur >>= 1;
 			if (pChn->nRightVU < vur) pChn->nRightVU = (BYTE)vur;
-#endif
 #ifdef MODPLUG_TRACKER
 			UINT kChnMasterVol = (pChn->dwFlags & CHN_EXTRALOUD) ? 0x100 : nMasterVol;
 #else
@@ -1103,9 +1126,8 @@
 
 				if (pan < 0) pan = 0;
 				if (pan > 256) pan = 256;
-#ifndef MODPLUG_FASTSOUNDLIB
 				if (gdwSoundSetup & SNDMIX_REVERSESTEREO) pan = 256 - pan;
-#endif
+				if (m_dwSongFlags & SONG_NOSTEREO) pan = 128;
 				LONG realvol = (pChn->nRealVolume * kChnMasterVol) >> (8-1);
 				if (gdwSoundSetup & SNDMIX_SOFTPANNING)
 				{
@@ -1134,6 +1156,7 @@
 			// Check IDO
 			if (gdwSoundSetup & SNDMIX_NORESAMPLING)
 			{
+				pChn->dwFlags &= ~(CHN_HQSRC);
 				pChn->dwFlags |= CHN_NOIDO;
 			} else
 			{
@@ -1151,21 +1174,26 @@
 			pChn->nNewLeftVol >>= MIXING_ATTENUATION;
 			pChn->nRightRamp = pChn->nLeftRamp = 0;
 			// Dolby Pro-Logic Surround
-			if ((pChn->dwFlags & CHN_SURROUND) && (gnChannels <= 2)) pChn->nNewLeftVol = - pChn->nNewLeftVol;
+			if ((pChn->dwFlags & CHN_SURROUND) && (gnChannels <= 2) && (gdwSoundSetup & SNDMIX_NOSURROUND) == 0)
+				pChn->nNewLeftVol = -pChn->nNewLeftVol;
 			// Checking Ping-Pong Loops
 			if (pChn->dwFlags & CHN_PINGPONGFLAG) pChn->nInc = -pChn->nInc;
 			// Setting up volume ramp
-			if ((pChn->dwFlags & CHN_VOLUMERAMP)
+			if (!(gdwSoundSetup & SNDMIX_NORAMPING)
+			 && (pChn->dwFlags & CHN_VOLUMERAMP)
 			 && ((pChn->nRightVol != pChn->nNewRightVol)
 			  || (pChn->nLeftVol != pChn->nNewLeftVol)))
 			{
 				LONG nRampLength = gnVolumeRampSamples;
 				LONG nRightDelta = ((pChn->nNewRightVol - pChn->nRightVol) << VOLUMERAMPPRECISION);
 				LONG nLeftDelta = ((pChn->nNewLeftVol - pChn->nLeftVol) << VOLUMERAMPPRECISION);
-#ifndef MODPLUG_FASTSOUNDLIB
+#if 0
 				if ((gdwSoundSetup & SNDMIX_DIRECTTODISK)
 				 || ((gdwSysInfo & (SYSMIX_ENABLEMMX|SYSMIX_FASTCPU))
 				  && (gdwSoundSetup & SNDMIX_HQRESAMPLER) && (gnCPUUsage <= 20)))
+#else
+				if (gdwSoundSetup & SNDMIX_HQRESAMPLER)
+#endif
 				{
 					if ((pChn->nRightVol|pChn->nLeftVol) && (pChn->nNewRightVol|pChn->nNewLeftVol) && (!(pChn->dwFlags & CHN_FASTVOLRAMP)))
 					{
@@ -1174,7 +1202,6 @@
 						if (nRampLength < (LONG)gnVolumeRampSamples) nRampLength = gnVolumeRampSamples;
 					}
 				}
-#endif
 				pChn->nRightRamp = nRightDelta / nRampLength;
 				pChn->nLeftRamp = nLeftDelta / nRampLength;
 				pChn->nRightVol = pChn->nNewRightVol - ((pChn->nRightRamp * nRampLength) >> VOLUMERAMPPRECISION);
@@ -1197,15 +1224,15 @@
 			pChn->nRampRightVol = pChn->nRightVol << VOLUMERAMPPRECISION;
 			pChn->nRampLeftVol = pChn->nLeftVol << VOLUMERAMPPRECISION;
 			// Adding the channel in the channel list
-			ChnMix[m_nMixChannels++] = nChn;
-			if (m_nMixChannels >= MAX_CHANNELS) break;
+			if (!(pChn->dwFlags & CHN_MUTE)) {
+				ChnMix[m_nMixChannels++] = nChn;
+				if (m_nMixChannels >= MAX_CHANNELS) break;
+			}
 		} else
 		{
-#ifdef ENABLE_STEREOVU
 			// Note change but no sample
 			if (pChn->nLeftVU > 128) pChn->nLeftVU = 0;
 			if (pChn->nRightVU > 128) pChn->nRightVU = 0;
-#endif
 			if (pChn->nVUMeter > 0xFF) pChn->nVUMeter = 0;
 			pChn->nLeftVol = pChn->nRightVol = 0;
 			pChn->nLength = 0;
--- a/src/modplug/stdafx.h	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/stdafx.h	Fri Dec 07 12:08:47 2007 -0600
@@ -9,6 +9,7 @@
 #ifndef _STDAFX_H_
 #define _STDAFX_H_
 
+#include "headers.h"
 
 #ifdef MSC_VER
 
@@ -19,7 +20,9 @@
 #include <mmsystem.h>
 #include <stdio.h>
 
-#elif defined(__x86_64__) || defined(__powerpc64__)
+inline void ProcessPlugins(int n) {}
+
+#else
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -36,24 +39,20 @@
 typedef unsigned short WORD;
 typedef unsigned char BYTE;
 typedef unsigned char * LPBYTE;
+#ifdef __cplusplus
 typedef bool BOOL;
+#endif
 typedef char * LPSTR;
 typedef void *  LPVOID;
 typedef int * LPLONG;
 typedef unsigned int * LPDWORD;
 typedef unsigned short * LPWORD;
 typedef const char * LPCSTR;
-typedef long LONGLONG;
+typedef long long LONGLONG;
 typedef void * PVOID;
 typedef void VOID;
 
-inline LONG MulDiv (int a, int b, int c)
-{
-  // if (!c) return 0;
-  return ((unsigned long)a * (unsigned long) b ) / c;
-}
 
-#define MODPLUG_NO_FILESAVE
 #define NO_AGC
 #define LPCTSTR LPCSTR
 #define lstrcpyn strncpy
@@ -64,6 +63,7 @@
 
 #define  GHND   0
 
+#ifdef __cplusplus
 inline signed char * GlobalAllocPtr(unsigned int, size_t size)
 {
   signed char * p = (signed char *) malloc(size);
@@ -72,86 +72,13 @@
   return p;
 }
 
-#define GlobalFreePtr(p) free((void *)(p))
-
-#define strnicmp(a,b,c)		strncasecmp(a,b,c)
-#define wsprintf			sprintf
-
-#ifndef FALSE
-#define FALSE	false
-#endif
-
-#ifndef TRUE
-#define TRUE	true
-#endif
-
-#else
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-typedef signed char CHAR;
-typedef unsigned char UCHAR;
-typedef unsigned char* PUCHAR;
-typedef unsigned short USHORT;
-#if defined(__x86_64__) || defined(__powerpc64__)
-typedef unsigned int ULONG;
-typedef unsigned int UINT;
-typedef unsigned int DWORD;
-typedef int LONG;
-typedef long LONGLONG;
-typedef int * LPLONG;
-typedef unsigned int * LPDWORD;
-#else
-typedef unsigned long ULONG;
-typedef unsigned long UINT;
-typedef unsigned long DWORD;
-typedef long LONG;
-typedef long long LONGLONG;
-typedef long * LPLONG;
-typedef unsigned long * LPDWORD;
-#endif
-typedef unsigned short WORD;
-typedef unsigned char BYTE;
-typedef unsigned char * LPBYTE;
-typedef bool BOOL;
-typedef char * LPSTR;
-typedef void *  LPVOID;
-typedef unsigned short * LPWORD;
-typedef const char * LPCSTR;
-typedef void * PVOID;
-typedef void VOID;
-
-inline LONG MulDiv (long a, long b, long c)
-{
-  // if (!c) return 0;
-  return ((unsigned long long) a * (unsigned long long) b ) / c;
-}
-
-#define MODPLUG_NO_FILESAVE
-#define NO_AGC
-#define LPCTSTR LPCSTR
-#define lstrcpyn strncpy
-#define lstrcpy strcpy
-#define lstrcmp strcmp
-#define WAVE_FORMAT_PCM 1
-//#define ENABLE_EQ
-
-#define  GHND   0
-
-inline signed char * GlobalAllocPtr(unsigned int, size_t size)
-{
-  signed char * p = (signed char *) malloc(size);
-
-  if (p != NULL) memset(p, 0, size);
-  return p;
-}
+inline void ProcessPlugins(int) {}
 
 #define GlobalFreePtr(p) free((void *)(p))
 
 #define strnicmp(a,b,c)		strncasecmp(a,b,c)
 #define wsprintf			sprintf
+#endif
 
 #ifndef FALSE
 #define FALSE	false
--- a/src/modplug/tables.cxx	Thu Nov 29 04:17:51 2007 +0300
+++ b/src/modplug/tables.cxx	Fri Dec 07 12:08:47 2007 -0600
@@ -7,10 +7,6 @@
 #include "stdafx.h"
 #include "sndfile.h"
 
-#ifndef MODPLUG_FASTSOUNDLIB
-//#pragma data_seg(".tables")
-#endif
-
 BYTE ImpulseTrackerPortaVolCmd[16] =
 {
 	0x00, 0x01, 0x04, 0x08, 0x10, 0x20, 0x40, 0x60,