From: <sv...@op...> - 2024-10-16 18:29:47
|
Author: sagamusix Date: Wed Oct 16 20:29:32 2024 New Revision: 21836 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=21836 Log: [Ref] Don't use fixed-size arrays for channel states in pattern editor code. Modified: trunk/OpenMPT/mptrack/Draw_pat.cpp trunk/OpenMPT/mptrack/View_pat.cpp trunk/OpenMPT/mptrack/View_pat.h Modified: trunk/OpenMPT/mptrack/Draw_pat.cpp ============================================================================== --- trunk/OpenMPT/mptrack/Draw_pat.cpp Wed Oct 16 18:24:00 2024 (r21835) +++ trunk/OpenMPT/mptrack/Draw_pat.cpp Wed Oct 16 20:29:32 2024 (r21836) @@ -50,16 +50,11 @@ COLUMN_BITS_FXPARAM = 0x10, COLUMN_BITS_FXCMDANDPARAM = 0x18, COLUMN_BITS_ALLCOLUMNS = 0x1F, - COLUMN_BITS_UNKNOWN = 0x20, // Appears to be unused - COLUMN_BITS_ALL = 0x3F, COLUMN_BITS_SKIP = 0x40, COLUMN_BITS_INVISIBLE = 0x80, }; - - - ///////////////////////////////////////////////////////////////////////////// // Effect colour codes @@ -526,7 +521,9 @@ MPT_ASSERT(pDC); UpdateSizes(); - if ((pModDoc = GetDocument()) == nullptr) return; + if ((pModDoc = GetDocument()) == nullptr) + return; + m_chnState.resize(pModDoc->GetNumChannels()); const int vuHeight = MulDiv(VUMETERS_HEIGHT, m_nDPIy, 96); const int colHeight = MulDiv(COLHDR_HEIGHT, m_nDPIy, 96); @@ -760,7 +757,7 @@ if(m_Status[psShowVUMeters]) { - OldVUMeters[ncolhdr] = 0; + m_chnState[ncolhdr].vuMeterOld = 0; DrawChannelVUMeter(hdc, rect.left, rect.bottom, ncolhdr); rect.top += vuHeight; rect.bottom += vuHeight; @@ -809,35 +806,34 @@ void CViewPattern::DrawPatternData(HDC hdc, PATTERNINDEX nPattern, bool selEnable, bool isPlaying, ROWINDEX startRow, ROWINDEX numRows, CHANNELINDEX startChan, CRect &rcClient, int *pypaint) { - uint8 selectedCols[MAX_BASECHANNELS] = {}; // Bit mask of selected channel components - static_assert(1 << PatternCursor::lastColumn <= Util::MaxValueOfType(selectedCols[0]) , "Columns are used as bitmasks."); + static_assert(1 << PatternCursor::lastColumn <= Util::MaxValueOfType(ChannelState{}.selectedCols), "Columns are used as bitmasks"); + static_assert(!((1 << PatternCursor::lastColumn) & (COLUMN_BITS_INVISIBLE | COLUMN_BITS_SKIP)), "Column bits and special bits overlap"); const CSoundFile &sndFile = GetDocument()->GetSoundFile(); if(!sndFile.Patterns.IsValidPat(nPattern)) - { return; - } const CPattern &pattern = sndFile.Patterns[nPattern]; const auto patternSetupFlags = TrackerSettings::Instance().m_dwPatternSetup.Get(); const PATTERNFONT *pfnt = PatternFont::currentFont; CRect rect; int xpaint, ypaint = *pypaint; - UINT nColumnWidth; - CHANNELINDEX ncols = sndFile.GetNumChannels(); - nColumnWidth = m_szCell.cx; + const CHANNELINDEX ncols = sndFile.GetNumChannels(); + const UINT nColumnWidth = m_szCell.cx; rect.SetRect(m_szHeader.cx, rcClient.top, m_szHeader.cx+nColumnWidth, rcClient.bottom); for(CHANNELINDEX cmk = startChan; cmk < ncols; cmk++) { - selectedCols[cmk] = selEnable ? m_Selection.GetSelectionBits(cmk) : 0; - if (!::RectVisible(hdc, &rect)) selectedCols[cmk] |= COLUMN_BITS_INVISIBLE; + m_chnState[cmk].selectedCols = selEnable ? m_Selection.GetSelectionBits(cmk) : 0; + if(!::RectVisible(hdc, &rect)) + m_chnState[cmk].selectedCols |= COLUMN_BITS_INVISIBLE; rect.left += nColumnWidth; rect.right += nColumnWidth; } // Max Visible Column CHANNELINDEX maxcol = ncols; - while ((maxcol > startChan) && (selectedCols[maxcol-1] & COLUMN_BITS_INVISIBLE)) maxcol--; + while((maxcol > startChan) && (m_chnState[maxcol -1].selectedCols & COLUMN_BITS_INVISIBLE)) + maxcol--; // Init bitmap border { UINT maxndx = sndFile.GetNumChannels() * m_szCell.cx; @@ -878,7 +874,7 @@ { // No speedup for these columns next time for(CHANNELINDEX iup = startChan; iup < maxcol; iup++) - selectedCols[iup] &= ~COLUMN_BITS_SKIP; + m_chnState[iup].selectedCols &= ~COLUMN_BITS_SKIP; // skip row ypaint += m_szCell.cy; if(ypaint >= rcClient.bottom) @@ -887,7 +883,7 @@ } rect.right = rect.left + m_szHeader.cx; - bool rowDisabled = sndFile.m_lockRowStart != ROWINDEX_INVALID && (row < sndFile.m_lockRowStart || row > sndFile.m_lockRowEnd); + const bool rowDisabled = sndFile.m_lockRowStart != ROWINDEX_INVALID && (row < sndFile.m_lockRowStart || row > sndFile.m_lockRowEnd); TCHAR s[32]; if(hexNumbers) wsprintf(s, _T("%s%02X"), compRow < 0 ? _T("-") : _T(""), std::abs(compRow)); @@ -948,14 +944,14 @@ // Eliminate non-visible column xpaint = m_szHeader.cx; col = startChan; - while ((selectedCols[col] & COLUMN_BITS_INVISIBLE) && (col < maxcol)) + while((m_chnState[col].selectedCols & COLUMN_BITS_INVISIBLE) && (col < maxcol)) { - selectedCols[col] &= ~COLUMN_BITS_SKIP; + m_chnState[col].selectedCols &= ~COLUMN_BITS_SKIP; col++; xpaint += nColumnWidth; } // Optimization: same row color ? - bool useSpeedUpMask = (oldrowcolor == EncodeRowColor(row_bkcol, row_col, bRowSel)) && !blendModeChanged; + const bool useSpeedUpMask = (oldrowcolor == EncodeRowColor(row_bkcol, row_col, bRowSel)) && !blendModeChanged; xbmp = nbmp = 0; do { @@ -967,7 +963,7 @@ const bool drawDefaultVolume = DrawDefaultVolume(m); DWORD dwSpeedUpMask = 0; - if (useSpeedUpMask && (selectedCols[col] & COLUMN_BITS_SKIP) && (row)) + if(useSpeedUpMask && (m_chnState[col].selectedCols & COLUMN_BITS_SKIP) && (row)) { const ModCommand *mold = m - ncols; const bool drawOldDefaultVolume = DrawDefaultVolume(mold); @@ -989,9 +985,9 @@ } if (dwSpeedUpMask == COLUMN_BITS_ALLCOLUMNS) goto DoBlit; } - selectedCols[col] |= COLUMN_BITS_SKIP; + m_chnState[col].selectedCols |= COLUMN_BITS_SKIP; col_sel = 0; - if (bRowSel) col_sel = selectedCols[col] & COLUMN_BITS_ALL; + if(bRowSel) col_sel = m_chnState[col].selectedCols & COLUMN_BITS_ALLCOLUMNS; tx_col = row_col; bk_col = row_bkcol; if (col_sel) @@ -1184,17 +1180,16 @@ if (ypaint >= rcClient.bottom) break; } *pypaint = ypaint; - } void CViewPattern::DrawChannelVUMeter(HDC hdc, int x, int y, UINT nChn) { - if(ChnVUMeters[nChn] == OldVUMeters[nChn]) + if(m_chnState[nChn].vuMeter == m_chnState[nChn].vuMeterOld) return; - uint8 vuL = static_cast<uint8>((ChnVUMeters[nChn] & 0xFF00) >> 8); - uint8 vuR = static_cast<uint8>(ChnVUMeters[nChn] & 0xFF); + uint8 vuL = static_cast<uint8>((m_chnState[nChn].vuMeter & 0xFF00) >> 8); + uint8 vuR = static_cast<uint8>(m_chnState[nChn].vuMeter & 0xFF); vuL /= 15; vuR /= 15; LimitMax(vuL, uint8(8)); @@ -1216,7 +1211,7 @@ BitBlt(hdc, x + midSpacer / 2, y, barWidth, m_ledHeight, m_vuMeterDC, srcOffsetX + barWidth, vuR * m_ledHeight, SRCCOPY); m_vuMeterDC.SelectObject(oldBitmap); - OldVUMeters[nChn] = ChnVUMeters[nChn]; + m_chnState[nChn].vuMeterOld = m_chnState[nChn].vuMeter; } @@ -1799,7 +1794,8 @@ CMainFrame *pMainFrm = CMainFrame::GetMainFrame(); const CModDoc *pModDoc = GetDocument(); - if ((!pModDoc) || (!pMainFrm)) return; + if(!pModDoc || !pMainFrm) + return; CRect rcClient; GetClientRect(&rcClient); int xofs = GetXScrollPos(); @@ -1807,11 +1803,13 @@ const bool isPlaying = (pMainFrm->GetFollowSong(pModDoc) == m_hWnd); int x = m_szHeader.cx; CHANNELINDEX nChn = static_cast<CHANNELINDEX>(xofs); + const CHANNELINDEX numChannels = std::min(pModDoc->GetNumChannels(), static_cast<CHANNELINDEX>(m_chnState.size())); const int yPos = rcClient.top + MulDiv(COLHDR_HEIGHT, m_nDPIy, 96); - while ((nChn < pModDoc->GetNumChannels()) && (x < rcClient.right)) + while(nChn < numChannels && x < rcClient.right) { - ChnVUMeters[nChn] = static_cast<uint16>(pnotify->pos[nChn]); - if ((!isPlaying) || pnotify->type[Notification::Stop]) ChnVUMeters[nChn] = 0; + m_chnState[nChn].vuMeter = static_cast<uint16>(pnotify->pos[nChn]); + if(!isPlaying || pnotify->type[Notification::Stop]) + m_chnState[nChn].vuMeter = 0; DrawChannelVUMeter(hdc, x, rcClient.top + yPos, nChn); nChn++; x += m_szCell.cx; Modified: trunk/OpenMPT/mptrack/View_pat.cpp ============================================================================== --- trunk/OpenMPT/mptrack/View_pat.cpp Wed Oct 16 18:24:00 2024 (r21835) +++ trunk/OpenMPT/mptrack/View_pat.cpp Wed Oct 16 20:29:32 2024 (r21836) @@ -177,9 +177,7 @@ { CModScrollView::OnInitialUpdate(); EnableToolTips(); - ChnVUMeters.fill(0); - OldVUMeters.fill(0); - m_previousNote.fill(NOTE_NONE); + m_chnState.assign(GetDocument()->GetNumChannels(), {}); m_splitActiveNoteChannel.fill(NOTE_CHANNEL_MAP_INVALID); m_activeNoteChannel.fill(NOTE_CHANNEL_MAP_INVALID); m_nPlayPat = PATTERNINDEX_INVALID; @@ -203,7 +201,6 @@ m_nLastPlayedRow = 0; m_nLastPlayedOrder = ORDERINDEX_INVALID; m_prevChordNote = NOTE_NONE; - m_previousPCevent.fill({PLUGINDEX_INVALID, 0}); } @@ -3643,7 +3640,8 @@ if(pnotify->type[Notification::Stop]) { m_baPlayingNote.reset(); - ChnVUMeters.fill(0); // Also zero all non-visible VU meters + for(auto &chnState : m_chnState) + chnState.vuMeter = 0; SetPlayCursor(PATTERNINDEX_INVALID, ROWINDEX_INVALID, 0); } @@ -3673,7 +3671,7 @@ continue; const ModCommand &m = *sndFile.Patterns[pattern].GetpModCommand(row, c); - if((m_previousPCevent[c] == plugParam && m.IsEmpty()) || (m.IsPcNote() && m.instr == plugSlot + 1 && m.GetValueVolCol() == paramIndex)) + if((c < m_chnState.size() && m_chnState[c].previousPCevent == plugParam && m.IsEmpty()) || (m.IsPcNote() && m.instr == plugSlot + 1 && m.GetValueVolCol() == paramIndex)) { return c; break; @@ -3725,7 +3723,8 @@ if(m.IsEmpty() || m.IsPcNote()) { m.Set(NOTE_PCS, static_cast<ModCommand::INSTR>(plugSlot + 1), static_cast<uint16>(paramIndex), static_cast<uint16>(pPlug->GetParameter(static_cast<PlugParamIndex>(paramIndex)) * ModCommand::maxColumnValue)); - m_previousPCevent[chn] = plugParam; + m_chnState.resize(sndFile.GetNumChannels()); + m_chnState[chn].previousPCevent = plugParam; } } else if(sndFile.GetModSpecifications().HasCommand(CMD_SMOOTHMIDI)) { @@ -3942,7 +3941,8 @@ ModCommand &m = GetModCommand(sndFile, editPos); pModDoc->GetPatternUndo().PrepareUndo(editPos.pattern, editPos.channel, editPos.row, 1, 1, "MIDI Mapping Record"); m.Set(NOTE_PCS, mappedIndex, static_cast<uint16>(paramIndex), static_cast<uint16>((paramValue * ModCommand::maxColumnValue) / 16383)); - m_previousPCevent[editPos.channel] = std::make_pair(static_cast<PLUGINDEX>(mappedIndex - 1), paramIndex); + m_chnState.resize(pModDoc->GetNumChannels()); + m_chnState[editPos.channel].previousPCevent = std::make_pair(static_cast<PLUGINDEX>(mappedIndex - 1), paramIndex); if(!liveRecord) InvalidateRow(editPos.row); pModDoc->SetModified(); @@ -5255,7 +5255,7 @@ bool modified = false; for(int i = 0; i < numNotes; i++) { - if(m_previousNote[noteChannels[i]] != notes[i]) + if(noteChannels[i] < m_chnState.size() && m_chnState[noteChannels[i]].previousNote != notes[i]) { // This might be a note-off from a past note, but since we already hit a new note on this channel, we ignore it. continue; @@ -5667,7 +5667,8 @@ if(newcmd.IsNote()) { - m_previousNote[nChn] = note; + m_chnState.resize(sndFile.GetNumChannels()); + m_chnState[nChn].previousNote = note; } // -- if recording, handle post note entry behaviour (move cursor etc..) @@ -5891,7 +5892,8 @@ m_chordPatternChannels[i] = curChn; ModCommand &m = newRow[curChn]; - m_previousNote[curChn] = m.note = chordNotes[i]; + m_chnState.resize(sndFile.GetNumChannels()); + m_chnState[curChn].previousNote = m.note = chordNotes[i]; if(newRow[chn].instr) { m.instr = newRow[chn].instr; Modified: trunk/OpenMPT/mptrack/View_pat.h ============================================================================== --- trunk/OpenMPT/mptrack/View_pat.h Wed Oct 16 18:24:00 2024 (r21835) +++ trunk/OpenMPT/mptrack/View_pat.h Wed Oct 16 20:29:32 2024 (r21836) @@ -211,19 +211,24 @@ std::array<std::vector<uint32>, 16> m_midiSustainBuffer; std::bitset<16> m_midiSustainActive; - std::array<uint16, MAX_BASECHANNELS> ChnVUMeters; - std::array<uint16, MAX_BASECHANNELS> OldVUMeters; + struct ChannelState + { + uint16 vuMeter = 0; + uint16 vuMeterOld = 0; + std::pair<PLUGINDEX, PlugParamIndex> previousPCevent = {PLUGINDEX_INVALID, 0}; + ModCommand::NOTE previousNote = NOTE_NONE; + uint8 selectedCols = 0; + }; + std::vector<ChannelState> m_chnState; std::bitset<128> m_baPlayingNote; CModDoc::NoteToChannelMap m_noteChannel; // Note -> Preview channel assignment - std::array<ModCommand::NOTE, 10> m_octaveKeyMemory; - std::array<ModCommand::NOTE, MAX_BASECHANNELS> m_previousNote; - std::array<std::pair<PLUGINDEX, PlugParamIndex>, MAX_BASECHANNELS> m_previousPCevent; // For multichannel recording + std::array<ModCommand::NOTE, (NOTE_MAX - NOTE_MIN + 12) / 12> m_octaveKeyMemory; std::array<uint8, NOTE_MAX + NOTE_MIN> m_activeNoteChannel; std::array<uint8, NOTE_MAX + NOTE_MIN> m_splitActiveNoteChannel; static constexpr uint8 NOTE_CHANNEL_MAP_INVALID = 0xFF; - static_assert(MAX_BASECHANNELS <= std::numeric_limits<decltype(m_activeNoteChannel)::value_type>::max()); - static_assert(MAX_BASECHANNELS <= NOTE_CHANNEL_MAP_INVALID); + static_assert(MAX_BASECHANNELS - 1 <= std::numeric_limits<decltype(m_activeNoteChannel)::value_type>::max()); + static_assert(MAX_BASECHANNELS - 1 < NOTE_CHANNEL_MAP_INVALID); public: std::unique_ptr<CEffectVis> m_pEffectVis; @@ -488,8 +493,6 @@ afx_msg void OnUpdateUndo(CCmdUI *pCmdUI); afx_msg void OnUpdateRedo(CCmdUI *pCmdUI); afx_msg void OnSelectPlugin(UINT nID); - // cppcheck-suppress duplInheritedMember - afx_msg LRESULT OnUpdatePosition(WPARAM nOrd, LPARAM nRow); afx_msg LRESULT OnMidiMsg(WPARAM, LPARAM); afx_msg LRESULT OnRecordPlugParamChange(WPARAM, LPARAM); afx_msg LRESULT OnCustomKeyMsg(WPARAM, LPARAM); |