From: <sag...@us...> - 2014-11-15 15:44:41
|
Revision: 4598 http://sourceforge.net/p/modplug/code/4598 Author: saga-games Date: 2014-11-15 15:44:29 +0000 (Sat, 15 Nov 2014) Log Message: ----------- [New/Mod] Added a compatible playback mode for S3M files: When enabled, OpenMPT emulates certain ST3 quirks as it did until now (linked pattern effect memory and ignored effects on muted channels). For files made with less ST3-compatible trackers, this flag is disabled automatically, so that the original (non-compatible) handling is used instead. S3M files made with OpenMPT always have this enabled, the flag is not saved in S3M files. Modified Paths: -------------- trunk/OpenMPT/mptrack/ModConvert.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/dlg_misc.cpp trunk/OpenMPT/soundlib/Load_s3m.cpp trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndfile.h Modified: trunk/OpenMPT/mptrack/ModConvert.cpp =================================================================== --- trunk/OpenMPT/mptrack/ModConvert.cpp 2014-11-13 15:07:12 UTC (rev 4597) +++ trunk/OpenMPT/mptrack/ModConvert.cpp 2014-11-15 15:44:29 UTC (rev 4598) @@ -51,11 +51,11 @@ // Trim envelopes and remove release nodes. -void UpdateEnvelopes(InstrumentEnvelope &mptEnv, CSoundFile &sndFile, std::bitset<wNumWarnings> &warnings) -//-------------------------------------------------------------------------------------------------------- +static void UpdateEnvelopes(InstrumentEnvelope &mptEnv, const CModSpecifications &specs, std::bitset<wNumWarnings> &warnings) +//--------------------------------------------------------------------------------------------------------------------------- { // shorten instrument envelope if necessary (for mod conversion) - const uint8 envMax = sndFile.GetModSpecifications().envelopePointsMax; + const uint8 envMax = specs.envelopePointsMax; #define TRIMENV(envLen) if(envLen > envMax) { envLen = envMax; CHANGEMODTYPE_WARNING(wTrimmedEnvelopes); } @@ -66,7 +66,7 @@ TRIMENV(mptEnv.nSustainEnd); if(mptEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET) { - if(sndFile.GetModSpecifications().hasReleaseNode) + if(specs.hasReleaseNode) { TRIMENV(mptEnv.nReleaseNode); } else @@ -76,7 +76,7 @@ } } - #undef TRIMENV +#undef TRIMENV } @@ -462,7 +462,7 @@ } // Is the "restart position" value allowed in this format? - if(m_SndFile.m_nRestartPos > 0 && !CSoundFile::GetModSpecifications(nNewType).hasRestartPos) + if(m_SndFile.m_nRestartPos > 0 && !specs.hasRestartPos) { // Try to fix it by placing a pattern jump command in the pattern. if(!RestartPosToPattern()) @@ -495,7 +495,7 @@ } // Check for patterns with custom time signatures (fixing will be applied in the pattern container) - if(!CSoundFile::GetModSpecifications(nNewType).hasPatternSignatures) + if(!specs.hasPatternSignatures) { for(PATTERNINDEX nPat = 0; nPat < m_SndFile.Patterns.Size(); nPat++) { @@ -525,12 +525,12 @@ m_SndFile.PrecomputeSampleLoops(false); // Song flags - if(!(CSoundFile::GetModSpecifications(nNewType).songFlags & SONG_LINEARSLIDES) && m_SndFile.m_SongFlags[SONG_LINEARSLIDES]) + if(!(specs.songFlags & SONG_LINEARSLIDES) && m_SndFile.m_SongFlags[SONG_LINEARSLIDES]) { CHANGEMODTYPE_WARNING(wLinearSlides); } if(oldTypeIsXM && newTypeIsIT_MPT) m_SndFile.m_SongFlags.set(SONG_ITCOMPATGXX); - m_SndFile.m_SongFlags &= (CSoundFile::GetModSpecifications(nNewType).songFlags | SONG_PLAY_FLAGS); + m_SndFile.m_SongFlags &= (specs.songFlags | SONG_PLAY_FLAGS); // Adjust mix levels if(newTypeIsMOD || newTypeIsS3M) @@ -542,8 +542,8 @@ CHANGEMODTYPE_WARNING(wMixmode); } - // Automatically enable compatible mode when converting from MOD and S3M, since it's automatically enabled in those formats. - if((nOldType & (MOD_TYPE_MOD | MOD_TYPE_S3M)) && (nNewType & (MOD_TYPE_XM | MOD_TYPE_IT))) + // Automatically enable compatible mode when converting from MOD, since it's automatically enabled there and should be used in the other formats as well. + if((nOldType & MOD_TYPE_MOD) && (nNewType & (MOD_TYPE_XM | MOD_TYPE_IT | MOD_TYPE_S3M))) { m_SndFile.SetModFlag(MSF_COMPATIBLE_PLAY, true); } @@ -561,9 +561,9 @@ for(INSTRUMENTINDEX i = 1; i <= m_SndFile.GetNumInstruments(); i++) if(m_SndFile.Instruments[i] != nullptr) { - UpdateEnvelopes(m_SndFile.Instruments[i]->VolEnv, m_SndFile, warnings); - UpdateEnvelopes(m_SndFile.Instruments[i]->PanEnv, m_SndFile, warnings); - UpdateEnvelopes(m_SndFile.Instruments[i]->PitchEnv, m_SndFile, warnings); + UpdateEnvelopes(m_SndFile.Instruments[i]->VolEnv, specs, warnings); + UpdateEnvelopes(m_SndFile.Instruments[i]->PanEnv, specs, warnings); + UpdateEnvelopes(m_SndFile.Instruments[i]->PitchEnv, specs, warnings); } // XM requires instruments, so we create them right away. Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2014-11-13 15:07:12 UTC (rev 4597) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2014-11-15 15:44:29 UTC (rev 4598) @@ -713,7 +713,7 @@ m_SndFile.m_nSamplePreAmp = m_SndFile.m_nVSTiVolume = 128; }*/ - if(m_SndFile.GetType() & (MOD_TYPE_IT | MOD_TYPE_XM)) + if(m_SndFile.GetType() & (MOD_TYPE_IT | MOD_TYPE_XM | MOD_TYPE_S3M)) { m_SndFile.SetModFlag(MSF_COMPATIBLE_PLAY, true); } Modified: trunk/OpenMPT/mptrack/dlg_misc.cpp =================================================================== --- trunk/OpenMPT/mptrack/dlg_misc.cpp 2014-11-13 15:07:12 UTC (rev 4597) +++ trunk/OpenMPT/mptrack/dlg_misc.cpp 2014-11-15 15:44:29 UTC (rev 4598) @@ -182,18 +182,19 @@ if(ITorMPT) { GetDlgItem(IDC_CHK_COMPATPLAY)->SetWindowText(_T("More Impulse Tracker &compatible playback")); + } else if(XM) + { + GetDlgItem(IDC_CHK_COMPATPLAY)->SetWindowText(_T("More Fasttracker 2 &compatible playback")); } else { - GetDlgItem(IDC_CHK_COMPATPLAY)->SetWindowText(_T("More Fasttracker 2 &compatible playback")); + GetDlgItem(IDC_CHK_COMPATPLAY)->SetWindowText(_T("More ScreamTracker 3 &compatible playback")); } - GetDlgItem(IDC_CHK_COMPATPLAY)->ShowWindow(XMorITorMPT); - GetDlgItem(IDC_CHK_MIDICCBUG)->ShowWindow(XMorITorMPT); - GetDlgItem(IDC_CHK_OLDRANDOM)->ShowWindow(ITorMPT); - GetDlgItem(IDC_CHK_OLDPITCH)->ShowWindow(XMorITorMPT); + GetDlgItem(IDC_CHK_OLDRANDOM)->ShowWindow(!XM); GetDlgItem(IDC_CHK_FT2VOLRAMP)->ShowWindow(XM); // Deprecated flags are greyed out if they are not being used. + GetDlgItem(IDC_CHK_COMPATPLAY)->EnableWindow(type != MOD_TYPE_MOD ? TRUE : FALSE); GetDlgItem(IDC_CHK_MIDICCBUG)->EnableWindow(sndFile.GetModFlag(MSF_MIDICC_BUGEMULATION) ? TRUE : FALSE); GetDlgItem(IDC_CHK_OLDRANDOM)->EnableWindow((ITorMPT && sndFile.GetModFlag(MSF_OLDVOLSWING)) ? TRUE : FALSE); GetDlgItem(IDC_CHK_OLDPITCH)->EnableWindow(sndFile.GetModFlag(MSF_OLD_MIDI_PITCHBENDS) ? TRUE : FALSE); @@ -242,36 +243,17 @@ } // Mixmode Box - GetDlgItem(IDC_TEXT_MIXMODE)->ShowWindow(XMorITorMPT); - m_PlugMixBox.ShowWindow(XMorITorMPT); + GetDlgItem(IDC_TEXT_MIXMODE)->EnableWindow(XMorITorMPT); + m_PlugMixBox.EnableWindow(XMorITorMPT); // Tempo mode box - m_TempoModeBox.ShowWindow(XMorITorMPT); - GetDlgItem(IDC_ROWSPERBEAT)->ShowWindow(XMorITorMPT); - GetDlgItem(IDC_ROWSPERMEASURE)->ShowWindow(XMorITorMPT); - GetDlgItem(IDC_TEXT_ROWSPERBEAT)->ShowWindow(XMorITorMPT); - GetDlgItem(IDC_TEXT_ROWSPERMEASURE)->ShowWindow(XMorITorMPT); - GetDlgItem(IDC_TEXT_TEMPOMODE)->ShowWindow(XMorITorMPT); - GetDlgItem(IDC_FRAME_TEMPOMODE)->ShowWindow(XMorITorMPT); - - // Version info - GetDlgItem(IDC_FRAME_MPTVERSION)->ShowWindow(XMorITorMPT); - GetDlgItem(IDC_TEXT_CREATEDWITH)->ShowWindow(XMorITorMPT); - GetDlgItem(IDC_TEXT_SAVEDWITH)->ShowWindow(XMorITorMPT); - GetDlgItem(IDC_EDIT_CREATEDWITH)->ShowWindow(XMorITorMPT); - GetDlgItem(IDC_EDIT_SAVEDWITH)->ShowWindow(XMorITorMPT); - - // Window height - some parts of the dialog won't be visible for all formats - RECT rWindow; - GetWindowRect(&rWindow); - - UINT iHeight; - int nItemID = (XMorITorMPT) ? IDC_FRAME_MPTVERSION : IDC_FRAME_MODFLAGS; - RECT rFrame; - GetDlgItem(nItemID)->GetWindowRect(&rFrame); - iHeight = rFrame.bottom - rWindow.top + 12; - MoveWindow(rWindow.left, rWindow.top, rWindow.right - rWindow.left, iHeight); - + m_TempoModeBox.EnableWindow(XMorITorMPT); + GetDlgItem(IDC_ROWSPERBEAT)->EnableWindow(XMorITorMPT); + GetDlgItem(IDC_ROWSPERMEASURE)->EnableWindow(XMorITorMPT); + GetDlgItem(IDC_TEXT_ROWSPERBEAT)->EnableWindow(XMorITorMPT); + GetDlgItem(IDC_TEXT_ROWSPERMEASURE)->EnableWindow(XMorITorMPT); + GetDlgItem(IDC_TEXT_TEMPOMODE)->EnableWindow(XMorITorMPT); + GetDlgItem(IDC_FRAME_TEMPOMODE)->EnableWindow(XMorITorMPT); } @@ -298,7 +280,7 @@ CString error; error.Format("Error: Maximum number of channels for this module type is %d.", maxChans); Reporting::Warning(error); - return FALSE; + return false; } if(maxChans < sndFile.GetNumChannels()) @@ -348,10 +330,10 @@ sndFile.SetMixLevels(static_cast<mixLevels>(m_PlugMixBox.GetItemData(sel))); } + sndFile.SetModFlags(0); + if(IsDlgButtonChecked(IDC_CHK_COMPATPLAY)) sndFile.SetModFlag(MSF_COMPATIBLE_PLAY, true); if(m_nType & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM)) { - sndFile.SetModFlags(0); - if(IsDlgButtonChecked(IDC_CHK_COMPATPLAY)) sndFile.SetModFlag(MSF_COMPATIBLE_PLAY, true); if(IsDlgButtonChecked(IDC_CHK_MIDICCBUG)) sndFile.SetModFlag(MSF_MIDICC_BUGEMULATION, true); if(IsDlgButtonChecked(IDC_CHK_OLDRANDOM)) sndFile.SetModFlag(MSF_OLDVOLSWING, true); if(IsDlgButtonChecked(IDC_CHK_OLDPITCH)) sndFile.SetModFlag(MSF_OLD_MIDI_PITCHBENDS, true); Modified: trunk/OpenMPT/soundlib/Load_s3m.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_s3m.cpp 2014-11-13 15:07:12 UTC (rev 4597) +++ trunk/OpenMPT/soundlib/Load_s3m.cpp 2014-11-15 15:44:29 UTC (rev 4598) @@ -223,6 +223,7 @@ } else { trackerStr = "Scream Tracker"; + SetModFlag(MSF_COMPATIBLE_PLAY, true); } break; case S3MFileHeader::trkImagoOrpheus: @@ -243,12 +244,15 @@ case S3MFileHeader::trkOpenMPT: trackerStr = "OpenMPT"; m_dwLastSavedWithVersion = (fileHeader.cwtv & S3MFileHeader::versionMask) << 16; + SetModFlag(MSF_COMPATIBLE_PLAY, true); break; case S3MFileHeader::trkBeRoTracker: madeWithTracker = "BeRoTracker"; + SetModFlag(MSF_COMPATIBLE_PLAY, true); break; case S3MFileHeader::trkCreamTracker: madeWithTracker = "CreamTracker"; + SetModFlag(MSF_COMPATIBLE_PLAY, true); break; } if(!trackerStr.empty()) @@ -562,6 +566,11 @@ fileHeader.dosEof = S3MFileHeader::idEOF; fileHeader.fileType = S3MFileHeader::idS3MType; + if(!IsCompatibleMode(TRK_SCREAMTRACKER)) + { + AddToLog("Compatible playback mode is currently disabled. This setting is not saved in S3M files and will be enabled automatically once the file is reloaded."); + } + // Orders ORDERINDEX writeOrders = Order.GetLengthTailTrimmed(); if(writeOrders < 2) Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2014-11-13 15:07:12 UTC (rev 4597) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2014-11-15 15:44:29 UTC (rev 4598) @@ -292,7 +292,7 @@ ModCommand *nextRow = nullptr; for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); p++, pChn++, nChn++) if(!p->IsEmpty()) { - if((GetType() == MOD_TYPE_S3M) && ChnSettings[nChn].dwFlags[CHN_MUTE]) // not even effects are processed on muted S3M channels + if(IsCompatibleMode(TRK_SCREAMTRACKER) && ChnSettings[nChn].dwFlags[CHN_MUTE]) // not even effects are processed on muted S3M channels continue; ModCommand::COMMAND command = p->command; ModCommand::PARAM param = p->param; @@ -1939,7 +1939,7 @@ //:xy --> note delay until tick x, note cut at tick x+y nStartTick = (param & 0xF0) >> 4; const UINT cutAtTick = nStartTick + (param & 0x0F); - NoteCut(nChn, cutAtTick, IsCompatibleMode(TRK_IMPULSETRACKER | TRK_SCREAMTRACKER)); + NoteCut(nChn, cutAtTick, IsCompatibleMode(TRK_IMPULSETRACKER) || GetType() == MOD_TYPE_S3M); } else if ((cmd == CMD_MODCMDEX) || (cmd == CMD_S3MCMDEX)) { if ((!param) && (GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT))) param = pChn->nOldCmdEx; else pChn->nOldCmdEx = param; @@ -1978,7 +1978,7 @@ // Pattern Loop ? if((((param & 0xF0) == 0x60 && cmd == CMD_MODCMDEX) || ((param & 0xF0) == 0xB0 && cmd == CMD_S3MCMDEX)) - && !(GetType() == MOD_TYPE_S3M && ChnSettings[nChn].dwFlags[CHN_MUTE])) // not even effects are processed on muted S3M channels + && !(IsCompatibleMode(TRK_SCREAMTRACKER) && ChnSettings[nChn].dwFlags[CHN_MUTE])) // not even effects are processed on muted S3M channels { ROWINDEX nloop = PatternLoop(pChn, param & 0x0F); if (nloop != ROWINDEX_INVALID) @@ -2352,7 +2352,7 @@ #endif // MODPLUG_TRACKER } - if((GetType() == MOD_TYPE_S3M) && ChnSettings[nChn].dwFlags[CHN_MUTE]) // not even effects are processed on muted S3M channels + if(IsCompatibleMode(TRK_SCREAMTRACKER) && ChnSettings[nChn].dwFlags[CHN_MUTE]) // not even effects are processed on muted S3M channels continue; // Volume Column Effect (except volume & panning) @@ -2613,7 +2613,7 @@ if(m_PlayState.m_nTickCount) break; if((!pChn->nPeriod || !pChn->nNote) && (pChn->pModInstrument == nullptr || !pChn->pModInstrument->HasValidMIDIChannel()) // Plugin arpeggio - && !IsCompatibleMode(TRK_IMPULSETRACKER | TRK_SCREAMTRACKER)) break; + && !IsCompatibleMode(TRK_IMPULSETRACKER) && GetType() != MOD_TYPE_S3M) break; if (!param && (GetType() & (MOD_TYPE_XM | MOD_TYPE_MOD))) break; // Only important when editing MOD/XM files (000 effects are removed when loading files where this means "no effect") pChn->nCommand = CMD_ARPEGGIO; if (param) pChn->nArpeggio = param; @@ -2746,7 +2746,7 @@ // S3M/IT Sxx Extended Commands case CMD_S3MCMDEX: - if(GetType() == MOD_TYPE_S3M && param == 0) + if(IsCompatibleMode(TRK_SCREAMTRACKER) && param == 0) { param = pChn->nArpeggio; // S00 uses the last non-zero effect parameter as memory, like other effects including Arpeggio, so we "borrow" our memory there. } @@ -2913,7 +2913,7 @@ break; } - if(GetType() == MOD_TYPE_S3M && param != 0) + if(IsCompatibleMode(TRK_SCREAMTRACKER) && param != 0) { UpdateS3MEffectMemory(pChn, param); } @@ -3971,7 +3971,7 @@ } // S3M/IT compatibility: Note Cut really cuts notes and does not just mute them (so that following volume commands could restore the sample) // Test case: scx.it - NoteCut(nChn, param, IsCompatibleMode(TRK_IMPULSETRACKER | TRK_SCREAMTRACKER)); + NoteCut(nChn, param, IsCompatibleMode(TRK_IMPULSETRACKER) || GetType() == MOD_TYPE_S3M); break; // SDx: Note Delay // SEx: Pattern Delay for x rows @@ -4879,7 +4879,7 @@ { // IT compatibility 10. Pattern loops (+ same fix for MOD / S3M files) // When finishing a pattern loop, the next loop without a dedicated SB0 starts on the first row after the previous loop. - if(IsCompatibleMode(TRK_IMPULSETRACKER | TRK_PROTRACKER | TRK_SCREAMTRACKER)) + if(IsCompatibleMode(TRK_IMPULSETRACKER) || (GetType() & (MOD_TYPE_MOD | MOD_TYPE_S3M))) { pChn->nPatternLoop = m_PlayState.m_nRow + 1; } @@ -4891,7 +4891,7 @@ // First time we get into the loop => Set loop count. // IT compatibility 10. Pattern loops (+ same fix for XM / MOD / S3M files) - if(!IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2 | TRK_PROTRACKER | TRK_SCREAMTRACKER)) + if(!IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2) && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_S3M))) { ModChannel *p = m_PlayState.Chn; for(CHANNELINDEX i = 0; i < GetNumChannels(); i++, p++) if (p != pChn) Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2014-11-13 15:07:12 UTC (rev 4597) +++ trunk/OpenMPT/soundlib/Sndfile.h 2014-11-15 15:44:29 UTC (rev 4598) @@ -295,8 +295,8 @@ // Hint 2: Always returns true for MOD / S3M format (if that is the format of the current file) bool IsCompatibleMode(MODTYPE type) const { - if(GetType() & type & (MOD_TYPE_MOD | MOD_TYPE_S3M)) - return true; // S3M and MOD format don't have compatibility flags, so we will always return true + if(GetType() & type & MOD_TYPE_MOD) + return true; // MOD format doesn't have compatibility flags, so we will always return true return ((GetType() & type) && GetModFlag(MSF_COMPATIBLE_PLAY)); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |