/* * PlugInterface.h * --------------- * Purpose: Interface class for plugin handling * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #ifndef NO_PLUGINS #include "../../soundlib/Snd_defs.h" #include "../../soundlib/MIDIEvents.h" #include "../../soundlib/Mixer.h" #include "PluginMixBuffer.h" #include "PluginStructs.h" OPENMPT_NAMESPACE_BEGIN struct VSTPluginLib; struct SNDMIXPLUGIN; struct ModInstrument; struct ModChannel; class CSoundFile; class CModDoc; class CAbstractVstEditor; struct SNDMIXPLUGINSTATE { // dwFlags flags enum PluginStateFlags { psfMixReady = 0x01, // Set when cleared psfHasInput = 0x02, // Set when plugin has non-silent input psfSilenceBypass = 0x04, // Bypass because of silence detection }; mixsample_t *pMixBuffer = nullptr; // Stereo effect send buffer uint32 dwFlags = 0; // PluginStateFlags uint32 inputSilenceCount = 0; // How much silence has been processed? (for plugin auto-turnoff) mixsample_t nVolDecayL = 0, nVolDecayR = 0; // End of sample click removal void ResetSilence() { dwFlags |= psfHasInput; dwFlags &= ~psfSilenceBypass; inputSilenceCount = 0; } }; class IMixPlugin { friend class CAbstractVstEditor; protected: IMixPlugin *m_pNext = nullptr, *m_pPrev = nullptr; VSTPluginLib &m_Factory; CSoundFile &m_SndFile; SNDMIXPLUGIN *m_pMixStruct; #ifdef MODPLUG_TRACKER CAbstractVstEditor *m_pEditor = nullptr; #endif // MODPLUG_TRACKER public: SNDMIXPLUGINSTATE m_MixState; PluginMixBuffer m_mixBuffer; // Float buffers (input and output) for plugins protected: mixsample_t m_MixBuffer[MIXBUFFERSIZE * 2 + 2]; // Stereo interleaved input (sample mixer renders here) float m_fGain = 1.0f; PLUGINDEX m_nSlot = 0; bool m_isSongPlaying = false; bool m_isResumed = false; public: bool m_recordAutomation = false; bool m_passKeypressesToPlug = false; bool m_recordMIDIOut = false; protected: virtual ~IMixPlugin(); // Insert plugin into list of loaded plugins. void InsertIntoFactoryList(); public: // Non-virtual part of the interface IMixPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); inline CSoundFile &GetSoundFile() { return m_SndFile; } inline const CSoundFile &GetSoundFile() const { return m_SndFile; } #ifdef MODPLUG_TRACKER CModDoc *GetModDoc(); const CModDoc *GetModDoc() const; void SetSlot(PLUGINDEX slot); inline PLUGINDEX GetSlot() const { return m_nSlot; } #endif // MODPLUG_TRACKER inline VSTPluginLib &GetPluginFactory() const { return m_Factory; } // Returns the next instance of the same plugin inline IMixPlugin *GetNextInstance() const { return m_pNext; } void SetDryRatio(float dryRatio); bool IsBypassed() const; void RecalculateGain(); // Query output latency from host (in seconds) double GetOutputLatency() const; // Destroy the plugin virtual void Release() = 0; virtual int32 GetUID() const = 0; virtual int32 GetVersion() const = 0; virtual void Idle() = 0; // Plugin latency in samples virtual uint32 GetLatency() const = 0; virtual int32 GetNumPrograms() const = 0; virtual int32 GetCurrentProgram() = 0; virtual void SetCurrentProgram(int32 nIndex) = 0; virtual PlugParamIndex GetNumParameters() const = 0; virtual void SetParameter(PlugParamIndex paramindex, PlugParamValue paramvalue) = 0; virtual PlugParamValue GetParameter(PlugParamIndex nIndex) = 0; // Save parameters for storing them in a module file virtual void SaveAllParameters(); // Restore parameters from module file virtual void RestoreAllParameters(int32 program); virtual void Process(float *pOutL, float *pOutR, uint32 numFrames) = 0; void ProcessMixOps(float *pOutL, float *pOutR, float *leftPlugOutput, float *rightPlugOutput, uint32 numFrames); // Render silence and return the highest resulting output level virtual float RenderSilence(uint32 numSamples); // MIDI event handling virtual bool MidiSend(uint32 /*midiCode*/) { return true; } virtual bool MidiSysexSend(mpt::const_byte_span /*sysex*/) { return true; } virtual void MidiCC(MIDIEvents::MidiCC /*nController*/, uint8 /*nParam*/, CHANNELINDEX /*trackChannel*/) { } virtual void MidiPitchBendRaw(int32 /*pitchbend*/, CHANNELINDEX /*trackChannel*/) {} virtual void MidiPitchBend(int32 /*increment*/, int8 /*pwd*/, CHANNELINDEX /*trackChannel*/) { } virtual void MidiVibrato(int32 /*depth*/, int8 /*pwd*/, CHANNELINDEX /*trackerChn*/) { } virtual void MidiCommand(const ModInstrument &/*instr*/, uint16 /*note*/, uint16 /*vol*/, CHANNELINDEX /*trackChannel*/) { } virtual void HardAllNotesOff() { } virtual bool IsNotePlaying(uint8 /*note*/, CHANNELINDEX /*trackerChn*/) { return false; } // Modify parameter by given amount. Only needs to be re-implemented if plugin architecture allows this to be performed atomically. virtual void ModifyParameter(PlugParamIndex nIndex, PlugParamValue diff); virtual void NotifySongPlaying(bool playing) { m_isSongPlaying = playing; } virtual bool IsSongPlaying() const { return m_isSongPlaying; } virtual bool IsResumed() const { return m_isResumed; } virtual void Resume() = 0; virtual void Suspend() = 0; // Tell the plugin that there is a discontinuity between the previous and next render call (e.g. aftert jumping around in the module) virtual void PositionChanged() = 0; virtual void Bypass(bool = true); bool ToggleBypass() { Bypass(!IsBypassed()); return IsBypassed(); } virtual bool IsInstrument() const = 0; virtual bool CanRecieveMidiEvents() = 0; // If false is returned, mixing this plugin can be skipped if its input are currently completely silent. virtual bool ShouldProcessSilence() = 0; virtual void ResetSilence() { m_MixState.ResetSilence(); } size_t GetOutputPlugList(std::vector &list); size_t GetInputPlugList(std::vector &list); size_t GetInputInstrumentList(std::vector &list); size_t GetInputChannelList(std::vector &list); #ifdef MODPLUG_TRACKER bool SaveProgram(); bool LoadProgram(mpt::PathString fileName = mpt::PathString()); virtual CString GetDefaultEffectName() = 0; // Cache a range of names, in case one-by-one retrieval would be slow (e.g. when using plugin bridge) virtual void CacheProgramNames(int32 /*firstProg*/, int32 /*lastProg*/) { } virtual void CacheParameterNames(int32 /*firstParam*/, int32 /*lastParam*/) { } // Allowed value range for a parameter virtual std::pair GetParamUIRange(PlugParamIndex /*param*/) { return {0.0f, 1.0f}; } // Scale allowed value range of a parameter to/from [0,1] PlugParamValue GetScaledUIParam(PlugParamIndex param); void SetScaledUIParam(PlugParamIndex param, PlugParamValue value); virtual CString GetParamName(PlugParamIndex param) = 0; virtual CString GetParamLabel(PlugParamIndex param) = 0; virtual CString GetParamDisplay(PlugParamIndex param) = 0; CString GetFormattedParamName(PlugParamIndex param); CString GetFormattedParamValue(PlugParamIndex param); virtual CString GetCurrentProgramName() = 0; virtual void SetCurrentProgramName(const CString &name) = 0; virtual CString GetProgramName(int32 program) = 0; CString GetFormattedProgramName(int32 index); virtual bool HasEditor() const = 0; protected: virtual CAbstractVstEditor *OpenEditor(); public: // Get the plugin's editor window CAbstractVstEditor *GetEditor() { return m_pEditor; } const CAbstractVstEditor *GetEditor() const { return m_pEditor; } void ToggleEditor(); void CloseEditor(); void SetEditorPos(int32 x, int32 y); void GetEditorPos(int32 &x, int32 &y) const; // Notify OpenMPT that a plugin parameter has changed and set document as modified void AutomateParameter(PlugParamIndex param); // Plugin state changed, set document as modified. void SetModified(); #endif virtual int GetNumInputChannels() const = 0; virtual int GetNumOutputChannels() const = 0; using ChunkData = mpt::const_byte_span; virtual bool ProgramsAreChunks() const { return false; } virtual ChunkData GetChunk(bool /*isBank*/) { return ChunkData(); } virtual void SetChunk(const ChunkData &/*chunk*/, bool /*isBank*/) { } virtual void BeginSetProgram(int32 /*program*/ = -1) {} virtual void EndSetProgram() {} virtual void BeginGetProgram(int32 /*program*/ = -1) {} virtual void EndGetProgram() {} }; inline void IMixPlugin::ModifyParameter(PlugParamIndex nIndex, PlugParamValue diff) { PlugParamValue val = GetParameter(nIndex) + diff; Limit(val, PlugParamValue(0), PlugParamValue(1)); SetParameter(nIndex, val); } // IMidiPlugin: Default implementation of plugins with MIDI input class IMidiPlugin : public IMixPlugin { protected: enum { // Pitch wheel constants kPitchBendShift = 12, // Use lowest 12 bits for fractional part and vibrato flag => 16.11 fixed point precision kPitchBendMask = (~1), kVibratoFlag = 1, }; struct PlugInstrChannel { int32 midiPitchBendPos = 0; // Current Pitch Wheel position, in 16.11 fixed point format. Lowest bit is used for indicating that vibrato was applied. Vibrato offset itself is not stored in this value. uint16 currentProgram = uint16_max; uint16 currentBank = uint16_max; uint8 noteOnMap[128][MAX_CHANNELS]; void ResetProgram() { currentProgram = uint16_max; currentBank = uint16_max; } }; std::array m_MidiCh; // MIDI channel state public: IMidiPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); void MidiCC(MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel) override; void MidiPitchBendRaw(int32 pitchbend, CHANNELINDEX trackerChn) override; void MidiPitchBend(int32 increment, int8 pwd, CHANNELINDEX trackerChn) override; void MidiVibrato(int32 depth, int8 pwd, CHANNELINDEX trackerChn) override; void MidiCommand(const ModInstrument &instr, uint16 note, uint16 vol, CHANNELINDEX trackChannel) override; bool IsNotePlaying(uint8 note, CHANNELINDEX trackerChn) override; // Get the MIDI channel currently associated with a given tracker channel virtual uint8 GetMidiChannel(const ModChannel &chn, CHANNELINDEX trackChannel) const; protected: uint8 GetMidiChannel(CHANNELINDEX trackChannel) const; // Plugin wants to send MIDI to OpenMPT virtual void ReceiveMidi(uint32 midiCode); virtual void ReceiveSysex(mpt::const_byte_span sysex); // Converts a 14-bit MIDI pitch bend position to our internal pitch bend position representation static constexpr int32 EncodePitchBendParam(int32 position) { return (position << kPitchBendShift); } // Converts the internal pitch bend position to a 14-bit MIDI pitch bend position static constexpr int16 DecodePitchBendParam(int32 position) { return static_cast(position >> kPitchBendShift); } // Apply Pitch Wheel Depth (PWD) to some MIDI pitch bend value. static inline void ApplyPitchWheelDepth(int32 &value, int8 pwd); void SendMidiPitchBend(uint8 midiCh, int32 newPitchBendPos); }; OPENMPT_NAMESPACE_END #endif // NO_PLUGINS