/* * 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 , * Adam Goode (endian and char fixes for PPC) */ #include //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 const 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=0) && (p[j]<=' ')) p[j--] = 0; while (j>=0) { if (((BYTE)p[j]) < ' ') p[j] = ' '; j--; } } // Adjust channels for (i=0; i 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; 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 { 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; iPlugRestoreAllParameters(); } } } } 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; ipSample) { FreeSample(pins->pSample); pins->pSample = NULL; } } for (i=0; iRelease(); 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 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_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= MAX_ORDERS) || (Order[nPos] >= MAX_PATTERNS)) return; for (UINT j=0; j= 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= 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= 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; juFlags & 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= 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= 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; juFlags & 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; jnLength; if (len > dwMemLength) break; signed char *pSample = pIns->pSample; const signed char *p = (const signed char *)lpMemFile; int delta = 0; for (UINT j=0; jnLength + 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> 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; jnLength * 2; if (len <= dwMemLength) memcpy(pIns->pSample, lpMemFile, len); short int *pSample = (short int *)pIns->pSample; for (UINT j=0; jnLength * 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; jnLength * 2; if (len > dwMemLength) break; short int *pSample = (short int *)pIns->pSample; short int *pSrc = (short int *)lpMemFile; for (UINT j=0; jnLength * 2; if (len*2 <= dwMemLength) { signed char *pSample = (signed char *)pIns->pSample; signed char *pSrc = (signed char *)lpMemFile; for (UINT j=0; jnLength; signed char *psrc = (signed char *)lpMemFile; signed char *pSample = (signed char *)pIns->pSample; if (len*2 > dwMemLength) break; for (UINT j=0; jnLength; short int *psrc = (short int *)lpMemFile; short int *pSample = (short int *)pIns->pSample; if (len*4 > dwMemLength) break; 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 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; jnLength; 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 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; jpSample; for (UINT j=0; j= 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; jnLength; 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 max) max = l; if (-l > max) max = -l; } max = (max / 128) + 1; signed short *pDest = (signed short *)pIns->pSample; for (UINT k=0; k 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 max) max = l; if (-l > max) max = -l; } max = (max / 128) + 1; signed short *pDest = (signed short *)pIns->pSample; for (UINT k=0; knLength; if (len*4 > dwMemLength) len = dwMemLength >> 2; LPCBYTE psrc = (LPCBYTE)lpMemFile; short int *pSample = (short int *)pIns->pSample; for (UINT j=0; jnLength; 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 WIN32 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 WIN32 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); else return FALSE; 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; ipatnote) && (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 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