winamp/Src/external_dependencies/openmpt-trunk/soundlib/plugins/PlugInterface.h
2024-09-24 14:54:57 +02:00

301 lines
11 KiB
C++

/*
* 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<float, MIXBUFFERSIZE> 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<IMixPlugin *> &list);
size_t GetInputPlugList(std::vector<IMixPlugin *> &list);
size_t GetInputInstrumentList(std::vector<INSTRUMENTINDEX> &list);
size_t GetInputChannelList(std::vector<CHANNELINDEX> &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<PlugParamValue, PlugParamValue> 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<PlugInstrChannel, 16> 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<int16>(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