Mercurial > audlegacy-plugins
diff src/modplug/load_it.cxx @ 2337:107c1fed3d92
Port Schism modplug core.
author | "Tony Vroon <chainsaw@gentoo.org>" |
---|---|
date | Thu, 24 Jan 2008 12:05:59 +0000 |
parents | 6907fc39b53f |
children | 5fe8ac99a33d |
line wrap: on
line diff
--- a/src/modplug/load_it.cxx Wed Jan 23 19:37:05 2008 +0100 +++ b/src/modplug/load_it.cxx Thu Jan 24 12:05:59 2008 +0000 @@ -2,15 +2,17 @@ * This source code is public domain. * * Authors: Olivier Lapicque <olivierl@jps.net>, - * Adam Goode <adam@evdebs.org> (Endian and char fixes for PPC) - * Marco Trillo <toad@arsystel.com> (Endian fixes for SaveIT, XM->IT Sample Converter) - * + * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC) */ #include "stdafx.h" #include "sndfile.h" #include "it_defs.h" +/* blah, -mrsb. +this is a schism header */ +#include "midi.h" + #ifdef MSC_VER #pragma warning(disable:4244) #endif @@ -22,11 +24,8 @@ { 0, 2, 4, 1, 3, 0, 0, 0 }; ////////////////////////////////////////////////////////// -// Impulse Tracker IT file support +// Impulse Tracker IT file support (import only) -// for conversion of XM samples -extern WORD XMPeriodTable[96+8]; -extern UINT XMLinearTable[768]; static inline UINT ConvertVolParam(UINT value) //-------------------------------------------- @@ -44,7 +43,7 @@ memcpy(penv->name, pis->name, 26); memcpy(penv->filename, pis->filename, 12); penv->nFadeOut = bswapLE16(pis->fadeout) << 6; - penv->nGlobalVol = 64; + penv->nGlobalVol = 128; for (UINT j=0; j<120; j++) { UINT note = pis->keyboard[j*2]; @@ -56,19 +55,19 @@ if (pis->flags & 0x01) penv->dwFlags |= ENV_VOLUME; if (pis->flags & 0x02) penv->dwFlags |= ENV_VOLLOOP; if (pis->flags & 0x04) penv->dwFlags |= ENV_VOLSUSTAIN; - penv->nVolLoopStart = pis->vls; - penv->nVolLoopEnd = pis->vle; - penv->nVolSustainBegin = pis->sls; - penv->nVolSustainEnd = pis->sle; - penv->nVolEnv = 25; + penv->VolEnv.nLoopStart = pis->vls; + penv->VolEnv.nLoopEnd = pis->vle; + penv->VolEnv.nSustainStart = pis->sls; + penv->VolEnv.nSustainEnd = pis->sle; + penv->VolEnv.nNodes = 25; for (UINT ev=0; ev<25; ev++) { - if ((penv->VolPoints[ev] = pis->nodes[ev*2]) == 0xFF) + if ((penv->VolEnv.Ticks[ev] = pis->nodes[ev*2]) == 0xFF) { - penv->nVolEnv = ev; + penv->VolEnv.nNodes = ev; break; } - penv->VolEnv[ev] = pis->nodes[ev*2+1]; + penv->VolEnv.Values[ev] = pis->nodes[ev*2+1]; } penv->nNNA = pis->nna; penv->nDCT = pis->dnc; @@ -82,8 +81,8 @@ penv->nMidiChannel = pis->mch; penv->wMidiBank = bswapLE16(pis->mbank); penv->nFadeOut = bswapLE16(pis->fadeout) << 5; - penv->nGlobalVol = pis->gbv >> 1; - if (penv->nGlobalVol > 64) penv->nGlobalVol = 64; + penv->nGlobalVol = pis->gbv; + if (penv->nGlobalVol > 128) penv->nGlobalVol = 128; for (UINT j=0; j<120; j++) { UINT note = pis->keyboard[j*2]; @@ -97,49 +96,49 @@ if (pis->volenv.flags & 2) penv->dwFlags |= ENV_VOLLOOP; if (pis->volenv.flags & 4) penv->dwFlags |= ENV_VOLSUSTAIN; if (pis->volenv.flags & 8) penv->dwFlags |= ENV_VOLCARRY; - penv->nVolEnv = pis->volenv.num; - if (penv->nVolEnv > 25) penv->nVolEnv = 25; + penv->VolEnv.nNodes = pis->volenv.num; + if (penv->VolEnv.nNodes > 25) penv->VolEnv.nNodes = 25; - penv->nVolLoopStart = pis->volenv.lpb; - penv->nVolLoopEnd = pis->volenv.lpe; - penv->nVolSustainBegin = pis->volenv.slb; - penv->nVolSustainEnd = pis->volenv.sle; + penv->VolEnv.nLoopStart = pis->volenv.lpb; + penv->VolEnv.nLoopEnd = pis->volenv.lpe; + penv->VolEnv.nSustainStart = pis->volenv.slb; + penv->VolEnv.nSustainEnd = pis->volenv.sle; // Panning Envelope if (pis->panenv.flags & 1) penv->dwFlags |= ENV_PANNING; if (pis->panenv.flags & 2) penv->dwFlags |= ENV_PANLOOP; if (pis->panenv.flags & 4) penv->dwFlags |= ENV_PANSUSTAIN; if (pis->panenv.flags & 8) penv->dwFlags |= ENV_PANCARRY; - penv->nPanEnv = pis->panenv.num; - if (penv->nPanEnv > 25) penv->nPanEnv = 25; - penv->nPanLoopStart = pis->panenv.lpb; - penv->nPanLoopEnd = pis->panenv.lpe; - penv->nPanSustainBegin = pis->panenv.slb; - penv->nPanSustainEnd = pis->panenv.sle; + penv->PanEnv.nNodes = pis->panenv.num; + if (penv->PanEnv.nNodes > 25) penv->PanEnv.nNodes = 25; + penv->PanEnv.nLoopStart = pis->panenv.lpb; + penv->PanEnv.nLoopEnd = pis->panenv.lpe; + penv->PanEnv.nSustainStart = pis->panenv.slb; + penv->PanEnv.nSustainEnd = pis->panenv.sle; // Pitch Envelope if (pis->pitchenv.flags & 1) penv->dwFlags |= ENV_PITCH; if (pis->pitchenv.flags & 2) penv->dwFlags |= ENV_PITCHLOOP; if (pis->pitchenv.flags & 4) penv->dwFlags |= ENV_PITCHSUSTAIN; if (pis->pitchenv.flags & 8) penv->dwFlags |= ENV_PITCHCARRY; if (pis->pitchenv.flags & 0x80) penv->dwFlags |= ENV_FILTER; - penv->nPitchEnv = pis->pitchenv.num; - if (penv->nPitchEnv > 25) penv->nPitchEnv = 25; - penv->nPitchLoopStart = pis->pitchenv.lpb; - penv->nPitchLoopEnd = pis->pitchenv.lpe; - penv->nPitchSustainBegin = pis->pitchenv.slb; - penv->nPitchSustainEnd = pis->pitchenv.sle; + penv->PitchEnv.nNodes = pis->pitchenv.num; + if (penv->PitchEnv.nNodes > 25) penv->PitchEnv.nNodes = 25; + penv->PitchEnv.nLoopStart = pis->pitchenv.lpb; + penv->PitchEnv.nLoopEnd = pis->pitchenv.lpe; + penv->PitchEnv.nSustainStart = pis->pitchenv.slb; + penv->PitchEnv.nSustainEnd = pis->pitchenv.sle; // Envelopes Data for (UINT ev=0; ev<25; ev++) { - penv->VolEnv[ev] = pis->volenv.data[ev*3]; - penv->VolPoints[ev] = (pis->volenv.data[ev*3+2] << 8) | (pis->volenv.data[ev*3+1]); - penv->PanEnv[ev] = pis->panenv.data[ev*3] + 32; - penv->PanPoints[ev] = (pis->panenv.data[ev*3+2] << 8) | (pis->panenv.data[ev*3+1]); - penv->PitchEnv[ev] = pis->pitchenv.data[ev*3] + 32; - penv->PitchPoints[ev] = (pis->pitchenv.data[ev*3+2] << 8) | (pis->pitchenv.data[ev*3+1]); + penv->VolEnv.Values[ev] = pis->volenv.data[ev*3]; + penv->VolEnv.Ticks[ev] = (pis->volenv.data[ev*3+2] << 8) | (pis->volenv.data[ev*3+1]); + penv->PanEnv.Values[ev] = pis->panenv.data[ev*3] + 32; + penv->PanEnv.Ticks[ev] = (pis->panenv.data[ev*3+2] << 8) | (pis->panenv.data[ev*3+1]); + penv->PitchEnv.Values[ev] = pis->pitchenv.data[ev*3] + 32; + penv->PitchEnv.Ticks[ev] = (pis->pitchenv.data[ev*3+2] << 8) | (pis->pitchenv.data[ev*3+1]); } - penv->nNNA = pis->nna; - penv->nDCT = pis->dct; - penv->nDNA = pis->dca; + penv->nNNA = pis->nna % 4; + penv->nDCT = pis->dct % 4; + penv->nDNA = pis->dca % 3; penv->nPPS = pis->pps; penv->nPPC = pis->ppc; penv->nIFC = pis->ifc; @@ -150,8 +149,8 @@ if (penv->nPan > 256) penv->nPan = 128; if (pis->dfp < 0x80) penv->dwFlags |= ENV_SETPANNING; } - if ((penv->nVolLoopStart >= 25) || (penv->nVolLoopEnd >= 25)) penv->dwFlags &= ~ENV_VOLLOOP; - if ((penv->nVolSustainBegin >= 25) || (penv->nVolSustainEnd >= 25)) penv->dwFlags &= ~ENV_VOLSUSTAIN; + if ((penv->VolEnv.nLoopStart >= 25) || (penv->VolEnv.nLoopEnd >= 25)) penv->dwFlags &= ~ENV_VOLLOOP; + if ((penv->VolEnv.nSustainStart >= 25) || (penv->VolEnv.nSustainEnd >= 25)) penv->dwFlags &= ~ENV_VOLSUSTAIN; return TRUE; } @@ -167,8 +166,112 @@ BYTE chnmask[64], channels_used[64]; MODCOMMAND lastvalue[64]; + if ((!lpStream) || (dwMemLength < 0xc2)) return FALSE; + pifh.id = bswapLE32(pifh.id); - pifh.reserved1 = bswapLE16(pifh.reserved1); + if (pifh.id == 0x49504D49) { + if (dwMemLength < 554) return FALSE; + + WORD tv; + INSTRUMENTHEADER *zenv = new INSTRUMENTHEADER; + if (!zenv) return FALSE; + memset(zenv, 0, sizeof(INSTRUMENTHEADER)); + memcpy(&tv, lpStream+0x1C, 2); /* trkvers */ + if (!ITInstrToMPT(lpStream, zenv, tv)) { + delete zenv; + return FALSE; + } + + /* okay, we need samples now */ + unsigned int q = 554; + BYTE expect_samples = lpStream[0x1E]; + + m_nType = MOD_TYPE_IT; + m_nInstruments = 1; + m_nSamples = expect_samples; + m_dwSongFlags = SONG_INSTRUMENTMODE | SONG_LINEARSLIDES /* eh? */; + + memcpy(m_szNames[0], lpStream + 0x20, 26); + m_szNames[0][26] = 0; + + if (q+(80*expect_samples) >= dwMemLength) { + delete zenv; + return FALSE; + } + + for (UINT nsmp = 0; nsmp < expect_samples; nsmp++) { + + ITSAMPLESTRUCT pis = *(ITSAMPLESTRUCT *)(lpStream+q); + q += 80; /* length of ITS header */ + + pis.id = bswapLE32(pis.id); + pis.length = bswapLE32(pis.length); + pis.loopbegin = bswapLE32(pis.loopbegin); + pis.loopend = bswapLE32(pis.loopend); + pis.C5Speed = bswapLE32(pis.C5Speed); + pis.susloopbegin = bswapLE32(pis.susloopbegin); + pis.susloopend = bswapLE32(pis.susloopend); + pis.samplepointer = bswapLE32(pis.samplepointer); + + if (pis.id == 0x53504D49) + { + MODINSTRUMENT *pins = &Ins[nsmp+1]; + memcpy(pins->name, pis.filename, 12); + pins->uFlags = 0; + pins->nLength = 0; + pins->nLoopStart = pis.loopbegin; + pins->nLoopEnd = pis.loopend; + pins->nSustainStart = pis.susloopbegin; + pins->nSustainEnd = pis.susloopend; + pins->nC4Speed = pis.C5Speed; + if (!pins->nC4Speed) pins->nC4Speed = 8363; + //if (pis.C5Speed < 256) pins->nC4Speed = 256; + pins->nVolume = pis.vol << 2; + if (pins->nVolume > 256) pins->nVolume = 256; + pins->nGlobalVol = pis.gvl; + if (pins->nGlobalVol > 64) pins->nGlobalVol = 64; + if (pis.flags & 0x10) pins->uFlags |= CHN_LOOP; + if (pis.flags & 0x20) pins->uFlags |= CHN_SUSTAINLOOP; + if (pis.flags & 0x40) pins->uFlags |= CHN_PINGPONGLOOP; + if (pis.flags & 0x80) pins->uFlags |= CHN_PINGPONGSUSTAIN; + pins->nPan = (pis.dfp & 0x7F) << 2; + if (pins->nPan > 256) pins->nPan = 256; + if (pis.dfp & 0x80) pins->uFlags |= CHN_PANNING; + pins->nVibType = autovibit2xm[pis.vit & 7]; + pins->nVibRate = pis.vis; + pins->nVibDepth = pis.vid & 0x7F; + pins->nVibSweep = pis.vir; + if ((pis.samplepointer) && (pis.samplepointer < dwMemLength) && (pis.length)) + { + pins->nLength = pis.length; + if (pins->nLength > MAX_SAMPLE_LENGTH) pins->nLength = MAX_SAMPLE_LENGTH; + UINT flags = (pis.cvt & 1) ? RS_PCM8S : RS_PCM8U; + if (pis.flags & 2) + { + flags += 5; + if (pis.flags & 4) flags |= RSF_STEREO; + pins->uFlags |= CHN_16BIT; + // IT 2.14 16-bit packed sample ? + if (pis.flags & 8) flags = ((pifh.cmwt >= 0x215) && (pis.cvt & 4)) ? RS_IT21516 : RS_IT21416; + } else + { + if (pis.flags & 4) flags |= RSF_STEREO; + if (pis.cvt == 0xFF) flags = RS_ADPCM4; else + // IT 2.14 8-bit packed sample ? + if (pis.flags & 8) flags = ((pifh.cmwt >= 0x215) && (pis.cvt & 4)) ? RS_IT2158 : RS_IT2148; + } + ReadSample(&Ins[nsmp+1], flags, (LPSTR)(lpStream+pis.samplepointer), dwMemLength - pis.samplepointer); + } + } + memcpy(m_szNames[nsmp+1], pis.name, 26); + + } + + Headers[1] = zenv; + return TRUE; + } + + pifh.ordnum = bswapLE16(pifh.ordnum); pifh.insnum = bswapLE16(pifh.insnum); pifh.smpnum = bswapLE16(pifh.smpnum); @@ -181,29 +284,42 @@ pifh.msgoffset = bswapLE32(pifh.msgoffset); pifh.reserved2 = bswapLE32(pifh.reserved2); - if ((!lpStream) || (dwMemLength < 0x100)) return FALSE; + + if ((pifh.id != 0x4D504D49) || (pifh.insnum >= MAX_INSTRUMENTS) - || (!pifh.smpnum) || (pifh.smpnum >= MAX_INSTRUMENTS) || (!pifh.ordnum)) return FALSE; + || (pifh.smpnum >= MAX_INSTRUMENTS)) return FALSE; if (dwMemPos + pifh.ordnum + pifh.insnum*4 + pifh.smpnum*4 + pifh.patnum*4 > dwMemLength) return FALSE; m_nType = MOD_TYPE_IT; + if (!(pifh.flags & 0x01)) m_dwSongFlags |= SONG_NOSTEREO; + if (pifh.flags & 0x04) m_dwSongFlags |= SONG_INSTRUMENTMODE; if (pifh.flags & 0x08) m_dwSongFlags |= SONG_LINEARSLIDES; if (pifh.flags & 0x10) m_dwSongFlags |= SONG_ITOLDEFFECTS; if (pifh.flags & 0x20) m_dwSongFlags |= SONG_ITCOMPATMODE; + if (pifh.flags & 0x40) { + midi_flags |= MIDI_PITCH_BEND; + midi_pitch_depth = pifh.pwd; + } if (pifh.flags & 0x80) m_dwSongFlags |= SONG_EMBEDMIDICFG; if (pifh.flags & 0x1000) m_dwSongFlags |= SONG_EXFILTERRANGE; memcpy(m_szNames[0], pifh.songname, 26); m_szNames[0][26] = 0; + if (pifh.cwtv >= 0x0213) { + m_rowHighlightMinor = pifh.hilight_minor; + m_rowHighlightMajor = pifh.hilight_major; + } else { + m_rowHighlightMinor = 4; + m_rowHighlightMajor = 16; + } // Global Volume - if (pifh.globalvol) - { - m_nDefaultGlobalVolume = pifh.globalvol << 1; - if (!m_nDefaultGlobalVolume) m_nDefaultGlobalVolume = 256; - if (m_nDefaultGlobalVolume > 256) m_nDefaultGlobalVolume = 256; - } + m_nDefaultGlobalVolume = pifh.globalvol << 1; + if (m_nDefaultGlobalVolume > 256) m_nDefaultGlobalVolume = 256; if (pifh.speed) m_nDefaultSpeed = pifh.speed; if (pifh.tempo) m_nDefaultTempo = pifh.tempo; - m_nSongPreAmp = pifh.mv & 0x7F; + m_nSongPreAmp = pifh.mv; + if (m_nSongPreAmp > 128) + m_nSongPreAmp = 128; + m_nStereoSeparation = pifh.sep; // Reading Channels Pan Positions for (int ipan=0; ipan<64; ipan++) if (pifh.chnpan[ipan] != 0xFF) { @@ -229,6 +345,7 @@ UINT nordsize = pifh.ordnum; if (nordsize > MAX_ORDERS) nordsize = MAX_ORDERS; memcpy(Order, lpStream+dwMemPos, nordsize); + dwMemPos += pifh.ordnum; // Reading Instrument Offsets memset(inspos, 0, sizeof(inspos)); @@ -263,6 +380,17 @@ patpos[j] = bswapLE32(patpos[j]); } dwMemPos += pifh.patnum * 4; + + for (UINT i = 0; i < pifh.ordnum; i++) { + if (Order[i] >= pifh.patnum && Order[i] < MAX_PATTERNS) { + pifh.patnum = Order[i]; + for (UINT j = patpossize; j < (unsigned)(pifh.patnum>>2); j++) + patpos[j] = 0; + patpossize = pifh.patnum; + } + } + + // Reading IT Extra Info if (dwMemPos + 2 < dwMemLength) { @@ -277,8 +405,13 @@ { memcpy(&m_MidiCfg, lpStream+dwMemPos, sizeof(MODMIDICFG)); dwMemPos += sizeof(MODMIDICFG); + } else { + ResetMidiCfg(); } + } else { + ResetMidiCfg(); } +#if 0 // Read pattern names: "PNAM" if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e50)) { @@ -295,8 +428,10 @@ dwMemPos += len; } } +#endif // 4-channels minimum m_nChannels = 4; +#if 0 // Read channel names: "CNAM" if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e43)) { @@ -319,6 +454,7 @@ { dwMemPos += LoadMixPlugins(lpStream+dwMemPos, dwMemLength-dwMemPos); } +#endif // Checking for unused channels UINT npatterns = pifh.patnum; if (npatterns > MAX_PATTERNS) npatterns = MAX_PATTERNS; @@ -366,8 +502,7 @@ } } // Reading Instruments - m_nInstruments = 0; - if (pifh.flags & 0x04) m_nInstruments = pifh.insnum; + m_nInstruments = pifh.insnum; if (m_nInstruments >= MAX_INSTRUMENTS) m_nInstruments = MAX_INSTRUMENTS-1; for (UINT nins=0; nins<m_nInstruments; nins++) { @@ -407,7 +542,7 @@ pins->nSustainEnd = pis.susloopend; pins->nC4Speed = pis.C5Speed; if (!pins->nC4Speed) pins->nC4Speed = 8363; - if (pis.C5Speed < 256) pins->nC4Speed = 256; + //if (pis.C5Speed < 256) pins->nC4Speed = 256; pins->nVolume = pis.vol << 2; if (pins->nVolume > 256) pins->nVolume = 256; pins->nGlobalVol = pis.gvl; @@ -422,7 +557,7 @@ pins->nVibType = autovibit2xm[pis.vit & 7]; pins->nVibRate = pis.vis; pins->nVibDepth = pis.vid & 0x7F; - pins->nVibSweep = (pis.vir + 3) / 4; + pins->nVibSweep = pis.vir; if ((pis.samplepointer) && (pis.samplepointer < dwMemLength) && (pis.length)) { pins->nLength = pis.length; @@ -453,6 +588,7 @@ if ((!patpos[npat]) || ((DWORD)patpos[npat] + 4 >= dwMemLength)) { PatternSize[npat] = 64; + PatternAllocSize[npat] = 64; Patterns[npat] = AllocatePattern(64, m_nChannels); continue; } @@ -462,6 +598,7 @@ if ((rows < 4) || (rows > 256)) continue; if (patpos[npat]+8+len > dwMemLength) continue; PatternSize[npat] = rows; + PatternAllocSize[npat] = rows; if ((Patterns[npat] = AllocatePattern(rows, m_nChannels)) == NULL) continue; memset(lastvalue, 0, sizeof(lastvalue)); memset(chnmask, 0, sizeof(chnmask)); @@ -551,7 +688,7 @@ // 193-202: Portamento To if ((vol >= 193) && (vol <= 202)) { m[ch].volcmd = VOLCMD_TONEPORTAMENTO; m[ch].vol = vol - 193; } else // 203-212: Vibrato - if ((vol >= 203) && (vol <= 212)) { m[ch].volcmd = VOLCMD_VIBRATOSPEED; m[ch].vol = vol - 203; } + if ((vol >= 203) && (vol <= 212)) { m[ch].volcmd = VOLCMD_VIBRATO; m[ch].vol = vol - 203; } lastvalue[ch].volcmd = m[ch].volcmd; lastvalue[ch].vol = m[ch].vol; } @@ -590,589 +727,6 @@ } -#ifndef MODPLUG_NO_FILESAVE -//#define SAVEITTIMESTAMP -#pragma warning(disable:4100) - -BOOL CSoundFile::SaveIT(LPCSTR lpszFileName, UINT nPacking) -//--------------------------------------------------------- -{ - DWORD dwPatNamLen, dwChnNamLen; - ITFILEHEADER header, writeheader; - ITINSTRUMENT iti, writeiti; - 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; // IMPM - lstrcpyn((char *)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; - // clip song pre-amp values (between 0x20 and 0x7f) - if (header.mv < 0x20) header.mv = 0x20; - if (header.mv > 0x7F) header.mv = 0x7F; - header.speed = m_nDefaultSpeed; - header.tempo = m_nDefaultTempo; - header.sep = m_nStereoSeparation; - dwHdrPos = sizeof(header) + header.ordnum; - // Channel Pan and Volume - memset(header.chnpan, 0xFF, 64); - memset(header.chnvol, 64, 64); - for (UINT ich=0; ich<m_nChannels; ich++) - { - header.chnpan[ich] = ChnSettings[ich].nPan >> 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 - memcpy(writeheader, header, sizeof(header)); - - // Byteswap header information - writeheader.id = bswapLE32(writeheader.id); - writeheader.reserved1 = bswapLE16(writeheader.reserved1); - writeheader.ordnum = bswapLE16(writeheader.ordnum); - writeheader.insnum = bswapLE16(writeheader.insnum); - writeheader.smpnum = bswapLE16(writeheader.smpnum); - writeheader.patnum = bswapLE16(writeheader.patnum); - writeheader.cwtv = bswapLE16(writeheader.cwtv); - writeheader.cmwt = bswapLE16(writeheader.cmwt); - writeheader.flags = bswapLE16(writeheader.flags); - writeheader.special = bswapLE16(writeheader.special); - writeheader.msglength = bswapLE16(writeheader.msglength); - writeheader.msgoffset = bswapLE32(writeheader.msgoffset); - writeheader.reserved2 = bswapLE32(writeheader.reserved2); - - fwrite(&writeheader, 1, sizeof(writeheader), f); - - fwrite(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 = bswapLE32(0x4d414e50); - UINT len= bswapLE32(dwPatNamLen); - fwrite(&d, 1, 4, f); - write(&len, 1, 4, f); - fwrite(m_lpszPatternNames, 1, dwPatNamLen, f); - } - // Writing channel Names - if (dwChnNamLen) - { - DWORD d = bswapLE32(0x4d414e43); - UINT len= bswapLE32(dwChnNamLen); - fwrite(&d, 1, 4, f); - fwrite(&len, 1, 4, f); - UINT nChnNames = dwChnNamLen / MAX_CHANNELNAME; - for (UINT inam=0; inam<nChnNames; inam++) - { - fwrite(ChnSettings[inam].szName, 1, MAX_CHANNELNAME, f); - } - } - // Writing mix plugins info - SaveMixPlugins(f, FALSE); - // Writing song message - dwPos = dwHdrPos + dwExtra + (header.insnum + header.smpnum + header.patnum) * 4; - if (header.special & 1) - { - dwPos += strlen(m_lpszSongComments) + 1; - fwrite(m_lpszSongComments, 1, strlen(m_lpszSongComments)+1, f); - } - // Writing instruments - for (UINT nins=1; nins<=header.insnum; nins++) - { - memset(&iti, 0, sizeof(iti)); - iti.id = 0x49504D49; // "IMPI" - iti.trkvers = 0x211; - if (Headers[nins]) - { - INSTRUMENTHEADER *penv = Headers[nins]; - memset(smpcount, 0, sizeof(smpcount)); - memcpy(iti.filename, penv->filename, 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); - - memcpy(&writeiti, &iti, sizeof(ITINSTRUMENT)); - - writeiti.fadeout = bswapLE16(writeiti.fadeout); - writeiti.id = bswapLE32(writeiti.id); - writeiti.trkvers = bswapLE16(writeiti.trkvers); - writeiti.mbank = bswapLE16(writeiti.mbank); - - fwrite(&writeiti, 1, sizeof(ITINSTRUMENT), f); - } - // Writing sample headers - memset(&itss, 0, sizeof(itss)); - for (UINT hsmp=0; hsmp<header.smpnum; hsmp++) - { - smppos[hsmp] = dwPos; - dwPos += sizeof(ITSAMPLESTRUCT); - fwrite(&itss, 1, sizeof(ITSAMPLESTRUCT), f); - } - // Writing Patterns - for (UINT npat=0; npat<header.patnum; npat++) - { - DWORD dwPatPos = dwPos; - UINT len; - if (!Patterns[npat]) continue; - patpos[npat] = dwPos; - patinfo[0] = 0; - patinfo[1] = bswapLE16(PatternSize[npat]); - patinfo[2] = 0; - patinfo[3] = 0; - // Check for empty pattern - if (PatternSize[npat] == 64) - { - MODCOMMAND *pzc = Patterns[npat]; - UINT nz = PatternSize[npat] * m_nChannels; - for (UINT iz=0; iz<nz; iz++) - { - if ((pzc[iz].note) || (pzc[iz].instr) - || (pzc[iz].volcmd) || (pzc[iz].command)) break; - } - if (iz == nz) - { - patpos[npat] = 0; - continue; - } - } - fwrite(patinfo, 8, 1, f); - dwPos += 8; - memset(chnmask, 0xFF, sizeof(chnmask)); - memset(lastvalue, 0, sizeof(lastvalue)); - MODCOMMAND *m = Patterns[npat]; - for (UINT row=0; row<PatternSize[npat]; row++) - { - len = 0; - for (UINT ch=0; ch<m_nChannels; ch++, m++) - { - BYTE b = 0; - UINT command = m->command; - UINT param = m->param; - UINT vol = 0xFF; - UINT note = m->note; - if (note) b |= 1; - if ((note) && (note < 0x80)) note--; // 0xfe->0x80 --Toad - 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_VIBRATOSPEED: vol = 203 + ConvertVolParam(m->vol); break; - case VOLCMD_VIBRATO: vol = 203; 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); - patinfo[0] = bswapLE16(patinfo[0]); // byteswap -- Toad - 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) // if no C5Speed assume it is XM Sample - { - UINT period; - - /** - * C5 note => number 61, but in XM samples: - * RealNote = Note + RelativeTone - */ - period = GetPeriodFromNote(61+psmp->RelativeTone, psmp->nFineTune, 0); - - if (period) - itss.C5Speed = GetFreqFromPeriod(period, 0, 0); - /** - * If it didn`t work, it may not be a XM file; - * so put the default C5Speed, 8363Hz. - */ - if (!itss.C5Speed) itss.C5Speed = 8363; - } - - 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((char *)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); - - itss.id = bswapLE32(itss.id); - itss.length = bswapLE32(itss.length); - itss.loopbegin = bswapLE32(itss.loopbegin); - itss.loopend = bswapLE32(itss.loopend); - itss.C5Speed = bswapLE32(itss.C5Speed); - itss.susloopbegin = bswapLE32(itss.susloopbegin); - itss.susloopend = bswapLE32(itss.susloopend); - itss.samplepointer = bswapLE32(itss.samplepointer); - - fwrite(&itss, 1, sizeof(ITSAMPLESTRUCT), f); - fseek(f, dwPos, SEEK_SET); - if ((psmp->pSample) && (psmp->nLength)) - { - dwPos += WriteSample(f, psmp, flags); - } - } - // Updating offsets - fseek(f, dwHdrPos, SEEK_SET); - - /* <Toad> Now we can byteswap them ;-) */ - UINT WW; - UINT WX; - WX = (UINT)header.insnum; - WX <<= 2; - for (WW=0; WW < (WX>>2); WW++) - inspos[WW] = bswapLE32(inspos[WW]); - - WX = (UINT)header.smpnum; - WX <<= 2; - for (WW=0; WW < (WX>>2); WW++) - smppos[WW] = bswapLE32(smppos[WW]); - - WX=(UINT)header.patnum; - WX <<= 2; - for (WW=0; WW < (WX>>2); WW++) - patpos[WW] = bswapLE32(patpos[WW]); - - if (header.insnum) fwrite(inspos, 4, header.insnum, f); - if (header.smpnum) fwrite(smppos, 4, header.smpnum, f); - if (header.patnum) fwrite(patpos, 4, header.patnum, f); - fclose(f); - return TRUE; -} - -//#pragma warning(default:4100) -#endif // MODPLUG_NO_FILESAVE - ////////////////////////////////////////////////////////////////////////////// // IT 2.14 compression @@ -1374,8 +928,7 @@ { DWORD chinfo[64]; CHAR s[32]; - DWORD nPluginSize, writeSwapDWORD; - SNDMIXPLUGININFO writePluginInfo; + DWORD nPluginSize; UINT nTotalSize = 0; UINT nChInfo = 0; @@ -1400,23 +953,9 @@ s[2] = '0' + (i/10); s[3] = '0' + (i%10); fwrite(s, 1, 4, f); - writeSwapDWORD = bswapLE32(nPluginSize); - fwrite(&writeSwapDWORD, 1, 4, f); - - // Copy Information To Be Written for ByteSwapping - memcpy(&writePluginInfo, &p->Info, sizeof(SNDMIXPLUGININFO)); - writePluginInfo.dwPluginId1 = bswapLE32(p->Info.dwPluginId1); - writePluginInfo.dwPluginId2 = bswapLE32(p->Info.dwPluginId2); - writePluginInfo.dwInputRouting = bswapLE32(p->Info.dwInputRouting); - writePluginInfo.dwOutputRouting = bswapLE32(p->Info.dwOutputRouting); - for (UINT j=0; j<4; j++) - { - writePluginInfo.dwReserved[j] = bswapLE32(p->Info.dwReserved[j]); - } - - fwrite(&writePluginInfo, 1, sizeof(SNDMIXPLUGININFO), f); - writeSwapDWORD = bswapLE32(m_MixPlugins[i].nPluginDataSize); - fwrite(&writeSwapDWORD, 1, 4, f); + fwrite(&nPluginSize, 1, 4, f); + fwrite(&p->Info, 1, sizeof(SNDMIXPLUGININFO), f); + fwrite(&m_MixPlugins[i].nPluginDataSize, 1, 4, f); if (m_MixPlugins[i].pPluginData) { fwrite(m_MixPlugins[i].pPluginData, 1, m_MixPlugins[i].nPluginDataSize, f); @@ -1432,7 +971,6 @@ if ((chinfo[j] = ChnSettings[j].nMixPlugin) != 0) { nChInfo = j+1; - chinfo[j] = bswapLE32(chinfo[j]); // inplace BS } } } @@ -1440,11 +978,10 @@ { if (f) { - nPluginSize = bswapLE32(0x58464843); + nPluginSize = 0x58464843; fwrite(&nPluginSize, 1, 4, f); nPluginSize = nChInfo*4; - writeSwapDWORD = bswapLE32(nPluginSize); - fwrite(&writeSwapDWORD, 1, 4, f); + fwrite(&nPluginSize, 1, 4, f); fwrite(chinfo, 1, nPluginSize, f); } nTotalSize += nChInfo*4 + 8;