From 2342d48be31847e7ead9d1cc682452e8f0122351 Mon Sep 17 00:00:00 2001 From: llornkcor Date: Sat, 20 Jul 2002 22:07:31 +0000 Subject: initial commit of modplugin --- (limited to 'core/multimedia/opieplayer/modplug/load_it.cpp') diff --git a/core/multimedia/opieplayer/modplug/load_it.cpp b/core/multimedia/opieplayer/modplug/load_it.cpp new file mode 100644 index 0000000..006b746 --- a/dev/null +++ b/core/multimedia/opieplayer/modplug/load_it.cpp @@ -0,0 +1,1415 @@ +/* + * 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 "stdafx.h" +#include "sndfile.h" +#include "it_defs.h" + +#ifdef WIN32 +#pragma warning(disable:4244) +#endif + +const BYTE autovibit2xm[8] = +{ 0, 3, 1, 4, 2, 0, 0, 0 }; + +const BYTE autovibxm2it[8] = +{ 0, 2, 4, 1, 3, 0, 0, 0 }; + +////////////////////////////////////////////////////////// +// Impulse Tracker IT file support (import only) + + +static inline UINT ConvertVolParam(UINT value) +//-------------------------------------------- +{ + return (value > 9) ? 9 : value; +} + + +BOOL CSoundFile::ITInstrToMPT(const void *p, INSTRUMENTHEADER *penv, UINT trkvers) +//-------------------------------------------------------------------------------- +{ + if (trkvers < 0x0200) + { + const ITOLDINSTRUMENT *pis = (const ITOLDINSTRUMENT *)p; + memcpy(penv->name, pis->name, 26); + memcpy(penv->filename, pis->filename, 12); + penv->nFadeOut = bswapLE16(pis->fadeout) << 6; + penv->nGlobalVol = 64; + for (UINT j=0; j<120; j++) + { + UINT note = pis->keyboard[j*2]; + UINT ins = pis->keyboard[j*2+1]; + if (ins < MAX_SAMPLES) penv->Keyboard[j] = ins; + if (note < 128) penv->NoteMap[j] = note+1; + else if (note >= 0xFE) penv->NoteMap[j] = note; + } + if (pis->flags & 0x01) penv->dwFlags |= ENV_VOLUME; + if (pis->flags & 0x02) penv->dwFlags |= ENV_VOLLOOP; + if (pis->flags & 0x04) penv->dwFlags |= ENV_VOLSUSTAIN; + penv->nVolLoopStart = pis->vls; + penv->nVolLoopEnd = pis->vle; + penv->nVolSustainBegin = pis->sls; + penv->nVolSustainEnd = pis->sle; + penv->nVolEnv = 25; + for (UINT ev=0; ev<25; ev++) + { + if ((penv->VolPoints[ev] = pis->nodes[ev*2]) == 0xFF) + { + penv->nVolEnv = ev; + break; + } + penv->VolEnv[ev] = pis->nodes[ev*2+1]; + } + penv->nNNA = pis->nna; + penv->nDCT = pis->dnc; + penv->nPan = 0x80; + } else + { + const ITINSTRUMENT *pis = (const ITINSTRUMENT *)p; + memcpy(penv->name, pis->name, 26); + memcpy(penv->filename, pis->filename, 12); + penv->nMidiProgram = pis->mpr; + penv->nMidiChannel = pis->mch; + penv->wMidiBank = bswapLE16(pis->mbank); + penv->nFadeOut = bswapLE16(pis->fadeout) << 5; + penv->nGlobalVol = pis->gbv >> 1; + if (penv->nGlobalVol > 64) penv->nGlobalVol = 64; + for (UINT j=0; j<120; j++) + { + UINT note = pis->keyboard[j*2]; + UINT ins = pis->keyboard[j*2+1]; + if (ins < MAX_SAMPLES) penv->Keyboard[j] = ins; + if (note < 128) penv->NoteMap[j] = note+1; + else if (note >= 0xFE) penv->NoteMap[j] = note; + } + // Volume Envelope + if (pis->volenv.flags & 1) penv->dwFlags |= ENV_VOLUME; + if (pis->volenv.flags & 2) penv->dwFlags |= ENV_VOLLOOP; + if (pis->volenv.flags & 4) penv->dwFlags |= ENV_VOLSUSTAIN; + if (pis->volenv.flags & 8) penv->dwFlags |= ENV_VOLCARRY; + penv->nVolEnv = pis->volenv.num; + if (penv->nVolEnv > 25) penv->nVolEnv = 25; + + penv->nVolLoopStart = pis->volenv.lpb; + penv->nVolLoopEnd = pis->volenv.lpe; + penv->nVolSustainBegin = pis->volenv.slb; + penv->nVolSustainEnd = pis->volenv.sle; + // Panning Envelope + if (pis->panenv.flags & 1) penv->dwFlags |= ENV_PANNING; + if (pis->panenv.flags & 2) penv->dwFlags |= ENV_PANLOOP; + if (pis->panenv.flags & 4) penv->dwFlags |= ENV_PANSUSTAIN; + if (pis->panenv.flags & 8) penv->dwFlags |= ENV_PANCARRY; + penv->nPanEnv = pis->panenv.num; + if (penv->nPanEnv > 25) penv->nPanEnv = 25; + penv->nPanLoopStart = pis->panenv.lpb; + penv->nPanLoopEnd = pis->panenv.lpe; + penv->nPanSustainBegin = pis->panenv.slb; + penv->nPanSustainEnd = pis->panenv.sle; + // Pitch Envelope + if (pis->pitchenv.flags & 1) penv->dwFlags |= ENV_PITCH; + if (pis->pitchenv.flags & 2) penv->dwFlags |= ENV_PITCHLOOP; + if (pis->pitchenv.flags & 4) penv->dwFlags |= ENV_PITCHSUSTAIN; + if (pis->pitchenv.flags & 8) penv->dwFlags |= ENV_PITCHCARRY; + if (pis->pitchenv.flags & 0x80) penv->dwFlags |= ENV_FILTER; + penv->nPitchEnv = pis->pitchenv.num; + if (penv->nPitchEnv > 25) penv->nPitchEnv = 25; + penv->nPitchLoopStart = pis->pitchenv.lpb; + penv->nPitchLoopEnd = pis->pitchenv.lpe; + penv->nPitchSustainBegin = pis->pitchenv.slb; + penv->nPitchSustainEnd = pis->pitchenv.sle; + // Envelopes Data + for (UINT ev=0; ev<25; ev++) + { + penv->VolEnv[ev] = pis->volenv.data[ev*3]; + penv->VolPoints[ev] = (pis->volenv.data[ev*3+2] << 8) | (pis->volenv.data[ev*3+1]); + penv->PanEnv[ev] = pis->panenv.data[ev*3] + 32; + penv->PanPoints[ev] = (pis->panenv.data[ev*3+2] << 8) | (pis->panenv.data[ev*3+1]); + penv->PitchEnv[ev] = pis->pitchenv.data[ev*3] + 32; + penv->PitchPoints[ev] = (pis->pitchenv.data[ev*3+2] << 8) | (pis->pitchenv.data[ev*3+1]); + } + penv->nNNA = pis->nna; + penv->nDCT = pis->dct; + penv->nDNA = pis->dca; + penv->nPPS = pis->pps; + penv->nPPC = pis->ppc; + penv->nIFC = pis->ifc; + penv->nIFR = pis->ifr; + penv->nVolSwing = pis->rv; + penv->nPanSwing = pis->rp; + penv->nPan = (pis->dfp & 0x7F) << 2; + if (penv->nPan > 256) penv->nPan = 128; + if (pis->dfp < 0x80) penv->dwFlags |= ENV_SETPANNING; + } + if ((penv->nVolLoopStart >= 25) || (penv->nVolLoopEnd >= 25)) penv->dwFlags &= ~ENV_VOLLOOP; + if ((penv->nVolSustainBegin >= 25) || (penv->nVolSustainEnd >= 25)) penv->dwFlags &= ~ENV_VOLSUSTAIN; + return TRUE; +} + + +BOOL CSoundFile::ReadIT(const BYTE *lpStream, DWORD dwMemLength) +//-------------------------------------------------------------- +{ + ITFILEHEADER pifh = *(ITFILEHEADER *)lpStream; + DWORD dwMemPos = sizeof(ITFILEHEADER); + DWORD inspos[MAX_INSTRUMENTS]; + DWORD smppos[MAX_SAMPLES]; + DWORD patpos[MAX_PATTERNS]; + BYTE chnmask[64], channels_used[64]; + MODCOMMAND lastvalue[64]; + + pifh.id = bswapLE32(pifh.id); + pifh.reserved1 = bswapLE16(pifh.reserved1); + pifh.ordnum = bswapLE16(pifh.ordnum); + pifh.insnum = bswapLE16(pifh.insnum); + pifh.smpnum = bswapLE16(pifh.smpnum); + pifh.patnum = bswapLE16(pifh.patnum); + pifh.cwtv = bswapLE16(pifh.cwtv); + pifh.cmwt = bswapLE16(pifh.cmwt); + pifh.flags = bswapLE16(pifh.flags); + pifh.special = bswapLE16(pifh.special); + pifh.msglength = bswapLE16(pifh.msglength); + pifh.msgoffset = bswapLE32(pifh.msgoffset); + pifh.reserved2 = bswapLE32(pifh.reserved2); + + if ((!lpStream) || (dwMemLength < 0x100)) return FALSE; + if ((pifh.id != 0x4D504D49) || (pifh.insnum >= MAX_INSTRUMENTS) + || (!pifh.smpnum) || (pifh.smpnum >= MAX_INSTRUMENTS) || (!pifh.ordnum)) return FALSE; + if (dwMemPos + pifh.ordnum + pifh.insnum*4 + + pifh.smpnum*4 + pifh.patnum*4 > dwMemLength) return FALSE; + m_nType = MOD_TYPE_IT; + if (pifh.flags & 0x08) m_dwSongFlags |= SONG_LINEARSLIDES; + if (pifh.flags & 0x10) m_dwSongFlags |= SONG_ITOLDEFFECTS; + if (pifh.flags & 0x20) m_dwSongFlags |= SONG_ITCOMPATMODE; + if (pifh.flags & 0x80) m_dwSongFlags |= SONG_EMBEDMIDICFG; + if (pifh.flags & 0x1000) m_dwSongFlags |= SONG_EXFILTERRANGE; + memcpy(m_szNames[0], pifh.songname, 26); + m_szNames[0][26] = 0; + // Global Volume + if (pifh.globalvol) + { + m_nDefaultGlobalVolume = pifh.globalvol << 1; + if (!m_nDefaultGlobalVolume) m_nDefaultGlobalVolume = 256; + if (m_nDefaultGlobalVolume > 256) m_nDefaultGlobalVolume = 256; + } + if (pifh.speed) m_nDefaultSpeed = pifh.speed; + if (pifh.tempo) m_nDefaultTempo = pifh.tempo; + m_nSongPreAmp = pifh.mv & 0x7F; + // Reading Channels Pan Positions + for (int ipan=0; ipan<64; ipan++) if (pifh.chnpan[ipan] != 0xFF) + { + ChnSettings[ipan].nVolume = pifh.chnvol[ipan]; + ChnSettings[ipan].nPan = 128; + if (pifh.chnpan[ipan] & 0x80) ChnSettings[ipan].dwFlags |= CHN_MUTE; + UINT n = pifh.chnpan[ipan] & 0x7F; + if (n <= 64) ChnSettings[ipan].nPan = n << 2; + if (n == 100) ChnSettings[ipan].dwFlags |= CHN_SURROUND; + } + if (m_nChannels < 4) m_nChannels = 4; + // Reading Song Message + if ((pifh.special & 0x01) && (pifh.msglength) && (pifh.msgoffset + pifh.msglength < dwMemLength)) + { + m_lpszSongComments = new char[pifh.msglength+1]; + if (m_lpszSongComments) + { + memcpy(m_lpszSongComments, lpStream+pifh.msgoffset, pifh.msglength); + m_lpszSongComments[pifh.msglength] = 0; + } + } + // Reading orders + UINT nordsize = pifh.ordnum; + if (nordsize > MAX_ORDERS) nordsize = MAX_ORDERS; + memcpy(Order, lpStream+dwMemPos, nordsize); + dwMemPos += pifh.ordnum; + // Reading Instrument Offsets + memset(inspos, 0, sizeof(inspos)); + UINT inspossize = pifh.insnum; + if (inspossize > MAX_INSTRUMENTS) inspossize = MAX_INSTRUMENTS; + inspossize <<= 2; + memcpy(inspos, lpStream+dwMemPos, inspossize); + for (UINT j=0; j < (inspossize>>2); j++) + { + inspos[j] = bswapLE32(inspos[j]); + } + dwMemPos += pifh.insnum * 4; + // Reading Samples Offsets + memset(smppos, 0, sizeof(smppos)); + UINT smppossize = pifh.smpnum; + if (smppossize > MAX_SAMPLES) smppossize = MAX_SAMPLES; + smppossize <<= 2; + memcpy(smppos, lpStream+dwMemPos, smppossize); + for (UINT j=0; j < (smppossize>>2); j++) + { + smppos[j] = bswapLE32(smppos[j]); + } + dwMemPos += pifh.smpnum * 4; + // Reading Patterns Offsets + memset(patpos, 0, sizeof(patpos)); + UINT patpossize = pifh.patnum; + if (patpossize > MAX_PATTERNS) patpossize = MAX_PATTERNS; + patpossize <<= 2; + memcpy(patpos, lpStream+dwMemPos, patpossize); + for (UINT j=0; j < (patpossize>>2); j++) + { + patpos[j] = bswapLE32(patpos[j]); + } + dwMemPos += pifh.patnum * 4; + // Reading IT Extra Info + if (dwMemPos + 2 < dwMemLength) + { + UINT nflt = bswapLE16(*((WORD *)(lpStream + dwMemPos))); + dwMemPos += 2; + if (dwMemPos + nflt * 8 < dwMemLength) dwMemPos += nflt * 8; + } + // Reading Midi Output & Macros + if (m_dwSongFlags & SONG_EMBEDMIDICFG) + { + if (dwMemPos + sizeof(MODMIDICFG) < dwMemLength) + { + memcpy(&m_MidiCfg, lpStream+dwMemPos, sizeof(MODMIDICFG)); + dwMemPos += sizeof(MODMIDICFG); + } + } + // Read pattern names: "PNAM" + if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e50)) + { + UINT len = bswapLE32(*((DWORD *)(lpStream+dwMemPos+4))); + dwMemPos += 8; + if ((dwMemPos + len <= dwMemLength) && (len <= MAX_PATTERNS*MAX_PATTERNNAME) && (len >= MAX_PATTERNNAME)) + { + m_lpszPatternNames = new char[len]; + if (m_lpszPatternNames) + { + m_nPatternNames = len / MAX_PATTERNNAME; + memcpy(m_lpszPatternNames, lpStream+dwMemPos, len); + } + dwMemPos += len; + } + } + // 4-channels minimum + m_nChannels = 4; + // Read channel names: "CNAM" + if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e43)) + { + UINT len = bswapLE32(*((DWORD *)(lpStream+dwMemPos+4))); + dwMemPos += 8; + if ((dwMemPos + len <= dwMemLength) && (len <= 64*MAX_CHANNELNAME)) + { + UINT n = len / MAX_CHANNELNAME; + if (n > m_nChannels) m_nChannels = n; + for (UINT i=0; i MAX_PATTERNS) npatterns = MAX_PATTERNS; + for (UINT patchk=0; patchk= dwMemLength)) continue; + UINT len = bswapLE16(*((WORD *)(lpStream+patpos[patchk]))); + UINT rows = bswapLE16(*((WORD *)(lpStream+patpos[patchk]+2))); + if ((rows < 4) || (rows > 256)) continue; + if (patpos[patchk]+8+len > dwMemLength) continue; + UINT i = 0; + const BYTE *p = lpStream+patpos[patchk]+8; + UINT nrow = 0; + while (nrow= len) break; + BYTE b = p[i++]; + if (!b) + { + nrow++; + continue; + } + UINT ch = b & 0x7F; + if (ch) ch = (ch - 1) & 0x3F; + if (b & 0x80) + { + if (i >= len) break; + chnmask[ch] = p[i++]; + } + // Channel used + if (chnmask[ch] & 0x0F) + { + if ((ch >= m_nChannels) && (ch < 64)) m_nChannels = ch+1; + } + // Note + if (chnmask[ch] & 1) i++; + // Instrument + if (chnmask[ch] & 2) i++; + // Volume + if (chnmask[ch] & 4) i++; + // Effect + if (chnmask[ch] & 8) i += 2; + if (i >= len) break; + } + } + // Reading Instruments + m_nInstruments = 0; + if (pifh.flags & 0x04) m_nInstruments = pifh.insnum; + if (m_nInstruments >= MAX_INSTRUMENTS) m_nInstruments = MAX_INSTRUMENTS-1; + for (UINT nins=0; nins 0) && (inspos[nins] < dwMemLength - sizeof(ITOLDINSTRUMENT))) + { + INSTRUMENTHEADER *penv = new INSTRUMENTHEADER; + if (!penv) continue; + Headers[nins+1] = penv; + memset(penv, 0, sizeof(INSTRUMENTHEADER)); + ITInstrToMPT(lpStream + inspos[nins], penv, pifh.cmwt); + } + } + // Reading Samples + m_nSamples = pifh.smpnum; + if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1; + for (UINT nsmp=0; nsmpname, pis.filename, 12); + pins->uFlags = 0; + pins->nLength = 0; + pins->nLoopStart = pis.loopbegin; + pins->nLoopEnd = pis.loopend; + pins->nSustainStart = pis.susloopbegin; + pins->nSustainEnd = pis.susloopend; + pins->nC4Speed = pis.C5Speed; + if (!pins->nC4Speed) pins->nC4Speed = 8363; + if (pis.C5Speed < 256) pins->nC4Speed = 256; + pins->nVolume = pis.vol << 2; + if (pins->nVolume > 256) pins->nVolume = 256; + pins->nGlobalVol = pis.gvl; + if (pins->nGlobalVol > 64) pins->nGlobalVol = 64; + if (pis.flags & 0x10) pins->uFlags |= CHN_LOOP; + if (pis.flags & 0x20) pins->uFlags |= CHN_SUSTAINLOOP; + if (pis.flags & 0x40) pins->uFlags |= CHN_PINGPONGLOOP; + if (pis.flags & 0x80) pins->uFlags |= CHN_PINGPONGSUSTAIN; + pins->nPan = (pis.dfp & 0x7F) << 2; + if (pins->nPan > 256) pins->nPan = 256; + if (pis.dfp & 0x80) pins->uFlags |= CHN_PANNING; + pins->nVibType = autovibit2xm[pis.vit & 7]; + pins->nVibRate = pis.vis; + pins->nVibDepth = pis.vid & 0x7F; + pins->nVibSweep = (pis.vir + 3) / 4; + if ((pis.samplepointer) && (pis.samplepointer < dwMemLength) && (pis.length)) + { + pins->nLength = pis.length; + if (pins->nLength > MAX_SAMPLE_LENGTH) pins->nLength = MAX_SAMPLE_LENGTH; + UINT flags = (pis.cvt & 1) ? RS_PCM8S : RS_PCM8U; + if (pis.flags & 2) + { + flags += 5; + if (pis.flags & 4) flags |= RSF_STEREO; + pins->uFlags |= CHN_16BIT; + // IT 2.14 16-bit packed sample ? + if (pis.flags & 8) flags = ((pifh.cmwt >= 0x215) && (pis.cvt & 4)) ? RS_IT21516 : RS_IT21416; + } else + { + if (pis.flags & 4) flags |= RSF_STEREO; + if (pis.cvt == 0xFF) flags = RS_ADPCM4; else + // IT 2.14 8-bit packed sample ? + if (pis.flags & 8) flags = ((pifh.cmwt >= 0x215) && (pis.cvt & 4)) ? RS_IT2158 : RS_IT2148; + } + ReadSample(&Ins[nsmp+1], flags, (LPSTR)(lpStream+pis.samplepointer), dwMemLength - pis.samplepointer); + } + } + memcpy(m_szNames[nsmp+1], pis.name, 26); + } + // Reading Patterns + for (UINT npat=0; npat= dwMemLength)) + { + PatternSize[npat] = 64; + Patterns[npat] = AllocatePattern(64, m_nChannels); + continue; + } + + UINT len = bswapLE16(*((WORD *)(lpStream+patpos[npat]))); + UINT rows = bswapLE16(*((WORD *)(lpStream+patpos[npat]+2))); + if ((rows < 4) || (rows > 256)) continue; + if (patpos[npat]+8+len > dwMemLength) continue; + PatternSize[npat] = rows; + if ((Patterns[npat] = AllocatePattern(rows, m_nChannels)) == NULL) continue; + memset(lastvalue, 0, sizeof(lastvalue)); + memset(chnmask, 0, sizeof(chnmask)); + MODCOMMAND *m = Patterns[npat]; + UINT i = 0; + const BYTE *p = lpStream+patpos[npat]+8; + UINT nrow = 0; + while (nrow= len) break; + BYTE b = p[i++]; + if (!b) + { + nrow++; + m+=m_nChannels; + continue; + } + UINT ch = b & 0x7F; + if (ch) ch = (ch - 1) & 0x3F; + if (b & 0x80) + { + if (i >= len) break; + chnmask[ch] = p[i++]; + } + if ((chnmask[ch] & 0x10) && (ch < m_nChannels)) + { + m[ch].note = lastvalue[ch].note; + } + if ((chnmask[ch] & 0x20) && (ch < m_nChannels)) + { + m[ch].instr = lastvalue[ch].instr; + } + if ((chnmask[ch] & 0x40) && (ch < m_nChannels)) + { + m[ch].volcmd = lastvalue[ch].volcmd; + m[ch].vol = lastvalue[ch].vol; + } + if ((chnmask[ch] & 0x80) && (ch < m_nChannels)) + { + m[ch].command = lastvalue[ch].command; + m[ch].param = lastvalue[ch].param; + } + if (chnmask[ch] & 1) // Note + { + if (i >= len) break; + UINT note = p[i++]; + if (ch < m_nChannels) + { + if (note < 0x80) note++; + m[ch].note = note; + lastvalue[ch].note = note; + channels_used[ch] = TRUE; + } + } + if (chnmask[ch] & 2) + { + if (i >= len) break; + UINT instr = p[i++]; + if (ch < m_nChannels) + { + m[ch].instr = instr; + lastvalue[ch].instr = instr; + } + } + if (chnmask[ch] & 4) + { + if (i >= len) break; + UINT vol = p[i++]; + if (ch < m_nChannels) + { + // 0-64: Set Volume + if (vol <= 64) { m[ch].volcmd = VOLCMD_VOLUME; m[ch].vol = vol; } else + // 128-192: Set Panning + if ((vol >= 128) && (vol <= 192)) { m[ch].volcmd = VOLCMD_PANNING; m[ch].vol = vol - 128; } else + // 65-74: Fine Volume Up + if (vol < 75) { m[ch].volcmd = VOLCMD_FINEVOLUP; m[ch].vol = vol - 65; } else + // 75-84: Fine Volume Down + if (vol < 85) { m[ch].volcmd = VOLCMD_FINEVOLDOWN; m[ch].vol = vol - 75; } else + // 85-94: Volume Slide Up + if (vol < 95) { m[ch].volcmd = VOLCMD_VOLSLIDEUP; m[ch].vol = vol - 85; } else + // 95-104: Volume Slide Down + if (vol < 105) { m[ch].volcmd = VOLCMD_VOLSLIDEDOWN; m[ch].vol = vol - 95; } else + // 105-114: Pitch Slide Up + if (vol < 115) { m[ch].volcmd = VOLCMD_PORTADOWN; m[ch].vol = vol - 105; } else + // 115-124: Pitch Slide Down + if (vol < 125) { m[ch].volcmd = VOLCMD_PORTAUP; m[ch].vol = vol - 115; } else + // 193-202: Portamento To + if ((vol >= 193) && (vol <= 202)) { m[ch].volcmd = VOLCMD_TONEPORTAMENTO; m[ch].vol = vol - 193; } else + // 203-212: Vibrato + if ((vol >= 203) && (vol <= 212)) { m[ch].volcmd = VOLCMD_VIBRATOSPEED; m[ch].vol = vol - 203; } + lastvalue[ch].volcmd = m[ch].volcmd; + lastvalue[ch].vol = m[ch].vol; + } + } + // Reading command/param + if (chnmask[ch] & 8) + { + if (i > len - 2) break; + UINT cmd = p[i++]; + UINT param = p[i++]; + if (ch < m_nChannels) + { + if (cmd) + { + m[ch].command = cmd; + m[ch].param = param; + S3MConvert(&m[ch], TRUE); + lastvalue[ch].command = m[ch].command; + lastvalue[ch].param = m[ch].param; + } + } + } + } + } + for (UINT ncu=0; ncu=m_nChannels) + { + ChnSettings[ncu].nVolume = 64; + ChnSettings[ncu].dwFlags &= ~CHN_MUTE; + } + } + m_nMinPeriod = 8; + m_nMaxPeriod = 0xF000; + return TRUE; +} + + +#ifndef MODPLUG_NO_FILESAVE +//#define SAVEITTIMESTAMP +#pragma warning(disable:4100) + +BOOL CSoundFile::SaveIT(LPCSTR lpszFileName, UINT nPacking) +//--------------------------------------------------------- +{ + DWORD dwPatNamLen, dwChnNamLen; + ITFILEHEADER header; + ITINSTRUMENT iti; + ITSAMPLESTRUCT itss; + BYTE smpcount[MAX_SAMPLES]; + DWORD inspos[MAX_INSTRUMENTS]; + DWORD patpos[MAX_PATTERNS]; + DWORD smppos[MAX_SAMPLES]; + DWORD dwPos = 0, dwHdrPos = 0, dwExtra = 2; + WORD patinfo[4]; + BYTE chnmask[64]; + BYTE buf[512]; + MODCOMMAND lastvalue[64]; + FILE *f; + + + if ((!lpszFileName) || ((f = fopen(lpszFileName, "wb")) == NULL)) return FALSE; + memset(inspos, 0, sizeof(inspos)); + memset(patpos, 0, sizeof(patpos)); + memset(smppos, 0, sizeof(smppos)); + // Writing Header + memset(&header, 0, sizeof(header)); + dwPatNamLen = 0; + dwChnNamLen = 0; + header.id = 0x4D504D49; + lstrcpyn(header.songname, m_szNames[0], 27); + header.reserved1 = 0x1004; + header.ordnum = 0; + while ((header.ordnum < MAX_ORDERS) && (Order[header.ordnum] < 0xFF)) header.ordnum++; + if (header.ordnum < MAX_ORDERS) Order[header.ordnum++] = 0xFF; + header.insnum = m_nInstruments; + header.smpnum = m_nSamples; + header.patnum = MAX_PATTERNS; + while ((header.patnum > 0) && (!Patterns[header.patnum-1])) header.patnum--; + header.cwtv = 0x217; + header.cmwt = 0x200; + header.flags = 0x0001; + header.special = 0x0006; + if (m_nInstruments) header.flags |= 0x04; + if (m_dwSongFlags & SONG_LINEARSLIDES) header.flags |= 0x08; + if (m_dwSongFlags & SONG_ITOLDEFFECTS) header.flags |= 0x10; + if (m_dwSongFlags & SONG_ITCOMPATMODE) header.flags |= 0x20; + if (m_dwSongFlags & SONG_EXFILTERRANGE) header.flags |= 0x1000; + header.globalvol = m_nDefaultGlobalVolume >> 1; + header.mv = m_nSongPreAmp; + if (header.mv < 0x20) header.mv = 0x20; + if (header.mv > 0x7F) header.mv = 0x7F; + header.speed = m_nDefaultSpeed; + header.tempo = m_nDefaultTempo; + header.sep = 128; + dwHdrPos = sizeof(header) + header.ordnum; + // Channel Pan and Volume + memset(header.chnpan, 0xFF, 64); + memset(header.chnvol, 64, 64); + for (UINT ich=0; ich> 2; + if (ChnSettings[ich].dwFlags & CHN_SURROUND) header.chnpan[ich] = 100; + header.chnvol[ich] = ChnSettings[ich].nVolume; + if (ChnSettings[ich].dwFlags & CHN_MUTE) header.chnpan[ich] |= 0x80; + if (ChnSettings[ich].szName[0]) + { + dwChnNamLen = (ich+1) * MAX_CHANNELNAME; + } + } + if (dwChnNamLen) dwExtra += dwChnNamLen + 8; +#ifdef SAVEITTIMESTAMP + dwExtra += 8; // Time Stamp +#endif + if (m_dwSongFlags & SONG_EMBEDMIDICFG) + { + header.flags |= 0x80; + header.special |= 0x08; + dwExtra += sizeof(MODMIDICFG); + } + // Pattern Names + if ((m_nPatternNames) && (m_lpszPatternNames)) + { + dwPatNamLen = m_nPatternNames * MAX_PATTERNNAME; + while ((dwPatNamLen >= MAX_PATTERNNAME) && (!m_lpszPatternNames[dwPatNamLen-MAX_PATTERNNAME])) dwPatNamLen -= MAX_PATTERNNAME; + if (dwPatNamLen < MAX_PATTERNNAME) dwPatNamLen = 0; + if (dwPatNamLen) dwExtra += dwPatNamLen + 8; + } + // Mix Plugins + dwExtra += SaveMixPlugins(NULL, TRUE); + // Comments + if (m_lpszSongComments) + { + header.special |= 1; + header.msglength = strlen(m_lpszSongComments)+1; + header.msgoffset = dwHdrPos + dwExtra + header.insnum*4 + header.patnum*4 + header.smpnum*4; + } + // Write file header + fwrite(&header, 1, sizeof(header), f); + fwrite(Order, 1, header.ordnum, f); + if (header.insnum) fwrite(inspos, 4, header.insnum, f); + if (header.smpnum) fwrite(smppos, 4, header.smpnum, f); + if (header.patnum) fwrite(patpos, 4, header.patnum, f); + // Writing editor history information + { +#ifdef SAVEITTIMESTAMP + SYSTEMTIME systime; + FILETIME filetime; + WORD timestamp[4]; + WORD nInfoEx = 1; + memset(timestamp, 0, sizeof(timestamp)); + fwrite(&nInfoEx, 1, 2, f); + GetSystemTime(&systime); + SystemTimeToFileTime(&systime, &filetime); + FileTimeToDosDateTime(&filetime, ×tamp[0], ×tamp[1]); + fwrite(timestamp, 1, 8, f); +#else + WORD nInfoEx = 0; + fwrite(&nInfoEx, 1, 2, f); +#endif + } + // Writing midi cfg + if (header.flags & 0x80) + { + fwrite(&m_MidiCfg, 1, sizeof(MODMIDICFG), f); + } + // Writing pattern names + if (dwPatNamLen) + { + DWORD d = 0x4d414e50; + fwrite(&d, 1, 4, f); + fwrite(&dwPatNamLen, 1, 4, f); + fwrite(m_lpszPatternNames, 1, dwPatNamLen, f); + } + // Writing channel Names + if (dwChnNamLen) + { + DWORD d = 0x4d414e43; + fwrite(&d, 1, 4, f); + fwrite(&dwChnNamLen, 1, 4, f); + UINT nChnNames = dwChnNamLen / MAX_CHANNELNAME; + for (UINT inam=0; inamfilename, 12); + memcpy(iti.name, penv->name, 26); + iti.mbank = penv->wMidiBank; + iti.mpr = penv->nMidiProgram; + iti.mch = penv->nMidiChannel; + iti.nna = penv->nNNA; + iti.dct = penv->nDCT; + iti.dca = penv->nDNA; + iti.fadeout = penv->nFadeOut >> 5; + iti.pps = penv->nPPS; + iti.ppc = penv->nPPC; + iti.gbv = (BYTE)(penv->nGlobalVol << 1); + iti.dfp = (BYTE)penv->nPan >> 2; + if (!(penv->dwFlags & ENV_SETPANNING)) iti.dfp |= 0x80; + iti.rv = penv->nVolSwing; + iti.rp = penv->nPanSwing; + iti.ifc = penv->nIFC; + iti.ifr = penv->nIFR; + iti.nos = 0; + for (UINT i=0; i<120; i++) if (penv->Keyboard[i] < MAX_SAMPLES) + { + UINT smp = penv->Keyboard[i]; + if ((smp) && (!smpcount[smp])) + { + smpcount[smp] = 1; + iti.nos++; + } + iti.keyboard[i*2] = penv->NoteMap[i] - 1; + iti.keyboard[i*2+1] = smp; + } + // Writing Volume envelope + if (penv->dwFlags & ENV_VOLUME) iti.volenv.flags |= 0x01; + if (penv->dwFlags & ENV_VOLLOOP) iti.volenv.flags |= 0x02; + if (penv->dwFlags & ENV_VOLSUSTAIN) iti.volenv.flags |= 0x04; + if (penv->dwFlags & ENV_VOLCARRY) iti.volenv.flags |= 0x08; + iti.volenv.num = (BYTE)penv->nVolEnv; + iti.volenv.lpb = (BYTE)penv->nVolLoopStart; + iti.volenv.lpe = (BYTE)penv->nVolLoopEnd; + iti.volenv.slb = penv->nVolSustainBegin; + iti.volenv.sle = penv->nVolSustainEnd; + // Writing Panning envelope + if (penv->dwFlags & ENV_PANNING) iti.panenv.flags |= 0x01; + if (penv->dwFlags & ENV_PANLOOP) iti.panenv.flags |= 0x02; + if (penv->dwFlags & ENV_PANSUSTAIN) iti.panenv.flags |= 0x04; + if (penv->dwFlags & ENV_PANCARRY) iti.panenv.flags |= 0x08; + iti.panenv.num = (BYTE)penv->nPanEnv; + iti.panenv.lpb = (BYTE)penv->nPanLoopStart; + iti.panenv.lpe = (BYTE)penv->nPanLoopEnd; + iti.panenv.slb = penv->nPanSustainBegin; + iti.panenv.sle = penv->nPanSustainEnd; + // Writing Pitch Envelope + if (penv->dwFlags & ENV_PITCH) iti.pitchenv.flags |= 0x01; + if (penv->dwFlags & ENV_PITCHLOOP) iti.pitchenv.flags |= 0x02; + if (penv->dwFlags & ENV_PITCHSUSTAIN) iti.pitchenv.flags |= 0x04; + if (penv->dwFlags & ENV_PITCHCARRY) iti.pitchenv.flags |= 0x08; + if (penv->dwFlags & ENV_FILTER) iti.pitchenv.flags |= 0x80; + iti.pitchenv.num = (BYTE)penv->nPitchEnv; + iti.pitchenv.lpb = (BYTE)penv->nPitchLoopStart; + iti.pitchenv.lpe = (BYTE)penv->nPitchLoopEnd; + iti.pitchenv.slb = (BYTE)penv->nPitchSustainBegin; + iti.pitchenv.sle = (BYTE)penv->nPitchSustainEnd; + // Writing Envelopes data + for (UINT ev=0; ev<25; ev++) + { + iti.volenv.data[ev*3] = penv->VolEnv[ev]; + iti.volenv.data[ev*3+1] = penv->VolPoints[ev] & 0xFF; + iti.volenv.data[ev*3+2] = penv->VolPoints[ev] >> 8; + iti.panenv.data[ev*3] = penv->PanEnv[ev] - 32; + iti.panenv.data[ev*3+1] = penv->PanPoints[ev] & 0xFF; + iti.panenv.data[ev*3+2] = penv->PanPoints[ev] >> 8; + iti.pitchenv.data[ev*3] = penv->PitchEnv[ev] - 32; + iti.pitchenv.data[ev*3+1] = penv->PitchPoints[ev] & 0xFF; + iti.pitchenv.data[ev*3+2] = penv->PitchPoints[ev] >> 8; + } + } else + // Save Empty Instrument + { + for (UINT i=0; i<120; i++) iti.keyboard[i*2] = i; + iti.ppc = 5*12; + iti.gbv = 128; + iti.dfp = 0x20; + iti.ifc = 0xFF; + } + if (!iti.nos) iti.trkvers = 0; + // Writing instrument + inspos[nins-1] = dwPos; + dwPos += sizeof(ITINSTRUMENT); + fwrite(&iti, 1, sizeof(ITINSTRUMENT), f); + } + // Writing sample headers + memset(&itss, 0, sizeof(itss)); + for (UINT hsmp=0; hsmpcommand; + UINT param = m->param; + UINT vol = 0xFF; + UINT note = m->note; + if (note) b |= 1; + if ((note) && (note < 0xFE)) note--; + if (m->instr) b |= 2; + if (m->volcmd) + { + UINT volcmd = m->volcmd; + switch(volcmd) + { + case VOLCMD_VOLUME: vol = m->vol; if (vol > 64) vol = 64; break; + case VOLCMD_PANNING: vol = m->vol + 128; if (vol > 192) vol = 192; break; + case VOLCMD_VOLSLIDEUP: vol = 85 + ConvertVolParam(m->vol); break; + case VOLCMD_VOLSLIDEDOWN: vol = 95 + ConvertVolParam(m->vol); break; + case VOLCMD_FINEVOLUP: vol = 65 + ConvertVolParam(m->vol); break; + case VOLCMD_FINEVOLDOWN: vol = 75 + ConvertVolParam(m->vol); break; + case VOLCMD_VIBRATO: vol = 203; break; + case VOLCMD_VIBRATOSPEED: vol = 203 + ConvertVolParam(m->vol); break; + case VOLCMD_TONEPORTAMENTO: vol = 193 + ConvertVolParam(m->vol); break; + case VOLCMD_PORTADOWN: vol = 105 + ConvertVolParam(m->vol); break; + case VOLCMD_PORTAUP: vol = 115 + ConvertVolParam(m->vol); break; + default: vol = 0xFF; + } + } + if (vol != 0xFF) b |= 4; + if (command) + { + S3MSaveConvert(&command, ¶m, TRUE); + if (command) b |= 8; + } + // Packing information + if (b) + { + // Same note ? + if (b & 1) + { + if ((note == lastvalue[ch].note) && (lastvalue[ch].volcmd & 1)) + { + b &= ~1; + b |= 0x10; + } else + { + lastvalue[ch].note = note; + lastvalue[ch].volcmd |= 1; + } + } + // Same instrument ? + if (b & 2) + { + if ((m->instr == lastvalue[ch].instr) && (lastvalue[ch].volcmd & 2)) + { + b &= ~2; + b |= 0x20; + } else + { + lastvalue[ch].instr = m->instr; + lastvalue[ch].volcmd |= 2; + } + } + // Same volume column byte ? + if (b & 4) + { + if ((vol == lastvalue[ch].vol) && (lastvalue[ch].volcmd & 4)) + { + b &= ~4; + b |= 0x40; + } else + { + lastvalue[ch].vol = vol; + lastvalue[ch].volcmd |= 4; + } + } + // Same command / param ? + if (b & 8) + { + if ((command == lastvalue[ch].command) && (param == lastvalue[ch].param) && (lastvalue[ch].volcmd & 8)) + { + b &= ~8; + b |= 0x80; + } else + { + lastvalue[ch].command = command; + lastvalue[ch].param = param; + lastvalue[ch].volcmd |= 8; + } + } + if (b != chnmask[ch]) + { + chnmask[ch] = b; + buf[len++] = (ch+1) | 0x80; + buf[len++] = b; + } else + { + buf[len++] = ch+1; + } + if (b & 1) buf[len++] = note; + if (b & 2) buf[len++] = m->instr; + if (b & 4) buf[len++] = vol; + if (b & 8) + { + buf[len++] = command; + buf[len++] = param; + } + } + } + buf[len++] = 0; + dwPos += len; + patinfo[0] += len; + fwrite(buf, 1, len, f); + } + fseek(f, dwPatPos, SEEK_SET); + fwrite(patinfo, 8, 1, f); + fseek(f, dwPos, SEEK_SET); + } + // Writing Sample Data + for (UINT nsmp=1; nsmp<=header.smpnum; nsmp++) + { + MODINSTRUMENT *psmp = &Ins[nsmp]; + memset(&itss, 0, sizeof(itss)); + memcpy(itss.filename, psmp->name, 12); + memcpy(itss.name, m_szNames[nsmp], 26); + itss.id = 0x53504D49; + itss.gvl = (BYTE)psmp->nGlobalVol; + if (m_nInstruments) + { + for (UINT iu=1; iu<=m_nInstruments; iu++) if (Headers[iu]) + { + INSTRUMENTHEADER *penv = Headers[iu]; + for (UINT ju=0; ju<128; ju++) if (penv->Keyboard[ju] == nsmp) + { + itss.flags = 0x01; + break; + } + } + } else + { + itss.flags = 0x01; + } + if (psmp->uFlags & CHN_LOOP) itss.flags |= 0x10; + if (psmp->uFlags & CHN_SUSTAINLOOP) itss.flags |= 0x20; + if (psmp->uFlags & CHN_PINGPONGLOOP) itss.flags |= 0x40; + if (psmp->uFlags & CHN_PINGPONGSUSTAIN) itss.flags |= 0x80; + itss.C5Speed = psmp->nC4Speed; + if (!itss.C5Speed) itss.C5Speed = 8363; + itss.length = psmp->nLength; + itss.loopbegin = psmp->nLoopStart; + itss.loopend = psmp->nLoopEnd; + itss.susloopbegin = psmp->nSustainStart; + itss.susloopend = psmp->nSustainEnd; + itss.vol = psmp->nVolume >> 2; + itss.dfp = psmp->nPan >> 2; + itss.vit = autovibxm2it[psmp->nVibType & 7]; + itss.vis = psmp->nVibRate; + itss.vid = psmp->nVibDepth; + itss.vir = (psmp->nVibSweep < 64) ? psmp->nVibSweep * 4 : 255; + if (psmp->uFlags & CHN_PANNING) itss.dfp |= 0x80; + if ((psmp->pSample) && (psmp->nLength)) itss.cvt = 0x01; + UINT flags = RS_PCM8S; +#ifndef NO_PACKING + if (nPacking) + { + if ((!(psmp->uFlags & (CHN_16BIT|CHN_STEREO))) + && (CanPackSample(psmp->pSample, psmp->nLength, nPacking))) + { + flags = RS_ADPCM4; + itss.cvt = 0xFF; + } + } else +#endif // NO_PACKING + { + if (psmp->uFlags & CHN_STEREO) + { + flags = RS_STPCM8S; + itss.flags |= 0x04; + } + if (psmp->uFlags & CHN_16BIT) + { + itss.flags |= 0x02; + flags = (psmp->uFlags & CHN_STEREO) ? RS_STPCM16S : RS_PCM16S; + } + } + itss.samplepointer = dwPos; + fseek(f, smppos[nsmp-1], SEEK_SET); + fwrite(&itss, 1, sizeof(ITSAMPLESTRUCT), f); + fseek(f, dwPos, SEEK_SET); + if ((psmp->pSample) && (psmp->nLength)) + { + dwPos += WriteSample(f, psmp, flags); + } + } + // Updating offsets + fseek(f, dwHdrPos, SEEK_SET); + if (header.insnum) fwrite(inspos, 4, header.insnum, f); + if (header.smpnum) fwrite(smppos, 4, header.smpnum, f); + if (header.patnum) fwrite(patpos, 4, header.patnum, f); + fclose(f); + return TRUE; +} + +#pragma warning(default:4100) +#endif // MODPLUG_NO_FILESAVE + +////////////////////////////////////////////////////////////////////////////// +// IT 2.14 compression + +DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n) +//----------------------------------------------------------------- +{ + DWORD retval = 0; + UINT i = n; + + if (n > 0) + { + do + { + if (!bitnum) + { + bitbuf = *ibuf++; + bitnum = 8; + } + retval >>= 1; + retval |= bitbuf << 31; + bitbuf >>= 1; + bitnum--; + i--; + } while (i); + i = n; + } + return (retval >> (32-i)); +} + +#define IT215_SUPPORT +void ITUnpack8Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215) +//------------------------------------------------------------------------------------------- +{ + signed char *pDst = pSample; + LPBYTE pSrc = lpMemFile; + DWORD wHdr = 0; + DWORD wCount = 0; + DWORD bitbuf = 0; + UINT bitnum = 0; + BYTE bLeft = 0, bTemp = 0, bTemp2 = 0; + + while (dwLen) + { + if (!wCount) + { + wCount = 0x8000; + wHdr = bswapLE16(*((LPWORD)pSrc)); + pSrc += 2; + bLeft = 9; + bTemp = bTemp2 = 0; + bitbuf = bitnum = 0; + } + DWORD d = wCount; + if (d > dwLen) d = dwLen; + // Unpacking + DWORD dwPos = 0; + do + { + WORD wBits = (WORD)ITReadBits(bitbuf, bitnum, pSrc, bLeft); + if (bLeft < 7) + { + DWORD i = 1 << (bLeft-1); + DWORD j = wBits & 0xFFFF; + if (i != j) goto UnpackByte; + wBits = (WORD)(ITReadBits(bitbuf, bitnum, pSrc, 3) + 1) & 0xFF; + bLeft = ((BYTE)wBits < bLeft) ? (BYTE)wBits : (BYTE)((wBits+1) & 0xFF); + goto Next; + } + if (bLeft < 9) + { + WORD i = (0xFF >> (9 - bLeft)) + 4; + WORD j = i - 8; + if ((wBits <= j) || (wBits > i)) goto UnpackByte; + wBits -= j; + bLeft = ((BYTE)(wBits & 0xFF) < bLeft) ? (BYTE)(wBits & 0xFF) : (BYTE)((wBits+1) & 0xFF); + goto Next; + } + if (bLeft >= 10) goto SkipByte; + if (wBits >= 256) + { + bLeft = (BYTE)(wBits + 1) & 0xFF; + goto Next; + } + UnpackByte: + if (bLeft < 8) + { + BYTE shift = 8 - bLeft; + signed char c = (signed char)(wBits << shift); + c >>= shift; + wBits = (WORD)c; + } + wBits += bTemp; + bTemp = (BYTE)wBits; + bTemp2 += bTemp; +#ifdef IT215_SUPPORT + pDst[dwPos] = (b215) ? bTemp2 : bTemp; +#else + pDst[dwPos] = bTemp; +#endif + SkipByte: + dwPos++; + Next: + if (pSrc >= lpMemFile+dwMemLength+1) return; + } while (dwPos < d); + // Move On + wCount -= d; + dwLen -= d; + pDst += d; + } +} + + +void ITUnpack16Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215) +//-------------------------------------------------------------------------------------------- +{ + signed short *pDst = (signed short *)pSample; + LPBYTE pSrc = lpMemFile; + DWORD wHdr = 0; + DWORD wCount = 0; + DWORD bitbuf = 0; + UINT bitnum = 0; + BYTE bLeft = 0; + signed short wTemp = 0, wTemp2 = 0; + + while (dwLen) + { + if (!wCount) + { + wCount = 0x4000; + wHdr = bswapLE16(*((LPWORD)pSrc)); + pSrc += 2; + bLeft = 17; + wTemp = wTemp2 = 0; + bitbuf = bitnum = 0; + } + DWORD d = wCount; + if (d > dwLen) d = dwLen; + // Unpacking + DWORD dwPos = 0; + do + { + DWORD dwBits = ITReadBits(bitbuf, bitnum, pSrc, bLeft); + if (bLeft < 7) + { + DWORD i = 1 << (bLeft-1); + DWORD j = dwBits; + if (i != j) goto UnpackByte; + dwBits = ITReadBits(bitbuf, bitnum, pSrc, 4) + 1; + bLeft = ((BYTE)(dwBits & 0xFF) < bLeft) ? (BYTE)(dwBits & 0xFF) : (BYTE)((dwBits+1) & 0xFF); + goto Next; + } + if (bLeft < 17) + { + DWORD i = (0xFFFF >> (17 - bLeft)) + 8; + DWORD j = (i - 16) & 0xFFFF; + if ((dwBits <= j) || (dwBits > (i & 0xFFFF))) goto UnpackByte; + dwBits -= j; + bLeft = ((BYTE)(dwBits & 0xFF) < bLeft) ? (BYTE)(dwBits & 0xFF) : (BYTE)((dwBits+1) & 0xFF); + goto Next; + } + if (bLeft >= 18) goto SkipByte; + if (dwBits >= 0x10000) + { + bLeft = (BYTE)(dwBits + 1) & 0xFF; + goto Next; + } + UnpackByte: + if (bLeft < 16) + { + BYTE shift = 16 - bLeft; + signed short c = (signed short)(dwBits << shift); + c >>= shift; + dwBits = (DWORD)c; + } + dwBits += wTemp; + wTemp = (signed short)dwBits; + wTemp2 += wTemp; +#ifdef IT215_SUPPORT + pDst[dwPos] = (b215) ? wTemp2 : wTemp; +#else + pDst[dwPos] = wTemp; +#endif + SkipByte: + dwPos++; + Next: + if (pSrc >= lpMemFile+dwMemLength+1) return; + } while (dwPos < d); + // Move On + wCount -= d; + dwLen -= d; + pDst += d; + if (pSrc >= lpMemFile+dwMemLength) break; + } +} + + +UINT CSoundFile::SaveMixPlugins(FILE *f, BOOL bUpdate) +//---------------------------------------------------- +{ + DWORD chinfo[64]; + CHAR s[32]; + DWORD nPluginSize; + UINT nTotalSize = 0; + UINT nChInfo = 0; + + for (UINT i=0; iInfo.dwPluginId1) || (p->Info.dwPluginId2)) + { + nPluginSize = sizeof(SNDMIXPLUGININFO)+4; // plugininfo+4 (datalen) + if ((p->pMixPlugin) && (bUpdate)) + { + p->pMixPlugin->SaveAllParameters(); + } + if (p->pPluginData) + { + nPluginSize += p->nPluginDataSize; + } + if (f) + { + s[0] = 'F'; + s[1] = 'X'; + s[2] = '0' + (i/10); + s[3] = '0' + (i%10); + fwrite(s, 1, 4, f); + fwrite(&nPluginSize, 1, 4, f); + fwrite(&p->Info, 1, sizeof(SNDMIXPLUGININFO), f); + fwrite(&m_MixPlugins[i].nPluginDataSize, 1, 4, f); + if (m_MixPlugins[i].pPluginData) + { + fwrite(m_MixPlugins[i].pPluginData, 1, m_MixPlugins[i].nPluginDataSize, f); + } + } + nTotalSize += nPluginSize + 8; + } + } + for (UINT j=0; j nLen-nPos-8) break;; + if ((bswapLE32(*(DWORD *)(p+nPos))) == 0x58464843) + { + for (UINT ch=0; ch<64; ch++) if (ch*4 < nPluginSize) + { + ChnSettings[ch].nMixPlugin = bswapLE32(*(DWORD *)(p+nPos+8+ch*4)); + } + } else + { + if ((p[nPos] != 'F') || (p[nPos+1] != 'X') + || (p[nPos+2] < '0') || (p[nPos+3] < '0')) + { + break; + } + nPlugin = (p[nPos+2]-'0')*10 + (p[nPos+3]-'0'); + if ((nPlugin < MAX_MIXPLUGINS) && (nPluginSize >= sizeof(SNDMIXPLUGININFO)+4)) + { + DWORD dwExtra = bswapLE32(*(DWORD *)(p+nPos+8+sizeof(SNDMIXPLUGININFO))); + m_MixPlugins[nPlugin].Info = *(const SNDMIXPLUGININFO *)(p+nPos+8); + m_MixPlugins[nPlugin].Info.dwPluginId1 = bswapLE32(m_MixPlugins[nPlugin].Info.dwPluginId1); + m_MixPlugins[nPlugin].Info.dwPluginId2 = bswapLE32(m_MixPlugins[nPlugin].Info.dwPluginId2); + m_MixPlugins[nPlugin].Info.dwInputRouting = bswapLE32(m_MixPlugins[nPlugin].Info.dwInputRouting); + m_MixPlugins[nPlugin].Info.dwOutputRouting = bswapLE32(m_MixPlugins[nPlugin].Info.dwOutputRouting); + for (UINT j=0; j<4; j++) + { + m_MixPlugins[nPlugin].Info.dwReserved[j] = bswapLE32(m_MixPlugins[nPlugin].Info.dwReserved[j]); + } + if ((dwExtra) && (dwExtra <= nPluginSize-sizeof(SNDMIXPLUGININFO)-4)) + { + m_MixPlugins[nPlugin].nPluginDataSize = 0; + m_MixPlugins[nPlugin].pPluginData = new signed char [dwExtra]; + if (m_MixPlugins[nPlugin].pPluginData) + { + m_MixPlugins[nPlugin].nPluginDataSize = dwExtra; + memcpy(m_MixPlugins[nPlugin].pPluginData, p+nPos+8+sizeof(SNDMIXPLUGININFO)+4, dwExtra); + } + } + } + } + nPos += nPluginSize + 8; + } + return nPos; +} + -- cgit v0.9.0.2