From: <sv...@op...> - 2024-05-31 13:50:52
|
Author: sagamusix Date: Fri May 31 15:50:38 2024 New Revision: 20882 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20882 Log: [Ref] Turn channel states into std::array, and provide convenience wrappers that just return the pattern channels or just the background channels. Modified: trunk/OpenMPT/mptrack/MainFrm.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/Modedit.cpp trunk/OpenMPT/mptrack/View_pat.cpp trunk/OpenMPT/soundlib/PlayState.cpp trunk/OpenMPT/soundlib/PlayState.h trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/Sndmix.cpp Modified: trunk/OpenMPT/mptrack/MainFrm.cpp ============================================================================== --- trunk/OpenMPT/mptrack/MainFrm.cpp Fri May 31 11:49:23 2024 (r20881) +++ trunk/OpenMPT/mptrack/MainFrm.cpp Fri May 31 15:50:38 2024 (r20882) @@ -1383,12 +1383,12 @@ } else { // Stop sample preview channels - for(CHANNELINDEX i = m_pSndFile->m_nChannels; i < MAX_CHANNELS; i++) + for(ModChannel &chn : m_pSndFile->m_PlayState.BackgroundChannels(*m_pSndFile)) { - if(m_pSndFile->m_PlayState.Chn[i].isPreviewNote) + if(chn.isPreviewNote) { - m_pSndFile->m_PlayState.Chn[i].nLength = 0; - m_pSndFile->m_PlayState.Chn[i].position.Set(0); + chn.nLength = 0; + chn.position.Set(0); } } } Modified: trunk/OpenMPT/mptrack/Moddoc.cpp ============================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp Fri May 31 11:49:23 2024 (r20881) +++ trunk/OpenMPT/mptrack/Moddoc.cpp Fri May 31 15:50:38 2024 (r20882) @@ -1155,9 +1155,8 @@ CriticalSection cs; // Apply note cut / off / fade (also on preview channels) m_SndFile.NoteChange(m_SndFile.m_PlayState.Chn[channel], note); - for(CHANNELINDEX c = m_SndFile.GetNumChannels(); c < MAX_CHANNELS; c++) + for(ModChannel &chn : m_SndFile.m_PlayState.BackgroundChannels(m_SndFile)) { - ModChannel &chn = m_SndFile.m_PlayState.Chn[c]; if(chn.isPreviewNote && (chn.pModSample || chn.pModInstrument)) { m_SndFile.NoteChange(chn, note); @@ -1263,13 +1262,13 @@ // If note == 0, just check if an instrument or sample is playing. bool CModDoc::IsNotePlaying(UINT note, SAMPLEINDEX nsmp, INSTRUMENTINDEX nins) { - ModChannel *pChn = &m_SndFile.m_PlayState.Chn[m_SndFile.GetNumChannels()]; - for (CHANNELINDEX i = m_SndFile.GetNumChannels(); i < MAX_CHANNELS; i++, pChn++) if (pChn->isPreviewNote) + for(ModChannel &chn : m_SndFile.m_PlayState.BackgroundChannels(m_SndFile)) { - if(pChn->nLength != 0 && !pChn->dwFlags[CHN_NOTEFADE | CHN_KEYOFF| CHN_MUTE] - && (note == pChn->nNewNote || note == NOTE_NONE) - && (pChn->pModSample == &m_SndFile.GetSample(nsmp) || !nsmp) - && (pChn->pModInstrument == m_SndFile.Instruments[nins] || !nins)) return true; + if(chn.isPreviewNote && chn.nLength != 0 && !chn.dwFlags[CHN_NOTEFADE | CHN_KEYOFF| CHN_MUTE] + && (note == chn.nNewNote || note == NOTE_NONE) + && (chn.pModSample == &m_SndFile.GetSample(nsmp) || !nsmp) + && (chn.pModInstrument == m_SndFile.Instruments[nins] || !nins)) + return true; } return false; } @@ -2140,10 +2139,14 @@ CriticalSection cs; // Kill editor voices - for(CHANNELINDEX i = m_SndFile.GetNumChannels(); i < MAX_CHANNELS; i++) if (m_SndFile.m_PlayState.Chn[i].isPreviewNote) + for(ModChannel &chn : m_SndFile.m_PlayState.BackgroundChannels(m_SndFile)) { - m_SndFile.m_PlayState.Chn[i].dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); - if (!isPlaying) m_SndFile.m_PlayState.Chn[i].nLength = 0; + if(chn.isPreviewNote) + { + chn.dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); + if(!isPlaying) + chn.nLength = 0; + } } m_SndFile.m_PlayState.m_flags.set(SONG_POSITIONCHANGED); @@ -2585,9 +2588,9 @@ CriticalSection cs; // Cut instruments/samples - for(CHANNELINDEX i = m_SndFile.GetNumChannels(); i < MAX_CHANNELS; i++) + for(ModChannel &chn : m_SndFile.m_PlayState.BackgroundChannels(m_SndFile)) { - m_SndFile.m_PlayState.Chn[i].dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); + chn.dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); } if ((nOrd < m_SndFile.Order().size()) && (m_SndFile.Order()[nOrd] == nPat)) m_SndFile.m_PlayState.m_nCurrentOrder = m_SndFile.m_PlayState.m_nNextOrder = nOrd; m_SndFile.m_PlayState.m_flags.reset(SONG_PAUSED | SONG_STEP); @@ -2635,9 +2638,9 @@ CriticalSection cs; // Cut instruments/samples - for(CHANNELINDEX i = m_SndFile.GetNumChannels(); i < MAX_CHANNELS; i++) + for(ModChannel &chn : m_SndFile.m_PlayState.BackgroundChannels(m_SndFile)) { - m_SndFile.m_PlayState.Chn[i].dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); + chn.dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); } m_SndFile.m_PlayState.m_flags.reset(SONG_PAUSED | SONG_STEP); m_SndFile.SetCurrentOrder(nOrd); @@ -2876,7 +2879,7 @@ SetPathName(newPath, FALSE); } - UpdateAllViews(NULL, UpdateHint().ModType()); + UpdateAllViews(nullptr, UpdateHint().ModType()); } Modified: trunk/OpenMPT/mptrack/Modedit.cpp ============================================================================== --- trunk/OpenMPT/mptrack/Modedit.cpp Fri May 31 11:49:23 2024 (r20881) +++ trunk/OpenMPT/mptrack/Modedit.cpp Fri May 31 15:50:38 2024 (r20882) @@ -86,10 +86,7 @@ // Increasing number of channels BeginWaitCursor(); std::vector<CHANNELINDEX> channels(nNewChannels, CHANNELINDEX_INVALID); - for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) - { - channels[chn] = chn; - } + std::iota(channels.begin(), channels.begin() + GetNumChannels(), CHANNELINDEX(0)); bool success = (ReArrangeChannels(channels) == nNewChannels); if(success) @@ -107,11 +104,12 @@ // Return true on success. bool CModDoc::RemoveChannels(const std::vector<bool> &keepMask, bool verbose) { + MPT_ASSERT(keepMask.size() == GetNumChannels()); CHANNELINDEX nRemainingChannels = 0; //First calculating how many channels are to be left - for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) + for(bool keep : keepMask) { - if(keepMask[chn]) + if(keep) nRemainingChannels++; } if(nRemainingChannels == GetNumChannels() || nRemainingChannels < m_SndFile.GetModSpecifications().channelsMin) @@ -135,9 +133,7 @@ for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { if(keepMask[chn]) - { channels[i++] = chn; - } } const bool success = (ReArrangeChannels(channels) == nRemainingChannels); if(success) @@ -255,7 +251,7 @@ channel.Reset(ModChannel::resetTotal, m_SndFile, chn, muteFlag); } - std::vector<ModChannel> chns(std::begin(m_SndFile.m_PlayState.Chn), std::begin(m_SndFile.m_PlayState.Chn) + oldNumChannels); + std::vector<ModChannel> chns(m_SndFile.m_PlayState.Chn.begin(), m_SndFile.m_PlayState.Chn.begin() + oldNumChannels); std::vector<ModChannelSettings> settings(std::begin(m_SndFile.ChnSettings), std::begin(m_SndFile.ChnSettings) + oldNumChannels); std::vector<RecordGroup> recordStates(oldNumChannels); auto chnMutePendings = m_SndFile.m_bChannelMuteTogglePending; @@ -377,7 +373,7 @@ GetSampleUndo().RearrangeSamples(newIndex); const auto muteFlag = CSoundFile::GetChannelMuteFlag(); - for(CHANNELINDEX c = 0; c < std::size(m_SndFile.m_PlayState.Chn); c++) + for(CHANNELINDEX c = 0; c < m_SndFile.m_PlayState.Chn.size(); c++) { ModChannel &chn = m_SndFile.m_PlayState.Chn[c]; for(SAMPLEINDEX i = 1; i <= oldNumSamples; i++) Modified: trunk/OpenMPT/mptrack/View_pat.cpp ============================================================================== --- trunk/OpenMPT/mptrack/View_pat.cpp Fri May 31 11:49:23 2024 (r20881) +++ trunk/OpenMPT/mptrack/View_pat.cpp Fri May 31 15:50:38 2024 (r20882) @@ -2234,9 +2234,9 @@ InvalidatePattern(true, true); // Cut instruments/samples in virtual channels - for(CHANNELINDEX i = sndFile.GetNumChannels(); i < MAX_CHANNELS; i++) + for(ModChannel &chn : sndFile.m_PlayState.BackgroundChannels(sndFile)) { - sndFile.m_PlayState.Chn[i].dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); + chn.dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); } sndFile.LoopPattern(m_nPattern); sndFile.m_PlayState.m_nNextRow = row == ROWINDEX_INVALID ? GetCurrentRow() : row; Modified: trunk/OpenMPT/soundlib/PlayState.cpp ============================================================================== --- trunk/OpenMPT/soundlib/PlayState.cpp Fri May 31 11:49:23 2024 (r20881) +++ trunk/OpenMPT/soundlib/PlayState.cpp Fri May 31 15:50:38 2024 (r20882) @@ -12,6 +12,7 @@ #include "PlayState.h" #include "MIDIMacros.h" #include "Mixer.h" +#include "Sndfile.h" OPENMPT_NAMESPACE_BEGIN @@ -19,7 +20,7 @@ PlayState::PlayState() { - std::fill(std::begin(Chn), std::end(Chn), ModChannel{}); + Chn.fill({}); m_midiMacroScratchSpace.reserve(kMacroLength); // Note: If macros ever become variable-length, the scratch space needs to be at least one byte longer than the longest macro in the file for end-of-SysEx insertion to stay allocation-free in the mixer! } @@ -33,4 +34,16 @@ } +mpt::span<ModChannel> PlayState::PatternChannels(const CSoundFile &sndFile) noexcept +{ + return mpt::as_span(Chn).subspan(0, std::min(Chn.size(), static_cast<size_t>(sndFile.GetNumChannels()))); +} + + +mpt::span<ModChannel> PlayState::BackgroundChannels(const CSoundFile &sndFile) noexcept +{ + return mpt::as_span(Chn).subspan(std::min(Chn.size(), static_cast<size_t>(sndFile.GetNumChannels()))); +} + + OPENMPT_NAMESPACE_END Modified: trunk/OpenMPT/soundlib/PlayState.h ============================================================================== --- trunk/OpenMPT/soundlib/PlayState.h Fri May 31 11:49:23 2024 (r20881) +++ trunk/OpenMPT/soundlib/PlayState.h Fri May 31 15:50:38 2024 (r20882) @@ -70,8 +70,8 @@ public: FlagSet<PlayFlags> m_flags = SONG_POSITIONCHANGED; - CHANNELINDEX ChnMix[MAX_CHANNELS]; // Index of channels in Chn to be actually mixed - ModChannel Chn[MAX_CHANNELS]; // Mixing channels... First m_nChannels channels are master channels (i.e. they are never NNA channels)! + std::array<CHANNELINDEX, MAX_CHANNELS> ChnMix; // Index of channels in Chn to be actually mixed + std::array<ModChannel, MAX_CHANNELS> Chn; // Mixing channels... First m_nChannels channels are directly mapped to pattern channels (i.e. they are never NNA channels)! GlobalScriptState m_globalScriptState; struct MIDIMacroEvaluationResults @@ -92,6 +92,18 @@ { return (m_nMusicSpeed + m_nFrameDelay) * std::max(m_nPatternDelay, uint32(1)); } + + mpt::span<ModChannel> PatternChannels(const CSoundFile &sndFile) noexcept; + mpt::span<const ModChannel> PatternChannels(const CSoundFile &sndFile) const noexcept + { + return const_cast<PlayState *>(this)->PatternChannels(sndFile); + } + + mpt::span<ModChannel> BackgroundChannels(const CSoundFile &sndFile) noexcept; + mpt::span<const ModChannel> BackgroundChannels(const CSoundFile &sndFile) const noexcept + { + return const_cast<PlayState *>(this)->PatternChannels(sndFile); + } }; Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp Fri May 31 11:49:23 2024 (r20881) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp Fri May 31 15:50:38 2024 (r20882) @@ -2208,7 +2208,7 @@ CHANNELINDEX CSoundFile::GetNNAChannel(CHANNELINDEX nChn) const { // Check for empty channel - for(CHANNELINDEX i = m_nChannels; i < MAX_CHANNELS; i++) + for(CHANNELINDEX i = m_nChannels; i < m_PlayState.Chn.size(); i++) { const ModChannel &c = m_PlayState.Chn[i]; // No sample and no plugin playing @@ -2231,7 +2231,7 @@ // All channels are used: check for lowest volume CHANNELINDEX result = CHANNELINDEX_INVALID; uint32 envpos = 0; - for(CHANNELINDEX i = m_nChannels; i < MAX_CHANNELS; i++) + for(CHANNELINDEX i = m_nChannels; i < m_PlayState.Chn.size(); i++) { const ModChannel &c = m_PlayState.Chn[i]; // Stopped OPL channel @@ -2326,7 +2326,7 @@ if(srcChn.dwFlags[CHN_MUTE]) return CHANNELINDEX_INVALID; - for(CHANNELINDEX i = nChn; i < MAX_CHANNELS; i++) + for(CHANNELINDEX i = nChn; i < m_PlayState.Chn.size(); i++) { // Only apply to background channels, or the same pattern channel if(i < m_nChannels && i != nChn) @@ -4278,11 +4278,10 @@ { SetFinetune(pattern, row, channel, m_PlayState, isSmooth); // Also apply to notes played via CModDoc::PlayNote - for(CHANNELINDEX chn = GetNumChannels(); chn < MAX_CHANNELS; chn++) + for(ModChannel &chn : m_PlayState.BackgroundChannels(*this)) { - auto &modChn = m_PlayState.Chn[chn]; - if(modChn.nMasterChn == channel + 1 && modChn.isPreviewNote && !modChn.dwFlags[CHN_KEYOFF]) - modChn.microTuning = m_PlayState.Chn[channel].microTuning; + if(chn.nMasterChn == channel + 1 && chn.isPreviewNote && !chn.dwFlags[CHN_KEYOFF]) + chn.microTuning = m_PlayState.Chn[channel].microTuning; } } @@ -5109,7 +5108,7 @@ case 1: case 2: { - for (CHANNELINDEX i = m_nChannels; i < MAX_CHANNELS; i++) + for(CHANNELINDEX i = m_nChannels; i < m_PlayState.Chn.size(); i++) { ModChannel &bkChn = m_PlayState.Chn[i]; if (bkChn.nMasterChn == nChn + 1) @@ -6380,11 +6379,10 @@ // IT compatibility 10. Pattern loops (+ same fix for XM / MOD / S3M files) if(!m_playBehaviour[kITFT2PatternLoop] && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_S3M))) { - auto p = std::cbegin(state.Chn); - for(CHANNELINDEX i = 0; i < GetNumChannels(); i++, p++) + for(const ModChannel &otherChn : state.PatternChannels(*this)) { // Loop on other channel - if(p != &chn && p->nPatternLoopCount) + if(&otherChn != &chn && otherChn.nPatternLoopCount) return; } } @@ -6651,7 +6649,7 @@ PLUGINDEX CSoundFile::GetBestPlugin(const PlayState &playState, CHANNELINDEX nChn, PluginPriority priority, PluginMutePriority respectMutes) const { - if (nChn >= MAX_CHANNELS) //Check valid channel number + if (nChn >= m_PlayState.Chn.size()) //Check valid channel number { return 0; } Modified: trunk/OpenMPT/soundlib/Sndfile.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp Fri May 31 11:49:23 2024 (r20881) +++ trunk/OpenMPT/soundlib/Sndfile.cpp Fri May 31 15:50:38 2024 (r20882) @@ -887,7 +887,7 @@ void CSoundFile::ResetPlayPos() { const auto muteFlag = GetChannelMuteFlag(); - for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++) + for(CHANNELINDEX i = 0; i < m_PlayState.Chn.size(); i++) m_PlayState.Chn[i].Reset(ModChannel::resetSetPosFull, *this, i, muteFlag); m_visitedRows.Initialize(true); @@ -1033,15 +1033,13 @@ { m_PlayState.m_flags.reset(SONG_FADINGSONG | SONG_ENDREACHED); m_PlayState.m_nBufferCount = 0; - for(auto &chn : m_PlayState.Chn) + for(CHANNELINDEX channel = 0; channel < m_PlayState.Chn.size(); channel++) { + ModChannel &chn = m_PlayState.Chn[channel]; chn.nROfs = chn.nLOfs = 0; chn.nLength = 0; if(chn.dwFlags[CHN_ADLIB] && m_opl) - { - CHANNELINDEX c = static_cast<CHANNELINDEX>(std::distance(std::begin(m_PlayState.Chn), &chn)); - m_opl->NoteCut(c); - } + m_opl->NoteCut(channel); } } @@ -1901,10 +1899,8 @@ return static_cast<double>(2500 * speed) / tempo.ToDouble(); case TempoMode::Modern: - { - // If there are any row delay effects, the row length factor compensates for those. - return 60000.0 / tempo.ToDouble() / static_cast<double>(m_PlayState.m_nCurrentRowsPerBeat); - } + // If there are any row delay effects, the row length factor compensates for those. + return 60000.0 / tempo.ToDouble() / static_cast<double>(m_PlayState.m_nCurrentRowsPerBeat); case TempoMode::Alternative: return static_cast<double>(1000 * speed) / tempo.ToDouble(); Modified: trunk/OpenMPT/soundlib/Sndfile.h ============================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h Fri May 31 11:49:23 2024 (r20881) +++ trunk/OpenMPT/soundlib/Sndfile.h Fri May 31 15:50:38 2024 (r20882) @@ -567,11 +567,9 @@ #endif // MODPLUG_TRACKER public: -#ifdef LIBOPENMPT_BUILD -#ifndef NO_PLUGINS +#if defined(LIBOPENMPT_BUILD) && !defined(NO_PLUGINS) std::unique_ptr<CVstPluginManager> m_PluginManager; #endif -#endif public: std::string m_songName; Modified: trunk/OpenMPT/soundlib/Sndmix.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp Fri May 31 11:49:23 2024 (r20881) +++ trunk/OpenMPT/soundlib/Sndmix.cpp Fri May 31 15:50:38 2024 (r20882) @@ -498,7 +498,7 @@ m_PlayState.m_nMusicSpeed = Order().GetDefaultSpeed(); m_PlayState.m_nMusicTempo = Order().GetDefaultTempo(); m_PlayState.m_nGlobalVolume = m_nDefaultGlobalVolume; - for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++) + for(CHANNELINDEX i = 0; i < m_PlayState.Chn.size(); i++) { auto &chn = m_PlayState.Chn[i]; if(chn.dwFlags[CHN_ADLIB] && m_opl) @@ -639,7 +639,7 @@ } // When jumping to the next subsong, stop all playing notes from the previous song... const auto muteFlag = CSoundFile::GetChannelMuteFlag(); - for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++) + for(CHANNELINDEX i = 0; i < m_PlayState.Chn.size(); i++) m_PlayState.Chn[i].Reset(ModChannel::resetSetPosFull, *this, i, muteFlag); StopAllVsti(); // ...and the global playback information. @@ -667,55 +667,55 @@ // Reset channel values ModCommand *m = Patterns[m_PlayState.m_nPattern].GetpModCommand(m_PlayState.m_nRow, 0); - for (ModChannel *pChn = m_PlayState.Chn, *pEnd = pChn + m_nChannels; pChn != pEnd; pChn++, m++) + for(ModChannel &chn : m_PlayState.PatternChannels(*this)) { // First, handle some quirks that happen after the last tick of the previous row... if(m_playBehaviour[KST3PortaAfterArpeggio] - && pChn->nCommand == CMD_ARPEGGIO // Previous row state! + && chn.nCommand == CMD_ARPEGGIO // Previous row state! && (m->command == CMD_PORTAMENTOUP || m->command == CMD_PORTAMENTODOWN)) { // In ST3, a portamento immediately following an arpeggio continues where the arpeggio left off. // Test case: PortaAfterArp.s3m - pChn->nPeriod = GetPeriodFromNote(pChn->nArpeggioLastNote, pChn->nFineTune, pChn->nC5Speed); + chn.nPeriod = GetPeriodFromNote(chn.nArpeggioLastNote, chn.nFineTune, chn.nC5Speed); } if(m_playBehaviour[kMODOutOfRangeNoteDelay] && !m->IsNote() - && pChn->rowCommand.IsNote() - && pChn->rowCommand.command == CMD_MODCMDEX && (pChn->rowCommand.param & 0xF0) == 0xD0 - && (pChn->rowCommand.param & 0x0Fu) >= m_PlayState.m_nMusicSpeed) + && chn.rowCommand.IsNote() + && chn.rowCommand.command == CMD_MODCMDEX && (chn.rowCommand.param & 0xF0) == 0xD0 + && (chn.rowCommand.param & 0x0Fu) >= m_PlayState.m_nMusicSpeed) { // In ProTracker, a note triggered by an out-of-range note delay can be heard on the next row // if there is no new note on that row. // Test case: NoteDelay-NextRow.mod - pChn->nPeriod = GetPeriodFromNote(pChn->rowCommand.note, pChn->nFineTune, 0); + chn.nPeriod = GetPeriodFromNote(chn.rowCommand.note, chn.nFineTune, 0); } if(m_playBehaviour[kST3TonePortaWithAdlibNote] && !m->IsNote() - && pChn->dwFlags[CHN_ADLIB] - && pChn->nPortamentoDest - && pChn->rowCommand.IsNote() - && pChn->rowCommand.IsTonePortamento()) + && chn.dwFlags[CHN_ADLIB] + && chn.nPortamentoDest + && chn.rowCommand.IsNote() + && chn.rowCommand.IsTonePortamento()) { // ST3: Adlib Note + Tone Portamento does not execute the slide, but changes to the target note instantly on the next row (unless there is another note with tone portamento) // Test case: TonePortamentoWithAdlibNote.s3m - pChn->nPeriod = pChn->nPortamentoDest; + chn.nPeriod = chn.nPortamentoDest; } - if(m_playBehaviour[kMODTempoOnSecondTick] && !m_playBehaviour[kMODVBlankTiming] && m_PlayState.m_nMusicSpeed == 1 && pChn->rowCommand.command == CMD_TEMPO) + if(m_playBehaviour[kMODTempoOnSecondTick] && !m_playBehaviour[kMODVBlankTiming] && m_PlayState.m_nMusicSpeed == 1 && chn.rowCommand.command == CMD_TEMPO) { // ProTracker sets the tempo after the first tick. This block handles the case of one tick per row. // Test case: TempoChange.mod - m_PlayState.m_nMusicTempo = TEMPO(std::max(ModCommand::PARAM(1), pChn->rowCommand.param), 0); + m_PlayState.m_nMusicTempo = TEMPO(std::max(ModCommand::PARAM(1), chn.rowCommand.param), 0); } - pChn->rowCommand = *m; - - pChn->rightVol = pChn->newRightVol; - pChn->leftVol = pChn->newLeftVol; - pChn->dwFlags.reset(CHN_VIBRATO | CHN_TREMOLO); - if(!m_playBehaviour[kITVibratoTremoloPanbrello]) pChn->nPanbrelloOffset = 0; - pChn->nCommand = CMD_NONE; - pChn->m_plugParamValueStep = 0; + chn.rightVol = chn.newRightVol; + chn.leftVol = chn.newLeftVol; + chn.dwFlags.reset(CHN_VIBRATO | CHN_TREMOLO); + if(!m_playBehaviour[kITVibratoTremoloPanbrello]) + chn.nPanbrelloOffset = 0; + chn.nCommand = CMD_NONE; + chn.m_plugParamValueStep = 0; + chn.rowCommand = *m++; } // Now that we know which pattern we're on, we can update time signatures (global or pattern-specific) @@ -2139,7 +2139,7 @@ //////////////////////////////////////////////////////////////////////////////////// // Update channels data m_nMixChannels = 0; - for (CHANNELINDEX nChn = 0; nChn < MAX_CHANNELS; nChn++) + for(CHANNELINDEX nChn = 0; nChn < m_PlayState.Chn.size(); nChn++) { ModChannel &chn = m_PlayState.Chn[nChn]; // FT2 Compatibility: Prevent notes to be stopped after a fadeout. This way, a portamento effect can pick up a faded instrument which is long enough. |