|
|
@@ -25,50 +25,72 @@ |
|
|
|
# include "../extra/RingBuffer.hpp" |
|
|
|
#endif |
|
|
|
|
|
|
|
#ifndef __cdecl |
|
|
|
# define __cdecl |
|
|
|
#endif |
|
|
|
|
|
|
|
#ifndef VESTIGE_HEADER |
|
|
|
# define VESTIGE_HEADER 1 |
|
|
|
#endif |
|
|
|
#define VST_FORCE_DEPRECATED 0 |
|
|
|
|
|
|
|
#include <clocale> |
|
|
|
#include <map> |
|
|
|
#include <string> |
|
|
|
#include <vector> |
|
|
|
|
|
|
|
#if VESTIGE_HEADER |
|
|
|
# include "vestige/vestige.h" |
|
|
|
#define effFlagsProgramChunks (1 << 5) |
|
|
|
#define effSetProgramName 4 |
|
|
|
#define effGetParamLabel 6 |
|
|
|
#define effGetParamDisplay 7 |
|
|
|
#define effGetChunk 23 |
|
|
|
#define effSetChunk 24 |
|
|
|
#define effCanBeAutomated 26 |
|
|
|
#define effGetProgramNameIndexed 29 |
|
|
|
#define effGetPlugCategory 35 |
|
|
|
#define effVendorSpecific 50 |
|
|
|
#define effEditKeyDown 59 |
|
|
|
#define effEditKeyUp 60 |
|
|
|
#define kVstVersion 2400 |
|
|
|
struct ERect { |
|
|
|
int16_t top, left, bottom, right; |
|
|
|
}; |
|
|
|
#else |
|
|
|
# include "vst/aeffectx.h" |
|
|
|
#ifndef __stdcall |
|
|
|
# define __stdcall |
|
|
|
#endif |
|
|
|
|
|
|
|
#include "xaymar-vst2/vst.h" |
|
|
|
|
|
|
|
extern "C" { |
|
|
|
|
|
|
|
// define the midi stuff ourselves |
|
|
|
typedef struct _VstMidiEvent { |
|
|
|
int32_t type; |
|
|
|
int32_t byteSize; |
|
|
|
int32_t deltaFrames; |
|
|
|
int32_t _ignore1[3]; |
|
|
|
char midiData[4]; |
|
|
|
char _ignore2[4]; |
|
|
|
} VstMidiEvent; |
|
|
|
|
|
|
|
typedef union _VstEvent { |
|
|
|
int32_t type; |
|
|
|
VstMidiEvent midi; // type 1 |
|
|
|
} VstEvent; |
|
|
|
|
|
|
|
typedef struct _HostVstEvents { |
|
|
|
int numEvents; |
|
|
|
void* reserved; |
|
|
|
const VstEvent* events[]; |
|
|
|
} HostVstEvents; |
|
|
|
|
|
|
|
typedef struct _PluginVstEvents { |
|
|
|
int numEvents; |
|
|
|
void* reserved; |
|
|
|
VstEvent* events[1]; |
|
|
|
} PluginVstEvents; |
|
|
|
|
|
|
|
// info from online documentation of VST provided by Steinberg |
|
|
|
typedef struct _VstTimeInfo { |
|
|
|
double samplePos; |
|
|
|
double sampleRate; |
|
|
|
double nanoSeconds; |
|
|
|
double ppqPos; |
|
|
|
double tempo; |
|
|
|
double barStartPos; |
|
|
|
double cycleStartPos; |
|
|
|
double cycleEndPos; |
|
|
|
int32_t timeSigNumerator; |
|
|
|
int32_t timeSigDenominator; |
|
|
|
int32_t smpteOffset; |
|
|
|
int32_t smpteFrameRate; |
|
|
|
int32_t samplesToNextClock; |
|
|
|
int32_t flags; |
|
|
|
} VstTimeInfo; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
START_NAMESPACE_DISTRHO |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
typedef std::map<const String, String> StringMap; |
|
|
|
|
|
|
|
static constexpr const int kVstMidiEventSize = static_cast<int>(sizeof(VstMidiEvent)); |
|
|
|
|
|
|
|
#if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT |
|
|
|
static const writeMidiFunc writeMidiCallback = nullptr; |
|
|
|
#endif |
|
|
@@ -136,8 +158,8 @@ static const setStateFunc setStateCallback = nullptr; |
|
|
|
class UIVst |
|
|
|
{ |
|
|
|
public: |
|
|
|
UIVst(const audioMasterCallback audioMaster, |
|
|
|
AEffect* const effect, |
|
|
|
UIVst(const vst_host_callback audioMaster, |
|
|
|
vst_effect* const effect, |
|
|
|
ParameterAndNotesHelper* const uiHelper, |
|
|
|
PluginExporter* const plugin, |
|
|
|
const intptr_t winId, const float scaleFactor) |
|
|
@@ -259,7 +281,7 @@ public: |
|
|
|
// ------------------------------------------------------------------- |
|
|
|
|
|
|
|
protected: |
|
|
|
inline intptr_t hostCallback(const int32_t opcode, |
|
|
|
inline intptr_t hostCallback(const VST_HOST_OPCODE opcode, |
|
|
|
const int32_t index = 0, |
|
|
|
const intptr_t value = 0, |
|
|
|
void* const ptr = nullptr, |
|
|
@@ -270,7 +292,7 @@ protected: |
|
|
|
|
|
|
|
void editParameter(const uint32_t index, const bool started) const |
|
|
|
{ |
|
|
|
hostCallback(started ? audioMasterBeginEdit : audioMasterEndEdit, index); |
|
|
|
hostCallback(started ? VST_HOST_OPCODE_2B : VST_HOST_OPCODE_2C, index); |
|
|
|
} |
|
|
|
|
|
|
|
void setParameterValue(const uint32_t index, const float realValue) |
|
|
@@ -279,7 +301,7 @@ protected: |
|
|
|
const float perValue(ranges.getNormalizedValue(realValue)); |
|
|
|
|
|
|
|
fPlugin->setParameterValue(index, realValue); |
|
|
|
hostCallback(audioMasterAutomate, index, 0, nullptr, perValue); |
|
|
|
hostCallback(VST_HOST_OPCODE_00, index, 0, nullptr, perValue); |
|
|
|
} |
|
|
|
|
|
|
|
void setSize(uint width, uint height) |
|
|
@@ -289,7 +311,7 @@ protected: |
|
|
|
width /= scaleFactor; |
|
|
|
height /= scaleFactor; |
|
|
|
# endif |
|
|
|
hostCallback(audioMasterSizeWindow, width, height); |
|
|
|
hostCallback(VST_HOST_OPCODE_0F, width, height); |
|
|
|
} |
|
|
|
|
|
|
|
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT |
|
|
@@ -313,8 +335,8 @@ protected: |
|
|
|
|
|
|
|
private: |
|
|
|
// Vst stuff |
|
|
|
const audioMasterCallback fAudioMaster; |
|
|
|
AEffect* const fEffect; |
|
|
|
const vst_host_callback fAudioMaster; |
|
|
|
vst_effect* const fEffect; |
|
|
|
ParameterAndNotesHelper* const fUiHelper; |
|
|
|
PluginExporter* const fPlugin; |
|
|
|
|
|
|
@@ -370,7 +392,7 @@ private: |
|
|
|
class PluginVst : public ParameterAndNotesHelper |
|
|
|
{ |
|
|
|
public: |
|
|
|
PluginVst(const audioMasterCallback audioMaster, AEffect* const effect) |
|
|
|
PluginVst(const vst_host_callback audioMaster, vst_effect* const effect) |
|
|
|
: fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback, nullptr), |
|
|
|
fAudioMaster(audioMaster), |
|
|
|
fEffect(effect) |
|
|
@@ -454,10 +476,10 @@ public: |
|
|
|
|
|
|
|
switch (opcode) |
|
|
|
{ |
|
|
|
case effGetProgram: |
|
|
|
case VST_EFFECT_OPCODE_03: // get program |
|
|
|
return 0; |
|
|
|
|
|
|
|
case effSetProgramName: |
|
|
|
case VST_EFFECT_OPCODE_04: // set program name |
|
|
|
if (char* const programName = (char*)ptr) |
|
|
|
{ |
|
|
|
strncpy(fProgramName, programName, 32); |
|
|
@@ -465,7 +487,7 @@ public: |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case effGetProgramName: |
|
|
|
case VST_EFFECT_OPCODE_05: // get program name |
|
|
|
if (char* const programName = (char*)ptr) |
|
|
|
{ |
|
|
|
strncpy(programName, fProgramName, 24); |
|
|
@@ -473,7 +495,7 @@ public: |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case effGetProgramNameIndexed: |
|
|
|
case VST_EFFECT_OPCODE_1D: // get program name indexed |
|
|
|
if (char* const programName = (char*)ptr) |
|
|
|
{ |
|
|
|
strncpy(programName, fProgramName, 24); |
|
|
@@ -481,7 +503,7 @@ public: |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case effGetParamDisplay: |
|
|
|
case VST_EFFECT_OPCODE_PARAM_GETVALUE: |
|
|
|
if (ptr != nullptr && index < static_cast<int32_t>(fPlugin.getParameterCount())) |
|
|
|
{ |
|
|
|
const uint32_t hints = fPlugin.getParameterHints(index); |
|
|
@@ -519,7 +541,7 @@ public: |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case effSetSampleRate: |
|
|
|
case VST_EFFECT_OPCODE_SET_SAMPLE_RATE: |
|
|
|
fPlugin.setSampleRate(opt, true); |
|
|
|
|
|
|
|
#if DISTRHO_PLUGIN_HAS_UI |
|
|
@@ -528,26 +550,26 @@ public: |
|
|
|
#endif |
|
|
|
break; |
|
|
|
|
|
|
|
case effSetBlockSize: |
|
|
|
case VST_EFFECT_OPCODE_SET_BLOCK_SIZE: |
|
|
|
fPlugin.setBufferSize(value, true); |
|
|
|
break; |
|
|
|
|
|
|
|
case effMainsChanged: |
|
|
|
case VST_EFFECT_OPCODE_SUSPEND: |
|
|
|
if (value != 0) |
|
|
|
{ |
|
|
|
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT |
|
|
|
fMidiEventCount = 0; |
|
|
|
|
|
|
|
// tell host we want MIDI events |
|
|
|
hostCallback(audioMasterWantMidi); |
|
|
|
hostCallback(VST_HOST_OPCODE_06); |
|
|
|
#endif |
|
|
|
|
|
|
|
// deactivate for possible changes |
|
|
|
fPlugin.deactivateIfNeeded(); |
|
|
|
|
|
|
|
// check if something changed |
|
|
|
const uint32_t bufferSize = static_cast<uint32_t>(hostCallback(audioMasterGetBlockSize)); |
|
|
|
const double sampleRate = static_cast<double>(hostCallback(audioMasterGetSampleRate)); |
|
|
|
const uint32_t bufferSize = static_cast<uint32_t>(hostCallback(VST_HOST_OPCODE_11)); |
|
|
|
const double sampleRate = static_cast<double>(hostCallback(VST_HOST_OPCODE_10)); |
|
|
|
|
|
|
|
if (bufferSize != 0) |
|
|
|
fPlugin.setBufferSize(bufferSize, true); |
|
|
@@ -564,7 +586,7 @@ public: |
|
|
|
break; |
|
|
|
|
|
|
|
#if DISTRHO_PLUGIN_HAS_UI |
|
|
|
case effEditGetRect: |
|
|
|
case VST_EFFECT_OPCODE_WINDOW_GETRECT: |
|
|
|
if (fVstUI != nullptr) |
|
|
|
{ |
|
|
|
fVstRect.right = fVstUI->getWidth(); |
|
|
@@ -597,12 +619,13 @@ public: |
|
|
|
fVstRect.bottom /= scaleFactor; |
|
|
|
#endif |
|
|
|
} |
|
|
|
*(ERect**)ptr = &fVstRect; |
|
|
|
*(vst_rect**)ptr = &fVstRect; |
|
|
|
return 1; |
|
|
|
|
|
|
|
case effEditOpen: |
|
|
|
delete fVstUI; // hosts which don't pair effEditOpen/effEditClose calls (Minihost Modular) |
|
|
|
case VST_EFFECT_OPCODE_WINDOW_CREATE: |
|
|
|
delete fVstUI; // for hosts which don't pair create/destroy calls (Minihost Modular) |
|
|
|
fVstUI = nullptr; |
|
|
|
|
|
|
|
{ |
|
|
|
# if DISTRHO_OS_MAC |
|
|
|
if (! fUsingNsView) |
|
|
@@ -643,7 +666,7 @@ public: |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case effEditClose: |
|
|
|
case VST_EFFECT_OPCODE_WINDOW_DESTROY: |
|
|
|
if (fVstUI != nullptr) |
|
|
|
{ |
|
|
|
delete fVstUI; |
|
|
@@ -652,18 +675,18 @@ public: |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case effEditIdle: |
|
|
|
case VST_EFFECT_OPCODE_13: // window idle |
|
|
|
if (fVstUI != nullptr) |
|
|
|
fVstUI->idle(); |
|
|
|
break; |
|
|
|
|
|
|
|
# if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI |
|
|
|
case effEditKeyDown: |
|
|
|
case VST_EFFECT_OPCODE_3B: // key down |
|
|
|
if (fVstUI != nullptr) |
|
|
|
return fVstUI->handlePluginKeyEvent(true, index, value); |
|
|
|
break; |
|
|
|
|
|
|
|
case effEditKeyUp: |
|
|
|
case VST_EFFECT_OPCODE_3C: // key up |
|
|
|
if (fVstUI != nullptr) |
|
|
|
return fVstUI->handlePluginKeyEvent(false, index, value); |
|
|
|
break; |
|
|
@@ -671,7 +694,7 @@ public: |
|
|
|
#endif // DISTRHO_PLUGIN_HAS_UI |
|
|
|
|
|
|
|
#if DISTRHO_PLUGIN_WANT_STATE |
|
|
|
case effGetChunk: |
|
|
|
case VST_EFFECT_OPCODE_17: // get chunk |
|
|
|
{ |
|
|
|
if (ptr == nullptr) |
|
|
|
return 0; |
|
|
@@ -758,7 +781,7 @@ public: |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
case effSetChunk: |
|
|
|
case VST_EFFECT_OPCODE_18: // set chunk |
|
|
|
{ |
|
|
|
if (value <= 1 || ptr == nullptr) |
|
|
|
return 0; |
|
|
@@ -842,39 +865,41 @@ public: |
|
|
|
#endif // DISTRHO_PLUGIN_WANT_STATE |
|
|
|
|
|
|
|
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT |
|
|
|
case effProcessEvents: |
|
|
|
case VST_EFFECT_OPCODE_19: // process events |
|
|
|
if (! fPlugin.isActive()) |
|
|
|
{ |
|
|
|
// host has not activated the plugin yet, nasty! |
|
|
|
vst_dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f); |
|
|
|
vst_dispatcher(VST_EFFECT_OPCODE_SUSPEND, 0, 1, nullptr, 0.0f); |
|
|
|
} |
|
|
|
|
|
|
|
if (const VstEvents* const events = (const VstEvents*)ptr) |
|
|
|
if (const HostVstEvents* const events = (const HostVstEvents*)ptr) |
|
|
|
{ |
|
|
|
if (events->numEvents == 0) |
|
|
|
break; |
|
|
|
|
|
|
|
for (int i=0, count=events->numEvents; i < count; ++i) |
|
|
|
{ |
|
|
|
const VstMidiEvent* const vstMidiEvent((const VstMidiEvent*)events->events[i]); |
|
|
|
const VstEvent* const vstEvent = events->events[i]; |
|
|
|
|
|
|
|
if (vstMidiEvent == nullptr) |
|
|
|
if (vstEvent == nullptr) |
|
|
|
break; |
|
|
|
if (vstMidiEvent->type != kVstMidiType) |
|
|
|
if (vstEvent->type != 1) |
|
|
|
continue; |
|
|
|
if (fMidiEventCount >= kMaxMidiEvents) |
|
|
|
break; |
|
|
|
|
|
|
|
const VstMidiEvent& vstMidiEvent(events->events[i]->midi); |
|
|
|
|
|
|
|
MidiEvent& midiEvent(fMidiEvents[fMidiEventCount++]); |
|
|
|
midiEvent.frame = vstMidiEvent->deltaFrames; |
|
|
|
midiEvent.frame = vstMidiEvent.deltaFrames; |
|
|
|
midiEvent.size = 3; |
|
|
|
std::memcpy(midiEvent.data, vstMidiEvent->midiData, sizeof(uint8_t)*3); |
|
|
|
std::memcpy(midiEvent.data, vstMidiEvent.midiData, sizeof(uint8_t)*3); |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
#endif |
|
|
|
|
|
|
|
case effCanBeAutomated: |
|
|
|
case VST_EFFECT_OPCODE_PARAM_ISAUTOMATABLE: |
|
|
|
if (index < static_cast<int32_t>(fPlugin.getParameterCount())) |
|
|
|
{ |
|
|
|
const uint32_t hints(fPlugin.getParameterHints(index)); |
|
|
@@ -885,7 +910,7 @@ public: |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case effCanDo: |
|
|
|
case VST_EFFECT_OPCODE_SUPPORTS: |
|
|
|
if (const char* const canDo = (const char*)ptr) |
|
|
|
{ |
|
|
|
#if DISTRHO_OS_MAC && DISTRHO_PLUGIN_HAS_UI |
|
|
@@ -924,9 +949,9 @@ public: |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case effVendorSpecific: |
|
|
|
case VST_EFFECT_OPCODE_CUSTOM: |
|
|
|
#if DISTRHO_PLUGIN_HAS_UI && !defined(DISTRHO_OS_MAC) |
|
|
|
if (index == CCONST('P', 'r', 'e', 'S') && value == CCONST('A', 'e', 'C', 's')) |
|
|
|
if (index == d_cconst('P', 'r', 'e', 'S') && value == d_cconst('A', 'e', 'C', 's')) |
|
|
|
{ |
|
|
|
if (d_isEqual(fLastScaleFactor, opt)) |
|
|
|
break; |
|
|
@@ -948,13 +973,13 @@ public: |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
float vst_getParameter(const int32_t index) |
|
|
|
float vst_getParameter(const uint32_t index) |
|
|
|
{ |
|
|
|
const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); |
|
|
|
return ranges.getNormalizedValue(fPlugin.getParameterValue(index)); |
|
|
|
} |
|
|
|
|
|
|
|
void vst_setParameter(const int32_t index, const float value) |
|
|
|
void vst_setParameter(const uint32_t index, const float value) |
|
|
|
{ |
|
|
|
const uint32_t hints = fPlugin.getParameterHints(index); |
|
|
|
const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); |
|
|
@@ -986,7 +1011,7 @@ public: |
|
|
|
if (! fPlugin.isActive()) |
|
|
|
{ |
|
|
|
// host has not activated the plugin yet, nasty! |
|
|
|
vst_dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f); |
|
|
|
vst_dispatcher(VST_EFFECT_OPCODE_SUSPEND, 0, 1, nullptr, 0.0f); |
|
|
|
} |
|
|
|
|
|
|
|
if (sampleFrames <= 0) |
|
|
@@ -996,22 +1021,22 @@ public: |
|
|
|
} |
|
|
|
|
|
|
|
#if DISTRHO_PLUGIN_WANT_TIMEPOS |
|
|
|
static const int kWantVstTimeFlags(kVstTransportPlaying|kVstPpqPosValid|kVstTempoValid|kVstTimeSigValid); |
|
|
|
static constexpr const int kWantVstTimeFlags = 0x2602; |
|
|
|
|
|
|
|
if (const VstTimeInfo* const vstTimeInfo = (const VstTimeInfo*)hostCallback(audioMasterGetTime, 0, kWantVstTimeFlags)) |
|
|
|
if (const VstTimeInfo* const vstTimeInfo = (const VstTimeInfo*)hostCallback(VST_HOST_OPCODE_07, 0, kWantVstTimeFlags)) |
|
|
|
{ |
|
|
|
fTimePosition.frame = vstTimeInfo->samplePos; |
|
|
|
fTimePosition.playing = vstTimeInfo->flags & kVstTransportPlaying; |
|
|
|
fTimePosition.playing = vstTimeInfo->flags & 0x2; |
|
|
|
|
|
|
|
// ticksPerBeat is not possible with VST2 |
|
|
|
fTimePosition.bbt.ticksPerBeat = 1920.0; |
|
|
|
|
|
|
|
if (vstTimeInfo->flags & kVstTempoValid) |
|
|
|
if (vstTimeInfo->flags & 0x400) |
|
|
|
fTimePosition.bbt.beatsPerMinute = vstTimeInfo->tempo; |
|
|
|
else |
|
|
|
fTimePosition.bbt.beatsPerMinute = 120.0; |
|
|
|
|
|
|
|
if ((vstTimeInfo->flags & (kVstPpqPosValid|kVstTimeSigValid)) == (kVstPpqPosValid|kVstTimeSigValid)) |
|
|
|
if ((vstTimeInfo->flags & 0x2200) == 0x2200) |
|
|
|
{ |
|
|
|
const double ppqPos = std::abs(vstTimeInfo->ppqPos); |
|
|
|
const int ppqPerBar = vstTimeInfo->timeSigNumerator * 4 / vstTimeInfo->timeSigDenominator; |
|
|
@@ -1091,8 +1116,8 @@ private: |
|
|
|
PluginExporter fPlugin; |
|
|
|
|
|
|
|
// VST stuff |
|
|
|
const audioMasterCallback fAudioMaster; |
|
|
|
AEffect* const fEffect; |
|
|
|
const vst_host_callback fAudioMaster; |
|
|
|
vst_effect* const fEffect; |
|
|
|
|
|
|
|
// Temporary data |
|
|
|
char fProgramName[32]; |
|
|
@@ -1108,9 +1133,9 @@ private: |
|
|
|
|
|
|
|
// UI stuff |
|
|
|
#if DISTRHO_PLUGIN_HAS_UI |
|
|
|
UIVst* fVstUI; |
|
|
|
ERect fVstRect; |
|
|
|
float fLastScaleFactor; |
|
|
|
UIVst* fVstUI; |
|
|
|
vst_rect fVstRect; |
|
|
|
float fLastScaleFactor; |
|
|
|
# if DISTRHO_OS_MAC |
|
|
|
bool fUsingNsView; |
|
|
|
# endif |
|
|
@@ -1127,7 +1152,7 @@ private: |
|
|
|
// ------------------------------------------------------------------- |
|
|
|
// host callback |
|
|
|
|
|
|
|
intptr_t hostCallback(const int32_t opcode, |
|
|
|
intptr_t hostCallback(const VST_HOST_OPCODE opcode, |
|
|
|
const int32_t index = 0, |
|
|
|
const intptr_t value = 0, |
|
|
|
void* const ptr = nullptr, |
|
|
@@ -1185,7 +1210,7 @@ private: |
|
|
|
} |
|
|
|
|
|
|
|
const ParameterRanges& ranges(fPlugin.getParameterRanges(i)); |
|
|
|
hostCallback(audioMasterAutomate, i, 0, nullptr, ranges.getNormalizedValue(curValue)); |
|
|
|
hostCallback(VST_HOST_OPCODE_00, i, 0, nullptr, ranges.getNormalizedValue(curValue)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -1200,7 +1225,7 @@ private: |
|
|
|
#if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST |
|
|
|
bool requestParameterValueChange(const uint32_t index, const float value) |
|
|
|
{ |
|
|
|
hostCallback(audioMasterAutomate, index, 0, nullptr, value); |
|
|
|
hostCallback(VST_HOST_OPCODE_00, index, 0, nullptr, value); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
@@ -1216,23 +1241,20 @@ private: |
|
|
|
if (midiEvent.size > 4) |
|
|
|
return true; |
|
|
|
|
|
|
|
VstEvents vstEvents; |
|
|
|
std::memset(&vstEvents, 0, sizeof(VstEvents)); |
|
|
|
|
|
|
|
VstMidiEvent vstMidiEvent; |
|
|
|
std::memset(&vstMidiEvent, 0, sizeof(VstMidiEvent)); |
|
|
|
PluginVstEvents vstEvents = {}; |
|
|
|
VstMidiEvent vstMidiEvent = {}; |
|
|
|
|
|
|
|
vstEvents.numEvents = 1; |
|
|
|
vstEvents.events[0] = (VstEvent*)&vstMidiEvent; |
|
|
|
|
|
|
|
vstMidiEvent.type = kVstMidiType; |
|
|
|
vstMidiEvent.byteSize = kVstMidiEventSize; |
|
|
|
vstMidiEvent.type = 1; |
|
|
|
vstMidiEvent.byteSize = static_cast<int32_t>(sizeof(VstMidiEvent));; |
|
|
|
vstMidiEvent.deltaFrames = midiEvent.frame; |
|
|
|
|
|
|
|
for (uint8_t i=0; i<midiEvent.size; ++i) |
|
|
|
vstMidiEvent.midiData[i] = midiEvent.data[i]; |
|
|
|
|
|
|
|
return hostCallback(audioMasterProcessEvents, 0, 0, &vstEvents) == 1; |
|
|
|
return hostCallback(VST_HOST_OPCODE_08, 0, 0, &vstEvents) == 1; |
|
|
|
} |
|
|
|
|
|
|
|
static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent) |
|
|
@@ -1276,10 +1298,10 @@ private: |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
struct ExtendedAEffect : AEffect { |
|
|
|
struct ExtendedAEffect : vst_effect { |
|
|
|
char _padding[63]; |
|
|
|
char valid; |
|
|
|
audioMasterCallback audioMaster; |
|
|
|
vst_host_callback audioMaster; |
|
|
|
PluginVst* pluginPtr; |
|
|
|
}; |
|
|
|
|
|
|
@@ -1304,7 +1326,7 @@ static struct Cleanup { |
|
|
|
// -------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
static inline |
|
|
|
ExtendedAEffect* getExtendedEffect(AEffect* const effect) |
|
|
|
ExtendedAEffect* getExtendedEffect(vst_effect* const effect) |
|
|
|
{ |
|
|
|
if (effect == nullptr) |
|
|
|
return nullptr; |
|
|
@@ -1317,7 +1339,7 @@ ExtendedAEffect* getExtendedEffect(AEffect* const effect) |
|
|
|
} |
|
|
|
|
|
|
|
static inline |
|
|
|
PluginVst* getEffectPlugin(AEffect* const effect) |
|
|
|
PluginVst* getEffectPlugin(vst_effect* const effect) |
|
|
|
{ |
|
|
|
if (effect == nullptr) |
|
|
|
return nullptr; |
|
|
@@ -1331,22 +1353,22 @@ PluginVst* getEffectPlugin(AEffect* const effect) |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
static intptr_t vst_dispatcherCallback(AEffect* const effect, const int32_t opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt) |
|
|
|
static intptr_t vst_dispatcherCallback(vst_effect* const effect, const VST_EFFECT_OPCODE opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt) |
|
|
|
{ |
|
|
|
// handle base opcodes |
|
|
|
switch (opcode) |
|
|
|
{ |
|
|
|
case effOpen: |
|
|
|
case VST_EFFECT_OPCODE_CREATE: |
|
|
|
if (ExtendedAEffect* const exteffect = getExtendedEffect(effect)) |
|
|
|
{ |
|
|
|
// some hosts call effOpen twice |
|
|
|
// some hosts call open/create twice |
|
|
|
if (exteffect->pluginPtr != nullptr) |
|
|
|
return 1; |
|
|
|
|
|
|
|
const audioMasterCallback audioMaster = exteffect->audioMaster; |
|
|
|
const vst_host_callback audioMaster = exteffect->audioMaster; |
|
|
|
|
|
|
|
d_nextBufferSize = audioMaster(effect, audioMasterGetBlockSize, 0, 0, nullptr, 0.0f); |
|
|
|
d_nextSampleRate = audioMaster(effect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f); |
|
|
|
d_nextBufferSize = audioMaster(effect, VST_HOST_OPCODE_11, 0, 0, nullptr, 0.0f); |
|
|
|
d_nextSampleRate = audioMaster(effect, VST_HOST_OPCODE_10, 0, 0, nullptr, 0.0f); |
|
|
|
d_nextCanRequestParameterValueChanges = true; |
|
|
|
|
|
|
|
// some hosts are not ready at this point or return 0 buffersize/samplerate |
|
|
@@ -1360,7 +1382,7 @@ static intptr_t vst_dispatcherCallback(AEffect* const effect, const int32_t opco |
|
|
|
} |
|
|
|
return 0; |
|
|
|
|
|
|
|
case effClose: |
|
|
|
case VST_EFFECT_OPCODE_DESTROY: |
|
|
|
if (ExtendedAEffect* const exteffect = getExtendedEffect(effect)) |
|
|
|
{ |
|
|
|
// delete plugin object |
|
|
@@ -1385,7 +1407,7 @@ static intptr_t vst_dispatcherCallback(AEffect* const effect, const int32_t opco |
|
|
|
} |
|
|
|
return 0; |
|
|
|
|
|
|
|
case effGetParamLabel: |
|
|
|
case VST_EFFECT_OPCODE_PARAM_GETLABEL: |
|
|
|
if (ptr != nullptr && index < static_cast<int32_t>(sPlugin->getParameterCount())) |
|
|
|
{ |
|
|
|
strncpy((char*)ptr, sPlugin->getParameterUnit(index), 8); |
|
|
@@ -1393,7 +1415,7 @@ static intptr_t vst_dispatcherCallback(AEffect* const effect, const int32_t opco |
|
|
|
} |
|
|
|
return 0; |
|
|
|
|
|
|
|
case effGetParamName: |
|
|
|
case VST_EFFECT_OPCODE_PARAM_GETNAME: |
|
|
|
if (ptr != nullptr && index < static_cast<int32_t>(sPlugin->getParameterCount())) |
|
|
|
{ |
|
|
|
const String& shortName(sPlugin->getParameterShortName(index)); |
|
|
@@ -1405,25 +1427,25 @@ static intptr_t vst_dispatcherCallback(AEffect* const effect, const int32_t opco |
|
|
|
} |
|
|
|
return 0; |
|
|
|
|
|
|
|
case effGetParameterProperties: |
|
|
|
case VST_EFFECT_OPCODE_38: // FIXME VST_EFFECT_OPCODE_GET_PARAMETER_PROPERTIES is wrong by 1 |
|
|
|
if (ptr != nullptr && index < static_cast<int32_t>(sPlugin->getParameterCount())) |
|
|
|
{ |
|
|
|
if (VstParameterProperties* const properties = (VstParameterProperties*)ptr) |
|
|
|
if (vst_parameter_properties* const properties = (vst_parameter_properties*)ptr) |
|
|
|
{ |
|
|
|
memset(properties, 0, sizeof(VstParameterProperties)); |
|
|
|
memset(properties, 0, sizeof(vst_parameter_properties)); |
|
|
|
|
|
|
|
// full name |
|
|
|
strncpy(properties->label, |
|
|
|
strncpy(properties->name, |
|
|
|
sPlugin->getParameterName(index), |
|
|
|
sizeof(properties->label)); |
|
|
|
sizeof(properties->name)); |
|
|
|
|
|
|
|
// short name |
|
|
|
const String& shortName(sPlugin->getParameterShortName(index)); |
|
|
|
|
|
|
|
if (shortName.isNotEmpty()) |
|
|
|
strncpy(properties->shortLabel, |
|
|
|
strncpy(properties->label, |
|
|
|
sPlugin->getParameterShortName(index), |
|
|
|
sizeof(properties->shortLabel)); |
|
|
|
sizeof(properties->label)); |
|
|
|
|
|
|
|
// parameter hints |
|
|
|
const uint32_t hints = sPlugin->getParameterHints(index); |
|
|
@@ -1433,20 +1455,20 @@ static intptr_t vst_dispatcherCallback(AEffect* const effect, const int32_t opco |
|
|
|
|
|
|
|
if (hints & kParameterIsBoolean) |
|
|
|
{ |
|
|
|
properties->flags |= kVstParameterIsSwitch; |
|
|
|
properties->flags |= VST_PARAMETER_FLAGS_SWITCH; |
|
|
|
} |
|
|
|
|
|
|
|
if (hints & kParameterIsInteger) |
|
|
|
{ |
|
|
|
const ParameterRanges& ranges(sPlugin->getParameterRanges(index)); |
|
|
|
properties->flags |= kVstParameterUsesIntegerMinMax; |
|
|
|
properties->minInteger = static_cast<int32_t>(ranges.min); |
|
|
|
properties->maxInteger = static_cast<int32_t>(ranges.max); |
|
|
|
properties->flags |= VST_PARAMETER_FLAGS_INTEGER_LIMITS; |
|
|
|
properties->min_value_i32 = static_cast<int32_t>(ranges.min); |
|
|
|
properties->max_value_i32 = static_cast<int32_t>(ranges.max); |
|
|
|
} |
|
|
|
|
|
|
|
if (hints & kParameterIsLogarithmic) |
|
|
|
{ |
|
|
|
properties->flags |= kVstParameterCanRamp; |
|
|
|
properties->flags |= VST_PARAMETER_FLAGS_UNKNOWN6; // can ramp |
|
|
|
} |
|
|
|
|
|
|
|
// parameter group (category in vst) |
|
|
@@ -1461,10 +1483,11 @@ static intptr_t vst_dispatcherCallback(AEffect* const effect, const int32_t opco |
|
|
|
|
|
|
|
if (portGroup.groupId == groupId) |
|
|
|
{ |
|
|
|
properties->flags |= VST_PARAMETER_FLAGS_CATEGORY; |
|
|
|
properties->category = i + 1; |
|
|
|
strncpy(properties->categoryLabel, |
|
|
|
strncpy(properties->category_label, |
|
|
|
portGroup.name.buffer(), |
|
|
|
sizeof(properties->categoryLabel)); |
|
|
|
sizeof(properties->category_label)); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
@@ -1473,7 +1496,7 @@ static intptr_t vst_dispatcherCallback(AEffect* const effect, const int32_t opco |
|
|
|
{ |
|
|
|
for (uint32_t i=0, count=sPlugin->getParameterCount(); i < count; ++i) |
|
|
|
if (sPlugin->getParameterGroupId(i) == groupId) |
|
|
|
++properties->numParametersInCategory; |
|
|
|
++properties->num_parameters_in_category; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -1482,14 +1505,14 @@ static intptr_t vst_dispatcherCallback(AEffect* const effect, const int32_t opco |
|
|
|
} |
|
|
|
return 0; |
|
|
|
|
|
|
|
case effGetPlugCategory: |
|
|
|
case VST_EFFECT_OPCODE_EFFECT_CATEGORY: |
|
|
|
#if DISTRHO_PLUGIN_IS_SYNTH |
|
|
|
return kPlugCategSynth; |
|
|
|
return VST_CATEGORY_02; |
|
|
|
#else |
|
|
|
return kPlugCategEffect; |
|
|
|
return VST_CATEGORY_01; |
|
|
|
#endif |
|
|
|
|
|
|
|
case effGetEffectName: |
|
|
|
case VST_EFFECT_OPCODE_EFFECT_NAME: |
|
|
|
if (char* const cptr = (char*)ptr) |
|
|
|
{ |
|
|
|
strncpy(cptr, sPlugin->getName(), 32); |
|
|
@@ -1497,7 +1520,7 @@ static intptr_t vst_dispatcherCallback(AEffect* const effect, const int32_t opco |
|
|
|
} |
|
|
|
return 0; |
|
|
|
|
|
|
|
case effGetVendorString: |
|
|
|
case VST_EFFECT_OPCODE_VENDOR_NAME: |
|
|
|
if (char* const cptr = (char*)ptr) |
|
|
|
{ |
|
|
|
strncpy(cptr, sPlugin->getMaker(), 32); |
|
|
@@ -1505,7 +1528,7 @@ static intptr_t vst_dispatcherCallback(AEffect* const effect, const int32_t opco |
|
|
|
} |
|
|
|
return 0; |
|
|
|
|
|
|
|
case effGetProductString: |
|
|
|
case VST_EFFECT_OPCODE_PRODUCT_NAME: |
|
|
|
if (char* const cptr = (char*)ptr) |
|
|
|
{ |
|
|
|
strncpy(cptr, sPlugin->getLabel(), 32); |
|
|
@@ -1513,12 +1536,15 @@ static intptr_t vst_dispatcherCallback(AEffect* const effect, const int32_t opco |
|
|
|
} |
|
|
|
return 0; |
|
|
|
|
|
|
|
case effGetVendorVersion: |
|
|
|
case VST_EFFECT_OPCODE_VENDOR_VERSION: |
|
|
|
return sPlugin->getVersion(); |
|
|
|
|
|
|
|
case effGetVstVersion: |
|
|
|
return kVstVersion; |
|
|
|
}; |
|
|
|
case VST_EFFECT_OPCODE_VST_VERSION: |
|
|
|
return VST_VERSION_2_4_0_0; |
|
|
|
|
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
// handle advanced opcodes |
|
|
|
if (PluginVst* const pluginPtr = getEffectPlugin(effect)) |
|
|
@@ -1527,26 +1553,26 @@ static intptr_t vst_dispatcherCallback(AEffect* const effect, const int32_t opco |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static float vst_getParameterCallback(AEffect* const effect, const int32_t index) |
|
|
|
static float vst_getParameterCallback(vst_effect* const effect, const uint32_t index) |
|
|
|
{ |
|
|
|
if (PluginVst* const pluginPtr = getEffectPlugin(effect)) |
|
|
|
return pluginPtr->vst_getParameter(index); |
|
|
|
return 0.0f; |
|
|
|
} |
|
|
|
|
|
|
|
static void vst_setParameterCallback(AEffect* const effect, const int32_t index, const float value) |
|
|
|
static void vst_setParameterCallback(vst_effect* const effect, const uint32_t index, const float value) |
|
|
|
{ |
|
|
|
if (PluginVst* const pluginPtr = getEffectPlugin(effect)) |
|
|
|
pluginPtr->vst_setParameter(index, value); |
|
|
|
} |
|
|
|
|
|
|
|
static void vst_processCallback(AEffect* const effect, float** const inputs, float** const outputs, const int32_t sampleFrames) |
|
|
|
static void vst_processCallback(vst_effect* const effect, const float* const* const inputs, float** const outputs, const int32_t sampleFrames) |
|
|
|
{ |
|
|
|
if (PluginVst* const pluginPtr = getEffectPlugin(effect)) |
|
|
|
pluginPtr->vst_processReplacing(const_cast<const float**>(inputs), outputs, sampleFrames); |
|
|
|
} |
|
|
|
|
|
|
|
static void vst_processReplacingCallback(AEffect* const effect, float** const inputs, float** const outputs, const int32_t sampleFrames) |
|
|
|
static void vst_processReplacingCallback(vst_effect* const effect, const float* const* const inputs, float** const outputs, const int32_t sampleFrames) |
|
|
|
{ |
|
|
|
if (PluginVst* const pluginPtr = getEffectPlugin(effect)) |
|
|
|
pluginPtr->vst_processReplacing(const_cast<const float**>(inputs), outputs, sampleFrames); |
|
|
@@ -1558,18 +1584,18 @@ END_NAMESPACE_DISTRHO |
|
|
|
|
|
|
|
DISTRHO_PLUGIN_EXPORT |
|
|
|
#if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WASM) || defined(DISTRHO_OS_WINDOWS) |
|
|
|
const AEffect* VSTPluginMain(audioMasterCallback audioMaster); |
|
|
|
const vst_effect* VSTPluginMain(vst_host_callback audioMaster); |
|
|
|
#else |
|
|
|
const AEffect* VSTPluginMain(audioMasterCallback audioMaster) asm ("main"); |
|
|
|
const vst_effect* VSTPluginMain(vst_host_callback audioMaster) asm ("main"); |
|
|
|
#endif |
|
|
|
|
|
|
|
DISTRHO_PLUGIN_EXPORT |
|
|
|
const AEffect* VSTPluginMain(const audioMasterCallback audioMaster) |
|
|
|
const vst_effect* VSTPluginMain(const vst_host_callback audioMaster) |
|
|
|
{ |
|
|
|
USE_NAMESPACE_DISTRHO |
|
|
|
|
|
|
|
// old version |
|
|
|
if (audioMaster(nullptr, audioMasterVersion, 0, 0, nullptr, 0.0f) == 0) |
|
|
|
if (audioMaster(nullptr, VST_HOST_OPCODE_01 /* version */, 0, 0, nullptr, 0.0f) == 0) |
|
|
|
return nullptr; |
|
|
|
|
|
|
|
// find plugin bundle |
|
|
@@ -1621,9 +1647,13 @@ const AEffect* VSTPluginMain(const audioMasterCallback audioMaster) |
|
|
|
std::memset(effect, 0, sizeof(ExtendedAEffect)); |
|
|
|
|
|
|
|
// vst fields |
|
|
|
effect->magic = kEffectMagic; |
|
|
|
effect->uniqueID = sPlugin->getUniqueId(); |
|
|
|
effect->version = sPlugin->getVersion(); |
|
|
|
#ifdef WORDS_BIGENDIAN |
|
|
|
effect->magic_number = 0x50747356; |
|
|
|
#else |
|
|
|
effect->magic_number = 0x56737450; |
|
|
|
#endif |
|
|
|
effect->unique_id = sPlugin->getUniqueId(); |
|
|
|
effect->version = sPlugin->getVersion(); |
|
|
|
|
|
|
|
// VST doesn't support parameter outputs. we can fake them, but it is a hack. Disabled by default. |
|
|
|
#ifdef DPF_VST_SHOW_PARAMETER_OUTPUTS |
|
|
@@ -1646,29 +1676,29 @@ const AEffect* VSTPluginMain(const audioMasterCallback audioMaster) |
|
|
|
#endif |
|
|
|
|
|
|
|
// plugin fields |
|
|
|
effect->numParams = numParams; |
|
|
|
effect->numPrograms = 1; |
|
|
|
effect->numInputs = DISTRHO_PLUGIN_NUM_INPUTS; |
|
|
|
effect->numOutputs = DISTRHO_PLUGIN_NUM_OUTPUTS; |
|
|
|
effect->num_params = numParams; |
|
|
|
effect->num_programs = 1; |
|
|
|
effect->num_inputs = DISTRHO_PLUGIN_NUM_INPUTS; |
|
|
|
effect->num_outputs = DISTRHO_PLUGIN_NUM_OUTPUTS; |
|
|
|
|
|
|
|
// plugin flags |
|
|
|
effect->flags |= effFlagsCanReplacing; |
|
|
|
effect->flags |= 1 << 4; // uses process_float |
|
|
|
#if DISTRHO_PLUGIN_IS_SYNTH |
|
|
|
effect->flags |= effFlagsIsSynth; |
|
|
|
effect->flags |= 1 << 8; |
|
|
|
#endif |
|
|
|
#if DISTRHO_PLUGIN_HAS_UI |
|
|
|
effect->flags |= effFlagsHasEditor; |
|
|
|
effect->flags |= 1 << 0; |
|
|
|
#endif |
|
|
|
#if DISTRHO_PLUGIN_WANT_STATE |
|
|
|
effect->flags |= effFlagsProgramChunks; |
|
|
|
effect->flags |= 1 << 5; |
|
|
|
#endif |
|
|
|
|
|
|
|
// static calls |
|
|
|
effect->dispatcher = vst_dispatcherCallback; |
|
|
|
effect->process = vst_processCallback; |
|
|
|
effect->getParameter = vst_getParameterCallback; |
|
|
|
effect->setParameter = vst_setParameterCallback; |
|
|
|
effect->processReplacing = vst_processReplacingCallback; |
|
|
|
effect->control = vst_dispatcherCallback; |
|
|
|
effect->process = vst_processCallback; |
|
|
|
effect->get_parameter = vst_getParameterCallback; |
|
|
|
effect->set_parameter = vst_setParameterCallback; |
|
|
|
effect->process_float = vst_processReplacingCallback; |
|
|
|
|
|
|
|
// special values |
|
|
|
effect->valid = 101; |
|
|
|