From: <sag...@us...> - 2010-09-07 14:37:33
|
Revision: 701 http://modplug.svn.sourceforge.net/modplug/?rev=701&view=rev Author: saga-games Date: 2010-09-07 14:37:26 +0000 (Tue, 07 Sep 2010) Log Message: ----------- [Ref] Moved the big pile of module conversion code to a separate file. Modified Paths: -------------- trunk/OpenMPT/mptrack/Moddoc.h trunk/OpenMPT/mptrack/Modedit.cpp trunk/OpenMPT/mptrack/mptrack.vcproj trunk/OpenMPT/mptrack/mptrack_08.vcproj Added Paths: ----------- trunk/OpenMPT/mptrack/ModConvert.cpp trunk/OpenMPT/mptrack/ModConvert.h Added: trunk/OpenMPT/mptrack/ModConvert.cpp =================================================================== --- trunk/OpenMPT/mptrack/ModConvert.cpp (rev 0) +++ trunk/OpenMPT/mptrack/ModConvert.cpp 2010-09-07 14:37:26 UTC (rev 701) @@ -0,0 +1,460 @@ +/* + * ModConvert.cpp + * -------------- + * Purpose: Code for converting between various module formats. + * Notes : (currently none) + * Authors: OpenMPT Devs + * + */ + +#include "Stdafx.h" +#include "Moddoc.h" +#include "Mainfrm.h" +#include "modsmp_ctrl.h" +#include "ModConvert.h" + + +#define CHANGEMODTYPE_WARNING(x) nWarnings |= (1 << x); +#define CHANGEMODTYPE_CHECK(x, s) if((nWarnings & (1 << x)) != 0) AddToLog(_T(s)); + + +bool CModDoc::ChangeModType(MODTYPE nNewType) +//------------------------------------------- +{ + uint64 nWarnings = 0; + PATTERNINDEX nResizedPatterns = 0; + + const MODTYPE nOldType = m_SndFile.GetType(); + + if (nNewType == nOldType && nNewType == MOD_TYPE_IT) + { + // Even if m_nType doesn't change, we might need to change extension in itp<->it case. + // This is because ITP is a HACK and doesn't genuinely change m_nType, + // but uses flages instead. + ChangeFileExtension(nNewType); + return true; + } + + if(nNewType == nOldType) + return true; + + const bool oldTypeIsMOD = (nOldType == MOD_TYPE_MOD), oldTypeIsXM = (nOldType == MOD_TYPE_XM), + oldTypeIsS3M = (nOldType == MOD_TYPE_S3M), oldTypeIsIT = (nOldType == MOD_TYPE_IT), + oldTypeIsMPT = (nOldType == MOD_TYPE_MPT), oldTypeIsMOD_XM = (oldTypeIsMOD || oldTypeIsXM), + oldTypeIsS3M_IT_MPT = (oldTypeIsS3M || oldTypeIsIT || oldTypeIsMPT), + oldTypeIsIT_MPT = (oldTypeIsIT || oldTypeIsMPT); + + const bool newTypeIsMOD = (nNewType == MOD_TYPE_MOD), newTypeIsXM = (nNewType == MOD_TYPE_XM), + newTypeIsS3M = (nNewType == MOD_TYPE_S3M), newTypeIsIT = (nNewType == MOD_TYPE_IT), + newTypeIsMPT = (nNewType == MOD_TYPE_MPT), newTypeIsMOD_XM = (newTypeIsMOD || newTypeIsXM), + newTypeIsS3M_IT_MPT = (newTypeIsS3M || newTypeIsIT || newTypeIsMPT), + newTypeIsXM_IT_MPT = (newTypeIsXM || newTypeIsIT || newTypeIsMPT), + newTypeIsIT_MPT = (newTypeIsIT || newTypeIsMPT); + + const CModSpecifications& specs = m_SndFile.GetModSpecifications(nNewType); + + /* + Incomplete list of MPTm-only features and extensions in the old formats: + + Features only available for MPTm: + -User definable tunings. + -Extended pattern range + -Extended sequence + -Multiple sequences ("songs") + -Pattern-specific time signatures + -Pattern effects :xy, S7D, S7E + -Long instrument envelopes + -Envelope release node (this was previously also usable in the IT format, but is deprecated in that format) + + Extended features in IT/XM/S3M/MOD(not all listed below are available in all of those formats): + -plugs + -Extended ranges for + -sample count + -instrument count + -pattern count + -sequence size + -Row count + -channel count + -tempo limits + -Extended sample/instrument properties. + -MIDI mapping directives + -Versioninfo + -channel names + -pattern names + -Alternative tempomodes + -For more info, see e.g. SaveExtendedSongProperties(), SaveExtendedInstrumentProperties() + */ + + // Check if conversion to 64 rows is necessary + for(PATTERNINDEX ipat=0; ipat<m_SndFile.Patterns.Size(); ipat++) + { + if ((m_SndFile.Patterns[ipat]) && (m_SndFile.Patterns[ipat].GetNumRows() != 64)) nResizedPatterns++; + } + + if(((m_SndFile.m_nInstruments) || (nResizedPatterns)) && (nNewType & (MOD_TYPE_MOD|MOD_TYPE_S3M))) + { + if(::MessageBox(NULL, + "This operation will convert all instruments to samples,\n" + "and resize all patterns to 64 rows.\n" + "Do you want to continue?", "Warning", MB_YESNO | MB_ICONQUESTION) != IDYES) return false; + BeginWaitCursor(); + BEGIN_CRITICAL(); + + // Converting instruments to samples + if(m_SndFile.m_nInstruments) + { + ConvertInstrumentsToSamples(); + CHANGEMODTYPE_WARNING(wInstrumentsToSamples); + } + + // Resizing all patterns to 64 rows + for(PATTERNINDEX nPat = 0; nPat < m_SndFile.Patterns.Size(); nPat++) if ((m_SndFile.Patterns[nPat]) && (m_SndFile.Patterns[nPat].GetNumRows() != 64)) + { + // try to save short patterns by inserting a pattern break. + if(m_SndFile.Patterns[nPat].GetNumRows() < 64) + { + m_SndFile.TryWriteEffect(nPat, m_SndFile.Patterns[nPat].GetNumRows() - 1, CMD_PATTERNBREAK, 0, false, CHANNELINDEX_INVALID, false, true); + } + m_SndFile.Patterns[nPat].Resize(64, false); + CHANGEMODTYPE_WARNING(wResizedPatterns); + } + + // Removing all instrument headers + for(CHANNELINDEX nChn = 0; nChn < MAX_CHANNELS; nChn++) + { + m_SndFile.Chn[nChn].pModInstrument = nullptr; + } + + for(INSTRUMENTINDEX nIns = 0; nIns < m_SndFile.m_nInstruments; nIns++) if (m_SndFile.Instruments[nIns]) + { + delete m_SndFile.Instruments[nIns]; + m_SndFile.Instruments[nIns] = nullptr; + } + m_SndFile.m_nInstruments = 0; + END_CRITICAL(); + EndWaitCursor(); + } //End if (((m_SndFile.m_nInstruments) || (b64)) && (nNewType & (MOD_TYPE_MOD|MOD_TYPE_S3M))) + BeginWaitCursor(); + + + ///////////////////////////// + // Converting pattern data + + for(PATTERNINDEX nPat = 0; nPat < m_SndFile.Patterns.Size(); nPat++) if (m_SndFile.Patterns[nPat]) + { + MODCOMMAND *m = m_SndFile.Patterns[nPat]; + + // This is used for -> MOD/XM conversion + vector<vector<MODCOMMAND::PARAM> > cEffectMemory; + cEffectMemory.resize(m_SndFile.GetNumChannels()); + for(size_t i = 0; i < m_SndFile.GetNumChannels(); i++) + { + cEffectMemory[i].resize(MAX_EFFECTS, 0); + } + + CHANNELINDEX nChannel = m_SndFile.m_nChannels - 1; + + for (UINT len = m_SndFile.Patterns[nPat].GetNumRows() * m_SndFile.m_nChannels; len; m++, len--) + { + nChannel = (nChannel + 1) % m_SndFile.m_nChannels; // 0...Channels - 1 + + m_SndFile.ConvertCommand(m, nOldType, nNewType); + + // Deal with effect memory for MOD/XM arpeggio + if (oldTypeIsS3M_IT_MPT && newTypeIsMOD_XM) + { + switch(m->command) + { + case CMD_ARPEGGIO: + case CMD_S3MCMDEX: + case CMD_MODCMDEX: + // No effect memory in XM / MOD + if(m->param == 0) + m->param = cEffectMemory[nChannel][m->command]; + else + cEffectMemory[nChannel][m->command] = m->param; + break; + } + } + + // Adjust effect memory for MOD files + if(newTypeIsMOD) + { + switch(m->command) + { + case CMD_PORTAMENTOUP: + case CMD_PORTAMENTODOWN: + case CMD_TONEPORTAVOL: + case CMD_VIBRATOVOL: + case CMD_VOLUMESLIDE: + // ProTracker doesn't have effect memory for these commands, so let's try to fix them + if(m->param == 0) + m->param = cEffectMemory[nChannel][m->command]; + else + cEffectMemory[nChannel][m->command] = m->param; + break; + + } + } + } + } + + //////////////////////////////////////////////// + // Converting instrument / sample / etc. data + + + // Do some sample conversion + for(SAMPLEINDEX nSmp = 1; nSmp <= m_SndFile.m_nSamples; nSmp++) + { + // No Sustain loops for MOD/S3M + if(newTypeIsMOD || newTypeIsS3M) + { + if(m_SndFile.Samples[nSmp].nSustainStart || m_SndFile.Samples[nSmp].nSustainEnd) + { + m_SndFile.Samples[nSmp].nSustainStart = m_SndFile.Samples[nSmp].nSustainEnd = 0; + CHANGEMODTYPE_WARNING(wSampleSustainLoops); + } + if(m_SndFile.Samples[nSmp].nVibDepth || m_SndFile.Samples[nSmp].nVibRate || m_SndFile.Samples[nSmp].nVibSweep) + { + m_SndFile.Samples[nSmp].nVibDepth = m_SndFile.Samples[nSmp].nVibRate = m_SndFile.Samples[nSmp].nVibSweep = m_SndFile.Samples[nSmp].nVibType = 0; + CHANGEMODTYPE_WARNING(wSampleAutoVibrato); + } + } + + // Transpose to Frequency (MOD/XM to S3M/IT/MPT) + if(oldTypeIsMOD_XM && newTypeIsS3M_IT_MPT) + { + m_SndFile.Samples[nSmp].nC5Speed = CSoundFile::TransposeToFrequency(m_SndFile.Samples[nSmp].RelativeTone, m_SndFile.Samples[nSmp].nFineTune); + m_SndFile.Samples[nSmp].RelativeTone = 0; + m_SndFile.Samples[nSmp].nFineTune = 0; + } + + // Frequency to Transpose, panning (S3M/IT/MPT to MOD/XM) + if(oldTypeIsS3M_IT_MPT && newTypeIsMOD_XM) + { + CSoundFile::FrequencyToTranspose(&m_SndFile.Samples[nSmp]); + if (!(m_SndFile.Samples[nSmp].uFlags & CHN_PANNING)) m_SndFile.Samples[nSmp].nPan = 128; + // No relative note for MOD files + // TODO: Pattern notes could be transposed based on the previous relative tone? + if(newTypeIsMOD && m_SndFile.Samples[nSmp].RelativeTone != 0) + { + m_SndFile.Samples[nSmp].RelativeTone = 0; + CHANGEMODTYPE_WARNING(wMODSampleFrequency); + } + } + + if(oldTypeIsXM && newTypeIsIT_MPT) + { + // Autovibrato settings (XM to IT, where sweep 0 means "no vibrato") + if(m_SndFile.Samples[nSmp].nVibSweep == 0 && m_SndFile.Samples[nSmp].nVibRate != 0 && m_SndFile.Samples[nSmp].nVibDepth != 0) + m_SndFile.Samples[nSmp].nVibSweep = 255; + } else if(oldTypeIsIT_MPT && newTypeIsXM) + { + // Autovibrato settings (IT to XM, where sweep 0 means "no sweep") + if(m_SndFile.Samples[nSmp].nVibSweep == 0) + m_SndFile.Samples[nSmp].nVibRate = m_SndFile.Samples[nSmp].nVibDepth = 0; + } + } + + // Convert IT/MPT to XM (instruments) + if(oldTypeIsIT_MPT && newTypeIsXM) + { + for(INSTRUMENTINDEX nIns = 1; nIns <= m_SndFile.GetNumInstruments(); nIns++) + { + MODINSTRUMENT *pIns = m_SndFile.Instruments[nIns]; + if (pIns) + { + for (UINT k = 0; k < NOTE_MAX; k++) + { + if ((pIns->NoteMap[k]) && (pIns->NoteMap[k] != (BYTE)(k+1))) + { + CHANGEMODTYPE_WARNING(wBrokenNoteMap); + break; + } + } + // Convert sustain loops to sustain "points" + if(pIns->VolEnv.nSustainStart != pIns->VolEnv.nSustainEnd) + { + CHANGEMODTYPE_WARNING(wInstrumentSustainLoops); + pIns->VolEnv.nSustainEnd = pIns->VolEnv.nSustainStart; + } + if(pIns->PanEnv.nSustainStart != pIns->PanEnv.nSustainEnd) + { + CHANGEMODTYPE_WARNING(wInstrumentSustainLoops); + pIns->PanEnv.nSustainEnd = pIns->PanEnv.nSustainStart; + } + pIns->VolEnv.dwFlags &= ~ENV_CARRY; + pIns->PanEnv.dwFlags &= ~ENV_CARRY; + pIns->PitchEnv.dwFlags &= ~(ENV_CARRY|ENV_ENABLED|ENV_FILTER); + pIns->dwFlags &= ~INS_SETPANNING; + pIns->nIFC &= 0x7F; + pIns->nIFR &= 0x7F; + } + } + } + + // Instrument tunings + if(oldTypeIsMPT) + { + for(INSTRUMENTINDEX nIns = 1; nIns <= m_SndFile.GetNumInstruments(); nIns++) + { + if(m_SndFile.Instruments[nIns] != nullptr && m_SndFile.Instruments[nIns]->pTuning != nullptr) + { + m_SndFile.Instruments[nIns]->SetTuning(nullptr); + CHANGEMODTYPE_WARNING(wInstrumentTuning); + } + } + } + + if(newTypeIsMOD) + { + // Not supported in MOD format + m_SndFile.m_nDefaultSpeed = 6; + m_SndFile.m_nDefaultTempo = 125; + m_SndFile.m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; + m_SndFile.m_nSamplePreAmp = 48; + m_SndFile.m_nVSTiVolume = 48; + CHANGEMODTYPE_WARNING(wMODGlobalVars); + + // Too many samples? + if(m_SndFile.m_nSamples > 31) + { + CHANGEMODTYPE_WARNING(wMOD31Samples); + } + } + + // Is the "restart position" value allowed in this format? + if(m_SndFile.m_nRestartPos > 0 && !CSoundFile::GetModSpecifications(nNewType).hasRestartPos) + { + m_SndFile.m_nRestartPos = 0; + CHANGEMODTYPE_WARNING(wRestartPos); + } + + // Fix channel settings (pan/vol) + for(CHANNELINDEX nChn = 0; nChn < m_SndFile.m_nChannels; nChn++) + { + if(newTypeIsMOD_XM || newTypeIsS3M) + { + if(m_SndFile.ChnSettings[nChn].nVolume != 64 || (m_SndFile.ChnSettings[nChn].dwFlags & CHN_SURROUND)) + { + m_SndFile.ChnSettings[nChn].nVolume = 64; + m_SndFile.ChnSettings[nChn].dwFlags &= ~CHN_SURROUND; + CHANGEMODTYPE_WARNING(wChannelVolSurround); + } + } + if(newTypeIsXM) + { + if(m_SndFile.ChnSettings[nChn].nPan != 128) + { + m_SndFile.ChnSettings[nChn].nPan = 128; + CHANGEMODTYPE_WARNING(wChannelPanning); + } + } + } + + // Check for patterns with custom time signatures (fixing will be applied in the pattern container) + if(!CSoundFile::GetModSpecifications(nNewType).hasPatternSignatures) + { + for(PATTERNINDEX nPat = 0; nPat < m_SndFile.GetNumPatterns(); nPat++) + { + if(m_SndFile.Patterns[nPat].GetOverrideSignature()) + { + CHANGEMODTYPE_WARNING(wPatternSignatures); + break; + } + } + } + + BEGIN_CRITICAL(); + m_SndFile.ChangeModTypeTo(nNewType); + if(!newTypeIsXM_IT_MPT && (m_SndFile.m_dwSongFlags & SONG_LINEARSLIDES)) + { + CHANGEMODTYPE_WARNING(wLinearSlides); + m_SndFile.m_dwSongFlags &= ~SONG_LINEARSLIDES; + } + if(!newTypeIsIT_MPT) m_SndFile.m_dwSongFlags &= ~(SONG_ITOLDEFFECTS|SONG_ITCOMPATGXX); + if(!newTypeIsS3M) m_SndFile.m_dwSongFlags &= ~SONG_FASTVOLSLIDES; + if(!newTypeIsMOD) m_SndFile.m_dwSongFlags &= ~SONG_PT1XMODE; + if(newTypeIsS3M || newTypeIsMOD) m_SndFile.m_dwSongFlags &= ~SONG_EXFILTERRANGE; + if(oldTypeIsXM && newTypeIsIT_MPT) m_SndFile.m_dwSongFlags |= SONG_ITCOMPATGXX; + + END_CRITICAL(); + ChangeFileExtension(nNewType); + + //rewbs.cutomKeys: update effect key commands + CInputHandler *ih = CMainFrame::GetMainFrame()->GetInputHandler(); + if (newTypeIsMOD_XM) + ih->SetXMEffects(); + else + ih->SetITEffects(); + //end rewbs.cutomKeys + + // Check mod specifications + m_SndFile.m_nDefaultTempo = CLAMP(m_SndFile.m_nDefaultTempo, specs.tempoMin, specs.tempoMax); + m_SndFile.m_nDefaultSpeed = CLAMP(m_SndFile.m_nDefaultSpeed, specs.speedMin, specs.speedMax); + + for(INSTRUMENTINDEX i = 1; i <= m_SndFile.m_nInstruments; i++) if(m_SndFile.Instruments[i] != nullptr) + { + UpdateEnvelopes(&(m_SndFile.Instruments[i]->VolEnv), nWarnings); + UpdateEnvelopes(&(m_SndFile.Instruments[i]->PanEnv), nWarnings); + UpdateEnvelopes(&(m_SndFile.Instruments[i]->PitchEnv), nWarnings); + } + + CHAR s[64]; + CHANGEMODTYPE_CHECK(wInstrumentsToSamples, "All instruments have been converted to samples.\n"); + wsprintf(s, "%d patterns have been resized to 64 rows\n", nResizedPatterns); + CHANGEMODTYPE_CHECK(wResizedPatterns, s); + CHANGEMODTYPE_CHECK(wSampleSustainLoops, "New format doesn't support sample sustain loops.\n"); + CHANGEMODTYPE_CHECK(wSampleAutoVibrato, "New format doesn't support sample autovibrato.\n"); + CHANGEMODTYPE_CHECK(wMODSampleFrequency, "Sample C-5 frequencies will be lost.\n"); + CHANGEMODTYPE_CHECK(wBrokenNoteMap, "Note Mapping will be lost when saving as XM.\n"); + CHANGEMODTYPE_CHECK(wInstrumentSustainLoops, "Sustain loops were converted to sustain points.\n"); + CHANGEMODTYPE_CHECK(wInstrumentTuning, "Instrument tunings will be lost.\n"); + CHANGEMODTYPE_CHECK(wMODGlobalVars, "Default speed, tempo and global volume will be lost.\n"); + CHANGEMODTYPE_CHECK(wMOD31Samples, "Samples above 31 will be lost when saving as MOD.\n"); + CHANGEMODTYPE_CHECK(wRestartPos, "Restart position is not supported by the new format.\n"); + CHANGEMODTYPE_CHECK(wChannelVolSurround, "Channel volume and surround are not supported by the new format.\n"); + CHANGEMODTYPE_CHECK(wChannelPanning, "Channel panning is not supported by the new format.\n"); + CHANGEMODTYPE_CHECK(wPatternSignatures, "Pattern-specific time signatures are not supported by the new format.\n"); + CHANGEMODTYPE_CHECK(wLinearSlides, "Linear Frequency Slides not supported by the new format.\n"); + CHANGEMODTYPE_CHECK(wTrimmedEnvelopes, "Instrument envelopes have been shortened.\n"); + CHANGEMODTYPE_CHECK(wReleaseNode, "Instrument envelope release nodes are not supported by the new format.\n"); + + SetModified(); + GetPatternUndo()->ClearUndo(); + GetSampleUndo()->ClearUndo(); + UpdateAllViews(NULL, HINT_MODTYPE | HINT_MODGENERAL); + EndWaitCursor(); + return true; +} + +// Trim envelopes and remove release nodes. +void CModDoc::UpdateEnvelopes(INSTRUMENTENVELOPE *mptEnv, uint64 &nWarnings) +//-------------------------------------------------------------------------- +{ + // shorten instrument envelope if necessary (for mod conversion) + const UINT iEnvMax = m_SndFile.GetModSpecifications().envelopePointsMax; + + #define TRIMENV(nPat) if(nPat > iEnvMax) { nPat = iEnvMax; CHANGEMODTYPE_WARNING(wTrimmedEnvelopes); } + + TRIMENV(mptEnv->nNodes); + TRIMENV(mptEnv->nLoopStart); + TRIMENV(mptEnv->nLoopEnd); + TRIMENV(mptEnv->nSustainStart); + TRIMENV(mptEnv->nSustainEnd); + if(mptEnv->nReleaseNode != ENV_RELEASE_NODE_UNSET) + { + TRIMENV(mptEnv->nReleaseNode); + if(!m_SndFile.GetModSpecifications().hasReleaseNode) + { + mptEnv->nReleaseNode = ENV_RELEASE_NODE_UNSET; + CHANGEMODTYPE_WARNING(wReleaseNode); + } + } + + #undef TRIMENV +} + + +#undef CHANGEMODTYPE_WARNING +#undef CHANGEMODTYPE_CHECK Added: trunk/OpenMPT/mptrack/ModConvert.h =================================================================== --- trunk/OpenMPT/mptrack/ModConvert.h (rev 0) +++ trunk/OpenMPT/mptrack/ModConvert.h 2010-09-07 14:37:26 UTC (rev 701) @@ -0,0 +1,31 @@ +/* + * ModConvert.h + * ------------ + * Purpose: Headers for module conversion code. + * Notes : (currently none) + * Authors: OpenMPT Devs + * + */ + + +// Warning types +enum enmWarnings +{ + wInstrumentsToSamples = 0, + wResizedPatterns, + wSampleSustainLoops, + wSampleAutoVibrato, + wMODSampleFrequency, + wBrokenNoteMap, + wInstrumentSustainLoops, + wInstrumentTuning, + wMODGlobalVars, + wMOD31Samples, + wRestartPos, + wChannelVolSurround, + wChannelPanning, + wPatternSignatures, + wLinearSlides, + wTrimmedEnvelopes, + wReleaseNode, +}; Modified: trunk/OpenMPT/mptrack/Moddoc.h =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.h 2010-09-05 23:08:56 UTC (rev 700) +++ trunk/OpenMPT/mptrack/Moddoc.h 2010-09-07 14:37:26 UTC (rev 701) @@ -336,7 +336,7 @@ //}}AFX_VIRTUAL // for mod conversion - uint8 UpdateEnvelopes(INSTRUMENTENVELOPE *mptEnv); + void UpdateEnvelopes(INSTRUMENTENVELOPE *mptEnv, uint64 &nWarnings); // Implementation Modified: trunk/OpenMPT/mptrack/Modedit.cpp =================================================================== --- trunk/OpenMPT/mptrack/Modedit.cpp 2010-09-05 23:08:56 UTC (rev 700) +++ trunk/OpenMPT/mptrack/Modedit.cpp 2010-09-07 14:37:26 UTC (rev 701) @@ -32,438 +32,6 @@ } -////////////////////////////////////////////////////////////////////// -// Module type conversion - -bool CModDoc::ChangeModType(MODTYPE nNewType) -//------------------------------------------- -{ - CHAR s[256]; - UINT b64 = 0; - - const MODTYPE nOldType = m_SndFile.GetType(); - - if (nNewType == nOldType && nNewType == MOD_TYPE_IT){ - // Even if m_nType doesn't change, we might need to change extension in itp<->it case. - // This is because ITP is a HACK and doesn't genuinely change m_nType, - // but uses flages instead. - ChangeFileExtension(nNewType); - return true; - } - - if(nNewType == nOldType) - return true; - - const bool oldTypeIsMOD = (nOldType == MOD_TYPE_MOD), oldTypeIsXM = (nOldType == MOD_TYPE_XM), - oldTypeIsS3M = (nOldType == MOD_TYPE_S3M), oldTypeIsIT = (nOldType == MOD_TYPE_IT), - oldTypeIsMPT = (nOldType == MOD_TYPE_MPT), oldTypeIsMOD_XM = (oldTypeIsMOD || oldTypeIsXM), - oldTypeIsS3M_IT_MPT = (oldTypeIsS3M || oldTypeIsIT || oldTypeIsMPT), - oldTypeIsIT_MPT = (oldTypeIsIT || oldTypeIsMPT); - - const bool newTypeIsMOD = (nNewType == MOD_TYPE_MOD), newTypeIsXM = (nNewType == MOD_TYPE_XM), - newTypeIsS3M = (nNewType == MOD_TYPE_S3M), newTypeIsIT = (nNewType == MOD_TYPE_IT), - newTypeIsMPT = (nNewType == MOD_TYPE_MPT), newTypeIsMOD_XM = (newTypeIsMOD || newTypeIsXM), - newTypeIsS3M_IT_MPT = (newTypeIsS3M || newTypeIsIT || newTypeIsMPT), - newTypeIsXM_IT_MPT = (newTypeIsXM || newTypeIsIT || newTypeIsMPT), - newTypeIsIT_MPT = (newTypeIsIT || newTypeIsMPT); - - const CModSpecifications& specs = m_SndFile.GetModSpecifications(nNewType); - - /* - Incomplete list of MPTm-only features and extensions in the old formats: - - Features only available for MPTm: - -User definable tunings. - -Extended pattern range - -Extended sequence - -Multiple sequences ("songs") - -Pattern-specific time signatures - -Pattern effects :xy, S7D, S7E - -Long instrument envelopes - -Envelope release node (this was previously also usable in the IT format, but is deprecated in that format) - - Extended features in IT/XM/S3M/MOD(not all listed below are available in all of those formats): - -plugs - -Extended ranges for - -sample count - -instrument count - -pattern count - -sequence size - -Row count - -channel count - -tempo limits - -Extended sample/instrument properties. - -MIDI mapping directives - -Versioninfo - -channel names - -pattern names - -Alternative tempomodes - -For more info, see e.g. SaveExtendedSongProperties(), SaveExtendedInstrumentProperties() - */ - - // Check if conversion to 64 rows is necessary - for (UINT ipat=0; ipat<m_SndFile.Patterns.Size(); ipat++) - { - if ((m_SndFile.Patterns[ipat]) && (m_SndFile.Patterns[ipat].GetNumRows() != 64)) b64++; - } - if (((m_SndFile.m_nInstruments) || (b64)) && (nNewType & (MOD_TYPE_MOD|MOD_TYPE_S3M))) - { - if (::MessageBox(NULL, - "This operation will convert all instruments to samples,\n" - "and resize all patterns to 64 rows.\n" - "Do you want to continue?", "Warning", MB_YESNO | MB_ICONQUESTION) != IDYES) return false; - BeginWaitCursor(); - BEGIN_CRITICAL(); - // Converting instruments to samples - if (m_SndFile.m_nInstruments) - { - ConvertInstrumentsToSamples(); - AddToLog("WARNING: All instruments have been converted to samples.\n"); - } - // Resizing all patterns to 64 rows - UINT nPatCvt = 0; - UINT i = 0; - for (i=0; i<m_SndFile.Patterns.Size(); i++) if ((m_SndFile.Patterns[i]) && (m_SndFile.Patterns[i].GetNumRows() != 64)) - { - if(m_SndFile.Patterns[i].GetNumRows() < 64) - { - // try to save short patterns by inserting a pattern break. - m_SndFile.TryWriteEffect(i, m_SndFile.Patterns[i].GetNumRows() - 1, CMD_PATTERNBREAK, 0, false, CHANNELINDEX_INVALID, false, true); - } - m_SndFile.Patterns[i].Resize(64, false); - if (b64 < 5) - { - wsprintf(s, "WARNING: Pattern %d resized to 64 rows\n", i); - AddToLog(s); - } - nPatCvt++; - } - if (nPatCvt >= 5) - { - wsprintf(s, "WARNING: %d patterns have been resized to 64 rows\n", i); - AddToLog(s); - } - // Removing all instrument headers - for (UINT i1=0; i1<MAX_CHANNELS; i1++) - { - m_SndFile.Chn[i1].pModInstrument = nullptr; - } - for (UINT i2=0; i2<m_SndFile.m_nInstruments; i2++) if (m_SndFile.Instruments[i2]) - { - delete m_SndFile.Instruments[i2]; - m_SndFile.Instruments[i2] = nullptr; - } - m_SndFile.m_nInstruments = 0; - END_CRITICAL(); - EndWaitCursor(); - } //End if (((m_SndFile.m_nInstruments) || (b64)) && (nNewType & (MOD_TYPE_MOD|MOD_TYPE_S3M))) - BeginWaitCursor(); - - - ///////////////////////////// - // Converting pattern data - - for (PATTERNINDEX nPat = 0; nPat < m_SndFile.Patterns.Size(); nPat++) if (m_SndFile.Patterns[nPat]) - { - MODCOMMAND *m = m_SndFile.Patterns[nPat]; - - // This is used for -> MOD/XM conversion - vector<vector<MODCOMMAND::PARAM> > cEffectMemory; - cEffectMemory.resize(m_SndFile.GetNumChannels()); - for(size_t i = 0; i < m_SndFile.GetNumChannels(); i++) - { - cEffectMemory[i].resize(MAX_EFFECTS, 0); - } - - UINT nChannel = m_SndFile.m_nChannels - 1; - - for (UINT len = m_SndFile.Patterns[nPat].GetNumRows() * m_SndFile.m_nChannels; len; m++, len--) - { - nChannel = (nChannel + 1) % m_SndFile.m_nChannels; // 0...Channels - 1 - - m_SndFile.ConvertCommand(m, nOldType, nNewType); - - // Deal with effect memory for MOD/XM arpeggio - if (oldTypeIsS3M_IT_MPT && newTypeIsMOD_XM) - { - switch(m->command) - { - case CMD_ARPEGGIO: - case CMD_S3MCMDEX: - case CMD_MODCMDEX: - // No effect memory in XM / MOD - if(m->param == 0) - m->param = cEffectMemory[nChannel][m->command]; - else - cEffectMemory[nChannel][m->command] = m->param; - break; - } - } - - // Adjust effect memory for MOD files - if(newTypeIsMOD) - { - switch(m->command) - { - case CMD_PORTAMENTOUP: - case CMD_PORTAMENTODOWN: - case CMD_TONEPORTAVOL: - case CMD_VIBRATOVOL: - case CMD_VOLUMESLIDE: - // ProTracker doesn't have effect memory for these commands, so let's try to fix them - if(m->param == 0) - m->param = cEffectMemory[nChannel][m->command]; - else - cEffectMemory[nChannel][m->command] = m->param; - break; - - } - } - } - } - - //////////////////////////////////////////////// - // Converting instrument / sample / etc. data - - - // Do some sample conversion - for (SAMPLEINDEX nSmp = 1; nSmp <= m_SndFile.m_nSamples; nSmp++) - { - // No Sustain loops for MOD/S3M - if(newTypeIsMOD || newTypeIsS3M) - { - m_SndFile.Samples[nSmp].nSustainStart = m_SndFile.Samples[nSmp].nSustainEnd = 0; - } - - // Transpose to Frequency (MOD/XM to S3M/IT/MPT) - if(oldTypeIsMOD_XM && newTypeIsS3M_IT_MPT) - { - m_SndFile.Samples[nSmp].nC5Speed = CSoundFile::TransposeToFrequency(m_SndFile.Samples[nSmp].RelativeTone, m_SndFile.Samples[nSmp].nFineTune); - m_SndFile.Samples[nSmp].RelativeTone = 0; - m_SndFile.Samples[nSmp].nFineTune = 0; - } - - // Frequency to Transpose (S3M/IT/MPT to MOD/XM) - if(oldTypeIsS3M_IT_MPT && newTypeIsXM) - { - CSoundFile::FrequencyToTranspose(&m_SndFile.Samples[nSmp]); - if (!(m_SndFile.Samples[nSmp].uFlags & CHN_PANNING)) m_SndFile.Samples[nSmp].nPan = 128; - } - - if(oldTypeIsXM && newTypeIsIT_MPT) - { - // Autovibrato settings (XM to IT, where sweep 0 means "no vibrato") - if(m_SndFile.Samples[nSmp].nVibSweep == 0 && m_SndFile.Samples[nSmp].nVibRate != 0 && m_SndFile.Samples[nSmp].nVibDepth != 0) - m_SndFile.Samples[nSmp].nVibSweep = 255; - } else if(oldTypeIsIT_MPT && newTypeIsXM) - { - // Autovibrato settings (IT to XM, where sweep 0 means "no sweep") - if(m_SndFile.Samples[nSmp].nVibSweep == 0) - m_SndFile.Samples[nSmp].nVibRate = m_SndFile.Samples[nSmp].nVibDepth = 0; - } - } - - // No Autovibrato for MOD/S3M - if(newTypeIsMOD || newTypeIsS3M) - { - ctrlSmp::ResetSamples(m_SndFile, ctrlSmp::SmpResetVibrato); - } - - if (oldTypeIsXM && newTypeIsIT_MPT) m_SndFile.m_dwSongFlags |= SONG_ITCOMPATGXX; - - // Convert IT/MPT to XM (instruments) - if (oldTypeIsIT_MPT && newTypeIsXM) - { - bool bBrokenNoteMap = false, bBrokenSustainLoop = false; - for(INSTRUMENTINDEX nIns = 1; nIns <= m_SndFile.GetNumInstruments(); nIns++) - { - MODINSTRUMENT *pIns = m_SndFile.Instruments[nIns]; - if (pIns) - { - for (UINT k = 0; k < NOTE_MAX; k++) - { - if ((pIns->NoteMap[k]) && (pIns->NoteMap[k] != (BYTE)(k+1))) - { - bBrokenNoteMap = true; - break; - } - } - // Convert sustain loops to sustain "points" - if(pIns->VolEnv.nSustainStart != pIns->VolEnv.nSustainEnd) - { - pIns->VolEnv.nSustainEnd = pIns->VolEnv.nSustainStart; - bBrokenSustainLoop = true; - } - if(pIns->PanEnv.nSustainStart != pIns->PanEnv.nSustainEnd) - { - pIns->PanEnv.nSustainEnd = pIns->PanEnv.nSustainStart; - bBrokenSustainLoop = true; - } - pIns->VolEnv.dwFlags &= ~ENV_CARRY; - pIns->PanEnv.dwFlags &= ~ENV_CARRY; - pIns->PitchEnv.dwFlags &= ~(ENV_CARRY|ENV_ENABLED|ENV_FILTER); - pIns->dwFlags &= ~INS_SETPANNING; - pIns->nIFC &= 0x7F; - pIns->nIFR &= 0x7F; - } - } - if (bBrokenNoteMap) AddToLog("WARNING: Note Mapping will be lost when saving as XM.\n"); - if (bBrokenSustainLoop) AddToLog("WARNING: Sustain loops were converted to sustain points.\n"); - } - - // Instrument tunings - if(oldTypeIsMPT) - { - bool bFirstWarn = true; - for(INSTRUMENTINDEX nIns = 1; nIns <= m_SndFile.GetNumInstruments(); nIns++) - { - if(m_SndFile.Instruments[nIns] != nullptr && m_SndFile.Instruments[nIns]->pTuning != nullptr) - { - m_SndFile.Instruments[nIns]->SetTuning(nullptr); - if(bFirstWarn) - { - AddToLog("WARNING: Instrument tunings will be lost!\n"); - bFirstWarn = false; - } - } - } - } - - if(newTypeIsMOD) - { - // Not supported in MOD format - m_SndFile.m_nDefaultSpeed = 6; - m_SndFile.m_nDefaultTempo = 125; - m_SndFile.m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; - m_SndFile.m_nSamplePreAmp = 48; - m_SndFile.m_nVSTiVolume = 48; - AddToLog("WARNING: Default speed, tempo and global volume will be lost.\n"); - - // Too many samples? - if(m_SndFile.m_nSamples > 31) - { - AddToLog("WARNING: Samples above 31 will be lost when saving as MOD!\n"); - } - } - - // Is the "restart position" value allowed in this format? - if(m_SndFile.m_nRestartPos > 0 && !CSoundFile::GetModSpecifications(nNewType).hasRestartPos) - { - m_SndFile.m_nRestartPos = 0; - AddToLog("WARNING: Restart position is not supported by the new format.\n"); - } - - - // Fix channel settings (pan/vol) - for(CHANNELINDEX nChn = 0; nChn < m_SndFile.m_nChannels; nChn++) - { - if(newTypeIsMOD_XM || newTypeIsS3M) - { - m_SndFile.ChnSettings[nChn].nVolume = 64; - m_SndFile.ChnSettings[nChn].dwFlags &= ~CHN_SURROUND; - } - if(newTypeIsXM) - { - m_SndFile.ChnSettings[nChn].nPan = 128; - } - } - - // Check for patterns with custom time signatures (fixing will be applied in the pattern container) - if(!CSoundFile::GetModSpecifications(nNewType).hasPatternSignatures) - { - for(PATTERNINDEX nPat = 0; nPat < m_SndFile.GetNumPatterns(); nPat++) - { - if(m_SndFile.Patterns[nPat].GetOverrideSignature()) - { - AddToLog("WARNING: Pattern-specific time signatures are not supported by the new format.\n"); - break; - } - } - } - - BEGIN_CRITICAL(); - m_SndFile.ChangeModTypeTo(nNewType); - if (!newTypeIsXM_IT_MPT && (m_SndFile.m_dwSongFlags & SONG_LINEARSLIDES)) - { - AddToLog("WARNING: Linear Frequency Slides not supported by the new format.\n"); - m_SndFile.m_dwSongFlags &= ~SONG_LINEARSLIDES; - } - if (!newTypeIsIT_MPT) m_SndFile.m_dwSongFlags &= ~(SONG_ITOLDEFFECTS|SONG_ITCOMPATGXX); - if (!newTypeIsS3M) m_SndFile.m_dwSongFlags &= ~SONG_FASTVOLSLIDES; - if (!newTypeIsMOD) m_SndFile.m_dwSongFlags &= ~SONG_PT1XMODE; - if (newTypeIsS3M || newTypeIsMOD) m_SndFile.m_dwSongFlags &= ~SONG_EXFILTERRANGE; - END_CRITICAL(); - ChangeFileExtension(nNewType); - - //rewbs.cutomKeys: update effect key commands - CInputHandler *ih = CMainFrame::GetMainFrame()->GetInputHandler(); - if (newTypeIsMOD_XM) - ih->SetXMEffects(); - else - ih->SetITEffects(); - //end rewbs.cutomKeys - - // Check mod specifications - m_SndFile.m_nDefaultTempo = CLAMP(m_SndFile.m_nDefaultTempo, specs.tempoMin, specs.tempoMax); - m_SndFile.m_nDefaultSpeed = CLAMP(m_SndFile.m_nDefaultSpeed, specs.speedMin, specs.speedMax); - - uint8 trimmedEnvelopes = 0; - for(INSTRUMENTINDEX i = 1; i <= m_SndFile.m_nInstruments; i++) if(m_SndFile.Instruments[i] != nullptr) - { - trimmedEnvelopes |= UpdateEnvelopes(&(m_SndFile.Instruments[i]->VolEnv)); - trimmedEnvelopes |= UpdateEnvelopes(&(m_SndFile.Instruments[i]->PanEnv)); - trimmedEnvelopes |= UpdateEnvelopes(&(m_SndFile.Instruments[i]->PitchEnv)); - } - if(trimmedEnvelopes & 1) - AddToLog("WARNING: Instrument envelopes have been shortened.\n"); - if(trimmedEnvelopes & 2) - AddToLog("WARNING: Instrument envelope release nodes are not supported by the new format.\n"); - - SetModified(); - GetPatternUndo()->ClearUndo(); - GetSampleUndo()->ClearUndo(); - UpdateAllViews(NULL, HINT_MODTYPE | HINT_MODGENERAL); - EndWaitCursor(); - return true; -} - -// Trim envelopes and remove release nodes. -// If bit 0 of the return value is set, the envelope has been shortened. -// If bit 1 of the return value is set, the envelope's release node has been removed. -uint8 CModDoc::UpdateEnvelopes(INSTRUMENTENVELOPE *mptEnv) -//-------------------------------------------------------- -{ - // shorten instrument envelope if necessary (for mod conversion) - const UINT iEnvMax = m_SndFile.GetModSpecifications().envelopePointsMax; - uint8 result = 0; - - #define TRIMENV(i) if(i > iEnvMax) { i = iEnvMax; result |= 1; } - - TRIMENV(mptEnv->nNodes); - TRIMENV(mptEnv->nLoopStart); - TRIMENV(mptEnv->nLoopEnd); - TRIMENV(mptEnv->nSustainStart); - TRIMENV(mptEnv->nSustainEnd); - if(mptEnv->nReleaseNode != ENV_RELEASE_NODE_UNSET) - { - TRIMENV(mptEnv->nReleaseNode); - if(!m_SndFile.GetModSpecifications().hasReleaseNode) - { - mptEnv->nReleaseNode = ENV_RELEASE_NODE_UNSET; - result |= 2; - } - } - - #undef TRIMENV - - return result; -} - - - - - - // Change the number of channels bool CModDoc::ChangeNumChannels(UINT nNewChannels, const bool showCancelInRemoveDlg) //---------------------------------------------------------------------------------- Modified: trunk/OpenMPT/mptrack/mptrack.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack.vcproj 2010-09-05 23:08:56 UTC (rev 700) +++ trunk/OpenMPT/mptrack/mptrack.vcproj 2010-09-07 14:37:26 UTC (rev 701) @@ -376,6 +376,9 @@ RelativePath="..\soundlib\modcommand.cpp"> </File> <File + RelativePath=".\ModConvert.cpp"> + </File> + <File RelativePath=".\Moddoc.cpp"> </File> <File @@ -825,6 +828,9 @@ RelativePath="..\soundlib\modcommand.h"> </File> <File + RelativePath=".\ModConvert.h"> + </File> + <File RelativePath=".\moddoc.h"> </File> <File Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2010-09-05 23:08:56 UTC (rev 700) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2010-09-07 14:37:26 UTC (rev 701) @@ -505,6 +505,10 @@ > </File> <File + RelativePath=".\ModConvert.cpp" + > + </File> + <File RelativePath=".\Moddoc.cpp" > </File> @@ -1095,6 +1099,10 @@ > </File> <File + RelativePath=".\ModConvert.h" + > + </File> + <File RelativePath=".\moddoc.h" > </File> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |