From: <sv...@op...> - 2024-09-26 12:57:33
|
Author: sagamusix Date: Thu Sep 26 14:57:21 2024 New Revision: 21758 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=21758 Log: Merged revision(s) 21685, 21755-21756 from trunk/OpenMPT: [Fix] OKT: Disable loop on type "B" samples if they're used on a mixed channel. Fixes sinfonia.okta (https://www.un4seen.com/forum/?topic=15448.msg143764#msg143764). ........ [Fix] OKT: Sample in last sample slot was never loaded. ........ [Fix] OKT: Of course there are modules in the wild where r21685 is not sufficient... so we keep a looped and unloop copy of type "B" samples now. Fixes super turri song.okta (https://www.un4seen.com/forum/?topic=15448.300#msg143803). ........ Modified: branches/OpenMPT-1.30/ (props changed) branches/OpenMPT-1.30/soundlib/Load_okt.cpp Modified: branches/OpenMPT-1.30/soundlib/Load_okt.cpp ============================================================================== --- branches/OpenMPT-1.30/soundlib/Load_okt.cpp Thu Sep 26 14:56:25 2024 (r21757) +++ branches/OpenMPT-1.30/soundlib/Load_okt.cpp Thu Sep 26 14:57:21 2024 (r21758) @@ -30,7 +30,7 @@ }; uint32be signature; // IFF chunk name - uint32be chunksize; // chunk size without header + uint32be chunkSize; // Chunk size without header }; MPT_BINARY_STRUCT(OktIffChunk, 8) @@ -38,11 +38,11 @@ struct OktSample { char name[20]; - uint32be length; // length in bytes + uint32be length; // Length in bytes uint16be loopStart; // *2 for real value uint16be loopLength; // ditto - uint16be volume; // default volume - uint16be type; // 7-/8-bit sample + uint16be volume; // Default volume + uint16be type; // 7-/8-bit sample (0: 7-bit, only usable on paired channels ["8" in GUI], 1: 8-bit, only usable on unpaired channels ["4" in GUI], 2: 7-bit, usable on all channels ["B" in GUI]) }; MPT_BINARY_STRUCT(OktSample, 32) @@ -51,7 +51,8 @@ // Parse the sample header block static void ReadOKTSamples(FileReader &chunk, CSoundFile &sndFile) { - sndFile.m_nSamples = std::min(static_cast<SAMPLEINDEX>(chunk.BytesLeft() / sizeof(OktSample)), static_cast<SAMPLEINDEX>(MAX_SAMPLES - 1)); + static_assert(MAX_SAMPLES >= 72); // For copies of type "B" samples + sndFile.m_nSamples = std::min(static_cast<SAMPLEINDEX>(chunk.BytesLeft() / sizeof(OktSample)), SAMPLEINDEX(36)); for(SAMPLEINDEX smp = 1; smp <= sndFile.GetNumSamples(); smp++) { @@ -66,6 +67,7 @@ mptSmp.nVolume = std::min(oktSmp.volume.get(), uint16(64)) * 4u; mptSmp.nLength = oktSmp.length & ~1; mptSmp.cues[0] = oktSmp.type; // Temporary storage for pattern reader, will be reset later + mptSmp.cues[1] = 0; // Parse loops const SmpLength loopStart = oktSmp.loopStart * 2; const SmpLength loopLength = oktSmp.loopLength * 2; @@ -122,20 +124,27 @@ if(note > 0 && note <= 36) { m.note = note + (NOTE_MIDDLEC - 13); + if(pairedChn[chn] && m.note >= NOTE_MIDDLEC + 22) + m.note = NOTE_MIDDLEC + 21; + m.instr = instr + 1; if(m.instr > 0 && m.instr <= sndFile.GetNumSamples()) { - const auto &sample = sndFile.GetSample(m.instr); + auto &sample = sndFile.GetSample(m.instr); // Default volume only works on raw Paula channels if(pairedChn[chn] && sample.nVolume < 256) - { m.volcmd = VOLCMD_VOLUME; m.vol = 64; - } + // If channel and sample type don't match, stop this channel (add 100 to the instrument number to make it understandable what happened during import) if((sample.cues[0] == 1 && pairedChn[chn] != 0) || (sample.cues[0] == 0 && pairedChn[chn] == 0)) { m.instr += 100; + } else if(sample.cues[0] == 2 && pairedChn[chn] && sample.uFlags[CHN_SUSTAINLOOP]) + { + // Type "B" sample: Loops only work on raw Paula channels + sample.cues[1] = 1; + m.instr += 36; } } } @@ -353,7 +362,7 @@ if(!file.ReadStruct(iffHead)) break; - FileReader chunk = file.ReadChunk(iffHead.chunksize); + FileReader chunk = file.ReadChunk(iffHead.chunkSize); if(!chunk.IsValid()) continue; @@ -461,12 +470,14 @@ // Read samples size_t fileSmp = 0; - for(SAMPLEINDEX smp = 1; smp < m_nSamples; smp++) + const SAMPLEINDEX origSamples = m_nSamples; + for(SAMPLEINDEX smp = 1; smp <= origSamples; smp++) { if(fileSmp >= sampleChunks.size() || !(loadFlags & loadSampleData)) break; ModSample &mptSample = Samples[smp]; + const bool needCopy = mptSample.cues[1] != 0; mptSample.SetDefaultCuePoints(); if(mptSample.nLength == 0) continue; @@ -481,6 +492,20 @@ SampleIO::signedPCM) .ReadSample(mptSample, sampleChunks[fileSmp]); + if(needCopy) + { + // Type "B" samples (can play on both paired and unpaired channels) can have loop information, + // which can only be used on unpaired channels. So we need a looped and unlooped copy of the sample. + m_nSamples = std::max(m_nSamples, static_cast<SAMPLEINDEX>(smp + 36)); + ModSample ©Sample = Samples[smp + 36]; + copySample.Initialize(); + copySample.nC5Speed = mptSample.nC5Speed; + copySample.nVolume = mptSample.nVolume; + copySample.nLength = mptSample.nLength; + copySample.CopyWaveform(mptSample); + m_szNames[smp + 36] = m_szNames[smp]; + } + fileSmp++; } |