T10: VST2 engine bridge (vestige.h clean-room, VST2AudioEngine.cpp, fake_vst2 test plugin)

This commit is contained in:
2026-08-11 16:18:45 +07:00
parent 6bc197b909
commit aaf21ddf89
4 changed files with 696 additions and 0 deletions
+194
View File
@@ -0,0 +1,194 @@
// vestige.h — clean-room VST2 (AEffect) API header (T10, spec 5.7 / spec III)
//
// QUYẾT ĐỊNH (T10): KHÔNG dùng aeffect.h/aeffectx.h chính thức (Steinberg
// ngừng license VST2 10/2018 — spec III). Viết lại từ kiến thức public của
// giao diện AEffect: struct + opcode enum đủ cho host (load, MIDI, GUI,
// processReplacing). Chỉ giữ phần host cần — không phải bản sao SDK.
//
// Nâng cấp nếu cần: thay bằng bridge có sẵn (Carla/Wine-VST) hoặc gộp JUCE.
#pragma once
#include <cstdint>
#include <stdint.h>
#define VSTCALLBACK __cdecl
#ifdef _WIN32
#define CCONST(a, b, c, d) ((int32)((d) << 24 | (c) << 16 | (b) << 8 | (a)))
#else
#define CCONST(a, b, c, d) ((int32)((a) << 24 | (b) << 16 | (c) << 8 | (d)))
#endif
typedef int32_t int32;
typedef intptr_t VstIntPtr;
typedef float VstParamValue;
//------------------------------------------------------------------------
// AEffect — layout công khai của VST2; KHÔNG đổi thứ tự field.
struct AEffect
{
int32 magic; // kEffectMagic = CCONST('V', 's', 't', 'P')
int32 (VSTCALLBACK* dispatcher)(AEffect*, int32 opcode, int32 index, VstIntPtr value, void* ptr, float opt);
void (VSTCALLBACK* process)(AEffect*, float** inputs, float** outputs, int32 sampleFrames);
void (VSTCALLBACK* setParameter)(AEffect*, int32 index, float parameter);
float (VSTCALLBACK* getParameter)(AEffect*, int32 index);
int32 (VSTCALLBACK* numPrograms)(AEffect*);
int32 (VSTCALLBACK* numParams)(AEffect*);
int32 (VSTCALLBACK* numInputs)(AEffect*);
int32 (VSTCALLBACK* numOutputs)(AEffect*);
int32 (VSTCALLBACK* flags)(AEffect*);
int32 resvd1;
int32 resvd2;
int32 initialDelay;
int32 realQualities;
int32 offQualities;
float ioRatio;
void* object;
void* user;
int32 uniqueID;
int32 version;
void (VSTCALLBACK* processReplacing)(AEffect*, float** inputs, float** outputs, int32 sampleFrames);
void (VSTCALLBACK* processDoubleReplacing)(AEffect*, double** inputs, double** outputs, int32 sampleFrames);
};
enum VstAEffectFlags
{
effFlagsHasEditor = 1 << 0,
effFlagsCanReplacing = 1 << 4,
effFlagsProgramChunks = 1 << 5,
effFlagsIsSynth = 1 << 8,
effFlagsNoSoundInStop = 1 << 9,
effFlagsCanDoubleReplacing = 1 << 12
};
//------------------------------------------------------------------------
// Dispatcher opcodes (host -> plugin)
enum VstEffectOpcodes
{
effOpen = 0,
effClose = 1,
effSetProgram = 2,
effGetProgram = 3,
effSetProgramName = 4,
effGetProgramName = 5,
effGetParamLabel = 6,
effGetParamDisplay = 7,
effGetParamName = 8,
effSetSampleRate = 10,
effSetBlockSize = 11,
effMainsChanged = 12,
effEditGetRect = 13,
effEditOpen = 14,
effEditClose = 15,
effEditIdle = 19,
effEditTop = 20,
effEditSleep = 21,
effIdentify = 22,
effGetChunk = 23,
effSetChunk = 24,
effProcessEvents = 25,
effCanBeAutomated = 26,
effGetEffectName = 39,
effGetVendorString = 41,
effGetProductString = 42,
effGetVendorVersion = 43,
effCanDo = 45,
effIdle = 47,
effSetViewPosition = 49,
effGetVstVersion = 52,
effEditKeyDown = 53,
effEditKeyUp = 54,
effStartProcess = 65,
effStopProcess = 66,
effSetProcessPrecision = 71
};
enum VstPluginCanDo
{
canDoSendVstEvents = 0,
canDoSendVstMidiEvent = 1,
canDoReceiveVstEvents = 2,
canDoReceiveVstMidiEvent = 3
};
//------------------------------------------------------------------------
// AudioMasterCallback opcodes (plugin -> host)
enum VstAudioMasterOpcodes
{
audioMasterAutomate = 0,
audioMasterVersion = 1,
audioMasterCurrentId = 2,
audioMasterIdle = 3,
audioMasterWantMidi = 6,
audioMasterGetTime = 7,
audioMasterProcessEvents = 8,
audioMasterGetVendorString = 14,
audioMasterGetProductString = 15,
audioMasterGetVendorVersion = 16,
audioMasterCanDo = 19,
audioMasterGetLanguage = 20,
audioMasterGetDirectory = 21,
audioMasterUpdateDisplay = 22,
audioMasterGetSampleRate = 35,
audioMasterGetBlockSize = 36,
audioMasterGetInputLatency = 29,
audioMasterGetOutputLatency = 30
};
//------------------------------------------------------------------------
// MIDI events qua effProcessEvents (không dùng giao diện MIDI cũ của AEffect)
struct VstEvent
{
int32 type;
int32 byteSize;
int32 flags;
intptr_t* data; // 4 bytes padding trên Win64 giữ layout
};
struct VstMidiEvent
{
int32 type; // kVstMidiType
int32 byteSize; // sizeof(VstMidiEvent)
int32 deltaFrames;
int32 flags; // kVstMidiEventIsRealtime
int32 noteLength; // 0
int32 noteOffset; // 0
char midiData[4]; // status, data1, data2, pad
char detune;
char noteOffVelocity;
char reserved1;
char reserved2;
};
struct VstEvents
{
int32 numEvents;
intptr_t reserved;
VstEvent* events[1];
};
enum VstEventTypes
{
kVstMidiType = 1
};
enum VstMidiEventFlags
{
kVstMidiEventIsRealtime = 1 << 0
};
//------------------------------------------------------------------------
// Editor rect (effEditGetRect)
struct ERect
{
short top;
short left;
short bottom;
short right;
};
//------------------------------------------------------------------------
// VST2 entry points (typedef names khác tên export để tránh redefinition)
typedef AEffect* (VSTCALLBACK* VSTPluginMainFn)(void* audioMasterCallback);
typedef AEffect* (VSTCALLBACK* VSTPluginMainOldFn)(void* audioMasterCallback, void* reserved);
typedef VstIntPtr (VSTCALLBACK* audioMasterCallbackFunc)(AEffect* effect, int32 opcode, int32 index, VstIntPtr value, void* ptr, float opt);