Skip to content

Commit

Permalink
[Fix] IT: Ignore sample data in slots that don't have the "sample dat…
Browse files Browse the repository at this point in the history
…a present" flag set, if the file vaguely looks IT-made. There's a bug in IT that sometimes doesn't reset the sample length after deleting a sample (presumably). For most files this does not make an audible difference, because such sample slots are typically unused, or the sample offset pointer points at the end of the file anyway. However, a small handful of files references these deleted samples in pattern data, so a lot of unwanted noise can be heard. See https://www.un4seen.com/forum/?topic=20542.0 for reference.

git-svn-id: https://source.openmpt.org/svn/openmpt/trunk/OpenMPT@22170 56274372-70c3-4bfc-bfc3-4c3a0b034d27
  • Loading branch information
sagamusix committed Nov 12, 2024
1 parent 67725f0 commit 997a8bb
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 5 deletions.
7 changes: 3 additions & 4 deletions soundlib/ITTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,10 +530,9 @@ void ITSample::ConvertToIT(const ModSample &mptSmp, MODTYPE fromType, bool compr
// Convert an ITSample to OpenMPT's internal sample representation.
uint32 ITSample::ConvertToMPT(ModSample &mptSmp) const
{
if(memcmp(id, "IMPS", 4))
{
return 0;
}
// IT does not check for the IMPS magic, and some bad XM->IT converter out there doesn't write the magic bytes for empty sample slots.
//if(memcmp(id, "IMPS", 4))
// return 0;

mptSmp.Initialize(MOD_TYPE_IT);
mptSmp.SetDefaultCuePoints(); // For old IT/MPTM files
Expand Down
16 changes: 15 additions & 1 deletion soundlib/Load_it.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,19 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)

bool possibleXMconversion = false;

// There's a bug in IT somewhere that resets the "sample data present" flag in sample headers, but keeps the sample length
// of a previously deleted sample (presumably).
// As old ModPlug versions didn't set this flag under some circumstances (if a sample wasn't referenced by any instruments in instrument mode),
// and because there appear to be some external tools that forget to set this flag at all, we only respect the flag if the file
// vaguely looks like it was saved with IT. Some files that play garbage data if we don't do this:
// astral projection.it by Lord Jon Ray
// classic illusions.it by Blackstar
// deep in dance.it by Simply DJ
// There are many more such files but they don't reference the broken samples in their pattern data, or the sample data pointer
// points right to the end of the file, so in both cases no audible problem can be observed.
const bool muteBuggySamples = !interpretModPlugMade && fileHeader.cwtv >= 0x0100 && fileHeader.cwtv <= 0x0217
&& (fileHeader.cwtv < 0x0207 || fileHeader.reserved != 0);

// Reading Samples
m_nSamples = std::min(static_cast<SAMPLEINDEX>(fileHeader.smpnum), static_cast<SAMPLEINDEX>(MAX_SAMPLES - 1));
bool lastSampleCompressed = false, anyADPCM = false;
Expand All @@ -792,9 +805,10 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
ITSample sampleHeader;
if(smpPos[i] > 0 && file.Seek(smpPos[i]) && file.ReadStruct(sampleHeader))
{
// IT does not check for the IMPS magic, and some bad XM->IT converter out there doesn't write the magic bytes for empty sample slots.
ModSample &sample = Samples[i + 1];
size_t sampleOffset = sampleHeader.ConvertToMPT(sample);
if(muteBuggySamples && !(sampleHeader.flags & ITSample::sampleDataPresent))
sample.nLength = 0;

m_szNames[i + 1] = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name);

Expand Down

0 comments on commit 997a8bb

Please sign in to comment.