diff options
Diffstat (limited to 'gst/modplug/libmodplug/sndfile.cpp')
-rw-r--r-- | gst/modplug/libmodplug/sndfile.cpp | 1872 |
1 files changed, 1872 insertions, 0 deletions
diff --git a/gst/modplug/libmodplug/sndfile.cpp b/gst/modplug/libmodplug/sndfile.cpp new file mode 100644 index 00000000..c4db8bcf --- /dev/null +++ b/gst/modplug/libmodplug/sndfile.cpp @@ -0,0 +1,1872 @@ +/* + * This source code is public domain. + * + * Authors: Olivier Lapicque <olivierl@jps.net>, + * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC) +*/ + +#include <math.h> //for GCCFIX +#include "stdafx.h" +#include "sndfile.h" + +#define MMCMP_SUPPORT + +#ifdef MMCMP_SUPPORT +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); +extern int DMFUnpack(LPBYTE psample, LPBYTE ibuf, LPBYTE ibufmax, UINT maxlen); +extern DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n); +extern void ITUnpack8Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215); +extern void ITUnpack16Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215); + + +#define MAX_PACK_TABLES 3 + + +// Compression table +static signed char UnpackTable[MAX_PACK_TABLES][16] = +//-------------------------------------------- +{ + // CPU-generated dynamic table + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + // u-Law table + {0, 1, 2, 4, 8, 16, 32, 64, + -1, -2, -4, -8, -16, -32, -48, -64}, + // Linear table + {0, 1, 2, 3, 5, 7, 12, 19, + -1, -2, -3, -5, -7, -12, -19, -31} +}; + + +////////////////////////////////////////////////////////// +// CSoundFile + +CSoundFile::CSoundFile() +//---------------------- +{ + m_nType = MOD_TYPE_NONE; + m_dwSongFlags = 0; + m_nChannels = 0; + m_nMixChannels = 0; + m_nSamples = 0; + m_nInstruments = 0; + m_nPatternNames = 0; + m_lpszPatternNames = NULL; + m_lpszSongComments = NULL; + m_nFreqFactor = m_nTempoFactor = 128; + m_nMasterVolume = 128; + m_nMinPeriod = 0x20; + m_nMaxPeriod = 0x7FFF; + m_nRepeatCount = 0; + memset(Chn, 0, sizeof(Chn)); + memset(ChnMix, 0, sizeof(ChnMix)); + memset(Ins, 0, sizeof(Ins)); + memset(ChnSettings, 0, sizeof(ChnSettings)); + memset(Headers, 0, sizeof(Headers)); + memset(Order, 0xFF, sizeof(Order)); + memset(Patterns, 0, sizeof(Patterns)); + memset(m_szNames, 0, sizeof(m_szNames)); + memset(m_MixPlugins, 0, sizeof(m_MixPlugins)); +} + + +CSoundFile::~CSoundFile() +//----------------------- +{ + Destroy(); +} + + +BOOL CSoundFile::Create(LPCBYTE lpStream, DWORD dwMemLength) +//---------------------------------------------------------- +{ + int i; + + m_nType = MOD_TYPE_NONE; + m_dwSongFlags = 0; + m_nChannels = 0; + m_nMixChannels = 0; + m_nSamples = 0; + m_nInstruments = 0; + m_nFreqFactor = m_nTempoFactor = 128; + m_nMasterVolume = 128; + m_nDefaultGlobalVolume = 256; + m_nGlobalVolume = 256; + m_nOldGlbVolSlide = 0; + m_nDefaultSpeed = 6; + m_nDefaultTempo = 125; + m_nPatternDelay = 0; + m_nFrameDelay = 0; + m_nNextRow = 0; + m_nRow = 0; + m_nPattern = 0; + m_nCurrentPattern = 0; + m_nNextPattern = 0; + m_nRestartPos = 0; + m_nMinPeriod = 16; + m_nMaxPeriod = 32767; + m_nSongPreAmp = 0x30; + m_nPatternNames = 0; + m_nMaxOrderPosition = 0; + m_lpszPatternNames = NULL; + m_lpszSongComments = NULL; + memset(Ins, 0, sizeof(Ins)); + memset(ChnMix, 0, sizeof(ChnMix)); + memset(Chn, 0, sizeof(Chn)); + memset(Headers, 0, sizeof(Headers)); + memset(Order, 0xFF, sizeof(Order)); + memset(Patterns, 0, sizeof(Patterns)); + memset(m_szNames, 0, sizeof(m_szNames)); + memset(m_MixPlugins, 0, sizeof(m_MixPlugins)); + ResetMidiCfg(); + for (UINT npt=0; npt<MAX_PATTERNS; npt++) PatternSize[npt] = 64; + for (UINT nch=0; nch<MAX_BASECHANNELS; nch++) + { + ChnSettings[nch].nPan = 128; + ChnSettings[nch].nVolume = 64; + ChnSettings[nch].dwFlags = 0; + ChnSettings[nch].szName[0] = 0; + } + if (lpStream) + { +#ifdef MMCMP_SUPPORT + BOOL bMMCmp = MMCMP_Unpack(&lpStream, &dwMemLength); +#endif + if ((!ReadXM(lpStream, dwMemLength)) + && (!ReadIT(lpStream, dwMemLength)) + && (!ReadS3M(lpStream, dwMemLength)) + && (!ReadWav(lpStream, dwMemLength)) +#ifndef MODPLUG_BASIC_SUPPORT + && (!ReadSTM(lpStream, dwMemLength)) + && (!ReadMed(lpStream, dwMemLength)) + && (!ReadMTM(lpStream, dwMemLength)) + && (!ReadMDL(lpStream, dwMemLength)) + && (!ReadDBM(lpStream, dwMemLength)) + && (!Read669(lpStream, dwMemLength)) + && (!ReadFAR(lpStream, dwMemLength)) + && (!ReadAMS(lpStream, dwMemLength)) + && (!ReadOKT(lpStream, dwMemLength)) + && (!ReadPTM(lpStream, dwMemLength)) + && (!ReadUlt(lpStream, dwMemLength)) + && (!ReadDMF(lpStream, dwMemLength)) + && (!ReadDSM(lpStream, dwMemLength)) + && (!ReadUMX(lpStream, dwMemLength)) + && (!ReadAMF(lpStream, dwMemLength)) + && (!ReadPSM(lpStream, dwMemLength)) + && (!ReadMT2(lpStream, dwMemLength)) +#endif // MODPLUG_BASIC_SUPPORT + && (!ReadMod(lpStream, dwMemLength))) m_nType = MOD_TYPE_NONE; +#ifdef MMCMP_SUPPORT + if (bMMCmp) + { + GlobalFreePtr(lpStream); + lpStream = NULL; + } +#endif + } + // Adjust song names + for (i=0; i<MAX_SAMPLES; i++) + { + LPSTR p = m_szNames[i]; + int j = 31; + p[j] = 0; + while ((j>=0) && (p[j]<=' ')) p[j--] = 0; + while (j>=0) + { + if (((BYTE)p[j]) < ' ') p[j] = ' '; + j--; + } + } + // Adjust channels + for (i=0; i<MAX_BASECHANNELS; i++) + { + if (ChnSettings[i].nVolume > 64) ChnSettings[i].nVolume = 64; + if (ChnSettings[i].nPan > 256) ChnSettings[i].nPan = 128; + Chn[i].nPan = ChnSettings[i].nPan; + Chn[i].nGlobalVol = ChnSettings[i].nVolume; + Chn[i].dwFlags = ChnSettings[i].dwFlags; + Chn[i].nVolume = 256; + Chn[i].nCutOff = 0x7F; + } + // Checking instruments + MODINSTRUMENT *pins = Ins; + + for (i=0; i<MAX_INSTRUMENTS; i++, pins++) + { + if (pins->pSample) + { + if (pins->nLoopEnd > pins->nLength) pins->nLoopEnd = pins->nLength; + if (pins->nLoopStart + 3 >= pins->nLoopEnd) + { + pins->nLoopStart = 0; + pins->nLoopEnd = 0; + } + if (pins->nSustainEnd > pins->nLength) pins->nSustainEnd = pins->nLength; + if (pins->nSustainStart + 3 >= pins->nSustainEnd) + { + pins->nSustainStart = 0; + pins->nSustainEnd = 0; + } + } else + { + pins->nLength = 0; + pins->nLoopStart = 0; + pins->nLoopEnd = 0; + pins->nSustainStart = 0; + pins->nSustainEnd = 0; + } + if (!pins->nLoopEnd) pins->uFlags &= ~CHN_LOOP; + if (!pins->nSustainEnd) pins->uFlags &= ~CHN_SUSTAINLOOP; + if (pins->nGlobalVol > 64) pins->nGlobalVol = 64; + } + // 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_nDefaultSpeed) m_nDefaultSpeed = 6; + m_nMusicSpeed = m_nDefaultSpeed; + m_nMusicTempo = m_nDefaultTempo; + m_nGlobalVolume = m_nDefaultGlobalVolume; + m_nNextPattern = 0; + m_nCurrentPattern = 0; + m_nPattern = 0; + m_nBufferCount = 0; + m_nTickCount = m_nMusicSpeed; + m_nNextRow = 0; + m_nRow = 0; + if ((m_nRestartPos >= MAX_ORDERS) || (Order[m_nRestartPos] >= MAX_PATTERNS)) m_nRestartPos = 0; + // Load plugins + if (gpMixPluginCreateProc) + { + for (UINT iPlug=0; iPlug<MAX_MIXPLUGINS; iPlug++) + { + if ((m_MixPlugins[iPlug].Info.dwPluginId1) + || (m_MixPlugins[iPlug].Info.dwPluginId2)) + { + gpMixPluginCreateProc(&m_MixPlugins[iPlug]); + if (m_MixPlugins[iPlug].pMixPlugin) + { + m_MixPlugins[iPlug].pMixPlugin->RestoreAllParameters(); + } + } + } + } + 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; +} + + +BOOL CSoundFile::Destroy() + +//------------------------ +{ + int i; + for (i=0; i<MAX_PATTERNS; i++) if (Patterns[i]) + { + FreePattern(Patterns[i]); + Patterns[i] = NULL; + } + m_nPatternNames = 0; + if (m_lpszPatternNames) + { + delete m_lpszPatternNames; + m_lpszPatternNames = NULL; + } + if (m_lpszSongComments) + { + delete m_lpszSongComments; + m_lpszSongComments = NULL; + } + for (i=1; i<MAX_SAMPLES; i++) + { + MODINSTRUMENT *pins = &Ins[i]; + if (pins->pSample) + { + FreeSample(pins->pSample); + pins->pSample = NULL; + } + } + for (i=0; i<MAX_INSTRUMENTS; i++) + { + if (Headers[i]) + { + delete Headers[i]; + Headers[i] = NULL; + } + } + for (i=0; i<MAX_MIXPLUGINS; i++) + { + if ((m_MixPlugins[i].nPluginDataSize) && (m_MixPlugins[i].pPluginData)) + { + m_MixPlugins[i].nPluginDataSize = 0; + delete [] (signed char*)m_MixPlugins[i].pPluginData; + m_MixPlugins[i].pPluginData = NULL; + } + m_MixPlugins[i].pMixState = NULL; + if (m_MixPlugins[i].pMixPlugin) + { + m_MixPlugins[i].pMixPlugin->Release(); + m_MixPlugins[i].pMixPlugin = NULL; + } + } + m_nType = MOD_TYPE_NONE; + m_nChannels = m_nSamples = m_nInstruments = 0; + return TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +// Memory Allocation + +MODCOMMAND *CSoundFile::AllocatePattern(UINT rows, UINT nchns) +//------------------------------------------------------------ +{ + MODCOMMAND *p = new MODCOMMAND[rows*nchns]; + if (p) memset(p, 0, rows*nchns*sizeof(MODCOMMAND)); + return p; +} + + +void CSoundFile::FreePattern(LPVOID pat) +//-------------------------------------- +{ + if (pat) delete [] (signed char*)pat; +} + + +signed char* CSoundFile::AllocateSample(UINT nbytes) +//------------------------------------------- +{ + signed char * p = (signed char *)GlobalAllocPtr(GHND, (nbytes+39) & ~7); + if (p) p += 16; + return p; +} + + +void CSoundFile::FreeSample(LPVOID p) +//----------------------------------- +{ + if (p) + { + GlobalFreePtr(((LPSTR)p)-16); + } +} + + +////////////////////////////////////////////////////////////////////////// +// Misc functions + +void CSoundFile::ResetMidiCfg() +//----------------------------- +{ + memset(&m_MidiCfg, 0, sizeof(m_MidiCfg)); + lstrcpy(&m_MidiCfg.szMidiGlb[MIDIOUT_START*32], "FF"); + lstrcpy(&m_MidiCfg.szMidiGlb[MIDIOUT_STOP*32], "FC"); + lstrcpy(&m_MidiCfg.szMidiGlb[MIDIOUT_NOTEON*32], "9c n v"); + lstrcpy(&m_MidiCfg.szMidiGlb[MIDIOUT_NOTEOFF*32], "9c n 0"); + lstrcpy(&m_MidiCfg.szMidiGlb[MIDIOUT_PROGRAM*32], "Cc p"); + lstrcpy(&m_MidiCfg.szMidiSFXExt[0], "F0F000z"); + for (int iz=0; iz<16; iz++) wsprintf(&m_MidiCfg.szMidiZXXExt[iz*32], "F0F001%02X", iz*8); +} + + +UINT CSoundFile::GetNumChannels() const +//------------------------------------- +{ + UINT n = 0; + for (UINT i=0; i<m_nChannels; i++) if (ChnSettings[i].nVolume) n++; + return n; +} + + +UINT CSoundFile::GetSongComments(LPSTR s, UINT len, UINT linesize) +//---------------------------------------------------------------- +{ + LPCSTR p = m_lpszSongComments; + if (!p) return 0; + UINT i = 2, ln=0; + if ((len) && (s)) s[0] = '\x0D'; + if ((len > 1) && (s)) s[1] = '\x0A'; + while ((*p) && (i+2 < len)) + { + BYTE c = (BYTE)*p++; + if ((c == 0x0D) || ((c == ' ') && (ln >= linesize))) + { if (s) { s[i++] = '\x0D'; s[i++] = '\x0A'; } else i+= 2; ln=0; } + else + if (c >= 0x20) { if (s) s[i++] = c; else i++; ln++; } + } + if (s) s[i] = 0; + return i; +} + + +UINT CSoundFile::GetRawSongComments(LPSTR s, UINT len, UINT linesize) +//------------------------------------------------------------------- +{ + LPCSTR p = m_lpszSongComments; + if (!p) return 0; + UINT i = 0, ln=0; + while ((*p) && (i < len-1)) + { + BYTE c = (BYTE)*p++; + if ((c == 0x0D) || (c == 0x0A)) + { + if (ln) + { + while (ln < linesize) { if (s) s[i] = ' '; i++; ln++; } + ln = 0; + } + } else + if ((c == ' ') && (!ln)) + { + UINT k=0; + while ((p[k]) && (p[k] >= ' ')) k++; + if (k <= linesize) + { + if (s) s[i] = ' '; + i++; + ln++; + } + } else + { + if (s) s[i] = c; + i++; + ln++; + if (ln == linesize) ln = 0; + } + } + if (ln) + { + while ((ln < linesize) && (i < len)) + { + if (s) s[i] = ' '; + i++; + ln++; + } + } + if (s) s[i] = 0; + return i; +} + + +BOOL CSoundFile::SetWaveConfig(UINT nRate,UINT nBits,UINT nChannels,BOOL bMMX) +//---------------------------------------------------------------------------- +{ + BOOL bReset = FALSE; + DWORD d = gdwSoundSetup & ~SNDMIX_ENABLEMMX; + if (bMMX) d |= SNDMIX_ENABLEMMX; + if ((gdwMixingFreq != nRate) || (gnBitsPerSample != nBits) || (gnChannels != nChannels) || (d != gdwSoundSetup)) bReset = TRUE; + gnChannels = nChannels; + gdwSoundSetup = d; + gdwMixingFreq = nRate; + gnBitsPerSample = nBits; + InitPlayer(bReset); + return TRUE; +} + + +BOOL CSoundFile::SetResamplingMode(UINT nMode) +//-------------------------------------------- +{ + DWORD d = gdwSoundSetup & ~(SNDMIX_NORESAMPLING|SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE); + switch(nMode) + { + case SRCMODE_NEAREST: d |= SNDMIX_NORESAMPLING; break; + case SRCMODE_LINEAR: break; + case SRCMODE_SPLINE: d |= SNDMIX_HQRESAMPLER; break; + case SRCMODE_POLYPHASE: d |= (SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE); break; + default: + return FALSE; + } + gdwSoundSetup = d; + return TRUE; +} + + +BOOL CSoundFile::SetMasterVolume(UINT nVol, BOOL bAdjustAGC) +//---------------------------------------------------------- +{ + if (nVol < 1) nVol = 1; + if (nVol > 0x200) nVol = 0x200; // x4 maximum + if ((nVol < m_nMasterVolume) && (nVol) && (gdwSoundSetup & SNDMIX_AGC) && (bAdjustAGC)) + { + gnAGC = gnAGC * m_nMasterVolume / nVol; + if (gnAGC > AGC_UNITY) gnAGC = AGC_UNITY; + } + m_nMasterVolume = nVol; + return TRUE; +} + + +void CSoundFile::SetAGC(BOOL b) +//----------------------------- +{ + if (b) + { + if (!(gdwSoundSetup & SNDMIX_AGC)) + { + gdwSoundSetup |= SNDMIX_AGC; + gnAGC = AGC_UNITY; + } + } else gdwSoundSetup &= ~SNDMIX_AGC; +} + + +UINT CSoundFile::GetNumPatterns() const +//------------------------------------- +{ + UINT i = 0; + while ((i < MAX_ORDERS) && (Order[i] < 0xFF)) i++; + return i; +} + + +UINT CSoundFile::GetNumInstruments() const +//---------------------------------------- +{ + UINT n=0; + for (UINT i=0; i<MAX_INSTRUMENTS; i++) if (Ins[i].pSample) n++; + return n; +} + + +UINT CSoundFile::GetMaxPosition() const +//------------------------------------- +{ + UINT max = 0; + UINT i = 0; + + while ((i < MAX_ORDERS) && (Order[i] != 0xFF)) + { + if (Order[i] < MAX_PATTERNS) max += PatternSize[Order[i]]; + i++; + } + return max; +} + + +UINT CSoundFile::GetCurrentPos() const +//------------------------------------ +{ + UINT pos = 0; + + for (UINT i=0; i<m_nCurrentPattern; i++) if (Order[i] < MAX_PATTERNS) + pos += PatternSize[Order[i]]; + return pos + m_nRow; +} + + +void CSoundFile::SetCurrentPos(UINT nPos) +//--------------------------------------- +{ + UINT i, nPattern; + + for (i=0; i<MAX_CHANNELS; i++) + { + Chn[i].nNote = Chn[i].nNewNote = Chn[i].nNewIns = 0; + Chn[i].pInstrument = NULL; + Chn[i].pHeader = NULL; + Chn[i].nPortamentoDest = 0; + Chn[i].nCommand = 0; + Chn[i].nPatternLoopCount = 0; + Chn[i].nPatternLoop = 0; + Chn[i].nFadeOutVol = 0; + Chn[i].dwFlags |= CHN_KEYOFF|CHN_NOTEFADE; + Chn[i].nTremorCount = 0; + } + if (!nPos) + { + for (i=0; i<MAX_CHANNELS; i++) + { + Chn[i].nPeriod = 0; + Chn[i].nPos = Chn[i].nLength = 0; + Chn[i].nLoopStart = 0; + Chn[i].nLoopEnd = 0; + Chn[i].nROfs = Chn[i].nLOfs = 0; + Chn[i].pSample = NULL; + Chn[i].pInstrument = NULL; + Chn[i].pHeader = NULL; + Chn[i].nCutOff = 0x7F; + Chn[i].nResonance = 0; + Chn[i].nLeftVol = Chn[i].nRightVol = 0; + Chn[i].nNewLeftVol = Chn[i].nNewRightVol = 0; + Chn[i].nLeftRamp = Chn[i].nRightRamp = 0; + Chn[i].nVolume = 256; + if (i < MAX_BASECHANNELS) + { + Chn[i].dwFlags = ChnSettings[i].dwFlags; + Chn[i].nPan = ChnSettings[i].nPan; + Chn[i].nGlobalVol = ChnSettings[i].nVolume; + } else + { + Chn[i].dwFlags = 0; + Chn[i].nPan = 128; + Chn[i].nGlobalVol = 64; + } + } + m_nGlobalVolume = m_nDefaultGlobalVolume; + m_nMusicSpeed = m_nDefaultSpeed; + m_nMusicTempo = m_nDefaultTempo; + } + m_dwSongFlags &= ~(SONG_PATTERNLOOP|SONG_CPUVERYHIGH|SONG_FADINGSONG|SONG_ENDREACHED|SONG_GLOBALFADE); + for (nPattern = 0; nPattern < MAX_ORDERS; nPattern++) + { + UINT ord = Order[nPattern]; + if (ord == 0xFE) continue; + if (ord == 0xFF) break; + if (ord < MAX_PATTERNS) + { + if (nPos < (UINT)PatternSize[ord]) break; + nPos -= PatternSize[ord]; + } + } + // Buggy position ? + if ((nPattern >= MAX_ORDERS) + || (Order[nPattern] >= MAX_PATTERNS) + || (nPos >= PatternSize[Order[nPattern]])) + { + nPos = 0; + nPattern = 0; + } + UINT nRow = nPos; + if ((nRow) && (Order[nPattern] < MAX_PATTERNS)) + { + MODCOMMAND *p = Patterns[Order[nPattern]]; + if ((p) && (nRow < PatternSize[Order[nPattern]])) + { + BOOL bOk = FALSE; + while ((!bOk) && (nRow > 0)) + { + UINT n = nRow * m_nChannels; + for (UINT k=0; k<m_nChannels; k++, n++) + { + if (p[n].note) + { + bOk = TRUE; + break; + } + } + if (!bOk) nRow--; + } + } + } + m_nNextPattern = nPattern; + m_nNextRow = nRow; + m_nTickCount = m_nMusicSpeed; + m_nBufferCount = 0; + m_nPatternDelay = 0; + m_nFrameDelay = 0; +} + + +void CSoundFile::SetCurrentOrder(UINT nPos) +//----------------------------------------- +{ + while ((nPos < MAX_ORDERS) && (Order[nPos] == 0xFE)) nPos++; + if ((nPos >= MAX_ORDERS) || (Order[nPos] >= MAX_PATTERNS)) return; + for (UINT j=0; j<MAX_CHANNELS; j++) + { + Chn[j].nPeriod = 0; + Chn[j].nNote = 0; + Chn[j].nPortamentoDest = 0; + Chn[j].nCommand = 0; + Chn[j].nPatternLoopCount = 0; + Chn[j].nPatternLoop = 0; + Chn[j].nTremorCount = 0; + } + if (!nPos) + { + SetCurrentPos(0); + } else + { + m_nNextPattern = nPos; + m_nRow = m_nNextRow = 0; + m_nPattern = 0; + m_nTickCount = m_nMusicSpeed; + m_nBufferCount = 0; + m_nTotalCount = 0; + m_nPatternDelay = 0; + m_nFrameDelay = 0; + } + m_dwSongFlags &= ~(SONG_PATTERNLOOP|SONG_CPUVERYHIGH|SONG_FADINGSONG|SONG_ENDREACHED|SONG_GLOBALFADE); +} + + +void CSoundFile::ResetChannels() +//------------------------------ +{ + m_dwSongFlags &= ~(SONG_CPUVERYHIGH|SONG_FADINGSONG|SONG_ENDREACHED|SONG_GLOBALFADE); + m_nBufferCount = 0; + for (UINT i=0; i<MAX_CHANNELS; i++) + { + Chn[i].nROfs = Chn[i].nLOfs = 0; + } +} + + +void CSoundFile::LoopPattern(int nPat, int nRow) +//---------------------------------------------- +{ + if ((nPat < 0) || (nPat >= MAX_PATTERNS) || (!Patterns[nPat])) + { + m_dwSongFlags &= ~SONG_PATTERNLOOP; + } else + { + if ((nRow < 0) || (nRow >= PatternSize[nPat])) nRow = 0; + m_nPattern = nPat; + m_nRow = m_nNextRow = nRow; + m_nTickCount = m_nMusicSpeed; + m_nPatternDelay = 0; + m_nFrameDelay = 0; + m_nBufferCount = 0; + m_dwSongFlags |= SONG_PATTERNLOOP; + } +} + + +UINT CSoundFile::GetBestSaveFormat() const +//---------------------------------------- +{ + if ((!m_nSamples) || (!m_nChannels)) return MOD_TYPE_NONE; + if (!m_nType) return MOD_TYPE_NONE; + if (m_nType & (MOD_TYPE_MOD|MOD_TYPE_OKT)) + return MOD_TYPE_MOD; + if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_STM|MOD_TYPE_ULT|MOD_TYPE_FAR|MOD_TYPE_PTM)) + return MOD_TYPE_S3M; + if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MED|MOD_TYPE_MTM|MOD_TYPE_MT2)) + return MOD_TYPE_XM; + return MOD_TYPE_IT; +} + + +UINT CSoundFile::GetSaveFormats() const +//------------------------------------- +{ + UINT n = 0; + if ((!m_nSamples) || (!m_nChannels) || (m_nType == MOD_TYPE_NONE)) return 0; + switch(m_nType) + { + case MOD_TYPE_MOD: n = MOD_TYPE_MOD; + case MOD_TYPE_S3M: n = MOD_TYPE_S3M; + } + n |= MOD_TYPE_XM | MOD_TYPE_IT; + if (!m_nInstruments) + { + if (m_nSamples < 32) n |= MOD_TYPE_MOD; + n |= MOD_TYPE_S3M; + } + return n; +} + + +UINT CSoundFile::GetSampleName(UINT nSample,LPSTR s) const +//-------------------------------------------------------- +{ + char sztmp[40] = ""; // changed from CHAR + memcpy(sztmp, m_szNames[nSample],32); + sztmp[31] = 0; + if (s) strcpy(s, sztmp); + return strlen(sztmp); +} + + +UINT CSoundFile::GetInstrumentName(UINT nInstr,LPSTR s) const +//----------------------------------------------------------- +{ + char sztmp[40] = ""; // changed from CHAR + if ((nInstr >= MAX_INSTRUMENTS) || (!Headers[nInstr])) + { + if (s) *s = 0; + return 0; + } + INSTRUMENTHEADER *penv = Headers[nInstr]; + memcpy(sztmp, penv->name, 32); + sztmp[31] = 0; + if (s) strcpy(s, sztmp); + return strlen(sztmp); +} + + +#ifndef NO_PACKING +UINT CSoundFile::PackSample(int &sample, int next) +//------------------------------------------------ +{ + UINT i = 0; + int delta = next - sample; + if (delta >= 0) + { + for (i=0; i<7; i++) if (delta <= (int)CompressionTable[i+1]) break; + } else + { + for (i=8; i<15; i++) if (delta >= (int)CompressionTable[i+1]) break; + } + sample += (int)CompressionTable[i]; + return i; +} + + +BOOL CSoundFile::CanPackSample(LPSTR pSample, UINT nLen, UINT nPacking, BYTE *result) +//----------------------------------------------------------------------------------- +{ + int pos, old, oldpos, besttable = 0; + DWORD dwErr, dwTotal, dwResult; + int i,j; + + if (result) *result = 0; + if ((!pSample) || (nLen < 1024)) return FALSE; + // Try packing with different tables + dwResult = 0; + for (j=1; j<MAX_PACK_TABLES; j++) + { + memcpy(CompressionTable, UnpackTable[j], 16); + dwErr = 0; + dwTotal = 1; + old = pos = oldpos = 0; + for (i=0; i<(int)nLen; i++) + { + int s = (int)pSample[i]; + PackSample(pos, s); + dwErr += abs(pos - oldpos); + dwTotal += abs(s - old); + old = s; + oldpos = pos; + } + dwErr = _muldiv(dwErr, 100, dwTotal); + if (dwErr >= dwResult) + { + dwResult = dwErr; + besttable = j; + } + } + memcpy(CompressionTable, UnpackTable[besttable], 16); + if (result) + { + if (dwResult > 100) *result = 100; else *result = (BYTE)dwResult; + } + return (dwResult >= nPacking) ? TRUE : FALSE; +} +#endif // NO_PACKING + +#ifndef MODPLUG_NO_FILESAVE + +UINT CSoundFile::WriteSample(FILE *f, MODINSTRUMENT *pins, UINT nFlags, UINT nMaxLen) +//----------------------------------------------------------------------------------- +{ + UINT len = 0, bufcount; + signed char buffer[4096]; + signed char *pSample = (signed char *)pins->pSample; + UINT nLen = pins->nLength; + + if ((nMaxLen) && (nLen > nMaxLen)) nLen = nMaxLen; + if ((!pSample) || (f == NULL) || (!nLen)) return 0; + switch(nFlags) + { +#ifndef NO_PACKING + // 3: 4-bit ADPCM data + case RS_ADPCM4: + { + int pos; + len = (nLen + 1) / 2; + fwrite(CompressionTable, 16, 1, f); + bufcount = 0; + pos = 0; + for (UINT j=0; j<len; j++) + { + BYTE b; + // Sample #1 + b = PackSample(pos, (int)pSample[j*2]); + // Sample #2 + b |= PackSample(pos, (int)pSample[j*2+1]) << 4; + buffer[bufcount++] = (signed char)b; + if (bufcount >= sizeof(buffer)) + { + fwrite(buffer, 1, bufcount, f); + bufcount = 0; + } + } + if (bufcount) fwrite(buffer, 1, bufcount, f); + len += 16; + } + break; +#endif // NO_PACKING + + // 16-bit samples + case RS_PCM16U: + case RS_PCM16D: + case RS_PCM16S: + { + short int *p = (short int *)pSample; + int s_old = 0, s_ofs; + len = nLen * 2; + bufcount = 0; + s_ofs = (nFlags == RS_PCM16U) ? 0x8000 : 0; + for (UINT j=0; j<nLen; j++) + { + int s_new = *p; + p++; + if (pins->uFlags & CHN_STEREO) + { + s_new = (s_new + (*p) + 1) >> 1; + p++; + } + if (nFlags == RS_PCM16D) + { + *((short *)(&buffer[bufcount])) = (short)(s_new - s_old); + s_old = s_new; + } else + { + *((short *)(&buffer[bufcount])) = (short)(s_new + s_ofs); + } + bufcount += 2; + if (bufcount >= sizeof(buffer) - 1) + { + fwrite(buffer, 1, bufcount, f); + bufcount = 0; + } + } + if (bufcount) fwrite(buffer, 1, bufcount, f); + } + break; + + + // 8-bit Stereo samples (not interleaved) + case RS_STPCM8S: + case RS_STPCM8U: + case RS_STPCM8D: + { + int s_ofs = (nFlags == RS_STPCM8U) ? 0x80 : 0; + for (UINT iCh=0; iCh<2; iCh++) + { + signed char *p = pSample + iCh; + int s_old = 0; + + bufcount = 0; + for (UINT j=0; j<nLen; j++) + { + int s_new = *p; + p += 2; + if (nFlags == RS_STPCM8D) + { + buffer[bufcount++] = (signed char)(s_new - s_old); + s_old = s_new; + } else + { + buffer[bufcount++] = (signed char)(s_new + s_ofs); + } + if (bufcount >= sizeof(buffer)) + { + fwrite(buffer, 1, bufcount, f); + bufcount = 0; + } + } + if (bufcount) fwrite(buffer, 1, bufcount, f); + } + } + len = nLen * 2; + break; + + // 16-bit Stereo samples (not interleaved) + case RS_STPCM16S: + case RS_STPCM16U: + case RS_STPCM16D: + { + int s_ofs = (nFlags == RS_STPCM16U) ? 0x8000 : 0; + for (UINT iCh=0; iCh<2; iCh++) + { + signed short *p = ((signed short *)pSample) + iCh; + int s_old = 0; + + bufcount = 0; + for (UINT j=0; j<nLen; j++) + { + int s_new = *p; + p += 2; + if (nFlags == RS_STPCM16D) + { + *((short *)(&buffer[bufcount])) = (short)(s_new - s_old); + s_old = s_new; + } else + { + *((short *)(&buffer[bufcount])) = (short)(s_new + s_ofs); + } + bufcount += 2; + if (bufcount >= sizeof(buffer)) + { + fwrite(buffer, 1, bufcount, f); + bufcount = 0; + } + } + if (bufcount) fwrite(buffer, 1, bufcount, f); + } + } + len = nLen*4; + break; + + // Stereo signed interleaved + case RS_STIPCM8S: + case RS_STIPCM16S: + len = nLen * 2; + if (nFlags == RS_STIPCM16S) len *= 2; + fwrite(pSample, 1, len, f); + break; + + // Default: assume 8-bit PCM data + default: + len = nLen; + bufcount = 0; + { + signed char *p = pSample; + int sinc = (pins->uFlags & CHN_16BIT) ? 2 : 1; + int s_old = 0, s_ofs = (nFlags == RS_PCM8U) ? 0x80 : 0; + if (pins->uFlags & CHN_16BIT) p++; + for (UINT j=0; j<len; j++) + { + int s_new = (signed char)(*p); + p += sinc; + if (pins->uFlags & CHN_STEREO) + { + s_new = (s_new + ((int)*p) + 1) >> 1; + p += sinc; + } + if (nFlags == RS_PCM8D) + { + buffer[bufcount++] = (signed char)(s_new - s_old); + s_old = s_new; + } else + { + buffer[bufcount++] = (signed char)(s_new + s_ofs); + } + if (bufcount >= sizeof(buffer)) + { + fwrite(buffer, 1, bufcount, f); + bufcount = 0; + } + } + if (bufcount) fwrite(buffer, 1, bufcount, f); + } + } + return len; +} + +#endif // MODPLUG_NO_FILESAVE + + +// Flags: +// 0 = signed 8-bit PCM data (default) +// 1 = unsigned 8-bit PCM data +// 2 = 8-bit ADPCM data with linear table +// 3 = 4-bit ADPCM data +// 4 = 16-bit ADPCM data with linear table +// 5 = signed 16-bit PCM data +// 6 = unsigned 16-bit PCM data + + +UINT CSoundFile::ReadSample(MODINSTRUMENT *pIns, UINT nFlags, LPCSTR lpMemFile, DWORD dwMemLength) +//------------------------------------------------------------------------------------------------ +{ + UINT len = 0, mem = pIns->nLength+6; + + if ((!pIns) || (pIns->nLength < 4) || (!lpMemFile)) return 0; + if (pIns->nLength > MAX_SAMPLE_LENGTH) pIns->nLength = MAX_SAMPLE_LENGTH; + pIns->uFlags &= ~(CHN_16BIT|CHN_STEREO); + if (nFlags & RSF_16BIT) + { + mem *= 2; + pIns->uFlags |= CHN_16BIT; + } + if (nFlags & RSF_STEREO) + { + mem *= 2; + pIns->uFlags |= CHN_STEREO; + } + if ((pIns->pSample = AllocateSample(mem)) == NULL) + { + pIns->nLength = 0; + return 0; + } + switch(nFlags) + { + // 1: 8-bit unsigned PCM data + case RS_PCM8U: + { + len = pIns->nLength; + if (len > dwMemLength) len = pIns->nLength = dwMemLength; + signed char *pSample = pIns->pSample; + for (UINT j=0; j<len; j++) pSample[j] = (signed char)(lpMemFile[j] - 0x80); + } + break; + + // 2: 8-bit ADPCM data with linear table + case RS_PCM8D: + { + len = pIns->nLength; + if (len > dwMemLength) break; + signed char *pSample = pIns->pSample; + const signed char *p = (const signed char *)lpMemFile; + int delta = 0; + + for (UINT j=0; j<len; j++) + { + delta += p[j]; + *pSample++ = (signed char)delta; + } + } + break; + + // 3: 4-bit ADPCM data + case RS_ADPCM4: + { + len = (pIns->nLength + 1) / 2; + if (len > dwMemLength - 16) break; + memcpy(CompressionTable, lpMemFile, 16); + lpMemFile += 16; + signed char *pSample = pIns->pSample; + signed char delta = 0; + for (UINT j=0; j<len; j++) + { + BYTE b0 = (BYTE)lpMemFile[j]; + BYTE b1 = (BYTE)(lpMemFile[j] >> 4); + delta = (signed char)GetDeltaValue((int)delta, b0); + pSample[0] = delta; + delta = (signed char)GetDeltaValue((int)delta, b1); + pSample[1] = delta; + pSample += 2; + } + len += 16; + } + break; + + // 4: 16-bit ADPCM data with linear table + case RS_PCM16D: + { + len = pIns->nLength * 2; + if (len > dwMemLength) break; + short int *pSample = (short int *)pIns->pSample; + short int *p = (short int *)lpMemFile; + int delta16 = 0; + for (UINT j=0; j<len; j+=2) + { + delta16 += bswapLE16(*p++); + *pSample++ = (short int)delta16; + } + } + break; + + // 5: 16-bit signed PCM data + case RS_PCM16S: + { + len = pIns->nLength * 2; + if (len <= dwMemLength) memcpy(pIns->pSample, lpMemFile, len); + short int *pSample = (short int *)pIns->pSample; + for (UINT j=0; j<len; j+=2) + { + *pSample++ = bswapLE16(*pSample); + } + } + break; + + // 16-bit signed mono PCM motorola byte order + case RS_PCM16M: + len = pIns->nLength * 2; + if (len > dwMemLength) len = dwMemLength & ~1; + if (len > 1) + { + signed char *pSample = (signed char *)pIns->pSample; + signed char *pSrc = (signed char *)lpMemFile; + for (UINT j=0; j<len; j+=2) + { + // pSample[j] = pSrc[j+1]; + // pSample[j+1] = pSrc[j]; + *((unsigned short *)(pSample+j)) = bswapBE16(*((unsigned short *)(pSrc+j))); + } + } + break; + + // 6: 16-bit unsigned PCM data + case RS_PCM16U: + { + len = pIns->nLength * 2; + if (len > dwMemLength) break; + short int *pSample = (short int *)pIns->pSample; + short int *pSrc = (short int *)lpMemFile; + for (UINT j=0; j<len; j+=2) *pSample++ = bswapLE16(*(pSrc++)) - 0x8000; + } + break; + + // 16-bit signed stereo big endian + case RS_STPCM16M: + len = pIns->nLength * 2; + if (len*2 <= dwMemLength) + { + signed char *pSample = (signed char *)pIns->pSample; + signed char *pSrc = (signed char *)lpMemFile; + for (UINT j=0; j<len; j+=2) + { + // pSample[j*2] = pSrc[j+1]; + // pSample[j*2+1] = pSrc[j]; + // pSample[j*2+2] = pSrc[j+1+len]; + // pSample[j*2+3] = pSrc[j+len]; + *((unsigned short *)(pSample+j*2)) = bswapBE16(*((unsigned short *)(pSrc+j))); + *((unsigned short *)(pSample+j*2+2)) = bswapBE16(*((unsigned short *)(pSrc+j+len))); + } + len *= 2; + } + break; + + // 8-bit stereo samples + case RS_STPCM8S: + case RS_STPCM8U: + case RS_STPCM8D: + { + int iadd_l = 0, iadd_r = 0; + if (nFlags == RS_STPCM8U) { iadd_l = iadd_r = -128; } + len = pIns->nLength; + signed char *psrc = (signed char *)lpMemFile; + signed char *pSample = (signed char *)pIns->pSample; + if (len*2 > dwMemLength) break; + for (UINT j=0; j<len; j++) + { + pSample[j*2] = (signed char)(psrc[0] + iadd_l); + pSample[j*2+1] = (signed char)(psrc[len] + iadd_r); + psrc++; + if (nFlags == RS_STPCM8D) + { + iadd_l = pSample[j*2]; + iadd_r = pSample[j*2+1]; + } + } + len *= 2; + } + break; + + // 16-bit stereo samples + case RS_STPCM16S: + case RS_STPCM16U: + case RS_STPCM16D: + { + int iadd_l = 0, iadd_r = 0; + if (nFlags == RS_STPCM16U) { iadd_l = iadd_r = -0x8000; } + len = pIns->nLength; + short int *psrc = (short int *)lpMemFile; + short int *pSample = (short int *)pIns->pSample; + if (len*4 > dwMemLength) break; + for (UINT j=0; j<len; j++) + { + pSample[j*2] = (short int) (bswapLE16(psrc[0]) + iadd_l); + pSample[j*2+1] = (short int) (bswapLE16(psrc[len]) + iadd_r); + psrc++; + if (nFlags == RS_STPCM16D) + { + iadd_l = pSample[j*2]; + iadd_r = pSample[j*2+1]; + } + } + len *= 4; + } + break; + + // IT 2.14 compressed samples + case RS_IT2148: + case RS_IT21416: + case RS_IT2158: + case RS_IT21516: + len = dwMemLength; + if (len < 4) break; + if ((nFlags == RS_IT2148) || (nFlags == RS_IT2158)) + ITUnpack8Bit(pIns->pSample, pIns->nLength, (LPBYTE)lpMemFile, dwMemLength, (nFlags == RS_IT2158)); + else + ITUnpack16Bit(pIns->pSample, pIns->nLength, (LPBYTE)lpMemFile, dwMemLength, (nFlags == RS_IT21516)); + break; + +#ifndef MODPLUG_BASIC_SUPPORT +#ifndef FASTSOUNDLIB + // 8-bit interleaved stereo samples + case RS_STIPCM8S: + case RS_STIPCM8U: + { + int iadd = 0; + if (nFlags == RS_STIPCM8U) { iadd = -0x80; } + len = pIns->nLength; + if (len*2 > dwMemLength) len = dwMemLength >> 1; + LPBYTE psrc = (LPBYTE)lpMemFile; + LPBYTE pSample = (LPBYTE)pIns->pSample; + for (UINT j=0; j<len; j++) + { + pSample[j*2] = (signed char)(psrc[0] + iadd); + pSample[j*2+1] = (signed char)(psrc[1] + iadd); + psrc+=2; + } + len *= 2; + } + break; + + // 16-bit interleaved stereo samples + case RS_STIPCM16S: + case RS_STIPCM16U: + { + int iadd = 0; + if (nFlags == RS_STIPCM16U) iadd = -32768; + len = pIns->nLength; + if (len*4 > dwMemLength) len = dwMemLength >> 2; + short int *psrc = (short int *)lpMemFile; + short int *pSample = (short int *)pIns->pSample; + for (UINT j=0; j<len; j++) + { + pSample[j*2] = (short int)(bswapLE16(psrc[0]) + iadd); + pSample[j*2+1] = (short int)(bswapLE16(psrc[1]) + iadd); + psrc += 2; + } + len *= 4; + } + break; + + // AMS compressed samples + case RS_AMS8: + case RS_AMS16: + len = 9; + if (dwMemLength > 9) + { + const char *psrc = lpMemFile; + char packcharacter = lpMemFile[8], *pdest = (char *)pIns->pSample; + len += bswapLE32(*((LPDWORD)(lpMemFile+4))); + if (len > dwMemLength) len = dwMemLength; + UINT dmax = pIns->nLength; + if (pIns->uFlags & CHN_16BIT) dmax <<= 1; + AMSUnpack(psrc+9, len-9, pdest, dmax, packcharacter); + } + break; + + // PTM 8bit delta to 16-bit sample + case RS_PTM8DTO16: + { + len = pIns->nLength * 2; + if (len > dwMemLength) break; + signed char *pSample = (signed char *)pIns->pSample; + signed char delta8 = 0; + for (UINT j=0; j<len; j++) + { + delta8 += lpMemFile[j]; + *pSample++ = delta8; + } + WORD *pSampleW = (WORD *)pIns->pSample; + for (UINT j=0; j<len; j+=2) // swaparoni! + { + *pSampleW++ = bswapLE16(*pSampleW); + } + } + break; + + // Huffman MDL compressed samples + case RS_MDL8: + case RS_MDL16: + len = dwMemLength; + if (len >= 4) + { + LPBYTE pSample = (LPBYTE)pIns->pSample; + LPBYTE ibuf = (LPBYTE)lpMemFile; + DWORD bitbuf = bswapLE32(*((DWORD *)ibuf)); + UINT bitnum = 32; + BYTE dlt = 0, lowbyte = 0; + ibuf += 4; + for (UINT j=0; j<pIns->nLength; j++) + { + BYTE hibyte; + BYTE sign; + if (nFlags == RS_MDL16) lowbyte = (BYTE)MDLReadBits(bitbuf, bitnum, ibuf, 8); + sign = (BYTE)MDLReadBits(bitbuf, bitnum, ibuf, 1); + if (MDLReadBits(bitbuf, bitnum, ibuf, 1)) + { + hibyte = (BYTE)MDLReadBits(bitbuf, bitnum, ibuf, 3); + } else + { + hibyte = 8; + while (!MDLReadBits(bitbuf, bitnum, ibuf, 1)) hibyte += 0x10; + hibyte += MDLReadBits(bitbuf, bitnum, ibuf, 4); + } + if (sign) hibyte = ~hibyte; + dlt += hibyte; + if (nFlags != RS_MDL16) + pSample[j] = dlt; + else + { + pSample[j<<1] = lowbyte; + pSample[(j<<1)+1] = dlt; + } + } + } + break; + + case RS_DMF8: + case RS_DMF16: + len = dwMemLength; + if (len >= 4) + { + UINT maxlen = pIns->nLength; + if (pIns->uFlags & CHN_16BIT) maxlen <<= 1; + LPBYTE ibuf = (LPBYTE)lpMemFile, ibufmax = (LPBYTE)(lpMemFile+dwMemLength); + len = DMFUnpack((LPBYTE)pIns->pSample, ibuf, ibufmax, maxlen); + } + break; + +#ifdef MODPLUG_TRACKER + // PCM 24-bit signed -> load sample, and normalize it to 16-bit + case RS_PCM24S: + case RS_PCM32S: + len = pIns->nLength * 3; + if (nFlags == RS_PCM32S) len += pIns->nLength; + if (len > dwMemLength) break; + if (len > 4*8) + { + UINT slsize = (nFlags == RS_PCM32S) ? 4 : 3; + LPBYTE pSrc = (LPBYTE)lpMemFile; + LONG max = 255; + if (nFlags == RS_PCM32S) pSrc++; + for (UINT j=0; j<len; j+=slsize) + { + LONG l = ((((pSrc[j+2] << 8) + pSrc[j+1]) << 8) + pSrc[j]) << 8; + l /= 256; + if (l > max) max = l; + if (-l > max) max = -l; + } + max = (max / 128) + 1; + signed short *pDest = (signed short *)pIns->pSample; + for (UINT k=0; k<len; k+=slsize) + { + LONG l = ((((pSrc[k+2] << 8) + pSrc[k+1]) << 8) + pSrc[k]) << 8; + *pDest++ = (signed short)(l / max); + } + } + break; + + // Stereo PCM 24-bit signed -> load sample, and normalize it to 16-bit + case RS_STIPCM24S: + case RS_STIPCM32S: + len = pIns->nLength * 6; + if (nFlags == RS_STIPCM32S) len += pIns->nLength * 2; + if (len > dwMemLength) break; + if (len > 8*8) + { + UINT slsize = (nFlags == RS_STIPCM32S) ? 4 : 3; + LPBYTE pSrc = (LPBYTE)lpMemFile; + LONG max = 255; + if (nFlags == RS_STIPCM32S) pSrc++; + for (UINT j=0; j<len; j+=slsize) + { + LONG l = ((((pSrc[j+2] << 8) + pSrc[j+1]) << 8) + pSrc[j]) << 8; + l /= 256; + if (l > max) max = l; + if (-l > max) max = -l; + } + max = (max / 128) + 1; + signed short *pDest = (signed short *)pIns->pSample; + for (UINT k=0; k<len; k+=slsize) + { + LONG lr = ((((pSrc[k+2] << 8) + pSrc[k+1]) << 8) + pSrc[k]) << 8; + k += slsize; + LONG ll = ((((pSrc[k+2] << 8) + pSrc[k+1]) << 8) + pSrc[k]) << 8; + pDest[0] = (signed short)ll; + pDest[1] = (signed short)lr; + pDest += 2; + } + } + break; + + // 16-bit signed big endian interleaved stereo + case RS_STIPCM16M: + { + len = pIns->nLength; + if (len*4 > dwMemLength) len = dwMemLength >> 2; + LPCBYTE psrc = (LPCBYTE)lpMemFile; + short int *pSample = (short int *)pIns->pSample; + for (UINT j=0; j<len; j++) + { + pSample[j*2] = (signed short)(((UINT)psrc[0] << 8) | (psrc[1])); + pSample[j*2+1] = (signed short)(((UINT)psrc[2] << 8) | (psrc[3])); + psrc += 4; + } + len *= 4; + } + break; + +#endif // MODPLUG_TRACKER +#endif // !FASTSOUNDLIB +#endif // !MODPLUG_BASIC_SUPPORT + + // Default: 8-bit signed PCM data + default: + len = pIns->nLength; + if (len > dwMemLength) len = pIns->nLength = dwMemLength; + memcpy(pIns->pSample, lpMemFile, len); + } + if (len > dwMemLength) + { + if (pIns->pSample) + { + pIns->nLength = 0; + FreeSample(pIns->pSample); + pIns->pSample = NULL; + } + return 0; + } + AdjustSampleLoop(pIns); + return len; +} + + +void CSoundFile::AdjustSampleLoop(MODINSTRUMENT *pIns) +//---------------------------------------------------- +{ + if (!pIns->pSample) return; + if (pIns->nLoopEnd > pIns->nLength) pIns->nLoopEnd = pIns->nLength; + if (pIns->nLoopStart+2 >= pIns->nLoopEnd) + { + pIns->nLoopStart = pIns->nLoopEnd = 0; + pIns->uFlags &= ~CHN_LOOP; + } + UINT len = pIns->nLength; + if (pIns->uFlags & CHN_16BIT) + { + short int *pSample = (short int *)pIns->pSample; + // Adjust end of sample + if (pIns->uFlags & CHN_STEREO) + { + 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] = pSample[len-1]; + } + if ((pIns->uFlags & (CHN_LOOP|CHN_PINGPONGLOOP|CHN_STEREO)) == CHN_LOOP) + { + // Fix bad loops + if ((pIns->nLoopEnd+3 >= pIns->nLength) || (m_nType & MOD_TYPE_S3M)) + { + pSample[pIns->nLoopEnd] = pSample[pIns->nLoopStart]; + pSample[pIns->nLoopEnd+1] = pSample[pIns->nLoopStart+1]; + pSample[pIns->nLoopEnd+2] = pSample[pIns->nLoopStart+2]; + pSample[pIns->nLoopEnd+3] = pSample[pIns->nLoopStart+3]; + pSample[pIns->nLoopEnd+4] = pSample[pIns->nLoopStart+4]; + } + } + } else + { + signed char *pSample = pIns->pSample; +#ifndef FASTSOUNDLIB + // Crappy samples (except chiptunes) ? + if ((pIns->nLength > 0x100) && (m_nType & (MOD_TYPE_MOD|MOD_TYPE_S3M)) + && (!(pIns->uFlags & CHN_STEREO))) + { + int smpend = pSample[pIns->nLength-1], smpfix = 0, kscan; + for (kscan=pIns->nLength-1; kscan>0; kscan--) + { + smpfix = pSample[kscan-1]; + if (smpfix != smpend) break; + } + int delta = smpfix - smpend; + if (((!(pIns->uFlags & CHN_LOOP)) || (kscan > (int)pIns->nLoopEnd)) + && ((delta < -8) || (delta > 8))) + { + while (kscan<(int)pIns->nLength) + { + if (!(kscan & 7)) + { + if (smpfix > 0) smpfix--; + if (smpfix < 0) smpfix++; + } + pSample[kscan] = (signed char)smpfix; + kscan++; + } + } + } +#endif + // Adjust end of sample + if (pIns->uFlags & CHN_STEREO) + { + 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] = pSample[len-1]; + } + if ((pIns->uFlags & (CHN_LOOP|CHN_PINGPONGLOOP|CHN_STEREO)) == CHN_LOOP) + { + if ((pIns->nLoopEnd+3 >= pIns->nLength) || (m_nType & (MOD_TYPE_MOD|MOD_TYPE_S3M))) + { + pSample[pIns->nLoopEnd] = pSample[pIns->nLoopStart]; + pSample[pIns->nLoopEnd+1] = pSample[pIns->nLoopStart+1]; + pSample[pIns->nLoopEnd+2] = pSample[pIns->nLoopStart+2]; + pSample[pIns->nLoopEnd+3] = pSample[pIns->nLoopStart+3]; + pSample[pIns->nLoopEnd+4] = pSample[pIns->nLoopStart+4]; + } + } + } +} + + +///////////////////////////////////////////////////////////// +// Transpose <-> Frequency conversions + +// returns 8363*2^((transp*128+ftune)/(12*128)) +DWORD CSoundFile::TransposeToFrequency(int transp, int ftune) +//----------------------------------------------------------- +{ + //---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); + int result; + DWORD freq; + + transp = (transp << 7) + ftune; + _asm { + fild transp + fld _factor + fmulp st(1), st(0) + fist result + fisub result + f2xm1 + fild result + fld _fbase + fscale + fstp st(1) + fmul st(1), st(0) + faddp st(1), st(0) + fistp freq + } + UINT derr = freq % 11025; + if (derr <= 8) freq -= derr; + if (derr >= 11015) freq += 11025-derr; + derr = freq % 1000; + if (derr <= 5) freq -= derr; + if (derr >= 995) freq += 1000-derr; + return freq; +#endif +} + + +// returns 12*128*log2(freq/8363) +int CSoundFile::FrequencyToTranspose(DWORD freq) +//---------------------------------------------- +{ + //---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; + LONG result; + + if (!freq) return 0; + _asm { + fld _factor + fild freq + fld _f1_8363 + fmulp st(1), st(0) + fyl2x + fistp result + } + return result; +#endif +} + + +void CSoundFile::FrequencyToTranspose(MODINSTRUMENT *psmp) +//-------------------------------------------------------- +{ + int f2t = FrequencyToTranspose(psmp->nC4Speed); + int transp = f2t >> 7; + int ftune = f2t & 0x7F; + if (ftune > 80) + { + transp++; + ftune -= 128; + } + if (transp > 127) transp = 127; + if (transp < -127) transp = -127; + psmp->RelativeTone = transp; + psmp->nFineTune = ftune; +} + + +void CSoundFile::CheckCPUUsage(UINT nCPU) +//--------------------------------------- +{ + if (nCPU > 100) nCPU = 100; + gnCPUUsage = nCPU; + if (nCPU < 90) + { + m_dwSongFlags &= ~SONG_CPUVERYHIGH; + } else + if ((m_dwSongFlags & SONG_CPUVERYHIGH) && (nCPU >= 94)) + { + UINT i=MAX_CHANNELS; + while (i >= 8) + { + i--; + if (Chn[i].nLength) + { + Chn[i].nLength = Chn[i].nPos = 0; + nCPU -= 2; + if (nCPU < 94) break; + } + } + } else + if (nCPU > 90) + { + m_dwSongFlags |= SONG_CPUVERYHIGH; + } +} + + +BOOL CSoundFile::SetPatternName(UINT nPat, LPCSTR lpszName) +//--------------------------------------------------------- +{ + char szName[MAX_PATTERNNAME] = ""; // changed from CHAR + if (nPat >= MAX_PATTERNS) return FALSE; + if (lpszName) lstrcpyn(szName, lpszName, MAX_PATTERNNAME); + szName[MAX_PATTERNNAME-1] = 0; + if (!m_lpszPatternNames) m_nPatternNames = 0; + if (nPat >= m_nPatternNames) + { + if (!lpszName[0]) return TRUE; + UINT len = (nPat+1)*MAX_PATTERNNAME; + char *p = new char[len]; // changed from CHAR + if (!p) return FALSE; + memset(p, 0, len); + if (m_lpszPatternNames) + { + memcpy(p, m_lpszPatternNames, m_nPatternNames * MAX_PATTERNNAME); + delete m_lpszPatternNames; + m_lpszPatternNames = NULL; + } + m_lpszPatternNames = p; + m_nPatternNames = nPat + 1; + } + memcpy(m_lpszPatternNames + nPat * MAX_PATTERNNAME, szName, MAX_PATTERNNAME); + return TRUE; +} + + +BOOL CSoundFile::GetPatternName(UINT nPat, LPSTR lpszName, UINT cbSize) const +//--------------------------------------------------------------------------- +{ + if ((!lpszName) || (!cbSize)) return FALSE; + lpszName[0] = 0; + if (cbSize > MAX_PATTERNNAME) cbSize = MAX_PATTERNNAME; + if ((m_lpszPatternNames) && (nPat < m_nPatternNames)) + { + memcpy(lpszName, m_lpszPatternNames + nPat * MAX_PATTERNNAME, cbSize); + lpszName[cbSize-1] = 0; + return TRUE; + } + return FALSE; +} + + +#ifndef FASTSOUNDLIB + +UINT CSoundFile::DetectUnusedSamples(BOOL *pbIns) +//----------------------------------------------- +{ + UINT nExt = 0; + + if (!pbIns) return 0; + if (m_nInstruments) + { + memset(pbIns, 0, MAX_SAMPLES * sizeof(BOOL)); + for (UINT ipat=0; ipat<MAX_PATTERNS; ipat++) + { + MODCOMMAND *p = Patterns[ipat]; + if (p) + { + UINT jmax = PatternSize[ipat] * m_nChannels; + for (UINT j=0; j<jmax; j++, p++) + { + if ((p->note) && (p->note <= 120)) + { + if ((p->instr) && (p->instr < MAX_INSTRUMENTS)) + { + INSTRUMENTHEADER *penv = Headers[p->instr]; + if (penv) + { + UINT n = penv->Keyboard[p->note-1]; + if (n < MAX_SAMPLES) pbIns[n] = TRUE; + } + } else + { + for (UINT k=1; k<=m_nInstruments; k++) + { + INSTRUMENTHEADER *penv = Headers[k]; + if (penv) + { + UINT n = penv->Keyboard[p->note-1]; + if (n < MAX_SAMPLES) pbIns[n] = TRUE; + } + } + } + } + } + } + } + for (UINT ichk=1; ichk<=m_nSamples; ichk++) + { + if ((!pbIns[ichk]) && (Ins[ichk].pSample)) nExt++; + } + } + return nExt; +} + + +BOOL CSoundFile::RemoveSelectedSamples(BOOL *pbIns) +//------------------------------------------------- +{ + if (!pbIns) return FALSE; + for (UINT j=1; j<MAX_SAMPLES; j++) + { + if ((!pbIns[j]) && (Ins[j].pSample)) + { + DestroySample(j); + if ((j == m_nSamples) && (j > 1)) m_nSamples--; + } + } + return TRUE; +} + + +BOOL CSoundFile::DestroySample(UINT nSample) +//------------------------------------------ +{ + if ((!nSample) || (nSample >= MAX_SAMPLES)) return FALSE; + if (!Ins[nSample].pSample) return TRUE; + MODINSTRUMENT *pins = &Ins[nSample]; + signed char *pSample = pins->pSample; + pins->pSample = NULL; + pins->nLength = 0; + pins->uFlags &= ~(CHN_16BIT); + for (UINT i=0; i<MAX_CHANNELS; i++) + { + if (Chn[i].pSample == pSample) + { + Chn[i].nPos = Chn[i].nLength = 0; + Chn[i].pSample = Chn[i].pCurrentSample = NULL; + } + } + FreeSample(pSample); + return TRUE; +} + +#endif // FASTSOUNDLIB + |