|
From: <sag...@us...> - 2013-04-04 15:23:53
|
Revision: 1729
http://sourceforge.net/p/modplug/code/1729
Author: saga-games
Date: 2013-04-04 15:23:39 +0000 (Thu, 04 Apr 2013)
Log Message:
-----------
[Fix] Retrig note was broken in IT compatible mode with VSTis (tx Nahkranoth)
[Imp] Retrig note also works with VSTis on rows without a note, and also with Cxx volume commands in XM (not that it really matters, anyway...).
Modified Paths:
--------------
trunk/OpenMPT/soundlib/ModChannel.h
trunk/OpenMPT/soundlib/Snd_fx.cpp
trunk/OpenMPT/soundlib/Sndmix.cpp
Modified: trunk/OpenMPT/soundlib/ModChannel.h
===================================================================
--- trunk/OpenMPT/soundlib/ModChannel.h 2013-04-04 13:10:13 UTC (rev 1728)
+++ trunk/OpenMPT/soundlib/ModChannel.h 2013-04-04 15:23:39 UTC (rev 1729)
@@ -150,6 +150,9 @@
typedef uint32 volume_t;
volume_t GetVSTVolume() { return (pModInstrument) ? pModInstrument->nGlobalVol * 4 : nVolume; }
+ // Check if the channel has a valid MIDI output. This function guarantees that pModInstrument != nullptr.
+ bool HasMIDIOutput() const { return pModInstrument != nullptr && pModInstrument->HasValidMIDIChannel(); }
+
//-->Variables used to make user-definable tuning modes work with pattern effects.
bool m_ReCalculateFreqOnFirstTick;
//If true, freq should be recalculated in ReadNote() on first tick.
Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp
===================================================================
--- trunk/OpenMPT/soundlib/Snd_fx.cpp 2013-04-04 13:10:13 UTC (rev 1728)
+++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2013-04-04 15:23:39 UTC (rev 1729)
@@ -948,7 +948,7 @@
if((n) && (n < MAX_SAMPLES))
{
pSmp = &Samples[n];
- } else if(IsCompatibleMode(TRK_IMPULSETRACKER) && !pIns->HasValidMIDIChannel())
+ } else if(IsCompatibleMode(TRK_IMPULSETRACKER) && !pChn->HasMIDIOutput())
{
// Impulse Tracker ignores empty slots.
// We won't ignore them if a plugin is assigned to this slot, so that VSTis still work as intended.
@@ -1451,7 +1451,7 @@
// Do we need to apply New/Duplicate Note Action to a VSTi?
bool applyNNAtoPlug = false;
IMixPlugin *pPlugin = NULL;
- if (pChn->pModInstrument && pChn->pModInstrument->HasValidMIDIChannel() && ModCommand::IsNote(pChn->nNote)) // instro sends to a midi chan
+ if(pChn->HasMIDIOutput() && ModCommand::IsNote(pChn->nNote)) // instro sends to a midi chan
{
PLUGINDEX nPlugin = GetBestPlugin(nChn, PrioritiseInstrument, RespectMutes);
@@ -4086,21 +4086,21 @@
//--------------------------------------------------------------------
{
// Retrig: bit 8 is set if it's the new XM retrig
- ModChannel *pChn = &Chn[nChn];
+ ModChannel &chn = Chn[nChn];
int nRetrigSpeed = param & 0x0F;
- int nRetrigCount = pChn->nRetrigCount;
+ int nRetrigCount = chn.nRetrigCount;
bool bDoRetrig = false;
//IT compatibility 15. Retrigger
if(IsCompatibleMode(TRK_IMPULSETRACKER))
{
- if(m_nTickCount == 0 && pChn->rowCommand.note)
+ if(m_nTickCount == 0 && chn.rowCommand.note)
{
- pChn->nRetrigCount = param & 0xf;
+ chn.nRetrigCount = param & 0xf;
}
- else if(!pChn->nRetrigCount || !--pChn->nRetrigCount)
+ else if(!chn.nRetrigCount || !--chn.nRetrigCount)
{
- pChn->nRetrigCount = param & 0xf;
+ chn.nRetrigCount = param & 0xf;
bDoRetrig = true;
}
} else if(IsCompatibleMode(TRK_FASTTRACKER2) && (param & 0x100))
@@ -4109,13 +4109,13 @@
if(m_SongFlags[SONG_FIRSTTICK])
{
// here are some really stupid things FT2 does
- if(pChn->rowCommand.volcmd == VOLCMD_VOLUME) return;
- if(pChn->rowCommand.instr > 0 && pChn->rowCommand.note == NOTE_NONE) nRetrigCount = 1;
- if(pChn->rowCommand.note != NOTE_NONE && pChn->rowCommand.note <= GetModSpecifications().noteMax) nRetrigCount++;
+ if(chn.rowCommand.volcmd == VOLCMD_VOLUME) return;
+ if(chn.rowCommand.instr > 0 && chn.rowCommand.note == NOTE_NONE) nRetrigCount = 1;
+ if(chn.rowCommand.note != NOTE_NONE && chn.rowCommand.note <= GetModSpecifications().noteMax) nRetrigCount++;
}
if (nRetrigCount >= nRetrigSpeed)
{
- if(!m_SongFlags[SONG_FIRSTTICK] || pChn->rowCommand.note == NOTE_NONE)
+ if(!m_SongFlags[SONG_FIRSTTICK] || chn.rowCommand.note == NOTE_NONE)
{
bDoRetrig = true;
nRetrigCount = 0;
@@ -4133,7 +4133,7 @@
{
int realspeed = nRetrigSpeed;
// FT2 bug: if a retrig (Rxy) occours together with a volume command, the first retrig interval is increased by one tick
- if ((param & 0x100) && (pChn->rowCommand.volcmd == VOLCMD_VOLUME) && (pChn->rowCommand.param & 0xF0)) realspeed++;
+ if ((param & 0x100) && (chn.rowCommand.volcmd == VOLCMD_VOLUME) && (chn.rowCommand.param & 0xF0)) realspeed++;
if(!m_SongFlags[SONG_FIRSTTICK] || (param & 0x100))
{
if (!realspeed) realspeed = 1;
@@ -4142,14 +4142,14 @@
} else if (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2)) nRetrigCount = 0;
if (nRetrigCount >= realspeed)
{
- if ((m_nTickCount) || ((param & 0x100) && (!pChn->rowCommand.note))) bDoRetrig = true;
+ if ((m_nTickCount) || ((param & 0x100) && (!chn.rowCommand.note))) bDoRetrig = true;
}
}
}
// IT compatibility: If a sample is shorter than the retrig time (i.e. it stops before the retrig counter hits zero), it is not retriggered.
// Test case: retrig-short.it
- if(pChn->nLength == 0 && IsCompatibleMode(TRK_IMPULSETRACKER))
+ if(chn.nLength == 0 && IsCompatibleMode(TRK_IMPULSETRACKER) && !chn.HasMIDIOutput())
{
return;
}
@@ -4159,10 +4159,10 @@
UINT dv = (param >> 4) & 0x0F;
if (dv)
{
- int vol = pChn->nVolume;
+ int vol = chn.nVolume;
// FT2 compatibility: Retrig + volume will not change volume of retrigged notes
- if(!IsCompatibleMode(TRK_FASTTRACKER2) || !(pChn->rowCommand.volcmd == VOLCMD_VOLUME))
+ if(!IsCompatibleMode(TRK_FASTTRACKER2) || !(chn.rowCommand.volcmd == VOLCMD_VOLUME))
{
if (retrigTable1[dv])
vol = (vol * retrigTable1[dv]) >> 4;
@@ -4172,18 +4172,18 @@
Limit(vol, 0, 256);
- pChn->nVolume = vol;
- pChn->dwFlags.set(CHN_FASTVOLRAMP);
+ chn.nVolume = vol;
+ chn.dwFlags.set(CHN_FASTVOLRAMP);
}
- UINT nNote = pChn->nNewNote;
- int32 nOldPeriod = pChn->nPeriod;
- if ((nNote) && (nNote <= NOTE_MAX) && (pChn->nLength)) CheckNNA(nChn, 0, nNote, true);
+ UINT nNote = chn.nNewNote;
+ int32 nOldPeriod = chn.nPeriod;
+ if ((nNote) && (nNote <= NOTE_MAX) && (chn.nLength)) CheckNNA(nChn, 0, nNote, true);
bool bResetEnv = false;
if (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))
{
- if ((pChn->rowCommand.instr) && (param < 0x100))
+ if ((chn.rowCommand.instr) && (param < 0x100))
{
- InstrumentChange(pChn, pChn->rowCommand.instr, false, false);
+ InstrumentChange(&chn, chn.rowCommand.instr, false, false);
bResetEnv = true;
}
if (param < 0x100) bResetEnv = true;
@@ -4191,19 +4191,20 @@
// IT compatibility: Really weird combination of envelopes and retrigger (see Storlek's q.it testcase)
// Test case: retrig.it
NoteChange(nChn, nNote, IsCompatibleMode(TRK_IMPULSETRACKER), bResetEnv);
- if (m_nInstruments)
+ if(m_nInstruments)
{
+ chn.rowCommand.note = nNote; // No retrig without note...
ProcessMidiOut(nChn); //Send retrig to Midi
}
- if ((GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) && (!pChn->rowCommand.note) && (nOldPeriod)) pChn->nPeriod = nOldPeriod;
+ if ((GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) && (!chn.rowCommand.note) && (nOldPeriod)) chn.nPeriod = nOldPeriod;
if (!(GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT))) nRetrigCount = 0;
// IT compatibility: see previous IT compatibility comment =)
- if(IsCompatibleMode(TRK_IMPULSETRACKER)) pChn->nPos = pChn->nPosLo = 0;
+ if(IsCompatibleMode(TRK_IMPULSETRACKER)) chn.nPos = chn.nPosLo = 0;
if (offset) //rewbs.volOffset: apply offset on retrig
{
- if (pChn->pModSample)
- pChn->nLength = pChn->pModSample->nLength;
+ if (chn.pModSample)
+ chn.nLength = chn.pModSample->nLength;
SampleOffset(nChn, offset);
}
}
@@ -4213,7 +4214,7 @@
// Now we can also store the retrig value for IT...
if(!IsCompatibleMode(TRK_IMPULSETRACKER))
- pChn->nRetrigCount = nRetrigCount;
+ chn.nRetrigCount = nRetrigCount;
}
@@ -4771,9 +4772,9 @@
return nullptr;
}
- const ModInstrument *pIns = Chn[chn].pModInstrument;
- if(pIns != nullptr && pIns->HasValidMIDIChannel())
+ if(Chn[chn].HasMIDIOutput())
{
+ const ModInstrument *pIns = Chn[chn].pModInstrument;
// Instrument sends to a MIDI channel
if(pIns->nMixPlug != 0 && pIns->nMixPlug <= MAX_MIXPLUGINS)
{
Modified: trunk/OpenMPT/soundlib/Sndmix.cpp
===================================================================
--- trunk/OpenMPT/soundlib/Sndmix.cpp 2013-04-04 13:10:13 UTC (rev 1728)
+++ trunk/OpenMPT/soundlib/Sndmix.cpp 2013-04-04 15:23:39 UTC (rev 1729)
@@ -2141,47 +2141,44 @@
void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn)
//------------------------------------------------
{
- ModChannel *pChn = &Chn[nChn];
+ ModChannel &chn = Chn[nChn];
- // Do we need to process midi?
+ // Do we need to process MIDI?
// For now there is no difference between mute and sync mute with VSTis.
- if(pChn->dwFlags[CHN_MUTE | CHN_SYNCMUTE]) return;
- if(!m_nInstruments
- || m_nPattern >= Patterns.Size()
- || m_nRow >= Patterns[m_nPattern].GetNumRows()
- || !Patterns[m_nPattern])
+ if(chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE] || !chn.HasMIDIOutput()) return;
+
+ // Get instrument info and plugin reference
+ const ModInstrument *pIns = chn.pModInstrument; // Can't be nullptr at this point, as we have valid MIDI output.
+
+ // No instrument or muted instrument?
+ if(pIns->dwFlags[INS_MUTE])
{
return;
}
- const ModCommand::NOTE note = pChn->rowCommand.note;
- const ModCommand::VOL vol = pChn->rowCommand.vol;
- const ModCommand::VOLCMD volcmd = pChn->rowCommand.volcmd;
-
- // Get instrument info and plugin reference
- ModInstrument *pIns = pChn->pModInstrument;
- PLUGINDEX nPlugin = 0;
+ // Check instrument plugins
+ const PLUGINDEX nPlugin = GetBestPlugin(nChn, PrioritiseInstrument, RespectMutes);
IMixPlugin *pPlugin = nullptr;
-
- if (pIns)
+ if(nPlugin > 0 && nPlugin <= MAX_MIXPLUGINS)
{
- // Check instrument plugins
- if (pIns->HasValidMIDIChannel())
- {
- nPlugin = GetBestPlugin(nChn, PrioritiseInstrument, RespectMutes);
- if ((nPlugin) && (nPlugin <= MAX_MIXPLUGINS))
- {
- pPlugin = m_MixPlugins[nPlugin-1].pMixPlugin;
- }
- }
-
- // Muted instrument?
- if(pIns != nullptr && pIns->dwFlags[INS_MUTE]) return;
+ pPlugin = m_MixPlugins[nPlugin - 1].pMixPlugin;
}
// Couldn't find a valid plugin
- if (pPlugin == nullptr) return;
+ if(pPlugin == nullptr) return;
+ const ModCommand::NOTE note = chn.rowCommand.note;
+ // Check for volume commands
+ uint8 vol = 0xFF;
+ if(chn.rowCommand.volcmd == VOLCMD_VOLUME)
+ {
+ vol = Util::Min(chn.rowCommand.vol, uint8(64));
+ } else if(chn.rowCommand.command == CMD_VOLUME)
+ {
+ vol = Util::Min(chn.rowCommand.param, uint8(64));
+ }
+ const bool hasVolCommand = (vol != 0xFF);
+
if(GetModFlag(MSF_MIDICC_BUGEMULATION))
{
if(note != NOTE_NONE)
@@ -2189,18 +2186,15 @@
ModCommand::NOTE realNote = note;
if(ModCommand::IsNote(note))
realNote = pIns->NoteMap[note - 1];
- pPlugin->MidiCommand(GetBestMidiChannel(nChn), pIns->nMidiProgram, pIns->wMidiBank, realNote, static_cast<uint16>(pChn->nVolume), nChn);
- } else if (volcmd == VOLCMD_VOLUME)
+ pPlugin->MidiCommand(GetBestMidiChannel(nChn), pIns->nMidiProgram, pIns->wMidiBank, realNote, static_cast<uint16>(chn.nVolume), nChn);
+ } else if(hasVolCommand)
{
pPlugin->MidiCC(GetBestMidiChannel(nChn), MIDIEvents::MIDICC_Volume_Fine, vol, nChn);
}
return;
}
-
- const bool hasVolCommand = (volcmd == VOLCMD_VOLUME);
- const UINT defaultVolume = pIns->nGlobalVol;
-
+ const uint32 defaultVolume = pIns->nGlobalVol;
//If new note, determine notevelocity to use.
if(note != NOTE_NONE)
@@ -2209,7 +2203,7 @@
switch(pIns->nPluginVelocityHandling)
{
case PLUGIN_VELOCITYHANDLING_CHANNEL:
- velocity = static_cast<uint16>(pChn->nVolume);
+ velocity = static_cast<uint16>(chn.nVolume);
break;
}
@@ -2229,7 +2223,7 @@
switch(pIns->nPluginVolumeHandling)
{
case PLUGIN_VOLUMEHANDLING_DRYWET:
- if(hasVolCommand) pPlugin->SetDryRatio(2*vol);
+ if(hasVolCommand) pPlugin->SetDryRatio(2 * vol);
else pPlugin->SetDryRatio(2 * defaultVolume);
break;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|