From: <sag...@us...> - 2009-08-30 22:27:26
|
Revision: 350 http://modplug.svn.sourceforge.net/modplug/?rev=350&view=rev Author: saga-games Date: 2009-08-30 22:27:15 +0000 (Sun, 30 Aug 2009) Log Message: ----------- [Fix] S3M Loader: Small modifications to pattern loader to load somewhat broken S3M files [Fix] S3M Loader: Don't reset global volume to max if it is min for "new" modules [Fix] S3M Loader: Smarter Zxx conversion [Fix] S3M Saver: Was completely broken for a reason that's beyond my understanding :) (order size only has to be multiple of 2, not 16!) [Imp] Mod Conversion: Convert 500/600 commands properly from MOD to any format, Adjust sustain loops for XM files, removed XM arpeggio conversion (it might be unwanted) Modified Paths: -------------- trunk/OpenMPT/mptrack/Modedit.cpp trunk/OpenMPT/soundlib/Load_s3m.cpp Modified: trunk/OpenMPT/mptrack/Modedit.cpp =================================================================== --- trunk/OpenMPT/mptrack/Modedit.cpp 2009-08-30 14:29:58 UTC (rev 349) +++ trunk/OpenMPT/mptrack/Modedit.cpp 2009-08-30 22:27:15 UTC (rev 350) @@ -396,15 +396,22 @@ } // End if (oldTypeIsIT_MPT && newTypeIsS3M) - //////////////////////// - // Convert XM arpeggio - if(m->command == CMD_ARPEGGIO && (newTypeIsXM || oldTypeIsXM)) + + /////////////////////////////////////////////////// + // Convert MOD to anything - adjust effect memory + if (oldTypeIsMOD) { - // swap notes - m->param = ((m->param & 0x0F) << 4) | ((m->param & 0xF0) >> 4); - } + switch(m->command) + { + case CMD_TONEPORTAVOL: // lacks memory -> 500 is the same as 300 + if(m->param == 0x00) m->command = CMD_TONEPORTAMENTO; + break; + case CMD_VIBRATOVOL: // lacks memory -> 600 is the same as 400 + if(m->param == 0x00) m->command = CMD_VIBRATO; + break; + } + } // End if (oldTypeIsMOD && newTypeIsXM) - ///////////////////////////////////////////////////////////////////////////////// // Convert anything to MOD - remove volume column, adjust retrig, effect memory if (newTypeIsMOD) @@ -664,26 +671,38 @@ CSoundFile::FrequencyToTranspose(&m_SndFile.Samples[i]); if (!(m_SndFile.Samples[i].uFlags & CHN_PANNING)) m_SndFile.Samples[i].nPan = 128; } - BOOL bBrokenNoteMap = FALSE; - for (UINT j=1; j<=m_SndFile.m_nInstruments; j++) + bool bBrokenNoteMap = false, bBrokenSustainLoop = false; + for (UINT j = 1; j <= m_SndFile.m_nInstruments; j++) { MODINSTRUMENT *pIns = m_SndFile.Instruments[j]; if (pIns) { - for (UINT k=0; k<NOTE_MAX; k++) + for (UINT k = 0; k < NOTE_MAX; k++) { if ((pIns->NoteMap[k]) && (pIns->NoteMap[k] != (BYTE)(k+1))) { - bBrokenNoteMap = TRUE; + 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->dwFlags &= ~(ENV_SETPANNING|ENV_VOLCARRY|ENV_PANCARRY|ENV_PITCHCARRY|ENV_FILTER|ENV_PITCH); 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"); } if(newTypeIsMOD) Modified: trunk/OpenMPT/soundlib/Load_s3m.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_s3m.cpp 2009-08-30 14:29:58 UTC (rev 349) +++ trunk/OpenMPT/soundlib/Load_s3m.cpp 2009-08-30 22:27:15 UTC (rev 350) @@ -18,43 +18,6 @@ extern WORD S3MFineTuneTable[16]; -static void HandleZxx(uint8& nType, MODCOMMAND* const m) -//------------------------------------------------------------------- -{ - if(nType == 0) - { - CString str; - str.Format(GetStrI18N("The S3M file contains Zxx effect. " - "It can be processed in the following ways:\n" - "Yes : Convert Zxx to S8x(set panning)-effects (PixPlay)\n" - "No : Remove Zxx effects\n" - "Cancel: Keep Zxx effects\n" - "\nNote that options (yes) and (no) modify the loaded pattern data." - )); - const int nResult = ::AfxMessageBox(str, MB_YESNOCANCEL|MB_ICONINFORMATION); - - if(nResult == IDYES) - nType = 2; - else if(nResult == IDNO) - nType = 3; - else - nType = 1; - } - if(nType != 1) - { - if(nType == 2) - { - m->command = CMD_S3MCMDEX; - m->param = 0x80 + (m->param & 0xF); - } - else - { - m->command = 0; - m->param = 0; - } - } -} - ////////////////////////////////////////////////////// // ScreamTracker S3M file support @@ -264,6 +227,7 @@ DWORD dwMemPos; BYTE insflags[128], inspack[128]; S3MFILEHEADER psfh = *(S3MFILEHEADER *)lpStream; + bool bKeepMidiMacros = false; psfh.reserved1 = LittleEndianW(psfh.reserved1); psfh.ordnum = LittleEndianW(psfh.ordnum); @@ -278,8 +242,26 @@ if (psfh.scrm != 0x4D524353) return false; if((psfh.cwtv & 0xF000) == 0x5000) // OpenMPT Version number (Major.Minor) + { m_dwLastSavedWithVersion = (psfh.cwtv & 0x0FFF) << 16; + bKeepMidiMacros = true; // simply load Zxx commands + } + if(psfh.cwtv == 0x1320 && psfh.special == 0 && (psfh.ordnum & 0x0F) == 0 && psfh.ultraclicks == 0 && (psfh.flags & ~0x50) == 0) + { + // MPT 1.16 and older versions of OpenMPT + m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 16, 00, 00); + bKeepMidiMacros = true; // simply load Zxx commands + } + if((psfh.cwtv & 0xF000) >= 0x2000) + { + // 2xyy - Orpheus, 3xyy - IT, 4xyy - Schism, 5xyy - OpenMPT + bKeepMidiMacros = true; // simply load Zxx commands + } + + if(!bKeepMidiMacros) // Remove macros so they don't interfere with other tunes + memset(&m_MidiCfg, 0, sizeof(m_MidiCfg)); + dwMemPos = 0x60; m_nType = MOD_TYPE_S3M; memset(m_szNames,0,sizeof(m_szNames)); @@ -292,7 +274,8 @@ m_nDefaultTempo = CLAMP(m_nDefaultTempo, 32, 255); // Global Volume m_nDefaultGlobalVolume = psfh.globalvol << 2; - if ((!m_nDefaultGlobalVolume) || (m_nDefaultGlobalVolume > 256)) m_nDefaultGlobalVolume = 256; + if(!m_nDefaultGlobalVolume && psfh.cwtv < 0x1320) m_nDefaultGlobalVolume = 256; // not very reliable, but it fixes a few tunes + if(m_nDefaultGlobalVolume > 256) m_nDefaultGlobalVolume = 256; m_nSamplePreAmp = psfh.mastervol & 0x7F; // Bit 8 = Stereo (we always use stereo) // Channels m_nChannels = 4; @@ -386,8 +369,14 @@ //ASSERT(iLooplength == 0 || iLooplength > 4); } } + + /* Try to find out if Zxx commands are supposed to be panning commands (PixPlay). + We won't convert if there are not enough Zxx commands, too "high" Zxx commands + or there are only "left" or "right" pannings (we assume that stereo should be somewhat balanced) */ + bool bDoNotConvertZxx = false; + int iZxxCountRight = 0, iZxxCountLeft = 0; + // Reading patterns - uint8 nZxxHandling = 0; for (UINT iPat=0; iPat<patnum; iPat++) { UINT nInd = ((DWORD)ptr[nins+iPat]) << 4; @@ -402,8 +391,9 @@ MODCOMMAND *p = Patterns[iPat]; UINT row = 0; UINT j = 0; - while (j < len) + while (row < 64) // this fixes ftp://us.aminet.net/pub/aminet/mods/8voic/s3m_hunt.lha (was: while (j < len)) { + if(j + nInd + 1 >= dwMemLength) break; BYTE b = src[j++]; if (!b) { @@ -416,6 +406,7 @@ MODCOMMAND *m = &p[row*m_nChannels+chn]; if (b & 0x20) { + if(j + nInd + 2 >= dwMemLength) break; m->note = src[j++]; if (m->note < 0xF0) m->note = (m->note & 0x0F) + 12*(m->note >> 4) + 13; else if (m->note == 0xFF) m->note = NOTE_NONE; @@ -423,6 +414,7 @@ } if (b & 0x40) { + if(j + nInd + 1 >= dwMemLength) break; UINT vol = src[j++]; if ((vol >= 128) && (vol <= 192)) { @@ -437,12 +429,22 @@ } if (b & 0x80) { + if(j + nInd + 2 >= dwMemLength) break; m->command = src[j++]; m->param = src[j++]; if (m->command) S3MConvert(m, FALSE); if(m->command == CMD_MIDI) { - HandleZxx(nZxxHandling, m); + if(m->param > 0x0F) + { + // PixPlay has Z00 to Z0F panning, so we ignore this. + bDoNotConvertZxx = true; + } + else + { + if(m->param < 0x08) iZxxCountLeft++; + if(m->param > 0x08) iZxxCountRight++; + } } } } else @@ -451,10 +453,27 @@ if (b & 0x40) j++; if (b & 0x80) j += 2; } - if (j >= len) break; } } } + + if((UINT)(iZxxCountLeft + iZxxCountRight) >= m_nChannels && !bDoNotConvertZxx && (iZxxCountLeft - iZxxCountRight > -(int)m_nChannels)) + { + // there are enough Zxx commands, so let's assume this was made to be played with PixPlay + for(PATTERNINDEX nPat = 0; nPat < Patterns.Size(); nPat++) if(Patterns[nPat]) + { + MODCOMMAND *m = Patterns[nPat]; + for(UINT len = PatternSize[nPat] * m_nChannels; len; m++, len--) + { + if(m->command == CMD_MIDI) + { + m->command = CMD_S3MCMDEX; + m->param |= 0x80; + } + } + } + } + // Reading samples for (UINT iRaw=1; iRaw<=insnum; iRaw++) if ((Samples[iRaw].nLength) && (insfile[iRaw])) { @@ -469,11 +488,6 @@ m_nMaxPeriod = 32767; if (psfh.flags & 0x10) m_dwSongFlags |= SONG_AMIGALIMITS; - if(nZxxHandling != 0 && nZxxHandling != 1 && GetpModDoc() != 0) - { - GetpModDoc()->SetModified(); - GetpModDoc()->SetShowSaveDialog(true); - } return true; } @@ -507,15 +521,14 @@ header[0x1B] = 0; header[0x1C] = 0x1A; header[0x1D] = 0x10; - // Changes to 1.17.02.53: - // -Try to save whole sequence instead of stopping on first empty order. - // -With more than 0xF0 orders, limit sequence to 0xF0 instead of just masking with 0xF0. - //TODO: Check whether the 0xF0 mask is correct. - // (there are two bytes reserved from the header, so why 0xF0 mask?). - //nbo = (GetNumPatterns() + 15) & 0xF0; + nbo = Order.GetLengthTailTrimmed(); - if(nbo > 0xF0) nbo = 0xF0; - if (!nbo) nbo = 1; + if (nbo < 2) + nbo = 2; + else if (nbo & 1) // number of orders must be even + nbo++; + nbo = (nbo + 15) & 0xF0; // TODO why does it not work otherwise? nbo should be multiple of 2, not 16! + if(nbo > 0xF0) nbo = 0xF0; // sequence too long header[0x20] = nbo & 0xFF; header[0x21] = nbo >> 8; nbi = m_nInstruments; @@ -536,7 +549,7 @@ // Following: One nibble = Major version, one byte = Minor version (hex) MptVersion::VersionNum vVersion = MptVersion::num; header[0x28] = (BYTE)((vVersion >> 16) & 0xFF); // the "17" in OpenMPT 1.17 - header[0x29] = 0x50 | (BYTE)((vVersion >> 24) & 0x0F); // the "1" in OpenMPT 1.17 + OpenMPT Identifier 5 (works only for versions up to 15.99 :)) + header[0x29] = 0x50 | (BYTE)((vVersion >> 24) & 0x0F); // the "1." in OpenMPT 1.17 + OpenMPT Identifier 5 (works only for versions up to 9.99 :)) header[0x2A] = 0x02; // Version = 1 => Signed samples header[0x2B] = 0x00; header[0x2C] = 'S'; @@ -548,7 +561,7 @@ header[0x32] = CLAMP(m_nDefaultTempo, 32, 255); header[0x33] = CLAMP(m_nSamplePreAmp, 0x10, 0x7F) | 0x80; // Bit 8 = Stereo header[0x34] = 0x10; // 16 Channels for UltraClick removal - header[0x35] = 0xFC; + header[0x35] = 0xFC; // Write pan positions for (i=0; i<32; i++) { if (i < m_nChannels) @@ -562,7 +575,7 @@ memset(patptr, 0, sizeof(patptr)); memset(insptr, 0, sizeof(insptr)); UINT ofs0 = 0x60 + nbo; - UINT ofs1 = ((0x60 + nbo + nbi*2 + nbp*2 + 15) & 0xFFF0) + 0x20; + UINT ofs1 = ((0x60 + nbo + nbi * 2 + nbp * 2 + 15) & 0xFFF0) + ((header[0x35] == 0xFC) ? 0x20 : 0); UINT ofs = ofs1; for (i=0; i<nbi; i++) insptr[i] = (WORD)((ofs + i*0x50) / 16); for (i=0; i<nbp; i++) patptr[i] = (WORD)((ofs + nbi*0x50) / 16); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |