Skip to content

Commit

Permalink
[Fix] IT: Fix various mind-boggling combinations of volume column and…
Browse files Browse the repository at this point in the history
… effect column portamento effects. Test cases: DoubleSlide.it, DoubleSlideCompatGxx.it

[Mod] OpenMPT: Version is now 1.32.00.26

git-svn-id: https://source.openmpt.org/svn/openmpt/trunk/OpenMPT@21807 56274372-70c3-4bfc-bfc3-4c3a0b034d27
  • Loading branch information
sagamusix committed Oct 13, 2024
1 parent 1dcb69b commit 92b88d4
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 26 deletions.
2 changes: 1 addition & 1 deletion common/versionNumber.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
#define VER_MAJORMAJOR 1
#define VER_MAJOR 32
#define VER_MINOR 00
#define VER_MINORMINOR 26
#define VER_MINORMINOR 27
1 change: 1 addition & 0 deletions mptrack/dlg_misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,7 @@ void CLegacyPlaybackSettingsDlg::OnFilterStringChanged()
case kITOffsetWithInstrNumber: desc = _T("Offset command with instrument number recalls offset with last note"); break;
case kContinueSampleWithoutInstr: desc = _T("New note without instrument number does not play looped samples from the start"); break;
case kMIDINotesFromChannelPlugin: desc = _T("MIDI notes can be sent to channel plugins"); break;
case kITDoublePortamentoSlides: desc = _T("Parameters of conflicting volume and effect column portamento commands may overwrite each other"); break;

default: MPT_ASSERT_NOTREACHED();
}
Expand Down
1 change: 1 addition & 0 deletions soundlib/Snd_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,7 @@ enum PlayBehaviour
kITOffsetWithInstrNumber, // IT applies offset commands even if just an instrument number without note is present
kContinueSampleWithoutInstr, // FTM: A note without instrument number continues looped samples with the new pitch instead of retriggering them
kMIDINotesFromChannelPlugin, // Behaviour before OpenMPT 1.26: Channel plugin can be used to send MIDI notes
kITDoublePortamentoSlides, // IT only reads parameters once per row, so if two commands sharing effect parameters are found in the two effect columns, they influence each other

// Add new play behaviours here.

Expand Down
102 changes: 79 additions & 23 deletions soundlib/Snd_fx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ class GetLengthMemory
case VOLCMD_TONEPORTAMENTO:
{
const auto [porta, clearEffectCommand] = sndFile.GetVolCmdTonePorta(m, 0);
sndFile.TonePortamento(*state, channel, porta);
sndFile.TonePortamento(*state, channel, porta, true);
if(clearEffectCommand)
command = CMD_NONE;
}
Expand All @@ -155,10 +155,10 @@ class GetLengthMemory
switch(command)
{
case CMD_TONEPORTAMENTO:
sndFile.TonePortamento(*state, channel, m.param);
sndFile.TonePortamento(*state, channel, m.param, false);
break;
case CMD_TONEPORTAVOL:
sndFile.TonePortamento(*state, channel, 0);
sndFile.TonePortamento(*state, channel, 0, false);
break;
case CMD_PORTAMENTOUP:
if(m.param || !(sndFile.GetType() & MOD_TYPE_MOD))
Expand Down Expand Up @@ -193,7 +193,7 @@ class GetLengthMemory
}

if(chn.autoSlide.IsActive(AutoSlideCommand::TonePortamento) && !chn.rowCommand.IsTonePortamento())
sndFile.TonePortamento(*state, channel, chn.portamentoSlide);
sndFile.TonePortamento(*state, channel, chn.portamentoSlide, false);
else if(chn.autoSlide.IsActive(AutoSlideCommand::TonePortamentoWithDuration))
sndFile.TonePortamentoWithDuration(chn, 0);
if(chn.autoSlide.IsActive(AutoSlideCommand::PortamentoUp))
Expand Down Expand Up @@ -3145,6 +3145,32 @@ bool CSoundFile::ProcessEffects()
{
doVolumeColumn = m_PlayState.m_nTickCount != 0 && (m_PlayState.m_nTickCount != nStartTick || (chn.rowCommand.instr == 0 && volcmd != VOLCMD_TONEPORTAMENTO));
}

// IT compatibility: Various mind-boggling behaviours when combining volume colum and effect column portamentos
// The most crucial thing here is to initialize effect memory in the exact right order, and use different effect memory for tone portamento in the both columns.
// Test cases: DoubleSlide.it, DoubleSlideCompatGxx.it
if(m_playBehaviour[kITDoublePortamentoSlides] && chn.isFirstTick)
{
const bool effectColumnTonePorta = (cmd == CMD_TONEPORTAMENTO || cmd == CMD_TONEPORTAVOL);
if(effectColumnTonePorta)
InitTonePortamento(chn, static_cast<uint16>(param));
if(volcmd == VOLCMD_TONEPORTAMENTO)
InitTonePortamento(chn, GetVolCmdTonePorta(chn.rowCommand, nStartTick).first);

if(vol && (volcmd == VOLCMD_PORTAUP || volcmd == VOLCMD_PORTADOWN))
{
chn.nOldPortaUp = chn.nOldPortaDown = vol << 2;
if(!effectColumnTonePorta && TonePortamentoSharesEffectMemory())
chn.portamentoSlide = vol << 2;
}
if(param && (cmd == CMD_PORTAMENTOUP || cmd == CMD_PORTAMENTODOWN))
{
chn.nOldPortaUp = chn.nOldPortaDown = static_cast<uint8>(param);
if(TonePortamentoSharesEffectMemory())
chn.portamentoSlide = static_cast<uint16>(param);
}
}

if(volcmd > VOLCMD_PANNING && doVolumeColumn)
{
if(volcmd == VOLCMD_TONEPORTAMENTO)
Expand All @@ -3153,7 +3179,7 @@ bool CSoundFile::ProcessEffects()
if(clearEffectCommand)
cmd = CMD_NONE;

TonePortamento(nChn, porta);
TonePortamento(nChn, porta, true);
} else
{
// FT2 Compatibility: FT2 ignores some volume commands with parameter = 0.
Expand Down Expand Up @@ -3333,13 +3359,13 @@ bool CSoundFile::ProcessEffects()

// Tone-Portamento
case CMD_TONEPORTAMENTO:
TonePortamento(nChn, static_cast<uint16>(param));
TonePortamento(nChn, static_cast<uint16>(param), false);
break;

// Tone-Portamento + Volume Slide
case CMD_TONEPORTAVOL:
if ((param) || (GetType() != MOD_TYPE_MOD)) VolumeSlide(chn, static_cast<ModCommand::PARAM>(param));
TonePortamento(nChn, 0);
TonePortamento(nChn, 0, false);
break;

// Vibrato
Expand Down Expand Up @@ -3873,7 +3899,7 @@ void CSoundFile::ProcessAutoSlides(PlayState &playState, CHANNELINDEX channel)
{
ModChannel &chn = playState.Chn[channel];
if(chn.autoSlide.IsActive(AutoSlideCommand::TonePortamento) && !chn.rowCommand.IsTonePortamento())
TonePortamento(channel, chn.portamentoSlide);
TonePortamento(channel, chn.portamentoSlide, false);
else if(chn.autoSlide.IsActive(AutoSlideCommand::TonePortamentoWithDuration))
TonePortamentoWithDuration(chn);
if(chn.autoSlide.IsActive(AutoSlideCommand::PortamentoUp))
Expand Down Expand Up @@ -4027,7 +4053,9 @@ void CSoundFile::PortamentoUp(PlayState &playState, CHANNELINDEX nChn, ModComman
{
ModChannel &chn = playState.Chn[nChn];

if(param)
// IT compatibility: Initialize effect memory in the right order in case there are portamentos in both effect columns.
// Test cases: DoubleSlide.it, DoubleSlideCompatGxx.it
if(param && !m_playBehaviour[kITDoublePortamentoSlides])
{
// FT2 compatibility: Separate effect memory for all portamento commands
// Test case: Porta-LinkMem.xm
Expand Down Expand Up @@ -4098,7 +4126,9 @@ void CSoundFile::PortamentoDown(PlayState &playState, CHANNELINDEX nChn, ModComm
{
ModChannel &chn = playState.Chn[nChn];

if(param)
// IT compatibility: Initialize effect memory in the right order in case there are portamentos in both effect columns.
// Test cases: DoubleSlide.it, DoubleSlideCompatGxx.it
if(param && !m_playBehaviour[kITDoublePortamentoSlides])
{
// FT2 compatibility: Separate effect memory for all portamento commands
// Test case: Porta-LinkMem.xm
Expand Down Expand Up @@ -4394,9 +4424,30 @@ std::pair<uint16, bool> CSoundFile::GetVolCmdTonePorta(const ModCommand &m, uint
}


void CSoundFile::TonePortamento(CHANNELINDEX nChn, uint16 param)
bool CSoundFile::TonePortamentoSharesEffectMemory() const
{
return (!m_SongFlags[SONG_ITCOMPATGXX] && m_playBehaviour[kITPortaMemoryShare]) || GetType() == MOD_TYPE_PLM;
}


void CSoundFile::InitTonePortamento(ModChannel &chn, uint16 param) const
{
// IT compatibility 03: Share effect memory with portamento up/down
if(TonePortamentoSharesEffectMemory())
{
if(param == 0)
param = chn.nOldPortaUp;
chn.nOldPortaUp = chn.nOldPortaDown = static_cast<uint8>(param);
}

if(param)
chn.portamentoSlide = param;
}


void CSoundFile::TonePortamento(CHANNELINDEX nChn, uint16 param, bool volumeColumn)
{
auto delta = TonePortamento(m_PlayState, nChn, param);
auto delta = TonePortamento(m_PlayState, nChn, param, volumeColumn);
if(!delta)
return;

Expand All @@ -4415,33 +4466,39 @@ void CSoundFile::TonePortamento(CHANNELINDEX nChn, uint16 param)


// Portamento Slide
int32 CSoundFile::TonePortamento(PlayState &playState, CHANNELINDEX nChn, uint16 param) const
int32 CSoundFile::TonePortamento(PlayState &playState, CHANNELINDEX nChn, uint16 param, bool volumeColumn) const
{
ModChannel &chn = playState.Chn[nChn];
chn.dwFlags.set(CHN_PORTAMENTO);
if(m_SongFlags[SONG_AUTO_TONEPORTA])
chn.autoSlide.SetActive(AutoSlideCommand::TonePortamento, param != 0 || m_SongFlags[SONG_AUTO_TONEPORTA_CONT]);

//IT compatibility 03: Share effect memory with portamento up/down
if((!m_SongFlags[SONG_ITCOMPATGXX] && m_playBehaviour[kITPortaMemoryShare]) || GetType() == MOD_TYPE_PLM)
int32 delta;
// IT compatibility: Initialize effect memory in the right order in case there are portamentos in both effect columns.
// Also, tone portamento in the effect column stores the slide amount separately from the regular E/F/G memory once the effect is running,
// while volume column tone portamento always accesses the effect memory directly.
// Test cases: DoubleSlide.it, DoubleSlideCompatGxx.it
if(m_playBehaviour[kITDoublePortamentoSlides])
{
if(param == 0) param = chn.nOldPortaUp;
chn.nOldPortaUp = chn.nOldPortaDown = static_cast<uint8>(param);
if(volumeColumn && TonePortamentoSharesEffectMemory())
delta = chn.nOldPortaUp;
else
delta = chn.portamentoSlide;
} else
{
InitTonePortamento(chn, param);
delta = chn.portamentoSlide;
}

if(param)
chn.portamentoSlide = param;

if(chn.HasCustomTuning())
{
//Behavior: Param tells number of finesteps(or 'fullsteps'(notes) with glissando)
//to slide per row(not per tick).
if(chn.portamentoSlide == 0)
if(delta == 0)
return 0;

const int32 oldPortamentoTickSlide = (playState.m_nTickCount != 0) ? chn.m_PortamentoTickSlide : 0;

int32 delta = chn.portamentoSlide;
if(chn.nPortamentoDest < 0)
delta = -delta;

Expand Down Expand Up @@ -4483,7 +4540,6 @@ int32 CSoundFile::TonePortamento(PlayState &playState, CHANNELINDEX nChn, uint16
|| (playState.m_nMusicSpeed == 1 && m_playBehaviour[kSlidesAtSpeed1])
|| m_SongFlags[SONG_FASTPORTAS];

int32 delta = chn.portamentoSlide;
if(GetType() == MOD_TYPE_PLM && delta >= 0xF0)
{
delta -= 0xF0;
Expand Down
1 change: 1 addition & 0 deletions soundlib/Sndfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,7 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
playBehaviour.set(kITNoSustainOnPortamento);
playBehaviour.set(kITEmptyNoteMapSlotIgnoreCell);
playBehaviour.set(kITOffsetWithInstrNumber);
playBehaviour.set(kITDoublePortamentoSlides);
break;

case MOD_TYPE_XM:
Expand Down
6 changes: 4 additions & 2 deletions soundlib/Sndfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -1086,8 +1086,10 @@ class CSoundFile
int16 CalculateFinetuneTarget(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel) const;
void NoteSlide(ModChannel &chn, uint32 param, bool slideUp, bool retrig) const;
std::pair<uint16, bool> GetVolCmdTonePorta(const ModCommand &m, uint32 startTick) const;
void TonePortamento(CHANNELINDEX chn, uint16 param);
int32 TonePortamento(PlayState &playState, CHANNELINDEX nChn, uint16 param) const;
bool TonePortamentoSharesEffectMemory() const;
void InitTonePortamento(ModChannel &chn, uint16 param) const;
void TonePortamento(CHANNELINDEX chn, uint16 param, bool volumeColumn);
int32 TonePortamento(PlayState &playState, CHANNELINDEX nChn, uint16 param, bool volumeColumn) const;
void TonePortamentoWithDuration(ModChannel &chn, uint16 param = uint16_max) const;
void Vibrato(ModChannel &chn, uint32 param) const;
void FineVibrato(ModChannel &chn, uint32 param) const;
Expand Down
1 change: 1 addition & 0 deletions soundlib/UpgradeModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ void CSoundFile::UpgradeModule()
{ kITNoSustainOnPortamento, MPT_V("1.32.00.13") },
{ kITEmptyNoteMapSlotIgnoreCell, MPT_V("1.32.00.13") },
{ kITOffsetWithInstrNumber, MPT_V("1.32.00.15") },
{ kITDoublePortamentoSlides, MPT_V("1.32.00.27") },
};

for(const auto &b : behaviours)
Expand Down

0 comments on commit 92b88d4

Please sign in to comment.