From: <sv...@op...> - 2024-12-28 23:02:02
|
Author: sagamusix Date: Sun Dec 29 00:01:50 2024 New Revision: 22639 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=22639 Log: [Fix] Plugin notes played live were no longer cleaning their channel status correctly with the new plugin NNA logic, causing unused NNA channels to pile up (https://bugs.openmpt.org/view.php?id=1853). Modified: trunk/OpenMPT/mptrack/Moddoc.cpp Modified: trunk/OpenMPT/mptrack/Moddoc.cpp ============================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp Sat Dec 28 21:10:22 2024 (r22638) +++ trunk/OpenMPT/mptrack/Moddoc.cpp Sun Dec 29 00:01:50 2024 (r22639) @@ -1085,8 +1085,9 @@ // Set instrument (or sample if there are no instruments) chn.ResetEnvelopes(); m_SndFile.InstrumentChange(chn, params.m_instr); - } else if(params.m_sample > 0 && params.m_sample <= GetNumSamples()) // Or set sample explicitely + } else if(params.m_sample > 0 && params.m_sample <= GetNumSamples()) { + // Or set sample explicitly ModSample &sample = m_SndFile.GetSample(params.m_sample); chn.pCurrentSample = sample.samplev(); chn.pModInstrument = nullptr; @@ -1118,8 +1119,6 @@ chn.nnaChannelAge = 0; // Handle sample looping. - // Changed line to fix http://forum.openmpt.org/index.php?topic=1700.0 - //if ((loopstart + 16 < loopend) && (loopstart >= 0) && (loopend <= (LONG)pchn.nLength)) if ((params.m_loopStart + 16 < params.m_loopEnd) && (params.m_loopStart >= 0) && (chn.pModSample != nullptr)) { chn.position.Set(params.m_loopStart); @@ -1199,13 +1198,15 @@ { CriticalSection cs; + const ModInstrument *pIns = nullptr; + IMixPlugin *pPlugin = nullptr; if(ins != INSTRUMENTINDEX_INVALID && ins <= m_SndFile.GetNumInstruments() && ModCommand::IsNote(ModCommand::NOTE(note))) { - const ModInstrument *pIns = m_SndFile.Instruments[ins]; - if(pIns && pIns->HasValidMIDIChannel()) // instro sends to a midi chan + pIns = m_SndFile.Instruments[ins]; + if(pIns && pIns->HasValidMIDIChannel()) { - PLUGINDEX plug = pIns->nMixPlug; // First try intrument VST - if((!plug || plug > MAX_MIXPLUGINS) // No good plug yet + PLUGINDEX plug = pIns->nMixPlug; // First try instrument VST + if((!plug || plug > MAX_MIXPLUGINS) // No good plug yet && currentChn < m_SndFile.ChnSettings.size()) { plug = m_SndFile.ChnSettings[currentChn].nMixPlugin; // Then try Channel VST @@ -1213,11 +1214,7 @@ if(plug && plug <= MAX_MIXPLUGINS) { - IMixPlugin *pPlugin = m_SndFile.m_MixPlugins[plug - 1].pMixPlugin; - if(pPlugin) - { - pPlugin->MidiCommand(*pIns, pIns->NoteMap[note - NOTE_MIN] | IMixPlugin::MIDI_NOTE_OFF, 0, currentChn); - } + pPlugin = m_SndFile.m_MixPlugins[plug - 1].pMixPlugin; } } } @@ -1226,25 +1223,33 @@ const CHANNELINDEX startChn = currentChn != CHANNELINDEX_INVALID ? currentChn : m_SndFile.GetNumChannels(); const CHANNELINDEX endChn = currentChn != CHANNELINDEX_INVALID ? currentChn + 1 : MAX_CHANNELS; ModChannel *pChn = &m_SndFile.m_PlayState.Chn[startChn]; - for(CHANNELINDEX i = startChn; i < endChn; i++, pChn++) + bool found = false; + for(CHANNELINDEX i = startChn; i < endChn && !found; i++, pChn++) { // Fade all channels > m_nChannels which are playing this note and aren't NNA channels. + if(pPlugin && pChn->pModInstrument == pIns && (currentChn == CHANNELINDEX_INVALID || currentChn == i) && pChn->lastMidiNoteWithoutArp == pIns->NoteMap[note - NOTE_MIN]) + { + pPlugin->MidiCommand(*pIns, pIns->NoteMap[note - NOTE_MIN] | IMixPlugin::MIDI_NOTE_OFF, 0, currentChn); + pChn->lastMidiNoteWithoutArp = NOTE_NONE; + found = true; + } if((pChn->isPreviewNote || i < m_SndFile.GetNumChannels()) && !pChn->dwFlags[mask] && (pChn->nLength || pChn->dwFlags[CHN_ADLIB]) && (note == pChn->nNewNote || note == NOTE_NONE)) { m_SndFile.KeyOff(*pChn); - if (!m_SndFile.m_nInstruments) pChn->dwFlags.reset(CHN_LOOP | CHN_PINGPONGFLAG); - if (fade) pChn->dwFlags.set(CHN_NOTEFADE); + if(!m_SndFile.m_nInstruments) pChn->dwFlags.reset(CHN_LOOP | CHN_PINGPONGFLAG); + if(fade) pChn->dwFlags.set(CHN_NOTEFADE); // Instantly stop samples that would otherwise play forever - if (pChn->pModInstrument && !pChn->pModInstrument->nFadeOut) + if(pChn->pModInstrument && !pChn->pModInstrument->nFadeOut) pChn->nFadeOutVol = 0; if(pChn->dwFlags[CHN_ADLIB] && m_SndFile.m_opl) { m_SndFile.m_opl->NoteOff(i); } - if (note) break; + if(note) + found = true; } } |