PlugInterface.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. * PlugInterface.h
  3. * ---------------
  4. * Purpose: Interface class for plugin handling
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #pragma once
  10. #include "openmpt/all/BuildSettings.hpp"
  11. #ifndef NO_PLUGINS
  12. #include "../../soundlib/Snd_defs.h"
  13. #include "../../soundlib/MIDIEvents.h"
  14. #include "../../soundlib/Mixer.h"
  15. #include "PluginMixBuffer.h"
  16. #include "PluginStructs.h"
  17. OPENMPT_NAMESPACE_BEGIN
  18. struct VSTPluginLib;
  19. struct SNDMIXPLUGIN;
  20. struct ModInstrument;
  21. struct ModChannel;
  22. class CSoundFile;
  23. class CModDoc;
  24. class CAbstractVstEditor;
  25. struct SNDMIXPLUGINSTATE
  26. {
  27. // dwFlags flags
  28. enum PluginStateFlags
  29. {
  30. psfMixReady = 0x01, // Set when cleared
  31. psfHasInput = 0x02, // Set when plugin has non-silent input
  32. psfSilenceBypass = 0x04, // Bypass because of silence detection
  33. };
  34. mixsample_t *pMixBuffer = nullptr; // Stereo effect send buffer
  35. uint32 dwFlags = 0; // PluginStateFlags
  36. uint32 inputSilenceCount = 0; // How much silence has been processed? (for plugin auto-turnoff)
  37. mixsample_t nVolDecayL = 0, nVolDecayR = 0; // End of sample click removal
  38. void ResetSilence()
  39. {
  40. dwFlags |= psfHasInput;
  41. dwFlags &= ~psfSilenceBypass;
  42. inputSilenceCount = 0;
  43. }
  44. };
  45. class IMixPlugin
  46. {
  47. friend class CAbstractVstEditor;
  48. protected:
  49. IMixPlugin *m_pNext = nullptr, *m_pPrev = nullptr;
  50. VSTPluginLib &m_Factory;
  51. CSoundFile &m_SndFile;
  52. SNDMIXPLUGIN *m_pMixStruct;
  53. #ifdef MODPLUG_TRACKER
  54. CAbstractVstEditor *m_pEditor = nullptr;
  55. #endif // MODPLUG_TRACKER
  56. public:
  57. SNDMIXPLUGINSTATE m_MixState;
  58. PluginMixBuffer<float, MIXBUFFERSIZE> m_mixBuffer; // Float buffers (input and output) for plugins
  59. protected:
  60. mixsample_t m_MixBuffer[MIXBUFFERSIZE * 2 + 2]; // Stereo interleaved input (sample mixer renders here)
  61. float m_fGain = 1.0f;
  62. PLUGINDEX m_nSlot = 0;
  63. bool m_isSongPlaying = false;
  64. bool m_isResumed = false;
  65. public:
  66. bool m_recordAutomation = false;
  67. bool m_passKeypressesToPlug = false;
  68. bool m_recordMIDIOut = false;
  69. protected:
  70. virtual ~IMixPlugin();
  71. // Insert plugin into list of loaded plugins.
  72. void InsertIntoFactoryList();
  73. public:
  74. // Non-virtual part of the interface
  75. IMixPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
  76. inline CSoundFile &GetSoundFile() { return m_SndFile; }
  77. inline const CSoundFile &GetSoundFile() const { return m_SndFile; }
  78. #ifdef MODPLUG_TRACKER
  79. CModDoc *GetModDoc();
  80. const CModDoc *GetModDoc() const;
  81. void SetSlot(PLUGINDEX slot);
  82. inline PLUGINDEX GetSlot() const { return m_nSlot; }
  83. #endif // MODPLUG_TRACKER
  84. inline VSTPluginLib &GetPluginFactory() const { return m_Factory; }
  85. // Returns the next instance of the same plugin
  86. inline IMixPlugin *GetNextInstance() const { return m_pNext; }
  87. void SetDryRatio(float dryRatio);
  88. bool IsBypassed() const;
  89. void RecalculateGain();
  90. // Query output latency from host (in seconds)
  91. double GetOutputLatency() const;
  92. // Destroy the plugin
  93. virtual void Release() = 0;
  94. virtual int32 GetUID() const = 0;
  95. virtual int32 GetVersion() const = 0;
  96. virtual void Idle() = 0;
  97. // Plugin latency in samples
  98. virtual uint32 GetLatency() const = 0;
  99. virtual int32 GetNumPrograms() const = 0;
  100. virtual int32 GetCurrentProgram() = 0;
  101. virtual void SetCurrentProgram(int32 nIndex) = 0;
  102. virtual PlugParamIndex GetNumParameters() const = 0;
  103. virtual void SetParameter(PlugParamIndex paramindex, PlugParamValue paramvalue) = 0;
  104. virtual PlugParamValue GetParameter(PlugParamIndex nIndex) = 0;
  105. // Save parameters for storing them in a module file
  106. virtual void SaveAllParameters();
  107. // Restore parameters from module file
  108. virtual void RestoreAllParameters(int32 program);
  109. virtual void Process(float *pOutL, float *pOutR, uint32 numFrames) = 0;
  110. void ProcessMixOps(float *pOutL, float *pOutR, float *leftPlugOutput, float *rightPlugOutput, uint32 numFrames);
  111. // Render silence and return the highest resulting output level
  112. virtual float RenderSilence(uint32 numSamples);
  113. // MIDI event handling
  114. virtual bool MidiSend(uint32 /*midiCode*/) { return true; }
  115. virtual bool MidiSysexSend(mpt::const_byte_span /*sysex*/) { return true; }
  116. virtual void MidiCC(MIDIEvents::MidiCC /*nController*/, uint8 /*nParam*/, CHANNELINDEX /*trackChannel*/) { }
  117. virtual void MidiPitchBendRaw(int32 /*pitchbend*/, CHANNELINDEX /*trackChannel*/) {}
  118. virtual void MidiPitchBend(int32 /*increment*/, int8 /*pwd*/, CHANNELINDEX /*trackChannel*/) { }
  119. virtual void MidiVibrato(int32 /*depth*/, int8 /*pwd*/, CHANNELINDEX /*trackerChn*/) { }
  120. virtual void MidiCommand(const ModInstrument &/*instr*/, uint16 /*note*/, uint16 /*vol*/, CHANNELINDEX /*trackChannel*/) { }
  121. virtual void HardAllNotesOff() { }
  122. virtual bool IsNotePlaying(uint8 /*note*/, CHANNELINDEX /*trackerChn*/) { return false; }
  123. // Modify parameter by given amount. Only needs to be re-implemented if plugin architecture allows this to be performed atomically.
  124. virtual void ModifyParameter(PlugParamIndex nIndex, PlugParamValue diff);
  125. virtual void NotifySongPlaying(bool playing) { m_isSongPlaying = playing; }
  126. virtual bool IsSongPlaying() const { return m_isSongPlaying; }
  127. virtual bool IsResumed() const { return m_isResumed; }
  128. virtual void Resume() = 0;
  129. virtual void Suspend() = 0;
  130. // Tell the plugin that there is a discontinuity between the previous and next render call (e.g. aftert jumping around in the module)
  131. virtual void PositionChanged() = 0;
  132. virtual void Bypass(bool = true);
  133. bool ToggleBypass() { Bypass(!IsBypassed()); return IsBypassed(); }
  134. virtual bool IsInstrument() const = 0;
  135. virtual bool CanRecieveMidiEvents() = 0;
  136. // If false is returned, mixing this plugin can be skipped if its input are currently completely silent.
  137. virtual bool ShouldProcessSilence() = 0;
  138. virtual void ResetSilence() { m_MixState.ResetSilence(); }
  139. size_t GetOutputPlugList(std::vector<IMixPlugin *> &list);
  140. size_t GetInputPlugList(std::vector<IMixPlugin *> &list);
  141. size_t GetInputInstrumentList(std::vector<INSTRUMENTINDEX> &list);
  142. size_t GetInputChannelList(std::vector<CHANNELINDEX> &list);
  143. #ifdef MODPLUG_TRACKER
  144. bool SaveProgram();
  145. bool LoadProgram(mpt::PathString fileName = mpt::PathString());
  146. virtual CString GetDefaultEffectName() = 0;
  147. // Cache a range of names, in case one-by-one retrieval would be slow (e.g. when using plugin bridge)
  148. virtual void CacheProgramNames(int32 /*firstProg*/, int32 /*lastProg*/) { }
  149. virtual void CacheParameterNames(int32 /*firstParam*/, int32 /*lastParam*/) { }
  150. // Allowed value range for a parameter
  151. virtual std::pair<PlugParamValue, PlugParamValue> GetParamUIRange(PlugParamIndex /*param*/) { return {0.0f, 1.0f}; }
  152. // Scale allowed value range of a parameter to/from [0,1]
  153. PlugParamValue GetScaledUIParam(PlugParamIndex param);
  154. void SetScaledUIParam(PlugParamIndex param, PlugParamValue value);
  155. virtual CString GetParamName(PlugParamIndex param) = 0;
  156. virtual CString GetParamLabel(PlugParamIndex param) = 0;
  157. virtual CString GetParamDisplay(PlugParamIndex param) = 0;
  158. CString GetFormattedParamName(PlugParamIndex param);
  159. CString GetFormattedParamValue(PlugParamIndex param);
  160. virtual CString GetCurrentProgramName() = 0;
  161. virtual void SetCurrentProgramName(const CString &name) = 0;
  162. virtual CString GetProgramName(int32 program) = 0;
  163. CString GetFormattedProgramName(int32 index);
  164. virtual bool HasEditor() const = 0;
  165. protected:
  166. virtual CAbstractVstEditor *OpenEditor();
  167. public:
  168. // Get the plugin's editor window
  169. CAbstractVstEditor *GetEditor() { return m_pEditor; }
  170. const CAbstractVstEditor *GetEditor() const { return m_pEditor; }
  171. void ToggleEditor();
  172. void CloseEditor();
  173. void SetEditorPos(int32 x, int32 y);
  174. void GetEditorPos(int32 &x, int32 &y) const;
  175. // Notify OpenMPT that a plugin parameter has changed and set document as modified
  176. void AutomateParameter(PlugParamIndex param);
  177. // Plugin state changed, set document as modified.
  178. void SetModified();
  179. #endif
  180. virtual int GetNumInputChannels() const = 0;
  181. virtual int GetNumOutputChannels() const = 0;
  182. using ChunkData = mpt::const_byte_span;
  183. virtual bool ProgramsAreChunks() const { return false; }
  184. virtual ChunkData GetChunk(bool /*isBank*/) { return ChunkData(); }
  185. virtual void SetChunk(const ChunkData &/*chunk*/, bool /*isBank*/) { }
  186. virtual void BeginSetProgram(int32 /*program*/ = -1) {}
  187. virtual void EndSetProgram() {}
  188. virtual void BeginGetProgram(int32 /*program*/ = -1) {}
  189. virtual void EndGetProgram() {}
  190. };
  191. inline void IMixPlugin::ModifyParameter(PlugParamIndex nIndex, PlugParamValue diff)
  192. {
  193. PlugParamValue val = GetParameter(nIndex) + diff;
  194. Limit(val, PlugParamValue(0), PlugParamValue(1));
  195. SetParameter(nIndex, val);
  196. }
  197. // IMidiPlugin: Default implementation of plugins with MIDI input
  198. class IMidiPlugin : public IMixPlugin
  199. {
  200. protected:
  201. enum
  202. {
  203. // Pitch wheel constants
  204. kPitchBendShift = 12, // Use lowest 12 bits for fractional part and vibrato flag => 16.11 fixed point precision
  205. kPitchBendMask = (~1),
  206. kVibratoFlag = 1,
  207. };
  208. struct PlugInstrChannel
  209. {
  210. 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.
  211. uint16 currentProgram = uint16_max;
  212. uint16 currentBank = uint16_max;
  213. uint8 noteOnMap[128][MAX_CHANNELS];
  214. void ResetProgram() { currentProgram = uint16_max; currentBank = uint16_max; }
  215. };
  216. std::array<PlugInstrChannel, 16> m_MidiCh; // MIDI channel state
  217. public:
  218. IMidiPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
  219. void MidiCC(MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel) override;
  220. void MidiPitchBendRaw(int32 pitchbend, CHANNELINDEX trackerChn) override;
  221. void MidiPitchBend(int32 increment, int8 pwd, CHANNELINDEX trackerChn) override;
  222. void MidiVibrato(int32 depth, int8 pwd, CHANNELINDEX trackerChn) override;
  223. void MidiCommand(const ModInstrument &instr, uint16 note, uint16 vol, CHANNELINDEX trackChannel) override;
  224. bool IsNotePlaying(uint8 note, CHANNELINDEX trackerChn) override;
  225. // Get the MIDI channel currently associated with a given tracker channel
  226. virtual uint8 GetMidiChannel(const ModChannel &chn, CHANNELINDEX trackChannel) const;
  227. protected:
  228. uint8 GetMidiChannel(CHANNELINDEX trackChannel) const;
  229. // Plugin wants to send MIDI to OpenMPT
  230. virtual void ReceiveMidi(uint32 midiCode);
  231. virtual void ReceiveSysex(mpt::const_byte_span sysex);
  232. // Converts a 14-bit MIDI pitch bend position to our internal pitch bend position representation
  233. static constexpr int32 EncodePitchBendParam(int32 position) { return (position << kPitchBendShift); }
  234. // Converts the internal pitch bend position to a 14-bit MIDI pitch bend position
  235. static constexpr int16 DecodePitchBendParam(int32 position) { return static_cast<int16>(position >> kPitchBendShift); }
  236. // Apply Pitch Wheel Depth (PWD) to some MIDI pitch bend value.
  237. static inline void ApplyPitchWheelDepth(int32 &value, int8 pwd);
  238. void SendMidiPitchBend(uint8 midiCh, int32 newPitchBendPos);
  239. };
  240. OPENMPT_NAMESPACE_END
  241. #endif // NO_PLUGINS