|
From: <sag...@us...> - 2014-02-12 22:17:34
|
Revision: 3708
http://sourceforge.net/p/modplug/code/3708
Author: saga-games
Date: 2014-02-12 22:17:26 +0000 (Wed, 12 Feb 2014)
Log Message:
-----------
[New] Implemented arpeggio effect for instrument plugins. Implementation is subject to change until the next official release.
Modified Paths:
--------------
trunk/OpenMPT/soundlib/ModChannel.h
trunk/OpenMPT/soundlib/Snd_fx.cpp
trunk/OpenMPT/soundlib/Sndfile.h
trunk/OpenMPT/soundlib/Sndmix.cpp
Modified: trunk/OpenMPT/soundlib/ModChannel.h
===================================================================
--- trunk/OpenMPT/soundlib/ModChannel.h 2014-02-12 17:23:45 UTC (rev 3707)
+++ trunk/OpenMPT/soundlib/ModChannel.h 2014-02-12 22:17:26 UTC (rev 3708)
@@ -89,6 +89,7 @@
uint8 nRestoreCutoffOnNewNote; //Like above
uint8 nNote, nNNA;
uint8 nLastNote; // Last note, ignoring note offs and cuts - for MIDI macros
+ uint8 nArpeggioLastNote, nArpeggioBaseNote; // For plugin arpeggio
uint8 nNewNote, nNewIns, nOldIns, nCommand, nArpeggio;
uint8 nOldVolumeSlide, nOldFineVolUpDown;
uint8 nOldPortaUpDown, nOldFinePortaUpDown, nOldExtraFinePortaUpDown;
Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp
===================================================================
--- trunk/OpenMPT/soundlib/Snd_fx.cpp 2014-02-12 17:23:45 UTC (rev 3707)
+++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2014-02-12 22:17:26 UTC (rev 3708)
@@ -2344,7 +2344,10 @@
// Arpeggio
case CMD_ARPEGGIO:
// IT compatibility 01. Don't ignore Arpeggio if no note is playing (also valid for ST3)
- if ((m_nTickCount) || (((!pChn->nPeriod) || !pChn->nNote) && !IsCompatibleMode(TRK_IMPULSETRACKER | TRK_SCREAMTRACKER))) break;
+ if(m_nTickCount) break;
+ if((!pChn->nPeriod || !pChn->nNote)
+ && (pChn->pModInstrument == nullptr || !pChn->pModInstrument->HasValidMIDIChannel()) // Plugin arpeggio
+ && !IsCompatibleMode(TRK_IMPULSETRACKER | TRK_SCREAMTRACKER)) break;
if ((!param) && (!(GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)))) break; // Only important when editing MOD/XM files
pChn->nCommand = CMD_ARPEGGIO;
if (param) pChn->nArpeggio = param;
@@ -4119,7 +4122,7 @@
{
// Not an internal device. Pass on to appropriate plugin.
const CHANNELINDEX plugChannel = (nChn < GetNumChannels()) ? nChn + 1 : pChn->nMasterChn;
- if(plugChannel > 0 && plugChannel <= GetNumChannels()) // XXX do we need this? I guess it might be relevant for previewing notes in the pattern...
+ if(plugChannel > 0 && plugChannel <= GetNumChannels()) // XXX do we need this? I guess it might be relevant for previewing notes in the pattern... Or when using this mechanism for volume/panning!
{
PLUGINDEX nPlug = 0;
if(!pChn->dwFlags[CHN_NOFX])
Modified: trunk/OpenMPT/soundlib/Sndfile.h
===================================================================
--- trunk/OpenMPT/soundlib/Sndfile.h 2014-02-12 17:23:45 UTC (rev 3707)
+++ trunk/OpenMPT/soundlib/Sndfile.h 2014-02-12 22:17:26 UTC (rev 3708)
@@ -729,7 +729,7 @@
void ProcessPitchPanSeparation(ModChannel *pChn);
void ProcessPanbrello(ModChannel *pChn);
- void ProcessArpeggio(ModChannel *pChn, int &period, CTuning::NOTEINDEXTYPE &arpeggioSteps);
+ void ProcessArpeggio(CHANNELINDEX nChn, int &period, CTuning::NOTEINDEXTYPE &arpeggioSteps);
void ProcessVibrato(CHANNELINDEX nChn, int &period, CTuning::RATIOTYPE &vibratoFactor);
void ProcessSampleAutoVibrato(ModChannel *pChn, int &period, CTuning::RATIOTYPE &vibratoFactor, int &nPeriodFrac);
Modified: trunk/OpenMPT/soundlib/Sndmix.cpp
===================================================================
--- trunk/OpenMPT/soundlib/Sndmix.cpp 2014-02-12 17:23:45 UTC (rev 3707)
+++ trunk/OpenMPT/soundlib/Sndmix.cpp 2014-02-12 22:17:26 UTC (rev 3708)
@@ -521,7 +521,6 @@
}
// Should we process tick0 effects?
if (!m_nMusicSpeed) m_nMusicSpeed = 1;
- m_SongFlags.set(SONG_FIRSTTICK);
//End of row? stop pattern step (aka "play row").
#ifdef MODPLUG_TRACKER
@@ -549,6 +548,7 @@
}
} else
{
+ m_SongFlags.set(SONG_FIRSTTICK);
m_SongFlags.reset(SONG_BREAKTOROW);
}
@@ -1108,51 +1108,54 @@
}
-void CSoundFile::ProcessArpeggio(ModChannel *pChn, int &period, CTuning::NOTEINDEXTYPE &arpeggioSteps)
-//----------------------------------------------------------------------------------------------------
+void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int &period, CTuning::NOTEINDEXTYPE &arpeggioSteps)
+//-----------------------------------------------------------------------------------------------------
{
- if (pChn->nCommand == CMD_ARPEGGIO)
+ ModChannel *pChn = &Chn[nChn];
+
+#ifndef NO_VST
+ // Plugin arpeggio
+ if(pChn->pModInstrument && pChn->pModInstrument->nMixPlug)
{
-#ifndef NO_VST
-#if 0
- // EXPERIMENTAL VSTi arpeggio. Far from perfect!
- // Note: We could use pChn->nLastNote here to simplify things.
- if(pChn->pModInstrument && pChn->pModInstrument->nMixPlug && !m_SongFlags[SONG_FIRSTTICK])
+ const ModInstrument *pIns = pChn->pModInstrument;
+ IMixPlugin *pPlugin = m_MixPlugins[pIns->nMixPlug - 1].pMixPlugin;
+ if(pPlugin)
{
- const ModInstrument *pIns = pChn->pModInstrument;
- IMixPlugin *pPlugin = m_MixPlugins[pIns->nMixPlug - 1].pMixPlugin;
- if(pPlugin)
+ uint8 step = 0;
+ const bool arpOnRow = (pChn->rowCommand.command == CMD_ARPEGGIO);
+ if(arpOnRow)
{
- // Temporary logic: This ensures that the first and last tick are both playing the base note.
- int nCount = (int)m_nTickCount - (int)(m_nMusicSpeed * (m_nPatternDelay + 1) + m_nFrameDelay - 1);
- int nStep = 0, nLastStep = 0;
- nCount = -nCount;
- switch(nCount % 3)
+ switch(m_nTickCount % 3)
{
- case 0:
- nStep = 0;
- nLastStep = pChn->nArpeggio & 0x0F;
- break;
- case 1:
- nStep = pChn->nArpeggio >> 4;
- nLastStep = 0;
- break;
- case 2:
- nStep = pChn->nArpeggio & 0x0F;
- nLastStep = pChn->nArpeggio >> 4;
- break;
+ case 1: step = pChn->nArpeggio >> 4; break;
+ case 2: step = pChn->nArpeggio & 0x0F; break;
}
- // First tick is always 0
- if(m_nTickCount == 1)
- nLastStep = 0;
+ pChn->nArpeggioBaseNote = pChn->nLastNote;
+ }
- pPlugin->MidiCommand(pIns->nMidiChannel, pIns->nMidiProgram, pIns->wMidiBank, pChn->nNote + nStep, pChn->nVolume, nChn);
- pPlugin->MidiCommand(pIns->nMidiChannel, pIns->nMidiProgram, pIns->wMidiBank, pChn->nNote + nLastStep + NOTE_KEYOFF, 0, nChn);
- }
+ // Trigger new note:
+ // - If there's an arpeggio on this row and
+ // - the note to trigger is not the same as the previous arpeggio note or
+ // - a pattern note has just been triggered on this tick
+ // - If there's no arpeggio
+ // - but an arpeggio note is still active and
+ // - there's no note stop or new note that would stop it anyway
+ if((arpOnRow && pChn->nArpeggioLastNote != pChn->nArpeggioBaseNote + step && (!m_SongFlags[SONG_FIRSTTICK] || !pChn->rowCommand.IsNote()))
+ || (!arpOnRow && pChn->rowCommand.note == NOTE_NONE && pChn->nArpeggioLastNote != NOTE_NONE))
+ pPlugin->MidiCommand(GetBestMidiChannel(nChn), pIns->nMidiProgram, pIns->wMidiBank, pChn->nArpeggioBaseNote + step, static_cast<uint16>(pChn->nVolume), nChn);
+ if(pChn->nArpeggioLastNote != NOTE_NONE)
+ pPlugin->MidiCommand(GetBestMidiChannel(nChn), pIns->nMidiProgram, pIns->wMidiBank, pChn->nArpeggioLastNote + NOTE_MAX_SPECIAL, 0, nChn);
+
+ if(pChn->rowCommand.command == CMD_ARPEGGIO)
+ pChn->nArpeggioLastNote = pChn->nArpeggioBaseNote + step;
+ else
+ pChn->nArpeggioLastNote = NOTE_NONE;
}
-#endif // 0
+ }
#endif // NO_VST
+ if(pChn->nCommand == CMD_ARPEGGIO)
+ {
if((GetType() & MOD_TYPE_MPT) && pChn->pModInstrument && pChn->pModInstrument->pTuning)
{
switch(m_nTickCount % 3)
@@ -1764,7 +1767,7 @@
period = GetPeriodFromNote(GetNoteFromPeriod(period), pChn->nFineTune, pChn->nC5Speed);
}
- ProcessArpeggio(pChn, period, arpeggioSteps);
+ ProcessArpeggio(nChn, period, arpeggioSteps);
// Preserve Amiga freq limits.
// In ST3, the frequency is always clamped to periods 113 to 856, while in ProTracker,
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|