From: <sv...@op...> - 2024-11-01 20:00:49
|
Author: sagamusix Date: Fri Nov 1 21:00:41 2024 New Revision: 22051 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=22051 Log: [Fix] Avoid using ModChannel::nNewIns as sample index, as it may have been misinterpreted in some situations when sample swapping was going to happen at at time where nNewIns was pointing to a new pattern instrument index. [Mod] Use tone poratmento with duration command to achieve instant portamentos in various imported formats. Modified: trunk/OpenMPT/soundlib/Fastmix.cpp trunk/OpenMPT/soundlib/InstrumentSynth.cpp trunk/OpenMPT/soundlib/Load_fc.cpp trunk/OpenMPT/soundlib/Load_gt2.cpp trunk/OpenMPT/soundlib/Load_symmod.cpp trunk/OpenMPT/soundlib/ModChannel.cpp trunk/OpenMPT/soundlib/ModChannel.h trunk/OpenMPT/soundlib/Snd_fx.cpp Modified: trunk/OpenMPT/soundlib/Fastmix.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Fastmix.cpp Fri Nov 1 18:32:05 2024 (r22050) +++ trunk/OpenMPT/soundlib/Fastmix.cpp Fri Nov 1 21:00:41 2024 (r22051) @@ -482,7 +482,7 @@ const bool pastLoopEnd = chn.position.GetUInt() >= chn.nLoopEnd && chn.dwFlags[CHN_LOOP]; const bool pastSampleEnd = chn.position.GetUInt() >= chn.nLength && !chn.dwFlags[CHN_LOOP] && chn.nLength && !chn.nMasterChn; - const bool doSampleSwap = m_playBehaviour[kMODSampleSwap] && chn.nNewIns && chn.nNewIns <= GetNumSamples() && chn.pModSample != &Samples[chn.nNewIns]; + const bool doSampleSwap = m_playBehaviour[kMODSampleSwap] && chn.swapSampleIndex && chn.swapSampleIndex <= GetNumSamples() && chn.pModSample != &Samples[chn.swapSampleIndex]; if((pastLoopEnd || pastSampleEnd) && doSampleSwap) { // ProTracker compatibility: Instrument changes without a note do not happen instantly, but rather when the sample loop has finished playing. @@ -498,7 +498,7 @@ } } #endif - const ModSample &smp = Samples[chn.nNewIns]; + const ModSample &smp = Samples[chn.swapSampleIndex]; chn.pModSample = &smp; chn.pCurrentSample = smp.samplev(); chn.dwFlags = (chn.dwFlags & CHN_CHANNELFLAGS) | smp.uFlags; @@ -511,11 +511,10 @@ chn.nLoopStart = smp.nLoopStart; chn.nLoopEnd = smp.nLoopEnd; chn.position.SetInt(chn.nLoopStart); + chn.swapSampleIndex = 0; mixLoopState.UpdateLookaheadPointers(chn); if(!chn.pCurrentSample) - { break; - } } else if(pastLoopEnd && !doSampleSwap && m_playBehaviour[kMODOneShotLoops] && chn.nLoopStart == 0) { // ProTracker "oneshot" loops (if loop start is 0, play the whole sample once and then repeat until loop end) Modified: trunk/OpenMPT/soundlib/InstrumentSynth.cpp ============================================================================== --- trunk/OpenMPT/soundlib/InstrumentSynth.cpp Fri Nov 1 18:32:05 2024 (r22050) +++ trunk/OpenMPT/soundlib/InstrumentSynth.cpp Fri Nov 1 21:00:41 2024 (r22051) @@ -160,7 +160,7 @@ const bool channelIsActive = chn.pCurrentSample && chn.nLength; if(sndFile.m_playBehaviour[kMODSampleSwap] && smp <= uint8_max && swapAtEnd && channelIsActive) { - chn.nNewIns = static_cast<uint8>(smp); + chn.swapSampleIndex = smp; return; } const ModSample &sample = sndFile.GetSample(smp); @@ -790,7 +790,7 @@ chn.nGlobalVol = static_cast<uint8>(std::clamp(chn.nGlobalVol + event.i16, 0, 64)); return false; case Event::Type::FTM_SetSample: - chn.nNewIns = event.u8 + 1; + chn.swapSampleIndex = event.u8 + 1; return false; case Event::Type::FTM_SetSampleStart: // Documentation says this should be in words, but it really appears to work with bytes. @@ -848,6 +848,7 @@ if(event.Byte1() & (0x04 | 0x08)) { chn.nNewIns = srcChn.nNewIns; + chn.swapSampleIndex = srcChn.swapSampleIndex; chn.pModSample = srcChn.pModSample; chn.position = srcChn.position; chn.dwFlags = (chn.dwFlags & CHN_CHANNELFLAGS) | (srcChn.dwFlags & CHN_SAMPLEFLAGS); Modified: trunk/OpenMPT/soundlib/Load_fc.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_fc.cpp Fri Nov 1 18:32:05 2024 (r22050) +++ trunk/OpenMPT/soundlib/Load_fc.cpp Fri Nov 1 21:00:41 2024 (r22051) @@ -338,7 +338,7 @@ Order().resize(numOrders); if(loadFlags & loadPatternData) Patterns.ResizeArray(numOrders); - std::array<std::array<uint8, 2>, 4> prevNote = {{}}; + std::array<uint8, 4> prevNote = {{}}; for(ORDERINDEX ord = 0; ord < numOrders; ord++) { Order()[ord] = ord; @@ -364,20 +364,21 @@ if(p[0] > 0 && p[0] != 0x49) { + prevNote[chn] = p[0]; m->note = NOTE_MIN + ((chnInfo.noteTranspose + p[0]) & 0x7F); if(int instr = (p[1] & 0x3F) + chnInfo.instrTranspose + 1; instr >= 1 && instr <= m_nInstruments) m->instr = static_cast<ModCommand::INSTR>(instr); else m->instr = static_cast<ModCommand::INSTR>(m_nInstruments); - - prevNote[chn] = {p[0], static_cast<uint8>(m->instr)}; - } else if(row == 0 && ord > 0 && orderData[ord - 1].channels[chn].noteTranspose != chnInfo.noteTranspose && prevNote[chn][0] > 0) + } else if(row == 0 && ord > 0 && orderData[ord - 1].channels[chn].noteTranspose != chnInfo.noteTranspose && prevNote[chn] > 0) { - m->note = NOTE_MIN + ((chnInfo.noteTranspose + prevNote[chn][0]) & 0x7F); - m->instr = prevNote[chn][1]; - m->SetVolumeCommand(VOLCMD_TONEPORTAMENTO, 9); + m->note = NOTE_MIN + ((chnInfo.noteTranspose + prevNote[chn]) & 0x7F); + if(p[1] & 0xC0) + m->SetVolumeCommand(VOLCMD_TONEPORTAMENTO, 9); + else + m->SetEffectCommand(CMD_TONEPORTA_DURATION, 0); } - if((p[1] & 0xC0)) + if(p[1] & 0xC0) m->SetEffectCommand(CMD_AUTO_PORTAMENTO_FC, 0); if(p[1] & 0x80) { Modified: trunk/OpenMPT/soundlib/Load_gt2.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_gt2.cpp Fri Nov 1 18:32:05 2024 (r22050) +++ trunk/OpenMPT/soundlib/Load_gt2.cpp Fri Nov 1 21:00:41 2024 (r22051) @@ -460,8 +460,8 @@ m.vol = 9; } else { - m.command = CMD_TONEPORTAMENTO; - m.param = 0xFF; + m.command = CMD_TONEPORTA_DURATION; + m.param = 0; } } } Modified: trunk/OpenMPT/soundlib/Load_symmod.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_symmod.cpp Fri Nov 1 18:32:05 2024 (r22050) +++ trunk/OpenMPT/soundlib/Load_symmod.cpp Fri Nov 1 21:00:41 2024 (r22051) @@ -1503,7 +1503,7 @@ if(mappedInst != chnState.lastInst) break; m.note = note; - m.SetEffectCommand(CMD_TONEPORTAMENTO, 0xFF); + m.SetEffectCommand(CMD_TONEPORTA_DURATION, 0); chnState.curPitchSlide = 0; chnState.tonePortaRemain = 0; chnState.retrigVibrato = chnState.retrigTremolo = true; @@ -1654,7 +1654,7 @@ break; case SymEvent::AddHalfTone: m.note = chnState.lastNote = Clamp(static_cast<uint8>(chnState.lastNote + event.param), NOTE_MIN, NOTE_MAX); - m.SetEffectCommand(CMD_TONEPORTAMENTO, 0xFF); + m.SetEffectCommand(CMD_TONEPORTA_DURATION, 0); chnState.tonePortaRemain = 0; break; Modified: trunk/OpenMPT/soundlib/ModChannel.cpp ============================================================================== --- trunk/OpenMPT/soundlib/ModChannel.cpp Fri Nov 1 18:32:05 2024 (r22050) +++ trunk/OpenMPT/soundlib/ModChannel.cpp Fri Nov 1 21:00:41 2024 (r22051) @@ -27,6 +27,7 @@ nNote = nNewNote = (sndFile.m_playBehaviour[kITInitialNoteMemory] ? NOTE_MIN : NOTE_NONE); nArpeggioLastNote = lastMidiNoteWithoutArp = NOTE_NONE; nNewIns = nOldIns = 0; + swapSampleIndex = 0; pModSample = defaultSample; pModInstrument = nullptr; nPortamentoDest = 0; Modified: trunk/OpenMPT/soundlib/ModChannel.h ============================================================================== --- trunk/OpenMPT/soundlib/ModChannel.h Fri Nov 1 18:32:05 2024 (r22050) +++ trunk/OpenMPT/soundlib/ModChannel.h Fri Nov 1 21:00:41 2024 (r22051) @@ -112,6 +112,7 @@ uint16 nRestorePanOnNewNote; // If > 0, nPan should be set to nRestorePanOnNewNote - 1 on new note. Used to recover from pan swing and IT sample / instrument panning. High bit set = surround uint16 nnaGeneration; // For PlaybackTest implementation CHANNELINDEX nMasterChn; + SAMPLEINDEX swapSampleIndex; // Sample to swap to when current sample (loop) has finished playing ModCommand rowCommand; // 8-bit members uint8 nGlobalVol; // Channel volume (CV in ITTECH.TXT) 0...64 Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp Fri Nov 1 18:32:05 2024 (r22050) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp Fri Nov 1 21:00:41 2024 (r22051) @@ -601,7 +601,7 @@ if (ModCommand::IsNote(note) && Instruments[p->instr]->Keyboard[note - NOTE_MIN] == 0) { chn.nNewNote = chn.nLastNote = note; - chn.nNewIns = static_cast<ModCommand::INSTR>(p->instr); + chn.nNewIns = p->instr; chn.rowCommand.Clear(); continue; } @@ -679,7 +679,7 @@ { if(chn.rowCommand.instr) { - chn.nNewIns = chn.rowCommand.instr; + chn.swapSampleIndex = chn.nNewIns = chn.rowCommand.instr; memory.chnSettings[nChn].vol = 0xFF; } if(chn.rowCommand.IsNote()) @@ -1486,7 +1486,7 @@ // We won't ignore them if a plugin is assigned to this slot, so that VSTis still work as intended. // Test case: emptyslot.it, PortaInsNum.it, gxsmp.it, gxsmp2.it chn.pModInstrument = nullptr; - chn.nNewIns = 0; + chn.swapSampleIndex = chn.nNewIns = 0; return; } pSmp = nullptr; @@ -1595,7 +1595,7 @@ if(returnAfterVolumeAdjust) return; // Instrument adjust - chn.nNewIns = 0; + chn.swapSampleIndex = chn.nNewIns = 0; // IT Compatiblity: NNA is reset on every note change, not every instrument change (fixes s7xinsnum.it). if (pIns && ((!m_playBehaviour[kITNNAReset] && pSmp) || pIns->nMixPlug || instrumentChanged)) @@ -1961,7 +1961,7 @@ chn.isPaused = false; if ((!bPorta) || (GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT))) - chn.nNewIns = 0; + chn.swapSampleIndex = chn.nNewIns = 0; uint32 period = GetPeriodFromNote(note, chn.nFineTune, chn.nC5Speed); chn.nPanbrelloOffset = 0; @@ -2779,6 +2779,7 @@ if(!triggerNote && chn.IsSamplePlaying()) { chn.nNewIns = static_cast<ModCommand::INSTR>(instr); + chn.swapSampleIndex = GetSampleIndex(chn.nLastNote, instr); if(instr <= GetNumSamples()) { chn.nVolume = Samples[instr].nVolume; @@ -2791,7 +2792,11 @@ if(triggerNote) { ModCommand::NOTE note = chn.rowCommand.note; - if(instr) chn.nNewIns = static_cast<ModCommand::INSTR>(instr); + if(instr) + { + chn.nNewIns = static_cast<ModCommand::INSTR>(instr); + chn.swapSampleIndex = GetSampleIndex(ModCommand::IsNote(note) ? note : chn.nLastNote, instr); + } if(ModCommand::IsNote(note) && m_playBehaviour[kFT2Transpose]) { @@ -3084,7 +3089,7 @@ InstrumentChange(chn, chn.nNewIns, bPorta, chn.pModSample == nullptr && chn.pModInstrument == nullptr, !(GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))); chn.nNewNote = note; - chn.nNewIns = 0; + chn.swapSampleIndex = chn.nNewIns = 0; } if(!chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE] && chn.pModSample != nullptr && chn.pModSample->uFlags[CHN_ADLIB] && m_opl && (instrChange || !m_opl->IsActive(nChn))) { |