summaryrefslogtreecommitdiff
path: root/soundlib/Snd_fx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'soundlib/Snd_fx.cpp')
-rw-r--r--soundlib/Snd_fx.cpp34
1 files changed, 29 insertions, 5 deletions
diff --git a/soundlib/Snd_fx.cpp b/soundlib/Snd_fx.cpp
index 08d26fd..a2b0b87 100644
--- a/soundlib/Snd_fx.cpp
+++ b/soundlib/Snd_fx.cpp
@@ -1327,6 +1327,7 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bo
{
const ModInstrument *pIns = instr <= GetNumInstruments() ? Instruments[instr] : nullptr;
const ModSample *pSmp = &Samples[instr];
+ const auto oldInsVol = chn.nInsVol;
ModCommand::NOTE note = chn.nNewNote;
if(note == NOTE_NONE && m_playBehaviour[kITInstrWithoutNote]) return;
@@ -1491,9 +1492,12 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bo
if(m_playBehaviour[kITEnvelopeReset])
{
const bool insNumber = (instr != 0);
+ // IT compatibility: Note-off with instrument number + Old Effects retriggers envelopes.
+ // Test case: ResetEnvNoteOffOldFx.it
+ const bool isKeyOff = chn.dwFlags[CHN_NOTEFADE | CHN_KEYOFF] || (chn.rowCommand.note == NOTE_KEYOFF && m_playBehaviour[kITInstrWithNoteOffOldEffects]);
reset = (!chn.nLength
|| (insNumber && bPorta && m_SongFlags[SONG_ITCOMPATGXX])
- || (insNumber && !bPorta && chn.dwFlags[CHN_NOTEFADE | CHN_KEYOFF] && m_SongFlags[SONG_ITOLDEFFECTS]));
+ || (insNumber && !bPorta && isKeyOff && m_SongFlags[SONG_ITOLDEFFECTS]));
// NOTE: IT2.14 with SB/GUS/etc. output is different. We are going after IT's WAV writer here.
// For SB/GUS/etc. emulation, envelope carry should only apply when the NNA isn't set to "Note Cut".
// Test case: CarryNNA.it
@@ -1597,6 +1601,21 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bo
chn.increment.Set(0);
}
+ // IT compatibility: Note-off with instrument number + Old Effects retriggers envelopes.
+ // If the instrument changes, keep playing the previous sample, but load the new instrument's envelopes.
+ // Test case: ResetEnvNoteOffOldFx.it
+ if(chn.rowCommand.note == NOTE_KEYOFF && m_playBehaviour[kITInstrWithNoteOffOldEffects] && m_SongFlags[SONG_ITOLDEFFECTS] && sampleChanged)
+ {
+ if(chn.pModSample)
+ {
+ chn.dwFlags |= (chn.pModSample->uFlags & CHN_SAMPLEFLAGS);
+ }
+ chn.nInsVol = oldInsVol;
+ chn.nVolume = pSmp->nVolume;
+ if(pSmp->uFlags[CHN_PANNING]) chn.nPan = pSmp->nPan;
+ return;
+ }
+
chn.pModSample = pSmp;
chn.nLength = pSmp->nLength;
chn.nLoopStart = pSmp->nLoopStart;
@@ -1622,13 +1641,11 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bo
// Don't reset finetune changed by "set finetune" command.
// Test case: finetune.xm, finetune.mod
// But *do* change the finetune if we switch to a different sample, to fix
- // Miranda`s axe by Jamson (jam007.xm) - this file doesn't use compatible play mode,
- // so we may want to use IsCompatibleMode instead if further problems arise.
+ // Miranda`s axe by Jamson (jam007.xm).
chn.nC5Speed = pSmp->nC5Speed;
chn.nFineTune = pSmp->nFineTune;
}
-
chn.nTranspose = pSmp->RelativeTone;
// FT2 compatibility: Don't reset portamento target with new instrument numbers.
@@ -1694,6 +1711,10 @@ void CSoundFile::NoteChange(ModChannel &chn, int note, bool bPorta, bool bResetE
if(note == NOTE_KEYOFF || !(GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)))
{
KeyOff(chn);
+ // IT compatibility: Note-off + instrument releases sample sustain but does not release envelopes or fade the instrument
+ // Test case: noteoff3.it, ResetEnvNoteOffOldFx2.it
+ if(!bPorta && m_playBehaviour[kITInstrWithNoteOffOldEffects] && m_SongFlags[SONG_ITOLDEFFECTS] && chn.rowCommand.instr)
+ chn.dwFlags.reset(CHN_NOTEFADE | CHN_KEYOFF);
} else // Invalid Note -> Note Fade
{
if(/*note == NOTE_FADE && */ GetNumInstruments())
@@ -2783,7 +2804,10 @@ bool CSoundFile::ProcessEffects()
if(smp > 0 && smp <= GetNumSamples() && !Samples[smp].uFlags[SMP_NODEFAULTVOLUME])
chn.nVolume = Samples[smp].nVolume;
}
- instr = 0;
+ // IT compatibility: Note-off with instrument number + Old Effects retriggers envelopes.
+ // Test case: ResetEnvNoteOffOldFx.it
+ if(!m_playBehaviour[kITInstrWithNoteOffOldEffects] || !m_SongFlags[SONG_ITOLDEFFECTS])
+ instr = 0;
}
if(ModCommand::IsNote(note))