Mercurial > audlegacy-plugins
view src/modplug/sndfile.cxx @ 2023:27239c2e3b47
iabervon: We appreciate the plugin you wrote for the VFS system, but,
it's now deprecated. We look forward to consider other plugins of yours
in the future. (curl plugin dropped from distribution, in favour of neon).
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Thu, 11 Oct 2007 15:40:36 -0500 |
parents | 9549fea94794 |
children | 032053ca08ab c349bd73af71 |
line wrap: on
line source
/* * 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)) && (!ReadS3M(lpStream, dwMemLength)) && (!ReadIT(lpStream, dwMemLength)) && (!ReadWav(lpStream, dwMemLength)) #ifndef MODPLUG_BASIC_SUPPORT && (!ReadSTM(lpStream, dwMemLength)) && (!ReadMed(lpStream, dwMemLength)) && (!ReadMTM(lpStream, dwMemLength)) && (!ReadMDL(lpStream, dwMemLength)) && (!ReadDBM(lpStream, dwMemLength)) && (!Read669(lpStream, dwMemLength)) && (!ReadFAR(lpStream, dwMemLength)) && (!ReadAMS(lpStream, dwMemLength)) && (!ReadOKT(lpStream, dwMemLength)) && (!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 temp = bswapLE16((short)(s_new - s_old)); *((short *)(&buffer[bufcount])) = temp; s_old = s_new; } else { short temp = bswapLE16((short)(s_new + s_ofs)); *((short *)(&buffer[bufcount])) = temp; } 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 temp = bswapLE16((short)(s_new - s_old)); *((short *)(&buffer[bufcount])) = temp; s_old = s_new; } else { short temp = bswapLE16((short)(s_new - s_ofs)); *((short *)(&buffer[bufcount])) = temp; } 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; if ((!pIns) || (pIns->nLength < 4) || (!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) { 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); ++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 MODPLUG_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); ++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 // !MODPLUG_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] = 0; pSample[len*2+7] = pSample[len*2+5] = pSample[len*2+3] = pSample[len*2+1] = 0; } else { pSample[len+4] = pSample[len+3] = pSample[len+2] = pSample[len+1] = pSample[len] = 0; } 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 MODPLUG_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] = 0; pSample[len*2+7] = pSample[len*2+5] = pSample[len*2+3] = pSample[len*2+1] = 0; } else { pSample[len+4] = pSample[len+3] = pSample[len+2] = pSample[len+1] = pSample[len] = 0; } 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 MODPLUG_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 // MODPLUG_FASTSOUNDLIB