1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
// VST2Plugin
#pragma once
#include "Interface.h"
#include "PluginFactory.h"
#define VST_FORCE_DEPRECATED 0
#include "aeffectx.h"
namespace vst {
class VST2Plugin;
class VST2Factory final : public PluginFactory {
public:
static VstInt32 shellPluginID;
VST2Factory(const std::string& path, bool probe);
~VST2Factory();
// probe a single plugin
PluginDesc::const_ptr probePlugin(int id) const override;
// create a new plugin instance
IPlugin::ptr create(const std::string& name, bool editor) const override;
private:
void doLoad();
std::unique_ptr<VST2Plugin> doCreate(PluginDesc::const_ptr desc, bool editor) const;
// Although calling convention specifiers like __cdecl and __stdcall
// should be meaningless on x86-64 platforms, Wine apparantely treats
// them as a hint that a function (pointer) uses the Microsoft x64 calling
// convention instead of System V! I couldn't find any documentation
// to confirm this, but it seems to work in practice. Otherwise,
// calling the entry point would crash immediately with stack corruption.
using EntryPoint = AEffect *(VSTCALLBACK *)(audioMasterCallback);
EntryPoint entry_;
};
//-----------------------------------------------------------------------------
class VST2Plugin final : public IPlugin {
friend class VST2Factory;
public:
static VstIntPtr VSTCALLBACK hostCallback(AEffect *plugin, VstInt32 opcode,
VstInt32 index, VstIntPtr value, void *p, float opt);
VST2Plugin(AEffect* plugin, IFactory::const_ptr f, PluginDesc::const_ptr desc, bool editor);
~VST2Plugin();
const PluginDesc& info() const override { return *info_; }
PluginDesc::const_ptr getInfo() const { return info_; }
int canDo(const char *what) const override;
intptr_t vendorSpecific(int index, intptr_t value, void *p, float opt) override;
void setupProcessing(double sampleRate, int maxBlockSize,
ProcessPrecision precision, ProcessMode mode) override;
void process(ProcessData& data) override;
void suspend() override;
void resume() override;
void setBypass(Bypass state) override;
void setNumSpeakers(int *input, int numInputs,
int *output, int numOutputs) override;
int getLatencySamples() override;
void setListener(IPluginListener* listener) override {
listener_ = listener;
}
void setTempoBPM(double tempo) override;
void setTimeSignature(int numerator, int denominator) override;
void setTransportPlaying(bool play) override;
void setTransportRecording(bool record) override;
void setTransportAutomationWriting(bool writing) override;
void setTransportAutomationReading(bool reading) override;
void setTransportCycleActive(bool active) override;
void setTransportCycleStart(double beat) override;
void setTransportCycleEnd(double beat) override;
void setTransportPosition(double beat) override;
double getTransportPosition() const override {
return timeInfo_.ppqPos;
}
void sendMidiEvent(const MidiEvent& event) override;
void sendSysexEvent(const SysexEvent& event) override;
void setParameter(int index, float value, int sampleOffset = 0) override;
bool setParameter(int index, std::string_view str, int sampleOffset = 0) override;
float getParameter(int index) const override;
size_t getParameterString(int index, ParamStringBuffer& buffer) const override;
void setProgram(int program) override;
void setProgramName(std::string_view name) override;
int getProgram() const override;
std::string getProgramName() const override;
std::string getProgramNameIndexed(int index) const override;
void readProgramFile(const std::string& path) override;
void readProgramData(const char *data, size_t size) override;
void writeProgramFile(const std::string& path) override;
void writeProgramData(std::string& buffer) override;
void readBankFile(const std::string& path) override;
void readBankData(const char *data, size_t size) override;
void writeBankFile(const std::string& path) override;
void writeBankData(std::string& buffer) override;
void openEditor(void *window) override;
void closeEditor() override;
bool getEditorRect(Rect& rect) const override;
void updateEditor() override;
void checkEditorSize(int &width, int &height) const override;
void resizeEditor(int width, int height) override;
IWindow *getWindow() const override {
return window_.get();
}
private:
std::string getPluginName() const;
std::string getPluginVendor() const;
std::string getPluginCategory() const;
std::string getPluginVersion() const;
std::string getSDKVersion() const;
std::string getParameterName(int index) const;
std::string getParameterLabel(int index) const;
int getNumInputs() const;
int getNumOutputs() const;
int getNumParameters() const;
int getNumPrograms() const;
bool hasEditor() const;
bool hasPrecision(ProcessPrecision precision) const;
bool isSynth() const;
bool hasTail() const;
int getTailSize() const;
bool hasBypass() const;
int getNumMidiInputChannels() const;
int getNumMidiOutputChannels() const;
bool hasMidiInput() const;
bool hasMidiOutput() const;
// other helpers
static bool canHostDo(const char *what);
bool hasFlag(VstAEffectFlags flag) const;
void checkLatency();
VstTimeInfo * getTimeInfo(VstInt32 flags);
bool hasChunkData() const;
void setProgramChunkData(const void *data, size_t size);
void getProgramChunkData(void **data, size_t *size) const;
void setBankChunkData(const void *data, size_t size);
void getBankChunkData(void **data, size_t *size) const;
// processing
void preProcess(int nsamples);
template<typename T, typename TProc>
void doProcess(ProcessData& data, TProc processRoutine);
template<typename T, typename TProc>
void bypassProcess(ProcessData& data, TProc processRoutine,
Bypass state, bool ramp);
void postProcess(int nsample);
// process VST events from plugin
void processEvents(VstEvents *events);
// dispatch to plugin
VstIntPtr dispatch(VstInt32 opCode, VstInt32 index = 0, VstIntPtr value = 0,
void *p = 0, float opt = 0) const;
// data members
VstIntPtr callback(VstInt32 opcode, VstInt32 index,
VstIntPtr value, void *ptr, float opt);
IFactory::const_ptr factory_; // keep alive
PluginDesc::const_ptr info_;
AEffect *plugin_ = nullptr;
// processing
int latency_ = 0;
ProcessMode mode_ = ProcessMode::Realtime;
VstTimeInfo timeInfo_;
Bypass bypass_ = Bypass::Off;
Bypass lastBypass_ = Bypass::Off;
bool haveBypass_ = false;
bool bypassSilent_ = false; // check if we can stop processing
// buffers for incoming MIDI and SysEx events
std::vector<VstMidiEvent> midiQueue_;
std::vector<VstMidiSysexEvent> sysexQueue_;
VstEvents *vstEvents_; // VstEvents is basically an array of VstEvent pointers
int vstEventBufferSize_ = 0;
bool editor_ = false;
// UI
IWindow::ptr window_;
IPluginListener* listener_ = nullptr;
};
} // vst
|