# HG changeset patch # User William Pitcock # Date 1197050927 21600 # Node ID 3673c7ec4ea2d1066de4afabbf92a4525efca524 # Parent 32f9f1e4a9ec0031b65f6e36712230a38c5527e7 Sync with schism's modplug engine. Suggested by G¸«ärkan Seng¸«än. diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/fastmix.cxx --- 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 * Markus Fick spline + fir-resampler @@ -12,10 +9,6 @@ #include "sndfile.h" #include -#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; nChndwFlags & 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 , 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 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 , 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 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 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 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 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; inROfs; 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 + diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/it_defs.h --- 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; diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_669.cxx --- 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; ichksamples; 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++) diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_amf.cxx --- 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 -*/ + */ /////////////////////////////////////////////////// // @@ -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; } + + diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_ams.cxx --- 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; inVolEnv; 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; iVolEnv.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 diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_dbm.cxx --- 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; inVolEnv; 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; iVolEnv.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+3jmpsize >= 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; diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_dsm.cxx --- 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)) diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_far.cxx --- 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; diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_it.cxx --- 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 , - * Adam Goode (Endian and char fixes for PPC) - * Marco Trillo (Endian fixes for SaveIT, XM->IT Sample Converter) - * + * Adam Goode (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; ninsnSustainEnd = 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; inamnFadeOut >> 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; iznote; 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); - - /* 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; diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_mdl.cxx --- 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; jchannels; 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; jname, 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; nvenVolEnv = 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; npenPanEnv = 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; } } } diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_med.cxx --- 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))) { diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_mid.cxx --- /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 +*/ + +////////////////////////////////////////////// +// 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= 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; trkptracks) && (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 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; inote_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; iptracks += 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; kprogram = 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= 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; +} + + diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_mod.cxx --- 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= 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> 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 diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_mt2.cxx --- 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; } } } diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_mtm.cxx --- 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++) { diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_okt.cxx --- 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; iid); - 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; nPatsize = 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= 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 } diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_ptm.cxx --- 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]; diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_s3m.cxx --- 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 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; io(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> 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; ivol; 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 diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_stm.cxx --- 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); diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_ult.cxx --- 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); } } diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_wav.cxx --- 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; nChnnLength = 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 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]; diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/load_xm.cxx --- 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= 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; io(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= 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> 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; insnLength; 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; ismpdpSample) { #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 + * + * Name Date Description + * + * Olivier Lapicque --/--/-- Creation + * Trevor Nunes 26/01/04 conditional compilation for AMD,MMX calls + * +*/ +#include "stdafx.h" +#include "sndfile.h" +#include + + +#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; ia1 * 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 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 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); +} diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/snd_flt.cxx --- 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 -#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 diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/snd_fx.cxx --- 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= 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; inLength) return i; + MODCHANNEL *pi = &Chn[m_nChannels]; + for (UINT i=m_nChannels; inLength) { + 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; jpHeader, *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= 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; nChnnCommand=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; inMasterChn == (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; inMasterChn == (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; inMasterChn == (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; inPatternLoopCount) 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 diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/sndfile.cxx --- 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= 0) && (p[j] == ' ')) p[j--] = 0; - } // Adjust channels for (i=0; ipSample) { 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= 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= 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= 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; jnLength * 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; jpSample, 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; juFlags & 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; ipatnote) && (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 (endian and char fixes for PPC) */ -#include "config.h" +#ifdef HAVE_CONFIG_H +# include +#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 diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/sndmix.cxx --- 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 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; nChnnRealtime) 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_nMusicSpeed) { + m_nTickCount = 0; + } + if (!ProcessEffects()) return FALSE; + } else + { + if (!ProcessRow()) return FALSE; + } + + { /* handle realtime closures */ + MODCHANNEL *pChn = Chn; + for (UINT nChn=0; nChnnRealtime && 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 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; nChnnROfs = 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; diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/stdafx.h --- 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 #include -#elif defined(__x86_64__) || defined(__powerpc64__) +inline void ProcessPlugins(int n) {} + +#else #include #include @@ -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 -#include -#include - -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 diff -r 32f9f1e4a9ec -r 3673c7ec4ea2 src/modplug/tables.cxx --- 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,