From: <sv...@op...> - 2024-06-07 23:19:50
|
Author: sagamusix Date: Sat Jun 8 01:19:39 2024 New Revision: 20949 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20949 Log: [Ref] CSoundFile::InitializeGlobals now takes the channel count in addition to the format to initialize to. With almost all supported formats, we can determine the correct channel count very early on, making it easier to initialize the correct number of channel headers, and allowing us to remove CSoundFile::InitializeChannels completely. In a second step, the fixed-size ChnSettings array and m_nChannels can be merged into a ChnSettings vector. [Reg] SymMOD: Require first chunk to be number of channels to simplify initialization. In practice, all SymMOD files are structured like that. Modified: trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/Undo.cpp trunk/OpenMPT/mptrack/View_gen.cpp trunk/OpenMPT/soundlib/Load_667.cpp trunk/OpenMPT/soundlib/Load_669.cpp trunk/OpenMPT/soundlib/Load_amf.cpp trunk/OpenMPT/soundlib/Load_ams.cpp trunk/OpenMPT/soundlib/Load_c67.cpp trunk/OpenMPT/soundlib/Load_dbm.cpp trunk/OpenMPT/soundlib/Load_digi.cpp trunk/OpenMPT/soundlib/Load_dmf.cpp trunk/OpenMPT/soundlib/Load_dsm.cpp trunk/OpenMPT/soundlib/Load_dsym.cpp trunk/OpenMPT/soundlib/Load_dtm.cpp trunk/OpenMPT/soundlib/Load_far.cpp trunk/OpenMPT/soundlib/Load_fmt.cpp trunk/OpenMPT/soundlib/Load_ftm.cpp trunk/OpenMPT/soundlib/Load_gdm.cpp trunk/OpenMPT/soundlib/Load_gmc.cpp trunk/OpenMPT/soundlib/Load_gt2.cpp trunk/OpenMPT/soundlib/Load_ice.cpp trunk/OpenMPT/soundlib/Load_imf.cpp trunk/OpenMPT/soundlib/Load_ims.cpp trunk/OpenMPT/soundlib/Load_it.cpp trunk/OpenMPT/soundlib/Load_itp.cpp trunk/OpenMPT/soundlib/Load_kris.cpp trunk/OpenMPT/soundlib/Load_mdl.cpp trunk/OpenMPT/soundlib/Load_med.cpp trunk/OpenMPT/soundlib/Load_mid.cpp trunk/OpenMPT/soundlib/Load_mo3.cpp trunk/OpenMPT/soundlib/Load_mod.cpp trunk/OpenMPT/soundlib/Load_mt2.cpp trunk/OpenMPT/soundlib/Load_mtm.cpp trunk/OpenMPT/soundlib/Load_mus_km.cpp trunk/OpenMPT/soundlib/Load_okt.cpp trunk/OpenMPT/soundlib/Load_plm.cpp trunk/OpenMPT/soundlib/Load_psm.cpp trunk/OpenMPT/soundlib/Load_ptm.cpp trunk/OpenMPT/soundlib/Load_puma.cpp trunk/OpenMPT/soundlib/Load_rtm.cpp trunk/OpenMPT/soundlib/Load_s3m.cpp trunk/OpenMPT/soundlib/Load_sfx.cpp trunk/OpenMPT/soundlib/Load_stk.cpp trunk/OpenMPT/soundlib/Load_stm.cpp trunk/OpenMPT/soundlib/Load_stp.cpp trunk/OpenMPT/soundlib/Load_symmod.cpp trunk/OpenMPT/soundlib/Load_uax.cpp trunk/OpenMPT/soundlib/Load_ult.cpp trunk/OpenMPT/soundlib/Load_wav.cpp trunk/OpenMPT/soundlib/Load_xm.cpp trunk/OpenMPT/soundlib/Load_xmf.cpp trunk/OpenMPT/soundlib/ModChannel.cpp trunk/OpenMPT/soundlib/ModChannel.h trunk/OpenMPT/soundlib/S3MTools.h trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/load_j2b.cpp Modified: trunk/OpenMPT/mptrack/Moddoc.cpp ============================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/mptrack/Moddoc.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -643,14 +643,6 @@ // Set up mix levels m_SndFile.m_PlayState.m_nGlobalVolume = m_SndFile.m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; m_SndFile.m_nSamplePreAmp = m_SndFile.m_nVSTiVolume = 48; - - for (CHANNELINDEX nChn = 0; nChn < MAX_BASECHANNELS; nChn++) - { - m_SndFile.ChnSettings[nChn].dwFlags.reset(); - m_SndFile.ChnSettings[nChn].nVolume = 64; - m_SndFile.ChnSettings[nChn].nPan = 128; - m_SndFile.m_PlayState.Chn[nChn].nGlobalVol = 64; - } // Setup LRRL panning scheme for MODs m_SndFile.SetupMODPanning(); } @@ -1178,9 +1170,9 @@ { PLUGINDEX plug = pIns->nMixPlug; // First try intrument VST if((!plug || plug > MAX_MIXPLUGINS) // No good plug yet - && currentChn < MAX_BASECHANNELS) // Chan OK + && currentChn < m_SndFile.ChnSettings.size()) { - plug = m_SndFile.ChnSettings[currentChn].nMixPlugin;// Then try Channel VST + plug = m_SndFile.ChnSettings[currentChn].nMixPlugin; // Then try Channel VST } if(plug && plug <= MAX_MIXPLUGINS) Modified: trunk/OpenMPT/mptrack/Undo.cpp ============================================================================== --- trunk/OpenMPT/mptrack/Undo.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/mptrack/Undo.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -152,7 +152,7 @@ if(storeChannelInfo) { - undo.channelInfo.assign(std::begin(sndFile.ChnSettings) + firstChn, std::begin(sndFile.ChnSettings) + firstChn + numChns); + undo.channelInfo.assign(sndFile.ChnSettings.begin() + firstChn, sndFile.ChnSettings.begin() + firstChn + numChns); } buffer.push_back(std::move(undo)); Modified: trunk/OpenMPT/mptrack/View_gen.cpp ============================================================================== --- trunk/OpenMPT/mptrack/View_gen.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/mptrack/View_gen.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -371,7 +371,7 @@ { const CHANNELINDEX nChn = m_nActiveTab * CHANNELS_IN_TAB + ichn; const BOOL bEnable = (nChn < sndFile.GetNumChannels()) ? TRUE : FALSE; - if(nChn < MAX_BASECHANNELS) + if(nChn < sndFile.GetNumChannels()) { const auto &chnSettings = sndFile.ChnSettings[nChn]; // Text @@ -605,7 +605,7 @@ const CSoundFile &sndFile = GetDocument()->GetSoundFile(); for(CHANNELINDEX ichn = 0; ichn < CHANNELS_IN_TAB; ichn++) { - if(const CHANNELINDEX nChn = m_nActiveTab * CHANNELS_IN_TAB + ichn; nChn < MAX_BASECHANNELS) + if(const CHANNELINDEX nChn = m_nActiveTab * CHANNELS_IN_TAB + ichn; nChn < sndFile.GetNumChannels()) { PLUGINDEX sel = sndFile.ChnSettings[nChn].nMixPlugin ? sndFile.ChnSettings[nChn].nMixPlugin - 1 : PLUGINDEX_INVALID; m_CbnEffects[ichn].Update(PluginComboBox::Config{PluginComboBox::ShowNoPlugin}.Hint(hint, pObj).CurrentSelection(sel), sndFile); Modified: trunk/OpenMPT/soundlib/Load_667.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_667.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_667.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -77,11 +77,10 @@ if(loadFlags == onlyVerifyHeader) return true; - InitializeGlobals(MOD_TYPE_S3M); + InitializeGlobals(MOD_TYPE_S3M, 18); m_SongFlags.set(SONG_IMPORTED); Order().SetDefaultTempoInt(150); Order().SetDefaultSpeed(fileHeader.speed); - m_nChannels = 18; m_nSamples = 64; ReadOrderFromFile<uint8>(Order(), file, fileHeader.numOrders); @@ -91,8 +90,6 @@ return false; } - InitializeChannels(); - for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { // Reorder OPL patch bytes (interleave modulator and carrier) Modified: trunk/OpenMPT/soundlib/Load_669.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_669.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_669.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -135,12 +135,11 @@ return false; } - InitializeGlobals(MOD_TYPE_669); + InitializeGlobals(MOD_TYPE_669, 8); m_nMinPeriod = 28 << 2; m_nMaxPeriod = 1712 << 3; Order().SetDefaultTempoInt(78); Order().SetDefaultSpeed(4); - m_nChannels = 8; m_playBehaviour.set(kPeriodsAreHertz); m_SongFlags.set(SONG_FASTPORTAS | SONG_AUTO_TONEPORTA); #ifdef MODPLUG_TRACKER @@ -179,7 +178,6 @@ // Set up panning for(CHANNELINDEX chn = 0; chn < 8; chn++) { - ChnSettings[chn].Reset(); ChnSettings[chn].nPan = (chn & 1) ? 0xD0 : 0x30; } Modified: trunk/OpenMPT/soundlib/Load_amf.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_amf.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_amf.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -125,10 +125,8 @@ return true; } - InitializeGlobals(MOD_TYPE_AMF0); - InitializeChannels(); + InitializeGlobals(MOD_TYPE_AMF0, 8); SetupMODPanning(true); - m_nChannels = 8; Order().SetDefaultSpeed(fileHeader.defaultSpeed); Order().SetDefaultTempoInt(fileHeader.defaultTempo); m_nSamples = fileHeader.numSamples; @@ -573,8 +571,7 @@ if(loadFlags == onlyVerifyHeader) return true; - InitializeGlobals(MOD_TYPE_AMF); - InitializeChannels(); + InitializeGlobals(MOD_TYPE_AMF, (fileSignature.version < 9) ? 4 : fileHeader.numChannels); if(isDMF) { @@ -588,13 +585,11 @@ } m_modFormat.charset = mpt::Charset::CP437; - m_nChannels = fileHeader.numChannels; m_nSamples = fileHeader.numSamples; if(fileSignature.version < 9) { // Old format revisions are fixed to 4 channels - m_nChannels = 4; for(CHANNELINDEX chn = 0; chn < 4; chn++) { ChnSettings[chn].nPan = (chn & 1) ? 0xC0 : 0x40; Modified: trunk/OpenMPT/soundlib/Load_ams.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_ams.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_ams.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -400,11 +400,9 @@ return true; } - InitializeGlobals(MOD_TYPE_AMS); - InitializeChannels(); + InitializeGlobals(MOD_TYPE_AMS, (fileHeader.channelConfig & 0x1F) + 1); m_SongFlags = SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS; - m_nChannels = (fileHeader.channelConfig & 0x1F) + 1; m_nSamples = fileHeader.numSamps; SetupMODPanning(true); @@ -774,12 +772,11 @@ return true; } - InitializeGlobals(MOD_TYPE_AMS); + InitializeGlobals(MOD_TYPE_AMS, 32); m_songName = std::move(songName); m_nInstruments = fileHeader.numIns; - m_nChannels = 32; SetupMODPanning(true); m_modFormat.formatName = U_("Velvet Studio"); @@ -912,7 +909,6 @@ // Channel names for(CHANNELINDEX chn = 0; chn < 32; chn++) { - ChnSettings[chn].Reset(); file.ReadSizedString<uint8le, mpt::String::spacePadded>(ChnSettings[chn].szName); } Modified: trunk/OpenMPT/soundlib/Load_c67.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_c67.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_c67.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -157,8 +157,7 @@ } } - InitializeGlobals(MOD_TYPE_S3M); - InitializeChannels(); + InitializeGlobals(MOD_TYPE_S3M, 4 + 9); m_modFormat.formatName = U_("CDFM"); m_modFormat.type = U_("c67"); @@ -169,7 +168,6 @@ Order().SetDefaultTempoInt(143); Order().SetRestartPos(fileHeader.restartPos); m_nSamples = 64; - m_nChannels = 4 + 9; m_playBehaviour.set(kOPLBeatingOscillators); m_SongFlags.set(SONG_IMPORTED); Modified: trunk/OpenMPT/soundlib/Load_dbm.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_dbm.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_dbm.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -347,10 +347,8 @@ return false; } - InitializeGlobals(MOD_TYPE_DBM); - InitializeChannels(); + InitializeGlobals(MOD_TYPE_DBM, Clamp<uint16, uint16>(infoData.channels, 1, MAX_BASECHANNELS)); // Note: MAX_BASECHANNELS is currently 127, but DBPro 2 supports up to 128 channels, DBPro 3 apparently up to 254. m_SongFlags = SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS; - m_nChannels = Clamp<uint16, uint16>(infoData.channels, 1, MAX_BASECHANNELS); // note: MAX_BASECHANNELS is currently 127, but DBPro 2 supports up to 128 channels, DBPro 3 apparently up to 254. m_nInstruments = std::min(static_cast<INSTRUMENTINDEX>(infoData.instruments), static_cast<INSTRUMENTINDEX>(MAX_INSTRUMENTS - 1)); m_nSamples = std::min(static_cast<SAMPLEINDEX>(infoData.samples), static_cast<SAMPLEINDEX>(MAX_SAMPLES - 1)); m_playBehaviour.set(kSlidesAtSpeed1); Modified: trunk/OpenMPT/soundlib/Load_digi.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_digi.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_digi.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -119,10 +119,7 @@ } // Globals - InitializeGlobals(MOD_TYPE_DIGI); - InitializeChannels(); - - m_nChannels = fileHeader.numChannels; + InitializeGlobals(MOD_TYPE_DIGI, fileHeader.numChannels); m_nSamples = 31; m_nSamplePreAmp = 256 / m_nChannels; Modified: trunk/OpenMPT/soundlib/Load_dmf.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_dmf.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_dmf.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -901,23 +901,6 @@ return true; } - InitializeGlobals(MOD_TYPE_DMF); - - m_modFormat.formatName = MPT_UFORMAT("Delusion Digital Music Format v{}")(fileHeader.version); - m_modFormat.madeWithTracker = fileHeader.version == 10 ? UL_("X-Tracker 32") : UL_("X-Tracker"); - m_modFormat.type = U_("dmf"); - m_modFormat.charset = mpt::Charset::CP437; - - m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songname); - m_songArtist = mpt::ToUnicode(mpt::Charset::CP437, mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.composer)); - - FileHistory mptHistory; - mptHistory.loadDate.day = Clamp(fileHeader.creationDay, uint8(1), uint8(31)); - mptHistory.loadDate.month = Clamp(fileHeader.creationMonth, uint8(1), uint8(12)); - mptHistory.loadDate.year = 1900 + fileHeader.creationYear; - m_FileHistory.clear(); - m_FileHistory.push_back(mptHistory); - // Go through all chunks now... cannot use our standard IFF chunk reader here because early X-Tracker versions write some malformed chunk headers... fun code ahead! ChunkReader::ChunkList<DMFChunk> chunks; while(file.CanRead(sizeof(DMFChunk))) @@ -941,6 +924,47 @@ } FileReader chunk; + // Read pattern chunk first so that we know how many channels there are + chunk = chunks.GetChunk(DMFChunk::idPATT); + if(!chunk.IsValid()) + return false; + + DMFPatterns patHeader; + chunk.ReadStruct(patHeader); + // First, find out where all of our patterns are... + std::vector<FileReader> patternChunks; + if(loadFlags & loadPatternData) + { + patternChunks.resize(patHeader.numPatterns); + const uint8 headerSize = fileHeader.version < 3 ? 9 : 8; + for(auto &patternChunk : patternChunks) + { + chunk.Skip(headerSize - sizeof(uint32le)); + const uint32 patLength = chunk.ReadUint32LE(); + if(!chunk.CanRead(patLength)) + return false; + chunk.SkipBack(headerSize); + patternChunk = chunk.ReadChunk(headerSize + patLength); + } + } + + InitializeGlobals(MOD_TYPE_DMF, Clamp<uint8, uint8>(patHeader.numTracks, 1, 32) + 1); // + 1 for global track (used for tempo stuff) + + m_modFormat.formatName = MPT_UFORMAT("Delusion Digital Music Format v{}")(fileHeader.version); + m_modFormat.madeWithTracker = fileHeader.version == 10 ? UL_("X-Tracker 32") : UL_("X-Tracker"); + m_modFormat.type = U_("dmf"); + m_modFormat.charset = mpt::Charset::CP437; + + m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songname); + m_songArtist = mpt::ToUnicode(mpt::Charset::CP437, mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.composer)); + + FileHistory mptHistory; + mptHistory.loadDate.day = Clamp(fileHeader.creationDay, uint8(1), uint8(31)); + mptHistory.loadDate.month = Clamp(fileHeader.creationMonth, uint8(1), uint8(12)); + mptHistory.loadDate.year = 1900 + fileHeader.creationYear; + m_FileHistory.clear(); + m_FileHistory.push_back(mptHistory); + // Read order list chunk = chunks.GetChunk(DMFChunk::idSEQU); ORDERINDEX seqLoopStart = 0, seqLoopEnd = ORDERINDEX_MAX; @@ -956,27 +980,8 @@ LimitMax(seqLoopStart, Order().GetLastIndex()); LimitMax(seqLoopEnd, Order().GetLastIndex()); - // Read patterns - chunk = chunks.GetChunk(DMFChunk::idPATT); - if(chunk.IsValid() && (loadFlags & loadPatternData)) + if(loadFlags & loadPatternData) { - DMFPatterns patHeader; - chunk.ReadStruct(patHeader); - m_nChannels = Clamp<uint8, uint8>(patHeader.numTracks, 1, 32) + 1; // + 1 for global track (used for tempo stuff) - - // First, find out where all of our patterns are... - std::vector<FileReader> patternChunks(patHeader.numPatterns); - for(auto &patternChunk : patternChunks) - { - const uint8 headerSize = fileHeader.version < 3 ? 9 : 8; - chunk.Skip(headerSize - sizeof(uint32le)); - const uint32 patLength = chunk.ReadUint32LE(); - if(!chunk.CanRead(patLength)) - return false; - chunk.SkipBack(headerSize); - patternChunk = chunk.ReadChunk(headerSize + patLength); - } - // Now go through the order list and load them. DMFPatternSettings settings(GetNumChannels()); @@ -1042,7 +1047,6 @@ } } - InitializeChannels(); m_SongFlags = SONG_LINEARSLIDES | SONG_ITCOMPATGXX; // this will be converted to IT format by MPT. SONG_ITOLDEFFECTS is not set because of tremor and vibrato. Order().SetDefaultSpeed(6); Order().SetDefaultTempoInt(120); Modified: trunk/OpenMPT/soundlib/Load_dsm.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_dsm.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_dsm.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -206,14 +206,13 @@ return false; } - InitializeGlobals(MOD_TYPE_DSM); + InitializeGlobals(MOD_TYPE_DSM, std::max(songHeader.numChannels.get(), uint16(1))); m_modFormat.formatName = U_("DSIK Format"); m_modFormat.type = U_("dsm"); m_modFormat.charset = mpt::Charset::CP437; m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, songHeader.songName); - m_nChannels = std::max(songHeader.numChannels.get(), uint16(1)); Order().SetDefaultSpeed(songHeader.speed); Order().SetDefaultTempoInt(songHeader.bpm); m_nDefaultGlobalVolume = std::min(songHeader.globalVol.get(), uint8(64)) * 4u; @@ -224,9 +223,8 @@ m_nSamplePreAmp = songHeader.mastervol & 0x7F; // Read channel panning - for(CHANNELINDEX chn = 0; chn < 16; chn++) + for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { - ChnSettings[chn].Reset(); if(songHeader.panPos[chn] <= 0x80) { ChnSettings[chn].nPan = songHeader.panPos[chn] * 2; @@ -400,9 +398,8 @@ if(loadFlags == onlyVerifyHeader) return true; - InitializeGlobals(MOD_TYPE_MOD); + InitializeGlobals(MOD_TYPE_MOD, fileHeader.numChannels); m_SongFlags = SONG_IMPORTED; - m_nChannels = fileHeader.numChannels; static_assert(MAX_BASECHANNELS >= 32 && MAX_SAMPLES > 255); m_nSamples = fileHeader.numSamples; m_nDefaultGlobalVolume = Util::muldivr_unsigned(fileHeader.globalVol, MAX_GLOBAL_VOLUME, 100); @@ -412,7 +409,6 @@ for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) { - ChnSettings[chn].Reset(); ChnSettings[chn].nPan = (file.ReadUint8() & 0x0F) * 0x11; } Modified: trunk/OpenMPT/soundlib/Load_dsym.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_dsym.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_dsym.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -235,15 +235,13 @@ if(loadFlags == onlyVerifyHeader) return true; - InitializeGlobals(MOD_TYPE_MOD); + InitializeGlobals(MOD_TYPE_MOD, fileHeader.numChannels); m_SongFlags.set(SONG_IMPORTED | SONG_AMIGALIMITS); m_SongFlags.reset(SONG_ISAMIGA); - m_nChannels = fileHeader.numChannels; m_nSamples = 63; for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) { - InitChannel(chn); ChnSettings[chn].nPan = (((chn & 3) == 1) || ((chn & 3) == 2)) ? 64 : 192; } Modified: trunk/OpenMPT/soundlib/Load_dtm.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_dtm.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_dtm.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -228,8 +228,30 @@ return true; } - InitializeGlobals(MOD_TYPE_DTM); - InitializeChannels(); + std::string songName; + file.ReadString<mpt::String::maybeNullTerminated>(songName, fileHeader.headerSize - (sizeof(fileHeader) - 8u)); + + auto chunks = ChunkReader(file).ReadChunks<DTMChunk>(1); + + // Read pattern properties + uint32 patternFormat; + if(FileReader chunk = chunks.GetChunk(DTMChunk::idPATT)) + { + const uint16 numChannels = chunk.ReadUint16BE(); + if(numChannels < 1 || numChannels > 32) + return false; + + InitializeGlobals(MOD_TYPE_DTM, numChannels); + + Patterns.ResizeArray(chunk.ReadUint16BE()); // Number of stored patterns, may be lower than highest pattern number + patternFormat = chunk.ReadUint32BE(); + if(patternFormat != DTM_PT_PATTERN_FORMAT && patternFormat != DTM_204_PATTERN_FORMAT && patternFormat != DTM_206_PATTERN_FORMAT) + return false; + } else + { + return false; + } + m_SongFlags.set(SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS | SONG_FASTPORTAS); m_playBehaviour.reset(kPeriodsAreHertz); m_playBehaviour.reset(kITVibratoTremoloPanbrello); @@ -240,10 +262,7 @@ Order().SetDefaultSpeed(fileHeader.speed); if(fileHeader.stereoMode == 0) SetupMODPanning(true); - - file.ReadString<mpt::String::maybeNullTerminated>(m_songName, fileHeader.headerSize - (sizeof(fileHeader) - 8u)); - - auto chunks = ChunkReader(file).ReadChunks<DTMChunk>(1); + m_songName = std::move(songName); // Read order list if(FileReader chunk = chunks.GetChunk(DTMChunk::idS_Q_)) @@ -256,26 +275,6 @@ } else { return false; - } - - // Read pattern properties - uint32 patternFormat; - if(FileReader chunk = chunks.GetChunk(DTMChunk::idPATT)) - { - m_nChannels = chunk.ReadUint16BE(); - if(m_nChannels < 1 || m_nChannels > 32) - { - return false; - } - Patterns.ResizeArray(chunk.ReadUint16BE()); // Number of stored patterns, may be lower than highest pattern number - patternFormat = chunk.ReadUint32BE(); - if(patternFormat != DTM_PT_PATTERN_FORMAT && patternFormat != DTM_204_PATTERN_FORMAT && patternFormat != DTM_206_PATTERN_FORMAT) - { - return false; - } - } else - { - return false; } // Read global info Modified: trunk/OpenMPT/soundlib/Load_far.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_far.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_far.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -162,8 +162,7 @@ } // Globals - InitializeGlobals(MOD_TYPE_FAR); - m_nChannels = 16; + InitializeGlobals(MOD_TYPE_FAR, 16); m_nSamplePreAmp = 32; Order().SetDefaultSpeed(fileHeader.defaultSpeed); Order().SetDefaultTempoInt(80); @@ -180,7 +179,6 @@ // Read channel settings for(CHANNELINDEX chn = 0; chn < 16; chn++) { - ChnSettings[chn].Reset(); ChnSettings[chn].dwFlags = fileHeader.onOff[chn] ? ChannelFlags(0) : CHN_MUTE; ChnSettings[chn].nPan = ((fileHeader.chnPanning[chn] & 0x0F) << 4) + 8; } Modified: trunk/OpenMPT/soundlib/Load_fmt.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_fmt.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_fmt.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -85,9 +85,7 @@ if(loadFlags == onlyVerifyHeader) return true; - InitializeGlobals(MOD_TYPE_S3M); - InitializeChannels(); - m_nChannels = 8; + InitializeGlobals(MOD_TYPE_S3M, 8); m_nSamples = 8; Order().SetDefaultTempo(TEMPO(45.5)); // 18.2 Hz timer m_playBehaviour.set(kOPLNoteStopWith0Hz); Modified: trunk/OpenMPT/soundlib/Load_ftm.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_ftm.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_ftm.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -102,9 +102,7 @@ else if(loadFlags == onlyVerifyHeader) return true; - InitializeGlobals(MOD_TYPE_MOD); - m_nChannels = 8; - InitializeChannels(); + InitializeGlobals(MOD_TYPE_MOD, 8); for(CHANNELINDEX chn = 0; chn < 8; chn++) { ChnSettings[chn].nPan = (chn < 2 || chn > 5) ? 64 : 192; Modified: trunk/OpenMPT/soundlib/Load_gdm.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_gdm.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_gdm.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -34,7 +34,7 @@ uint16le trackerID; // Composing Tracker ID code (00 = 2GDM) uint8le trackerMajorVer; // Tracker's major version uint8le trackerMinorVer; // Tracker's minor version - uint8le panMap[32]; // 0-Left to 15-Right, 255-N/U + uint8le panMap[32]; // 0-Left to 15-Right, 16=Surround, 255-N/U uint8le masterVol; // Range: 0...64 uint8le tempo; // Initial music tempo (6) uint8le bpm; // Initial music BPM (125) @@ -57,6 +57,11 @@ uint16le scrollyScriptLength; uint32le textGraphicOffset; // Offset of text graphic (huh?) uint16le textGraphicLength; + + uint8 GetNumChannels() const + { + return static_cast<uint8>(std::distance(std::begin(panMap), std::find(std::begin(panMap), std::end(panMap), uint8_max))); + } }; MPT_BINARY_STRUCT(GDMFileHeader, 157) @@ -120,7 +125,8 @@ || std::memcmp(fileHeader.magic2, "GMFS", 4) || fileHeader.formatMajorVer != 1 || fileHeader.formatMinorVer != 0 || fileHeader.originalFormat >= std::size(gdmFormatOrigin) - || fileHeader.originalFormat == 0) + || fileHeader.originalFormat == 0 + || !fileHeader.GetNumChannels()) { return false; } @@ -162,7 +168,7 @@ return true; } - InitializeGlobals(gdmFormatOrigin[fileHeader.originalFormat]); + InitializeGlobals(gdmFormatOrigin[fileHeader.originalFormat], fileHeader.GetNumChannels()); m_SongFlags.set(SONG_IMPORTED); m_modFormat.formatName = U_("General Digital Music"); @@ -185,10 +191,8 @@ } // Read channel pan map... 0...15 = channel panning, 16 = surround channel, 255 = channel does not exist - m_nChannels = 32; - for(CHANNELINDEX i = 0; i < 32; i++) + for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) { - ChnSettings[i].Reset(); if(fileHeader.panMap[i] < 16) { ChnSettings[i].nPan = static_cast<uint16>(std::min((fileHeader.panMap[i] * 16) + 8, 256)); @@ -196,16 +200,8 @@ { ChnSettings[i].nPan = 128; ChnSettings[i].dwFlags = CHN_SURROUND; - } else if(fileHeader.panMap[i] == 0xFF) - { - m_nChannels = i; - break; } } - if(m_nChannels < 1) - { - return false; - } m_nDefaultGlobalVolume = std::min(fileHeader.masterVol * 4u, 256u); Order().SetDefaultSpeed(fileHeader.tempo); Modified: trunk/OpenMPT/soundlib/Load_gmc.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_gmc.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_gmc.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -110,8 +110,7 @@ else if(loadFlags == onlyVerifyHeader) return true; - InitializeGlobals(MOD_TYPE_MOD); - m_nChannels = 4; + InitializeGlobals(MOD_TYPE_MOD, 4); m_nSamples = 15; m_nMinPeriod = 113 * 4; m_nMaxPeriod = 856 * 4; Modified: trunk/OpenMPT/soundlib/Load_gt2.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_gt2.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_gt2.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -532,12 +532,10 @@ return true; // Globals - InitializeGlobals(MOD_TYPE_MPT); - InitializeChannels(); + InitializeGlobals(MOD_TYPE_MPT, fileHeader.numChannels); m_SongFlags.set(SONG_IMPORTED); m_playBehaviour = GetDefaultPlaybackBehaviour(MOD_TYPE_IT); m_playBehaviour.set(kApplyOffsetWithoutNote); - m_nChannels = fileHeader.numChannels; SetupMODPanning(true); m_modFormat.madeWithTracker = U_("Graoumf Tracker"); @@ -1182,9 +1180,24 @@ if(loadFlags == onlyVerifyHeader) return true; + std::vector<uint16be> pannedTracks; + file.ReadVector(pannedTracks, fileHeader.numPannedTracks); + + ChunkReader chunkFile(file); + auto chunks = chunkFile.ReadChunksUntil<GT2Chunk>(1, GT2Chunk::idENDC); + + if(auto chunk = chunks.GetChunk(GT2Chunk::idPATS); chunk.CanRead(2)) + { + if(uint16 channels = chunk.ReadUint16BE(); channels >= 1 && channels <= MAX_BASECHANNELS) + InitializeGlobals(MOD_TYPE_MPT, channels); + else + return false; + } else + { + return false; + } + // Globals - InitializeGlobals(MOD_TYPE_MPT); - InitializeChannels(); m_SongFlags.set(SONG_IMPORTED | SONG_EXFILTERRANGE); m_playBehaviour = GetDefaultPlaybackBehaviour(MOD_TYPE_IT); m_playBehaviour.set(kFT2ST3OffsetOutOfRange, fileHeader.fileVersion >= 6); @@ -1196,7 +1209,6 @@ mptHistory.loadDate.year = fileHeader.year; m_FileHistory.push_back(mptHistory); - m_nChannels = 32; m_modFormat.madeWithTracker = mpt::ToUnicode(mpt::Charset::ASCII, mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.trackerName)); m_modFormat.formatName = (fileHeader.fileVersion <= 5 ? MPT_UFORMAT("Graoumf Tracker v{}") : MPT_UFORMAT("Graoumf Tracker 2 v{}"))(fileHeader.fileVersion); m_modFormat.type = U_("gt2"); @@ -1205,36 +1217,21 @@ m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songName); m_nSamplePreAmp = 256; - m_nDefaultGlobalVolume = 384 / (3 + m_nChannels); // See documentation on command 5xxx + m_nDefaultGlobalVolume = 384 / (3 + m_nChannels); // See documentation on command 5xxx: Default linear master volume is 12288 / (3 + number of channels) if(fileHeader.fileVersion <= 5) { Order().SetDefaultSpeed(std::max(fileHeader.speed.get(), uint16(1))); Order().SetDefaultTempoInt(std::max(fileHeader.tempo.get(), uint16(1))); m_nDefaultGlobalVolume = std::min(Util::muldivr_unsigned(fileHeader.masterVol, MAX_GLOBAL_VOLUME, 4095), uint32(MAX_GLOBAL_VOLUME)); - uint16 tracks = fileHeader.numPannedTracks; - LimitMax(tracks, MAX_BASECHANNELS); + const CHANNELINDEX tracks = std::min(static_cast<CHANNELINDEX>(pannedTracks.size()), m_nChannels); for(CHANNELINDEX chn = 0; chn < tracks; chn++) { - ChnSettings[chn].nPan = std::min(static_cast<uint16>(Util::muldivr_unsigned(file.ReadUint16BE(), 256, 4095)), uint16(256)); + ChnSettings[chn].nPan = std::min(static_cast<uint16>(Util::muldivr_unsigned(pannedTracks[chn], 256, 4095)), uint16(256)); } } file.Seek(fileHeader.headerSize); - ChunkReader chunkFile(file); - auto chunks = chunkFile.ReadChunksUntil<GT2Chunk>(1, GT2Chunk::idENDC); - - if(auto chunk = chunks.GetChunk(GT2Chunk::idPATS); chunk.CanRead(2)) - { - if(uint16 channels = chunk.ReadUint16BE(); channels >= 1 && channels <= MAX_BASECHANNELS) - m_nChannels = channels; - else - return false; - } else - { - return false; - } - if(auto chunk = chunks.GetChunk(GT2Chunk::idSONG); chunk.CanRead(2)) { ORDERINDEX numOrders = chunk.ReadUint16BE(); Modified: trunk/OpenMPT/soundlib/Load_ice.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_ice.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_ice.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -63,14 +63,14 @@ if(IsMagic(magic, "MTN\0")) { - InitializeGlobals(MOD_TYPE_MOD); + InitializeGlobals(MOD_TYPE_MOD, 4); m_modFormat.formatName = U_("MnemoTroN SoundTracker"); m_modFormat.type = U_("st26"); m_modFormat.madeWithTracker = U_("SoundTracker 2.6"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; } else if(IsMagic(magic, "IT10")) { - InitializeGlobals(MOD_TYPE_MOD); + InitializeGlobals(MOD_TYPE_MOD, 4); m_modFormat.formatName = U_("Ice Tracker"); m_modFormat.type = U_("ice"); m_modFormat.madeWithTracker = U_("Ice Tracker 1.0 / 1.1"); @@ -112,7 +112,6 @@ return true; // Now we can be pretty sure that this is a valid ICE file. Set up default song settings. - m_nChannels = 4; SetupMODPanning(true); Order().SetDefaultSpeed(6); Order().SetDefaultTempoInt(125); Modified: trunk/OpenMPT/soundlib/Load_imf.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_imf.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_imf.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -45,6 +45,19 @@ uint8le unused2[8]; char im10[4]; // 'IM10' IMFChannel channels[32]; // Channel settings + + CHANNELINDEX GetNumChannels() const + { + uint8 detectedChannels = 0; + for(uint8 chn = 0; chn < 32; chn++) + { + if(channels[chn].status < 2) + detectedChannels = chn + 1; + else if(channels[chn].status > 2) + return 0; + } + return detectedChannels; + } }; MPT_BINARY_STRUCT(IMFFileHeader, 576) @@ -365,29 +378,8 @@ || fileHeader.bpm < 32 || fileHeader.master > 64 || fileHeader.amp < 4 - || fileHeader.amp > 127) - { - return false; - } - bool channelFound = false; - for(const auto &chn : fileHeader.channels) - { - switch(chn.status) - { - case 0: // enabled; don't worry about it - channelFound = true; - break; - case 1: // mute - channelFound = true; - break; - case 2: // disabled - // nothing - break; - default: // uhhhh.... freak out - return false; - } - } - if(!channelFound) + || fileHeader.amp > 127 + || !fileHeader.GetNumChannels()) { return false; } @@ -437,52 +429,40 @@ return true; } + InitializeGlobals(MOD_TYPE_IMF, fileHeader.GetNumChannels()); + + m_modFormat.formatName = U_("Imago Orpheus"); + m_modFormat.type = U_("imf"); + m_modFormat.charset = mpt::Charset::CP437; + // Read channel configuration - std::bitset<32> ignoreChannels; // bit set for each channel that's completely disabled - uint8 detectedChannels = 0; - for(uint8 chn = 0; chn < 32; chn++) + std::bitset<32> ignoreChannels; // bit set for each channel that's completely disabled + uint64 channelMuteStatus = 0xAAAA'AAAA << (m_nChannels * 2); + for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) { - ChnSettings[chn].Reset(); ChnSettings[chn].nPan = static_cast<uint16>(fileHeader.channels[chn].panning * 256 / 255); - ChnSettings[chn].szName = mpt::String::ReadBuf(mpt::String::nullTerminated, fileHeader.channels[chn].name); - + channelMuteStatus |= fileHeader.channels[chn].status << (chn * 2); // TODO: reverb/chorus? switch(fileHeader.channels[chn].status) { - case 0: // enabled; don't worry about it - detectedChannels = chn + 1; + case 0: // enabled; don't worry about it break; - case 1: // mute + case 1: // mute ChnSettings[chn].dwFlags = CHN_MUTE; - detectedChannels = chn + 1; break; - case 2: // disabled + case 2: // disabled ChnSettings[chn].dwFlags = CHN_MUTE; ignoreChannels[chn] = true; break; - default: // uhhhh.... freak out - return false; } } - - InitializeGlobals(MOD_TYPE_IMF); - m_nChannels = detectedChannels; - - m_modFormat.formatName = U_("Imago Orpheus"); - m_modFormat.type = U_("imf"); - m_modFormat.charset = mpt::Charset::CP437; - - //From mikmod: work around an Orpheus bug - if(fileHeader.channels[0].status == 0) + // BEHIND.IMF: All channels but the first are muted + // mikmod refers to this as an Orpheus bug, but I haven't seen any other files like this, so maybe it's just an incorrectly saved file? + if(channelMuteStatus == 0xAAAA'AAAA'5555'5554) { - CHANNELINDEX chn; - for(chn = 1; chn < 16; chn++) - if(fileHeader.channels[chn].status != 1) - break; - if(chn == 16) - for(chn = 1; chn < 16; chn++) - ChnSettings[chn].dwFlags.reset(CHN_MUTE); + for(CHANNELINDEX chn = 1; chn < m_nChannels; chn++) + ChnSettings[chn].dwFlags.reset(CHN_MUTE); } // Song Name Modified: trunk/OpenMPT/soundlib/Load_ims.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_ims.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_ims.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -89,19 +89,17 @@ if(loadFlags == onlyVerifyHeader) return true; - InitializeGlobals(MOD_TYPE_MOD); + InitializeGlobals(MOD_TYPE_MOD, 4); m_SongFlags.set(SONG_IMPORTED); Order().SetDefaultTempoInt(125); Order().SetDefaultSpeed(6); Order().SetRestartPos(fileHeader.order.restartPos); m_nMinPeriod = 113 * 4; m_nMaxPeriod = 1712 * 4; - m_nChannels = 4; m_nSamples = 31; m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songName); ReadOrderFromArray(Order(), fileHeader.order.orderList, fileHeader.order.numOrders); - InitializeChannels(); file.Seek(20); for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) Modified: trunk/OpenMPT/soundlib/Load_it.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_it.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -430,7 +430,7 @@ return true; } - InitializeGlobals(MOD_TYPE_IT); + InitializeGlobals(MOD_TYPE_IT, 0); bool interpretModPlugMade = false; mpt::ustring madeWithTracker; @@ -537,17 +537,6 @@ Order().SetDefaultTempoInt(std::max(uint8(31), static_cast<uint8>(fileHeader.tempo))); m_nSamplePreAmp = std::min(static_cast<uint8>(fileHeader.mv), uint8(128)); - // Reading Channels Pan Positions - for(CHANNELINDEX i = 0; i < 64; i++) if(fileHeader.chnpan[i] != 0xFF) - { - ChnSettings[i].Reset(); - ChnSettings[i].nVolume = Clamp<uint8, uint8>(fileHeader.chnvol[i], 0, 64); - if(fileHeader.chnpan[i] & 0x80) ChnSettings[i].dwFlags.set(CHN_MUTE); - uint8 n = fileHeader.chnpan[i] & 0x7F; - if(n <= 64) ChnSettings[i].nPan = n * 4; - if(n == 100) ChnSettings[i].dwFlags.set(CHN_SURROUND); - } - // Reading orders file.Seek(sizeof(ITFileHeader)); if(GetType() == MOD_TYPE_MPT && fileHeader.cwtv > 0x88A && fileHeader.cwtv <= 0x88D) @@ -697,18 +686,15 @@ hasModPlugExtensions = true; } - m_nChannels = 1; // Read channel names: "CNAM" if(file.ReadMagic("CNAM")) { FileReader chnNames = file.ReadChunk(file.ReadUint32LE()); - const CHANNELINDEX readChns = std::min(MAX_BASECHANNELS, static_cast<CHANNELINDEX>(chnNames.GetLength() / MAX_CHANNELNAME)); - m_nChannels = readChns; + m_nChannels = std::min(MAX_BASECHANNELS, static_cast<CHANNELINDEX>(chnNames.GetLength() / MAX_CHANNELNAME)); hasModPlugExtensions = true; - - for(CHANNELINDEX i = 0; i < readChns; i++) + for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { - chnNames.ReadString<mpt::String::maybeNullTerminated>(ChnSettings[i].szName, MAX_CHANNELNAME); + chnNames.ReadString<mpt::String::maybeNullTerminated>(ChnSettings[chn].szName, MAX_CHANNELNAME); } } @@ -984,6 +970,22 @@ // Need to do this before reading the patterns because m_nChannels might be modified by LoadExtendedSongProperties. *sigh* const bool hasExtendedSongProperties = LoadExtendedSongProperties(file, false, &interpretModPlugMade); + // Reading Channels Pan Positions + const CHANNELINDEX headerChannels = std::min(GetNumChannels(), CHANNELINDEX(64)); + for(CHANNELINDEX i = 0; i < headerChannels; i++) + { + if(fileHeader.chnpan[i] == 0xFF) + continue; + ChnSettings[i].nVolume = Clamp<uint8, uint8>(fileHeader.chnvol[i], 0, 64); + if(fileHeader.chnpan[i] & 0x80) + ChnSettings[i].dwFlags.set(CHN_MUTE); + uint8 n = fileHeader.chnpan[i] & 0x7F; + if(n <= 64) + ChnSettings[i].nPan = n * 4; + if(n == 100) + ChnSettings[i].dwFlags.set(CHN_SURROUND); + } + // Reading Patterns Patterns.ResizeArray(numPats); for(PATTERNINDEX pat = 0; pat < numPats; pat++) Modified: trunk/OpenMPT/soundlib/Load_itp.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_itp.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_itp.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -86,43 +86,63 @@ { uint32le magic; uint32le version; + + bool IsValid() const + { + return magic == MagicBE(".itp") + && version >= 0x00000100 && version <= 0x00000103; + } + + uint32 GetHeaderMinimumAdditionalSize() const + { + return 76 + (version <= 0x102 ? 4 : 0); + } }; MPT_BINARY_STRUCT(ITPHeader, 8) -static bool ValidateHeader(const ITPHeader &hdr) +struct ITPSongHeader { - if(hdr.magic != MagicBE(".itp")) - { - return false; - } - if(hdr.version < 0x00000100 || hdr.version > 0x00000103) + enum SongFlags { - return false; - } - return true; -} + ITP_EMBEDMIDICFG = 0x00001, // Embed macros in file + ITP_ITOLDEFFECTS = 0x00004, // Old Impulse Tracker effect implementations + ITP_ITCOMPATGXX = 0x00008, // IT "Compatible Gxx" (IT's flag to behave more like other trackers w/r/t portamento effects) + ITP_LINEARSLIDES = 0x00010, // Linear slides vs. Amiga slides + ITP_EXFILTERRANGE = 0x08000, // Cutoff Filter has double frequency range (up to ~10Khz) + ITP_ITPROJECT = 0x20000, // Is a project file + ITP_ITPEMBEDIH = 0x40000, // Embed instrument headers in project file + }; + uint32le flags; // See SongFlangs + uint32le globalVolume; + uint32le samplePreAmp; + uint32le speed; + uint32le tempo; + uint32le numChannels; + uint32le channelNameLength; + + bool IsValid() const + { + return (flags & ITP_ITPROJECT) != 0 + && speed >= 1 + && tempo >= 32 + && numChannels >= 1 && numChannels <= MAX_BASECHANNELS; + } +}; -static uint64 GetHeaderMinimumAdditionalSize(const ITPHeader &hdr) -{ - return 76 + (hdr.version <= 0x102 ? 4 : 0); -} +MPT_BINARY_STRUCT(ITPSongHeader, 28) CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderITP(MemoryFileReader file, const uint64 *pfilesize) { ITPHeader hdr; if(!file.ReadStruct(hdr)) - { return ProbeWantMoreData; - } - if(!ValidateHeader(hdr)) - { + if(!hdr.IsValid()) return ProbeFailure; - } - return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(hdr)); + return ProbeAdditionalSize(file, pfilesize, hdr.GetHeaderMinimumAdditionalSize()); } @@ -135,76 +155,51 @@ return false; #else // !MPT_EXTERNAL_SAMPLES && !MPT_FUZZ_TRACKER - enum ITPSongFlags - { - ITP_EMBEDMIDICFG = 0x00001, // Embed macros in file - ITP_ITOLDEFFECTS = 0x00004, // Old Impulse Tracker effect implementations - ITP_ITCOMPATGXX = 0x00008, // IT "Compatible Gxx" (IT's flag to behave more like other trackers w/r/t portamento effects) - ITP_LINEARSLIDES = 0x00010, // Linear slides vs. Amiga slides - ITP_EXFILTERRANGE = 0x08000, // Cutoff Filter has double frequency range (up to ~10Khz) - ITP_ITPROJECT = 0x20000, // Is a project file - ITP_ITPEMBEDIH = 0x40000, // Embed instrument headers in project file - }; - file.Rewind(); ITPHeader hdr; if(!file.ReadStruct(hdr)) - { return false; - } - if(!ValidateHeader(hdr)) - { + if(!hdr.IsValid()) return false; - } - if(!file.CanRead(mpt::saturate_cast<FileReader::pos_type>(GetHeaderMinimumAdditionalSize(hdr)))) - { + if(!file.CanRead(hdr.GetHeaderMinimumAdditionalSize())) return false; - } if(loadFlags == onlyVerifyHeader) - { return true; - } const uint32 version = hdr.version; - InitializeGlobals(MOD_TYPE_IT); - m_playBehaviour.reset(); - file.ReadSizedString<uint32le, mpt::String::maybeNullTerminated>(m_songName); - - // Song comments - m_songMessage.Read(file, file.ReadUint32LE(), SongMessage::leCR); + std::string songName, songMessage; + file.ReadSizedString<uint32le, mpt::String::maybeNullTerminated>(songName); + file.ReadSizedString<uint32le, mpt::String::maybeNullTerminated>(songMessage); - // Song global config - const uint32 songFlags = file.ReadUint32LE(); - if(!(songFlags & ITP_ITPROJECT)) - { + ITPSongHeader songHeader; + if(!file.ReadStruct(songHeader) || !songHeader.IsValid()) return false; - } + + InitializeGlobals(MOD_TYPE_IT, static_cast<CHANNELINDEX>(songHeader.numChannels)); + m_playBehaviour.reset(); + m_SongFlags.set(SONG_IMPORTED); - if(songFlags & ITP_ITOLDEFFECTS) + if(songHeader.flags & ITPSongHeader::ITP_ITOLDEFFECTS) m_SongFlags.set(SONG_ITOLDEFFECTS); - if(songFlags & ITP_ITCOMPATGXX) + if(songHeader.flags & ITPSongHeader::ITP_ITCOMPATGXX) m_SongFlags.set(SONG_ITCOMPATGXX); - if(songFlags & ITP_LINEARSLIDES) + if(songHeader.flags & ITPSongHeader::ITP_LINEARSLIDES) m_SongFlags.set(SONG_LINEARSLIDES); - if(songFlags & ITP_EXFILTERRANGE) + if(songHeader.flags & ITPSongHeader::ITP_EXFILTERRANGE) m_SongFlags.set(SONG_EXFILTERRANGE); - m_nDefaultGlobalVolume = file.ReadUint32LE(); - m_nSamplePreAmp = file.ReadUint32LE(); - Order().SetDefaultSpeed(std::max(uint32(1), file.ReadUint32LE())); - Order().SetDefaultTempoInt(std::max(uint32(32), file.ReadUint32LE())); - m_nChannels = static_cast<CHANNELINDEX>(file.ReadUint32LE()); - if(m_nChannels == 0 || m_nChannels > MAX_BASECHANNELS) - { - return false; - } + m_nDefaultGlobalVolume = songHeader.globalVolume; + m_nSamplePreAmp = songHeader.samplePreAmp; + Order().SetDefaultSpeed(songHeader.speed); + Order().SetDefaultTempoInt(songHeader.tempo); - // channel name string length (=MAX_CHANNELNAME) - uint32 size = file.ReadUint32LE(); + m_songName = std::move(songName); + m_songMessage.SetRaw(std::move(songMessage)); // Channels' data + uint32 size = songHeader.channelNameLength; for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) { ChnSettings[chn].nPan = std::min(static_cast<uint16>(file.ReadUint32LE()), uint16(256)); @@ -378,7 +373,7 @@ uint32 code = file.ReadUint32LE(); // Embed instruments' header [v1.01] - if(version >= 0x101 && (songFlags & ITP_ITPEMBEDIH) && code == MagicBE("EBIH")) + if(version >= 0x101 && (songHeader.flags & ITPSongHeader::ITP_ITPEMBEDIH) && code == MagicBE("EBIH")) { code = file.ReadUint32LE(); @@ -417,7 +412,7 @@ m_nMinPeriod = 8; // Before OpenMPT 1.20.01.09, the MIDI macros were always read from the file, even if the "embed" flag was not set. - if(m_dwLastSavedWithVersion >= MPT_V("1.20.01.09") && !(songFlags & ITP_EMBEDMIDICFG)) + if(m_dwLastSavedWithVersion >= MPT_V("1.20.01.09") && !(songHeader.flags & ITPSongHeader::ITP_EMBEDMIDICFG)) { m_MidiCfg.Reset(); } Modified: trunk/OpenMPT/soundlib/Load_kris.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_kris.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_kris.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -58,7 +58,7 @@ return false; uint32 tracksOffset = 1984; - InitializeGlobals(MOD_TYPE_MOD); + InitializeGlobals(MOD_TYPE_MOD, 4); file.Seek(0); file.ReadString<mpt::String::spacePadded>(m_songName, 22); @@ -91,7 +91,6 @@ if(loadFlags == onlyVerifyHeader) return true; - m_nChannels = 4; SetupMODPanning(true); Order().SetDefaultSpeed(6); Order().SetDefaultTempoInt(125); Modified: trunk/OpenMPT/soundlib/Load_mdl.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mdl.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_mdl.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -65,10 +65,21 @@ char composer[20]; uint16le numOrders; uint16le restartPos; - uint8le globalVol; // 1...255 - uint8le speed; // 1...255 - uint8le tempo; // 4...255 + uint8le globalVol; // 1...255 + uint8le speed; // 1...255 + uint8le tempo; // 4...255 uint8le chnSetup[32]; + + uint8 GetNumChannels() const + { + uint8 numChannels = 0; + for(uint8 c = 0; c < 32; c++) + { + if(!(chnSetup[c] & 0x80)) + numChannels = c + 1; + } + return numChannels; + } }; MPT_BINARY_STRUCT(MDLInfoBlock, 91) @@ -418,6 +429,28 @@ } +static uint8 GetMDLPatternChannelCount(FileReader chunk, uint8 numChannels, const uint8 fileVersion) +{ + const uint8 numPats = chunk.ReadUint8(); + for(uint8 pat = 0; pat < numPats && numChannels < 32; pat++) + { + uint8 readChans = 32; + if(fileVersion >= 0x10) + { + MDLPatternHeader patHead; + chunk.ReadStruct(patHead); + readChans = patHead.channels; + } + for(uint8 chn = 0; chn < readChans; chn++) + { + if(chunk.ReadUint16LE() > 0 && chn >= numChannels && chn < 32) + numChannels = chn + 1; + } + } + return numChannels; +} + + static bool ValidateHeader(const MDLFileHeader &fileHeader) { if(std::memcmp(fileHeader.id, "DMDL", 4) @@ -473,7 +506,9 @@ return false; } - InitializeGlobals(MOD_TYPE_MDL); + // In case any muted channels contain data, be sure that we import them as well. + const uint8 numChannels = std::max(GetMDLPatternChannelCount(chunks.GetChunk(MDLChunk::idPats), info.GetNumChannels(), fileHeader.version), uint8(1)); + InitializeGlobals(MOD_TYPE_MDL, numChannels); m_SongFlags = SONG_ITCOMPATGXX; m_playBehaviour.set(kPerChannelGlobalVolSlide); m_playBehaviour.set(kApplyOffsetWithoutNote); @@ -500,17 +535,13 @@ ReadOrderFromFile<uint8>(Order(), chunk, info.numOrders); Order().SetRestartPos(info.restartPos); - m_nChannels = 0; - for(CHANNELINDEX c = 0; c < 32; c++) + for(CHANNELINDEX c = 0; c < GetNumChannels(); c++) { - ChnSettings[c].Reset(); ChnSettings[c].nPan = (info.chnSetup[c] & 0x7F) * 2u; if(ChnSettings[c].nPan == 254) ChnSettings[c].nPan = 256; if(info.chnSetup[c] & 0x80) ChnSettings[c].dwFlags.set(CHN_MUTE); - else - m_nChannels = c + 1; chunk.ReadString<mpt::String::spacePadded>(ChnSettings[c].szName, 8); } @@ -680,27 +711,6 @@ if((loadFlags & loadPatternData) && (chunk = chunks.GetChunk(MDLChunk::idPats)).IsValid()) { PATTERNINDEX numPats = chunk.ReadUint8(); - - // In case any muted channels contain data, be sure that we import them as well. - for(PATTERNINDEX pat = 0; pat < numPats; pat++) - { - CHANNELINDEX numChans = 32; - if(fileHeader.version >= 0x10) - { - MDLPatternHeader patHead; - chunk.ReadStruct(patHead); - if(patHead.channels > m_nChannels && patHead.channels <= 32) - m_nChannels = patHead.channels; - numChans = patHead.channels; - } - for(CHANNELINDEX chn = 0; chn < numChans; chn++) - { - if(chunk.ReadUint16LE() > 0 && chn >= m_nChannels && chn < 32) - m_nChannels = chn + 1; - } - } - chunk.Seek(1); - Patterns.ResizeArray(numPats); for(PATTERNINDEX pat = 0; pat < numPats; pat++) { Modified: trunk/OpenMPT/soundlib/Load_med.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_med.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_med.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -873,10 +873,6 @@ if(loadFlags == onlyVerifyHeader) return true; - InitializeGlobals(MOD_TYPE_MED); - InitializeChannels(); - const uint8 version = fileHeader.version - '0'; - file.Seek(fileHeader.songOffset); FileReader sampleHeaderChunk = file.ReadChunk(63 * sizeof(MMD0Sample)); @@ -886,16 +882,12 @@ if(songHeader.numSamples > 63 || songHeader.numBlocks > 0x7FFF) return false; - MMD0Exp expData{}; - if(fileHeader.expDataOffset && file.Seek(fileHeader.expDataOffset)) - { - file.ReadStruct(expData); - } - + const uint8 version = fileHeader.version - '0'; const auto [numChannels, numSongs] = MEDScanNumChannels(file, version); if(numChannels < 1 || numChannels > MAX_BASECHANNELS) return false; - m_nChannels = numChannels; + + InitializeGlobals(MOD_TYPE_MED, numChannels); // Start with the instruments, as those are shared between songs @@ -910,6 +902,12 @@ } m_nInstruments = m_nSamples = songHeader.numSamples; + MMD0Exp expData{}; + if(fileHeader.expDataOffset && file.Seek(fileHeader.expDataOffset)) + { + file.ReadStruct(expData); + } + FileReader expDataChunk; if(expData.instrExtOffset != 0 && file.Seek(expData.instrExtOffset)) { Modified: trunk/OpenMPT/soundlib/Load_mid.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mid.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_mid.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -621,8 +621,7 @@ return true; } - InitializeGlobals(MOD_TYPE_MID); - InitializeChannels(); + InitializeGlobals(MOD_TYPE_MID, MAX_BASECHANNELS); #ifdef MODPLUG_TRACKER const uint32 quantize = Clamp(TrackerSettings::Instance().midiImportQuantize.Get(), 4u, 256u); @@ -652,7 +651,6 @@ TEMPO tempo{120, 0}; Order().SetDefaultTempo(tempo); Order().SetDefaultSpeed(ticksPerRow); - m_nChannels = MAX_BASECHANNELS; m_nDefaultRowsPerBeat = quantize / 4; m_nDefaultRowsPerMeasure = 4 * m_nDefaultRowsPerBeat; m_nSamplePreAmp = m_nVSTiVolume = 32; Modified: trunk/OpenMPT/soundlib/Load_mo3.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mo3.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_mo3.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -873,11 +873,9 @@ mpt::IO::FileCursor<mpt::IO::FileCursorTraitsFileData, mpt::IO::FileCursorFilenameTraits<mpt::PathString>> fileCursor{musicChunkData, std::move(filenamePtr)}; FileReader musicChunk{fileCursor}; - InitializeGlobals(); - InitializeChannels(); - - musicChunk.ReadNullString(m_songName); - musicChunk.ReadNullString(m_songMessage); + std::string songName, songMessage; + musicChunk.ReadNullString(songName); + musicChunk.ReadNullString(songMessage); MO3FileHeader fileHeader; if(!musicChunk.ReadStruct(fileHeader) @@ -889,23 +887,24 @@ return false; } - m_nChannels = fileHeader.numChannels; + MODTYPE modType = MOD_TYPE_XM; + if(fileHeader.flags & MO3FileHeader::isIT) + modType = MOD_TYPE_IT; + else if(fileHeader.flags & MO3FileHeader::isS3M) + modType = MOD_TYPE_S3M; + else if(fileHeader.flags & MO3FileHeader::isMOD) + modType = MOD_TYPE_MOD; + else if(fileHeader.flags & MO3FileHeader::isMTM) + modType = MOD_TYPE_MTM; + + InitializeGlobals(modType, fileHeader.numChannels); Order().SetRestartPos(fileHeader.restartPos); m_nInstruments = fileHeader.numInstruments; m_nSamples = fileHeader.numSamples; Order().SetDefaultSpeed(fileHeader.defaultSpeed ? fileHeader.defaultSpeed : 6); Order().SetDefaultTempoInt(fileHeader.defaultTempo ? fileHeader.defaultTempo : 125); - - if(fileHeader.flags & MO3FileHeader::isIT) - SetType(MOD_TYPE_IT); - else if(fileHeader.flags & MO3FileHeader::isS3M) - SetType(MOD_TYPE_S3M); - else if(fileHeader.flags & MO3FileHeader::isMOD) - SetType(MOD_TYPE_MOD); - else if(fileHeader.flags & MO3FileHeader::isMTM) - SetType(MOD_TYPE_MTM); - else - SetType(MOD_TYPE_XM); + m_songName = std::move(songName); + m_songMessage.SetRaw(std::move(songMessage)); m_SongFlags.set(SONG_IMPORTED); if(fileHeader.flags & MO3FileHeader::linearSlides) Modified: trunk/OpenMPT/soundlib/Load_mod.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_mod.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -297,8 +297,7 @@ return true; } - InitializeGlobals(MOD_TYPE_MOD); - m_nChannels = modMagicResult.numChannels; + InitializeGlobals(MOD_TYPE_MOD, modMagicResult.numChannels); bool isNoiseTracker = modMagicResult.isNoiseTracker; bool isStartrekker = modMagicResult.isStartrekker; Modified: trunk/OpenMPT/soundlib/Load_mt2.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mt2.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_mt2.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -447,8 +447,7 @@ return true; } - InitializeGlobals(MOD_TYPE_MT2); - InitializeChannels(); + InitializeGlobals(MOD_TYPE_MT2, fileHeader.numChannels); m_modFormat.formatName = MPT_UFORMAT("MadTracker {}.{}")(fileHeader.version >> 8, mpt::ufmt::hex0<2>(fileHeader.version & 0xFF)); m_modFormat.type = U_("mt2"); @@ -456,7 +455,6 @@ m_modFormat.charset = mpt::Charset::Windows1252; m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songName); - m_nChannels = fileHeader.numChannels; Order().SetDefaultSpeed(Clamp<uint8, uint8>(fileHeader.ticksPerLine, 1, 31)); Order().SetDefaultTempoInt(125); m_SongFlags = SONG_LINEARSLIDES | SONG_ITCOMPATGXX | SONG_EXFILTERRANGE; Modified: trunk/OpenMPT/soundlib/Load_mtm.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mtm.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_mtm.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -135,10 +135,9 @@ return true; } - InitializeGlobals(MOD_TYPE_MTM); + InitializeGlobals(MOD_TYPE_MTM, fileHeader.numChannels); m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songName); m_nSamples = fileHeader.numSamples; - m_nChannels = fileHeader.numChannels; m_modFormat.formatName = U_("MultiTracker"); m_modFormat.type = U_("mtm"); @@ -157,7 +156,6 @@ // Setting Channel Pan Position for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { - ChnSettings[chn].Reset(); ChnSettings[chn].nPan = ((fileHeader.panPos[chn] & 0x0F) << 4) + 8; } Modified: trunk/OpenMPT/soundlib/Load_mus_km.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mus_km.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_mus_km.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -169,10 +169,8 @@ if(songChunks.empty() || sampleChunks.empty()) return false; - InitializeGlobals(MOD_TYPE_MOD); - InitializeChannels(); + InitializeGlobals(MOD_TYPE_MOD, 4); m_SongFlags = SONG_AMIGALIMITS | SONG_IMPORTED | SONG_ISAMIGA; // Yes, those were not Amiga games but the format fully conforms to Amiga limits, so allow the Amiga Resampler to be used. - m_nChannels = 4; m_nSamples = 0; static constexpr uint16 MUS_SAMPLE_UNUSED = 255; // Sentinel value to check if a sample needs to be duplicated Modified: trunk/OpenMPT/soundlib/Load_okt.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_okt.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_okt.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -346,7 +346,7 @@ std::array<int8, 8> pairedChn{{}}; ORDERINDEX numOrders = 0; - InitializeGlobals(MOD_TYPE_OKT); + InitializeGlobals(MOD_TYPE_OKT, 0); m_modFormat.formatName = U_("Oktalyzer"); m_modFormat.type = U_("okt"); @@ -367,7 +367,7 @@ { case OktIffChunk::idCMOD: // Channel setup table - if(m_nChannels == 0 && chunk.GetLength() >= 8) + if(m_nChannels == 0 && chunk.CanRead(8)) { const auto chnTable = chunk.ReadArray<uint16be, 4>(); for(CHANNELINDEX chn = 0; chn < 4; chn++) @@ -376,10 +376,10 @@ { pairedChn[m_nChannels] = 1; pairedChn[m_nChannels + 1] = -1; - ChnSettings[m_nChannels].Reset(); + mpt::reconstruct(ChnSettings[m_nChannels]); ChnSettings[m_nChannels++].nPan = (((chn & 3) == 1) || ((chn & 3) == 2)) ? 0xC0 : 0x40; } - ChnSettings[m_nChannels].Reset(); + mpt::reconstruct(ChnSettings[m_nChannels]); ChnSettings[m_nChannels++].nPan = (((chn & 3) == 1) || ((chn & 3) == 2)) ? 0xC0 : 0x40; } Modified: trunk/OpenMPT/soundlib/Load_plm.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_plm.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_plm.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -145,8 +145,7 @@ return false; } - InitializeGlobals(MOD_TYPE_PLM); - InitializeChannels(); + InitializeGlobals(MOD_TYPE_PLM, fileHeader.numChannels + 1); // Additional channel for writing pattern breaks m_SongFlags = SONG_ITOLDEFFECTS; m_playBehaviour.set(kApplyOffsetWithoutNote); @@ -156,7 +155,6 @@ // Some PLMs use ASCIIZ, some space-padding strings...weird. Oh, and the file browser stops at 0 bytes in the name, the main GUI doesn't. m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songName); - m_nChannels = fileHeader.numChannels + 1; // Additional channel for writing pattern breaks m_nSamplePreAmp = fileHeader.amplify; Order().SetDefaultTempoInt(fileHeader.tempo); Order().SetDefaultSpeed(fileHeader.speed); Modified: trunk/OpenMPT/soundlib/Load_psm.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_psm.cpp Fri Jun 7 19:29:11 2024 (r20948) +++ trunk/OpenMPT/soundlib/Load_psm.cpp Sat Jun 8 01:19:39 2024 (r20949) @@ -311,8 +311,21 @@ else if(loadFlags == onlyVerifyHeader) return true; + auto songChunks = chunks.GetAllChunks(PSMChunk::idSONG); + CHANNELINDEX numChannels = 0; + for(FileReader chunk : songChunks) + { + PSMSongHeader songHeader; + if(!chunk.ReadStruct(songHeader) || songHeader.compression != 0x0... [truncated message content] |