From: <sag...@us...> - 2009-08-24 20:58:07
|
Revision: 341 http://modplug.svn.sourceforge.net/modplug/?rev=341&view=rev Author: saga-games Date: 2009-08-24 20:57:36 +0000 (Mon, 24 Aug 2009) Log Message: ----------- [Fix] MOD / XM Loading / Saving: More intelligent conversion of Speed / Tempo commands [Fix] MOD Loading: Last pattern was not loading in .MODs that have no samples [Ref] Made some CSoundFile functions private Modified Paths: -------------- trunk/OpenMPT/mptrack/typedefs.h trunk/OpenMPT/soundlib/Load_mod.cpp trunk/OpenMPT/soundlib/Load_psm.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h Modified: trunk/OpenMPT/mptrack/typedefs.h =================================================================== --- trunk/OpenMPT/mptrack/typedefs.h 2009-08-24 11:43:54 UTC (rev 340) +++ trunk/OpenMPT/mptrack/typedefs.h 2009-08-24 20:57:36 UTC (rev 341) @@ -34,6 +34,8 @@ typedef uint32 ROWINDEX; const ROWINDEX ROWINDEX_MAX = uint32_max; typedef uint16 CHANNELINDEX; + const CHANNELINDEX CHANNELINDEX_MAX = uint16_max; + const CHANNELINDEX CHANNELINDEX_INVALID = CHANNELINDEX_MAX; typedef uint16 ORDERINDEX; const ORDERINDEX ORDERINDEX_MAX = uint16_max; const ORDERINDEX ORDERINDEX_INVALID = ORDERINDEX_MAX; Modified: trunk/OpenMPT/soundlib/Load_mod.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp 2009-08-24 11:43:54 UTC (rev 340) +++ trunk/OpenMPT/soundlib/Load_mod.cpp 2009-08-24 20:57:36 UTC (rev 341) @@ -41,7 +41,7 @@ case 0x0D: command = CMD_PATTERNBREAK; param = ((param >> 4) * 10) + (param & 0x0F); break; case 0x0E: command = CMD_MODCMDEX; break; case 0x0F: command = (param <= (UINT)((m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) ? 0x1F : 0x20)) ? CMD_SPEED : CMD_TEMPO; - if ((param == 0xFF) && (m_nSamples == 15)) command = 0; break; //<rewbs> what the hell is this?! :) //<jojo> it's the "stop tune" command! :-P + if ((param == 0xFF) && (m_nSamples == 15) && (m_nType & MOD_TYPE_MOD)) command = 0; break; //<rewbs> what the hell is this?! :) //<jojo> it's the "stop tune" command! :-P // Extension for XM extended effects case 'G' - 55: command = CMD_GLOBALVOLUME; break; //16 case 'H' - 55: command = CMD_GLOBALVOLSLIDE; if (param & 0xF0) param &= 0xF0; break; @@ -97,16 +97,24 @@ case CMD_TREMOLO: command = 0x07; break; case CMD_PANNING8: command = 0x08; - if (bXM) + if(m_nType & MOD_TYPE_S3M) { - if (!(m_nType & (MOD_TYPE_IT|MOD_TYPE_MPT)) && (m_nType != MOD_TYPE_XM) && (param <= 0x80)) + if(param <= 0x80) { - param <<= 1; - if (param > 255) param = 255; + param = min(param << 1, 0xFF); } - } else - { - if ((m_nType & (MOD_TYPE_IT|MOD_TYPE_MPT)) || (m_nType == MOD_TYPE_XM)) param >>= 1; + else if(param == 0xA4) + { + if(bCompatibilityExport || !bXM) + { + command = param = 0; + } + else + { + command = 'X' - 55; + param = 91; + } + } } break; case CMD_OFFSET: command = 0x09; break; @@ -115,8 +123,8 @@ case CMD_VOLUME: command = 0x0C; break; case CMD_PATTERNBREAK: command = 0x0D; param = ((param / 10) << 4) | (param % 10); break; case CMD_MODCMDEX: command = 0x0E; break; - case CMD_SPEED: command = 0x0F; if (param > 0x20) param = 0x20; break; - case CMD_TEMPO: if (param >= 0x20) { command = 0x0F; break; } + case CMD_SPEED: command = 0x0F; param = min(param, (bXM) ? 0x1F : 0x20); break; + case CMD_TEMPO: command = 0x0F; param = max(param, (bXM) ? 0x20 : 0x21); break; case CMD_GLOBALVOLUME: command = 'G' - 55; break; case CMD_GLOBALVOLSLIDE: command = 'H' - 55; break; case CMD_KEYOFF: command = 'K' - 55; break; @@ -355,7 +363,7 @@ if (ipat < MAX_PATTERNS) { if(Patterns.Insert(ipat, 64)) break; - if (dwMemPos + m_nChannels*256 >= dwMemLength) break; + if (dwMemPos + m_nChannels * 256 > dwMemLength) break; MODCOMMAND *m = Patterns[ipat]; LPCBYTE p = lpStream + dwMemPos; for (UINT j=m_nChannels*64; j; m++,p+=4,j--) @@ -371,18 +379,21 @@ } dwMemPos += m_nChannels*256; } - // Reading instruments + + // Reading samples DWORD dwErrCheck = 0; - for (UINT ismp=1; ismp<=m_nSamples; ismp++) if (Samples[ismp].nLength) + for (UINT ismp = 1; ismp <= m_nSamples; ismp++) if (Samples[ismp].nLength) { - LPSTR p = (LPSTR)(lpStream+dwMemPos); + LPSTR p = (LPSTR)(lpStream + dwMemPos); UINT flags = 0; - if (dwMemPos + 5 >= dwMemLength) break; - if (!_strnicmp(p, "ADPCM", 5)) + if (dwMemPos + 5 <= dwMemLength) { - flags = 3; - p += 5; - dwMemPos += 5; + if (!_strnicmp(p, "ADPCM", 5)) + { + flags = 3; + p += 5; + dwMemPos += 5; + } } DWORD dwSize = ReadSample(&Samples[ismp], flags, p, dwMemLength - dwMemPos); if (dwSize) @@ -394,7 +405,7 @@ #ifdef MODPLUG_TRACKER return true; #else - return (dwErrCheck) ? TRUE : FALSE; + return (dwErrCheck) ? true : false; #endif } Modified: trunk/OpenMPT/soundlib/Load_psm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_psm.cpp 2009-08-24 11:43:54 UTC (rev 340) +++ trunk/OpenMPT/soundlib/Load_psm.cpp 2009-08-24 20:57:36 UTC (rev 341) @@ -77,17 +77,9 @@ }; #pragma pack() -BYTE convert_psm_porta(BYTE param, bool bNewFormat) +inline BYTE convert_psm_porta(BYTE param, bool bNewFormat) { - if(bNewFormat) - { - return param; - } - else - { - if(param < 4) return param | 0xF0; - else return (param >> 2); - } + return ((bNewFormat) ? (param) : ((param < 4) ? (param | 0xF0) : (param >> 2))); } bool CSoundFile::ReadPSM(const LPCBYTE lpStream, const DWORD dwMemLength) @@ -109,7 +101,6 @@ // Yep, this seems to be a valid file. m_nType = MOD_TYPE_PSM; - //m_dwSongFlags |= SONG_LINEARSLIDES; // TODO m_nChannels = 0; dwMemPos += 12; @@ -207,6 +198,7 @@ break; } } + // Sinaria song dates if(version == 800211 || version == 940902 || version == 940903 || version == 940906 || version == 940914 || version == 941213) bNewFormat = true; Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2009-08-24 11:43:54 UTC (rev 340) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2009-08-24 20:57:36 UTC (rev 341) @@ -3040,3 +3040,152 @@ return *p; } +/* Try to write an (volume) effect in a given channel or any channel of a pattern in a specific row. + Usage: nPat - Pattern that should be modified + nRow - Row that should be modified + nEffect - (Volume) Effect that should be written + nParam - Effect that should be written + bIsVolumeEffect - Indicates whether the given effect is a volume effect or not + nChn - Channel that should be modified - use CHANNELINDEX_INVALID to allow all channels of the given row + bAllowMultipleEffects - If false, No effect will be written if an effect of the same type is already present in the channel(s) + bAllowNextRow - Indicates whether it is allowed to use the next row if there's no space for the effect + bRetry - For internal use only. Indicates whether an effect "rewrite" has already taken place (for recursive calls) +*/ +bool CSoundFile::TryWriteEffect(PATTERNINDEX nPat, ROWINDEX nRow, BYTE nEffect, BYTE nParam, bool bIsVolumeEffect, CHANNELINDEX nChn, bool bAllowMultipleEffects, bool bAllowNextRow, bool bRetry) +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +{ + // NOTE: Effect remapping is only implemented for a few basic effects. + CHANNELINDEX nScanChnMin = nChn, nScanChnMax = nChn; + MODCOMMAND *p = Patterns[nPat], *m; + + // Scan all channels + if(nChn == CHANNELINDEX_INVALID) + { + nScanChnMin = 0; + nScanChnMax = m_nChannels - 1; + } + + // Scan channel(s) for same effect type - if an effect of the same type is already present, exit. + if(bAllowMultipleEffects == false) + { + for(CHANNELINDEX i = nScanChnMin; i <= nScanChnMax; i++) + { + m = p + nRow * m_nChannels + i; + if(!bIsVolumeEffect && m->command == nEffect) + return true; + if(bIsVolumeEffect && m->volcmd == nEffect) + return true; + } + } + + // Easy case: check if there's some space left to put the effect somewhere + for(CHANNELINDEX i = nScanChnMin; i <= nScanChnMax; i++) + { + m = p + nRow * m_nChannels + i; + if(!bIsVolumeEffect && m->command == CMD_NONE) + { + m->command = nEffect; + m->param = nParam; + return true; + } + if(bIsVolumeEffect && m->volcmd == VOLCMD_NONE) + { + m->volcmd = nEffect; + m->vol = nParam; + return true; + } + } + + // Ok, apparently there's no space. If we haven't tried already, try to map it to the volume column or effect column instead. + if(bRetry == true) { + // Move some effects that also work in the volume column, so there's place for our new effect. + if(!bIsVolumeEffect) + { + for(CHANNELINDEX i = nScanChnMin; i <= nScanChnMax; i++) + { + m = p + nRow * m_nChannels + i; + switch(m->command) + { + case CMD_VOLUME: + m->volcmd = VOLCMD_VOLUME; + m->vol = m->param; + m->command = nEffect; + m->param = nParam; + return true; + + case CMD_PANNING8: + if(m_nType & MOD_TYPE_S3M && nParam > 0x80) + break; + + m->volcmd = VOLCMD_VOLUME; + m->command = nEffect; + + if(m_nType & MOD_TYPE_S3M) + { + m->vol = m->param >> 1; + } + else + { + m->vol = (m->param >> 2) + 1; + } + + m->param = nParam; + return true; + } + } + } + + // Let's try it again by writing into the "other" effect column. + BYTE nNewEffect = CMD_NONE; + if(bIsVolumeEffect) + { + switch(nEffect) + { + case VOLCMD_PANNING: + nNewEffect = CMD_PANNING8; + if(m_nType & MOD_TYPE_S3M) + nParam <<= 1; + else + nParam = min(nParam << 2, 0xFF); + break; + case VOLCMD_VOLUME: + nNewEffect = CMD_VOLUME; + break; + } + } else + { + switch(nEffect) + { + case CMD_PANNING8: + nNewEffect = VOLCMD_PANNING; + if(m_nType & MOD_TYPE_S3M) + { + if(nParam <= 0x80) + nParam >>= 1; + else + nNewEffect = CMD_NONE; + } + else + { + nParam = (nParam >> 2) + 1; + } + break; + case CMD_VOLUME: + nNewEffect = CMD_VOLUME; + break; + } + } + if(nNewEffect != CMD_NONE) + { + if(TryWriteEffect(nPat, nRow, nNewEffect, nParam, !bIsVolumeEffect, nChn, bAllowMultipleEffects, bAllowNextRow, false) == true) return true; + } + } + + // Try in the next row if possible (this may also happen if we already retried) + if(bAllowNextRow && (nRow + 1 < Patterns[nPat].GetNumRows())) + { + return TryWriteEffect(nPat, nRow + 1, nEffect, nParam, bIsVolumeEffect, nChn, bAllowMultipleEffects, bAllowNextRow, bRetry); + } + + return false; +} Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2009-08-24 11:43:54 UTC (rev 340) +++ trunk/OpenMPT/soundlib/Sndfile.h 2009-08-24 20:57:36 UTC (rev 341) @@ -1148,7 +1148,15 @@ void CheckNNA(UINT nChn, UINT instr, int note, BOOL bForceCut); void NoteChange(UINT nChn, int note, BOOL bPorta=FALSE, BOOL bResetEnv=TRUE, BOOL bManual=FALSE); void InstrumentChange(MODCHANNEL *pChn, UINT instr, BOOL bPorta=FALSE,BOOL bUpdVol=TRUE,BOOL bResetEnv=TRUE); + // Channel Effects + void KeyOff(UINT nChn); + // Global Effects + void SetTempo(UINT param, bool setAsNonModcommand = false); + void SetSpeed(UINT param); + +private: + // Channel Effects void PortamentoUp(MODCHANNEL *pChn, UINT param, const bool fineAsRegular = false); void PortamentoDown(MODCHANNEL *pChn, UINT param, const bool fineAsRegular = false); void MidiPortamento(MODCHANNEL *pChn, int param); @@ -1170,7 +1178,6 @@ void RetrigNote(UINT nChn, UINT param, UINT offset=0); //rewbs.volOffset: added last param void SampleOffset(UINT nChn, UINT param, bool bPorta); //rewbs.volOffset: moved offset code to own method void NoteCut(UINT nChn, UINT nTick); - void KeyOff(UINT nChn); int PatternLoop(MODCHANNEL *, UINT param); void ExtendedMODCommands(UINT nChn, UINT param); void ExtendedS3MCommands(UINT nChn, UINT param); @@ -1180,12 +1187,14 @@ void SetupChannelFilter(MODCHANNEL *pChn, BOOL bReset, int flt_modifier=256) const; // Low-Level effect processing void DoFreqSlide(MODCHANNEL *pChn, LONG nFreqSlide); - // Global Effects - void SetTempo(UINT param, bool setAsNonModcommand = false); - void SetSpeed(UINT param); void GlobalVolSlide(UINT param, UINT * nOldGlobalVolSlide); DWORD IsSongFinished(UINT nOrder, UINT nRow) const; BOOL IsValidBackwardJump(UINT nStartOrder, UINT nStartRow, UINT nJumpOrder, UINT nJumpRow) const; +public: + + // Write pattern effect functions + bool TryWriteEffect(PATTERNINDEX nPat, ROWINDEX nRow, BYTE nEffect, BYTE nParam, bool bIsVolumeEffect, CHANNELINDEX nChn = CHANNELINDEX_INVALID, bool bAllowMultipleEffects = true, bool bAllowNextRow = false, bool bRetry = true); + // Read/Write sample functions char GetDeltaValue(char prev, UINT n) const { return (char)(prev + CompressionTable[n & 0x0F]); } UINT PackSample(int &sample, int next); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |