Files
SonicForgeStudio/native_host/tests/fake_vst2.cpp
T

143 lines
4.1 KiB
C++

// fake_vst2.cpp — test plugin VST2 tối thiểu để verify bridge T10.
// Sine 440Hz stereo qua processReplacing; editor trả rect giả.
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <cmath>
#include <cstring>
#include "vestige.h"
namespace {
struct FakeState
{
float phase = 0.0f;
int32 sampleRate = 44100;
float gain = 0.5f; // param 0 — "Gain" (0..1)
};
FakeState g_state;
void* g_audioMaster = nullptr;
void VSTCALLBACK fakeSetParameter (AEffect* effect, int32 index, float value)
{
if (index == 0)
{
g_state.gain = value;
// Báo host: param đổi từ editor/plugin (T11) — chống loop host-side.
if (g_audioMaster)
{
typedef VstIntPtr (VSTCALLBACK* AMFn) (AEffect*, int32, int32, VstIntPtr, void*, float);
reinterpret_cast<AMFn> (g_audioMaster) (effect, audioMasterAutomate, index, 0, nullptr,
value);
}
}
}
float VSTCALLBACK fakeGetParameter (AEffect*, int32 index)
{
if (index == 0)
return g_state.gain;
return 0.0f;
}
int32 VSTCALLBACK fakeDispatcher (AEffect* effect, int32 opcode, int32 index,
VstIntPtr value, void* ptr, float opt)
{
(void) index;
(void) value;
(void) ptr;
(void) opt;
switch (opcode)
{
case effOpen:
return 1;
case effClose:
return 1;
case effSetSampleRate:
g_state.sampleRate = static_cast<int32> (opt);
return 1;
case effMainsChanged:
return 1;
case effStartProcess:
case effStopProcess:
return 1;
case effEditGetRect:
{
static ERect rect = {0, 0, 300, 400};
*reinterpret_cast<ERect**> (ptr) = &rect;
return 1;
}
case effEditOpen:
return 1;
case effEditClose:
return 1;
case effProcessEvents:
return 1;
case effGetEffectName:
std::strncpy (static_cast<char*> (ptr), "FakeVST2", 64);
return 1;
case effGetVendorString:
std::strncpy (static_cast<char*> (ptr), "SonicForgeStudio", 64);
return 1;
case effGetProductString:
std::strncpy (static_cast<char*> (ptr), "FakeVST2", 64);
return 1;
case effGetVendorVersion:
return 1;
case effIdentify:
return CCONST ('N', 'v', 'E', 'f');
case effCanDo:
return 0;
default:
return 0;
}
}
void VSTCALLBACK fakeProcessReplacing (AEffect*, float** inputs, float** outputs,
int32 sampleFrames)
{
(void) inputs;
float* outL = outputs[0];
float* outR = outputs[1];
const float freq = 440.0f;
const float dt = freq / static_cast<float> (g_state.sampleRate);
for (int32 i = 0; i < sampleFrames; ++i)
{
float v = 0.25f * std::sin (2.0f * 3.14159265f * g_state.phase);
g_state.phase += dt;
if (g_state.phase >= 1.0f)
g_state.phase -= 1.0f;
outL[i] = v;
outR[i] = v;
}
}
AEffect g_effect;
AEffect* VSTCALLBACK createInstance (void* audioMaster)
{
g_audioMaster = audioMaster;
std::memset (&g_effect, 0, sizeof (g_effect));
g_effect.magic = CCONST ('V', 's', 't', 'P');
g_effect.dispatcher = &fakeDispatcher;
g_effect.processReplacing = &fakeProcessReplacing;
g_effect.setParameter = &fakeSetParameter;
g_effect.getParameter = &fakeGetParameter;
g_effect.numInputs = [] (AEffect*) -> int32 { return 0; };
g_effect.numOutputs = [] (AEffect*) -> int32 { return 2; };
g_effect.numParams = [] (AEffect*) -> int32 { return 1; };
g_effect.numPrograms = [] (AEffect*) -> int32 { return 0; };
g_effect.flags = [] (AEffect*) -> int32 { return effFlagsCanReplacing | effFlagsIsSynth; };
g_effect.uniqueID = CCONST ('F', 'k', '2', 'V');
g_effect.version = 1;
return &g_effect;
}
} // namespace
extern "C" __declspec (dllexport) AEffect* VSTPluginMain (void* audioMaster)
{
return createInstance (audioMaster);
}