From: <sag...@us...> - 2012-07-09 16:13:29
|
Revision: 1322 http://modplug.svn.sourceforge.net/modplug/?rev=1322&view=rev Author: saga-games Date: 2012-07-09 16:13:18 +0000 (Mon, 09 Jul 2012) Log Message: ----------- [New] Plugins can also receive tracker portamento (Hxx / 4xx) now. At a pitch wheel depth of +/-2 semitones, the behaviour is identical to sample vibrato. Modified Paths: -------------- trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/Vstplug.h trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/ModChannel.h trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/Sndmix.cpp trunk/OpenMPT/soundlib/plugins/PlugInterface.h Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2012-07-09 00:54:37 UTC (rev 1321) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2012-07-09 16:13:18 UTC (rev 1322) @@ -2369,12 +2369,13 @@ //-------------------------------------------------------------------------------------- { const int16 increment = static_cast<int16>(nParam * 0x2000 / 0xFF); - int16 newPitchBendPos = m_nMidiPitchBendPos[nMidiCh] + increment; + int16 newPitchBendPos = (m_nMidiPitchBendPos[nMidiCh] & vstPitchBendMask) + increment; Limit(newPitchBendPos, int16(MIDIEvents::pitchBendMin), int16(MIDIEvents::pitchBendMax)); MidiPitchBend(nMidiCh, newPitchBendPos); } + //Set midi pitch for given midi channel using uncoverted midi value (0-16383) void CVstPlugin::MidiPitchBend(uint8 nMidiCh, int16 newPitchBendPos) //------------------------------------------------------------------ @@ -2385,6 +2386,28 @@ } +void CVstPlugin::MidiVibrato(uint8 nMidiCh, int16 depth) +//------------------------------------------------------ +{ + if(depth != 0 || (m_nMidiPitchBendPos[nMidiCh] & vstVibratoFlag)) + { + // Temporarily add vibrato offset to current pitch + int16 pitch = (m_nMidiPitchBendPos[nMidiCh] & vstPitchBendMask) + depth; + Limit(pitch, static_cast<int16>(MIDIEvents::pitchBendMin), static_cast<int16>(MIDIEvents::pitchBendMax)); + MidiSend(MIDIEvents::BuildPitchBendEvent(nMidiCh, pitch)); + } + + // Update vibrato status + if(depth != 0) + { + m_nMidiPitchBendPos[nMidiCh] |= vstVibratoFlag; + } else + { + m_nMidiPitchBendPos[nMidiCh] &= ~vstVibratoFlag; + } +} + + //rewbs.introVST - many changes to MidiCommand, still to be refined. void CVstPlugin::MidiCommand(uint8 nMidiCh, uint8 nMidiProg, uint16 wMidiBank, uint16 note, uint16 vol, CHANNELINDEX trackChannel) //-------------------------------------------------------------------------------------------------------------------------------- Modified: trunk/OpenMPT/mptrack/Vstplug.h =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.h 2012-07-09 00:54:37 UTC (rev 1321) +++ trunk/OpenMPT/mptrack/Vstplug.h 2012-07-09 16:13:18 UTC (rev 1322) @@ -129,6 +129,9 @@ { // Number of MIDI events that can be sent to a plugin at once (the internal queue is not affected by this number, it can hold any number of events) vstNumProcessEvents = 256, + + vstPitchBendMask = 0x7FFF, + vstVibratoFlag = 0x8000, }; ULONG m_nRefCount; @@ -145,7 +148,7 @@ SNDMIXPLUGINSTATE m_MixState; UINT m_nInputs, m_nOutputs; VSTInstrChannel m_MidiCh[16]; - short m_nMidiPitchBendPos[16]; + int16 m_nMidiPitchBendPos[16]; // Current pitch wheel depth. Highest bit is used for indicating that vibrato was applied. Vibrato offset itself is not stored in this value. CModDoc* m_pModDoc; //rewbs.plugDocAware CSoundFile* m_pSndFile; //rewbs.plugDocAware @@ -235,6 +238,7 @@ bool MidiSend(DWORD dwMidiCode); void MidiCC(uint8 nMidiCh, MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel); void MidiPitchBend(uint8 nMidiCh, int nParam, CHANNELINDEX trackChannel); + void MidiVibrato(uint8 nMidiCh, int16 depth); void MidiCommand(uint8 nMidiCh, uint8 nMidiProg, uint16 wMidiBank, uint16 note, uint16 vol, CHANNELINDEX trackChannel); void HardAllNotesOff(); //rewbs.VSTiNoteHoldonStopFix bool isPlaying(UINT note, UINT midiChn, UINT trackerChn); //rewbs.instroVST Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-07-09 00:54:37 UTC (rev 1321) +++ trunk/OpenMPT/mptrack/version.h 2012-07-09 16:13:18 UTC (rev 1322) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 02 -#define VER_MINORMINOR 00 +#define VER_MINORMINOR 01 //Creates version number from version parts that appears in version string. //For example MAKE_VERSION_NUMERIC(1,17,02,28) gives version number of Modified: trunk/OpenMPT/soundlib/ModChannel.h =================================================================== --- trunk/OpenMPT/soundlib/ModChannel.h 2012-07-09 00:54:37 UTC (rev 1321) +++ trunk/OpenMPT/soundlib/ModChannel.h 2012-07-09 16:13:18 UTC (rev 1322) @@ -44,6 +44,7 @@ // 2nd cache line DWORD nLength; DWORD dwFlags; + DWORD dwOldFlags; // Flags from previous tick DWORD nLoopStart; DWORD nLoopEnd; int nRampRightVol; @@ -61,9 +62,8 @@ int nPeriod, nC5Speed, nPortamentoDest; int nCalcVolume; // Calculated channel volume, 14-Bit (without global volume, pre-amp etc applied) - for MIDI macros ModInstrument *pModInstrument; // Currently assigned instrument slot - ModChannelEnvInfo VolEnv, PanEnv, PitchEnv; // Envelope playback info + ModChannelEnvInfo VolEnv, PanEnv, PitchEnv; // Envelope playback info ModSample *pModSample; // Currently assigned sample slot - CHANNELINDEX nMasterChn; DWORD nVUMeter; int nGlobalVol; // Channel volume (CV in ITTECH.TXT) int nInsVol; // Sample / Instrument volume (SV * IV in ITTECH.TXT) @@ -78,6 +78,7 @@ int nRetrigCount, nRetrigParam; ROWINDEX nPatternLoop; UINT nNoteSlideCounter, nNoteSlideSpeed, nNoteSlideStep; + CHANNELINDEX nMasterChn; // 8-bit members BYTE nRestoreResonanceOnNewNote; //Like above BYTE nRestoreCutoffOnNewNote; //Like above @@ -169,11 +170,11 @@ // Default pattern channel settings -struct ModChannelSettings +struct __declspec(align(32)) ModChannelSettings { - UINT nPan; // Initial pan - UINT nVolume; // Initial channel volume - DWORD dwFlags; // Channel flags + uint16 nPan; // Initial pan + uint16 nVolume; // Initial channel volume + uint32 dwFlags; // Channel flags PLUGINDEX nMixPlugin; // Assigned plugin CHAR szName[MAX_CHANNELNAME]; // Channel name }; Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-07-09 00:54:37 UTC (rev 1321) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-07-09 16:13:18 UTC (rev 1322) @@ -2624,34 +2624,18 @@ } } + void CSoundFile::MidiPortamento(CHANNELINDEX nChn, int param) //----------------------------------------------------------- { - if((Chn[nChn].dwFlags & (CHN_MUTE | CHN_SYNCMUTE)) != 0) + IMixPlugin *plugin = GetChannelInstrumentPlugin(nChn); + if(plugin != nullptr) { - // Don't process portamento on muted channels. Note that this might have a side-effect - // on other channels which trigger notes on the same MIDI channel of the same plugin, - // as those won't be pitch-bent anymore. - return; + plugin->MidiPitchBend(GetBestMidiChannel(nChn), param, 0); } - - //Send midi pitch bend event if there's a plugin: - const ModInstrument *pIns = Chn[nChn].pModInstrument; - if (pIns && pIns->HasValidMIDIChannel()) - { - // instro sends to a midi chan - UINT nPlug = pIns->nMixPlug; - if ((nPlug) && (nPlug <= MAX_MIXPLUGINS)) - { - IMixPlugin *pPlug = (IMixPlugin*)m_MixPlugins[nPlug-1].pMixPlugin; - if (pPlug) - { - pPlug->MidiPitchBend(GetBestMidiChannel(nChn), param, 0); - } - } - } } + void CSoundFile::FinePortamentoUp(ModChannel *pChn, UINT param) //------------------------------------------------------------- { @@ -4580,21 +4564,48 @@ // Unlike channel settings, pModInstrument is copied from the original chan to the NNA chan, // so we don't need to worry about finding the master chan. - PLUGINDEX nPlugin = 0; - if (Chn[nChn].pModInstrument) + PLUGINDEX plug = 0; + if(Chn[nChn].pModInstrument != nullptr) { if (respectMutes == RespectMutes && Chn[nChn].pModSample && (Chn[nChn].pModSample->uFlags & CHN_MUTE)) { - nPlugin = 0; + plug = 0; } else { - nPlugin = Chn[nChn].pModInstrument->nMixPlug; + plug = Chn[nChn].pModInstrument->nMixPlug; } } - return nPlugin; + return plug; } +// Retrieve the plugin that is associated with the channel's current instrument. +// No plugin is returned if the channel is muted or if the instrument doesn't have a MIDI channel set up, +// As this is meant to be used with instrument plugins. +IMixPlugin *CSoundFile::GetChannelInstrumentPlugin(CHANNELINDEX chn) const +//------------------------------------------------------------------------ +{ + if((Chn[chn].dwFlags & (CHN_MUTE | CHN_SYNCMUTE)) != 0) + { + // Don't process portamento on muted channels. Note that this might have a side-effect + // on other channels which trigger notes on the same MIDI channel of the same plugin, + // as those won't be pitch-bent anymore. + return nullptr; + } + + const ModInstrument *pIns = Chn[chn].pModInstrument; + if(pIns != nullptr && pIns->HasValidMIDIChannel()) + { + // Instrument sends to a MIDI channel + if(pIns->nMixPlug != 0 && pIns->nMixPlug <= MAX_MIXPLUGINS) + { + return m_MixPlugins[pIns->nMixPlug - 1].pMixPlugin; + } + } + return nullptr; +} + + uint8 CSoundFile::GetBestMidiChannel(CHANNELINDEX nChn) const //---------------------------------------------------------- { Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2012-07-09 00:54:37 UTC (rev 1321) +++ trunk/OpenMPT/soundlib/Sndfile.h 2012-07-09 16:13:18 UTC (rev 1322) @@ -531,7 +531,7 @@ void ProcessPanbrello(ModChannel *pChn); void ProcessArpeggio(ModChannel *pChn, int &period, CTuning::NOTEINDEXTYPE &arpeggioSteps); - void ProcessVibrato(ModChannel *pChn, int &period, CTuning::RATIOTYPE &vibratoFactor); + void ProcessVibrato(CHANNELINDEX nChn, int &period, CTuning::RATIOTYPE &vibratoFactor); void ProcessSampleAutoVibrato(ModChannel *pChn, int &period, CTuning::RATIOTYPE &vibratoFactor, int &nPeriodFrac); void ProcessRamping(ModChannel *pChn); @@ -712,6 +712,7 @@ private: PLUGINDEX __cdecl GetChannelPlugin(CHANNELINDEX nChn, PluginMutePriority respectMutes) const; PLUGINDEX __cdecl GetActiveInstrumentPlugin(CHANNELINDEX, PluginMutePriority respectMutes) const; + IMixPlugin *__cdecl GetChannelInstrumentPlugin(CHANNELINDEX chn) const; void HandlePatternTransitionEvents(); Modified: trunk/OpenMPT/soundlib/Sndmix.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp 2012-07-09 00:54:37 UTC (rev 1321) +++ trunk/OpenMPT/soundlib/Sndmix.cpp 2012-07-09 16:13:18 UTC (rev 1322) @@ -1016,7 +1016,8 @@ { if(IsCompatibleMode(TRK_FASTTRACKER2)) { - // Weird XM tremor. + // FT2 Compatibility: Weird XM tremor. + // Test case: Tremor.xm if(pChn->nTremorCount & 0x80) { if(!(m_dwSongFlags & SONG_FIRSTTICK) && pChn->nCommand == CMD_TREMOR) @@ -1539,33 +1540,34 @@ } -void CSoundFile::ProcessVibrato(ModChannel *pChn, int &period, CTuning::RATIOTYPE &vibratoFactor) +void CSoundFile::ProcessVibrato(CHANNELINDEX nChn, int &period, CTuning::RATIOTYPE &vibratoFactor) //----------------------------------------------------------------------------------------------- { - if (pChn->dwFlags & CHN_VIBRATO) + ModChannel &chn = Chn[nChn]; + + if(chn.dwFlags & CHN_VIBRATO) { - UINT vibpos = pChn->nVibratoPos; + UINT vibpos = chn.nVibratoPos; - int vdelta = GetVibratoDelta(pChn->nVibratoType, vibpos); - if((GetType() & MOD_TYPE_XM) && (pChn->nVibratoType & 0x03) == 1) + int vdelta = GetVibratoDelta(chn.nVibratoType, vibpos); + if((GetType() & MOD_TYPE_XM) && (chn.nVibratoType & 0x03) == 1) { // FT2 compatibility: Vibrato ramp down table is upside down. // Test case: VibratoWaveforms.xm vdelta = -vdelta; } - if(GetType() == MOD_TYPE_MPT && pChn->pModInstrument && pChn->pModInstrument->pTuning) + if(GetType() == MOD_TYPE_MPT && chn.pModInstrument && chn.pModInstrument->pTuning) { //Hack implementation: Scaling vibratofactor to [0.95; 1.05] //using figure from above tables and vibratodepth parameter - vibratoFactor += 0.05F * vdelta * pChn->m_VibratoDepth / 128.0F; - pChn->m_CalculateFreq = true; - pChn->m_ReCalculateFreqOnFirstTick = false; + vibratoFactor += 0.05F * vdelta * chn.m_VibratoDepth / 128.0F; + chn.m_CalculateFreq = true; + chn.m_ReCalculateFreqOnFirstTick = false; if(m_nTickCount + 1 == m_nMusicSpeed) - pChn->m_ReCalculateFreqOnFirstTick = true; - } - else + chn.m_ReCalculateFreqOnFirstTick = true; + } else { // Original behaviour @@ -1584,12 +1586,14 @@ vdepth = 6; vdelta = -vdelta; } - } - else + } else { vdepth = ((!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) || (m_dwSongFlags & SONG_ITOLDEFFECTS)) ? 6 : 7; } - vdelta = (vdelta * (int)pChn->nVibratoDepth) >> vdepth; + + vdelta = (vdelta * (int)chn.nVibratoDepth) >> vdepth; + int16 midiDelta = static_cast<int16>(-vdelta); // Periods are upside down + if ((m_dwSongFlags & SONG_LINEARSLIDES) && (m_nType & (MOD_TYPE_IT | MOD_TYPE_MPT))) { int l = vdelta; @@ -1605,15 +1609,33 @@ } } period += vdelta; + + // Process MIDI vibrato for plugins: + IMixPlugin *plugin = GetChannelInstrumentPlugin(nChn); + if(plugin != nullptr) + { + midiDelta *= (MIDIEvents::pitchBendMax - MIDIEvents::pitchBendCentre) / 127; + plugin->MidiVibrato(GetBestMidiChannel(nChn), midiDelta); + } } - if ((m_nTickCount) || ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && (!(m_dwSongFlags & SONG_ITOLDEFFECTS)))) + + // Advance vibrato position + if(m_nTickCount || ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && (!(m_dwSongFlags & SONG_ITOLDEFFECTS)))) { // IT compatibility: IT has its own, more precise tables if(IsCompatibleMode(TRK_IMPULSETRACKER)) - pChn->nVibratoPos = (vibpos + 4 * pChn->nVibratoSpeed) & 0xFF; + chn.nVibratoPos = (vibpos + 4 * chn.nVibratoSpeed) & 0xFF; else - pChn->nVibratoPos = (vibpos + pChn->nVibratoSpeed) & 0x3F; + chn.nVibratoPos = (vibpos + chn.nVibratoSpeed) & 0x3F; } + } else if(chn.dwOldFlags & CHN_VIBRATO) + { + // Stop MIDI vibrato for plugins: + IMixPlugin *plugin = GetChannelInstrumentPlugin(nChn); + if(plugin != nullptr) + { + plugin->MidiVibrato(GetBestMidiChannel(nChn), 0); + } } } @@ -2067,12 +2089,17 @@ ProcessMacroOnChannel(nChn); // After MIDI macros have been processed, we can also process the pitch / filter envelope and other pitch-related things. - if (samplePlaying) + if(samplePlaying) { + ProcessPitchFilterEnvelope(pChn, period); + } + + // Plugins may also receive vibrato + ProcessVibrato(nChn, period, vibratoFactor); + + if(samplePlaying) + { int nPeriodFrac = 0; - - ProcessPitchFilterEnvelope(pChn, period); - ProcessVibrato(pChn, period, vibratoFactor); ProcessSampleAutoVibrato(pChn, period, vibratoFactor, nPeriodFrac); // Final Period @@ -2333,6 +2360,8 @@ pChn->nLeftVol = pChn->nRightVol = 0; pChn->nLength = 0; } + + pChn->dwOldFlags = pChn->dwFlags; } // Checking Max Mix Channels reached: ordering by volume Modified: trunk/OpenMPT/soundlib/plugins/PlugInterface.h =================================================================== --- trunk/OpenMPT/soundlib/plugins/PlugInterface.h 2012-07-09 00:54:37 UTC (rev 1321) +++ trunk/OpenMPT/soundlib/plugins/PlugInterface.h 2012-07-09 16:13:18 UTC (rev 1322) @@ -43,6 +43,7 @@ virtual bool MidiSend(DWORD dwMidiCode) = 0; virtual void MidiCC(uint8 nMidiCh, MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel) = 0; virtual void MidiPitchBend(uint8 nMidiCh, int nParam, CHANNELINDEX trackChannel) = 0; + virtual void MidiVibrato(uint8 nMidiCh, int16 depth) = 0; virtual void MidiCommand(uint8 nMidiCh, uint8 nMidiProg, uint16 wMidiBank, uint16 note, uint16 vol, CHANNELINDEX trackChannel) = 0; virtual void HardAllNotesOff() = 0; //rewbs.VSTCompliance virtual void RecalculateGain() = 0; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |