phase4: Linux native_bridge build (Docker) — sfizz from source, --render SF2/SFZ
- Dockerfile: build sfizz tu native_bridge/sfizz-src (hoac git clone v1.2.3), sed fix sfizz.pc (-llibsfizz -> -lsfizz), cmake bridge voi 3 flag SMTG OFF (VSTGUI/plugin/hosting examples) — bridge headless chi can --render. - CMakeLists: nhanh non-WIN32 build daw_vst_bridge tu main_linux.cpp + RenderJob.cpp + NativeInstrumentEngine.cpp (SF2/SF3 + SFZ; VST3/VST2 hosting Windows-only, guard #ifdef _WIN32). gui_probe/plugin_host/ seh_channel_test chi build tren Windows. - RenderJob.cpp: JSON parser (sheredom json.h) khong con phu thuoc HAVE_VST3SDK — render SF2/SFZ chay duoc khong can VST3 SDK. - NativeInstrumentEngine.cpp: guard windows.h/VST3/VST2/Sandbox/SEH. - main.cpp: g_engine unconditional + guard disable_ime_contexts (_WIN32). - engine.spec: bo pedalboard collect_dynamic_libs + hidden imports. - vst_engine/render_engine: DecentSampler -> NotImplementedError + huong dan convert .dspreset -> .vstpreset; pianobook fallback synth. - Verified: WSL Ubuntu 24.04 build OK, bridge Linux --render SF2 ra WAV 44100 stereo peak 1575; Python tests 115 passed 1 skipped. - Dockerfile build chua test duoc (may khong co Docker).
This commit is contained in:
@@ -3,15 +3,19 @@
|
||||
|
||||
#include <fluidsynth.h>
|
||||
#include <sfizz.hpp>
|
||||
#ifdef _WIN32
|
||||
#include "Vst3Instrument.h"
|
||||
#include "Vst2Instrument.h"
|
||||
#include "SandboxVst3Host.h"
|
||||
#endif
|
||||
|
||||
// void* members keep fluid types out of the public header; cast here.
|
||||
#define FS_SYNTH (static_cast<fluid_synth_t*>(synth))
|
||||
#define FS_SETTINGS (static_cast<fluid_settings_t*>(settings))
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
@@ -168,6 +172,7 @@ std::unique_ptr<INativeInstrument> InstrumentEngineManager::create_instrument(In
|
||||
switch (type) {
|
||||
case InstrumentType::SOUNDFONT_SF2_SF3: return std::make_unique<FluidSynthInstrument>();
|
||||
case InstrumentType::SFZ: return std::make_unique<SfizzInstrument>();
|
||||
#ifdef _WIN32
|
||||
case InstrumentType::VST3:
|
||||
// G4.2: SF_SANDBOX_VST3=1 -> host the VST3 in a child
|
||||
// process (plugin_host.exe). Crash kills only the child.
|
||||
@@ -176,6 +181,13 @@ std::unique_ptr<INativeInstrument> InstrumentEngineManager::create_instrument(In
|
||||
return std::make_unique<Vst3Instrument>();
|
||||
case InstrumentType::VST2:
|
||||
return std::make_unique<Vst2Instrument>();
|
||||
#else
|
||||
case InstrumentType::VST3:
|
||||
case InstrumentType::VST2:
|
||||
// Linux bridge: SF2/SF3 + SFZ only (Docker render). VST3/VST2
|
||||
// hosting is Windows-only (COM/HWND/SHM realtime loop).
|
||||
return nullptr;
|
||||
#endif
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -191,6 +203,7 @@ bool InstrumentEngineManager::assign(uint32_t channel, InstrumentType type,
|
||||
loaded = static_cast<FluidSynthInstrument*>(inst.get())->loadSoundFontFile(path, sampleRate);
|
||||
else if (type == InstrumentType::SFZ)
|
||||
loaded = static_cast<SfizzInstrument*>(inst.get())->loadSfzFile(path, sampleRate);
|
||||
#ifdef _WIN32
|
||||
else if (type == InstrumentType::VST3) {
|
||||
if (auto* v = dynamic_cast<Vst3Instrument*>(inst.get()))
|
||||
loaded = v->loadPlugin(path, sampleRate);
|
||||
@@ -207,6 +220,7 @@ bool InstrumentEngineManager::assign(uint32_t channel, InstrumentType type,
|
||||
if (auto* v = dynamic_cast<Vst3Instrument*>(inst.get()))
|
||||
v->setChannel(channel);
|
||||
}
|
||||
#endif
|
||||
if (!loaded) return false;
|
||||
// init() AFTER load: FluidSynth creates its synth inside loadSoundFontFile.
|
||||
if (!inst->init(sampleRate, blockSize)) return false;
|
||||
@@ -415,8 +429,11 @@ static float* alignF(std::vector<float>& v, size_t n) {
|
||||
// (0xC0000005) is caught here — the channel is muted instead of killing the
|
||||
// whole bridge process. /EHa (set in CMakeLists) allows mixing with the
|
||||
// outer C++ try/catch net in main.cpp.
|
||||
#ifdef _WIN32
|
||||
static DWORD g_sehCode = 0;
|
||||
static void* g_sehAddr = nullptr;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
static bool SafeProcessChannel(INativeInstrument* inst, float* outL, float* outR, uint32_t n, DWORD* outCode) {
|
||||
*outCode = 0;
|
||||
__try {
|
||||
@@ -429,6 +446,18 @@ static bool SafeProcessChannel(INativeInstrument* inst, float* outL, float* outR
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static bool SafeProcessChannel(INativeInstrument* inst, float* outL, float* outR, uint32_t n, uint32_t* outCode) {
|
||||
*outCode = 0;
|
||||
try {
|
||||
inst->processAudioBlock(outL, outR, n);
|
||||
return true;
|
||||
} catch (...) {
|
||||
*outCode = 1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void InstrumentEngineManager::renderAll(float* outputL, float* outputR, uint32_t numSamples) {
|
||||
if (isBypassed_.load()) {
|
||||
@@ -446,11 +475,12 @@ void InstrumentEngineManager::renderAll(float* outputL, float* outputR, uint32_t
|
||||
float* spR = alignF(scratchR_, numSamples);
|
||||
std::memset(spL, 0, numSamples * sizeof(float));
|
||||
std::memset(spR, 0, numSamples * sizeof(float));
|
||||
DWORD sehCode = 0;
|
||||
uint32_t sehCode = 0;
|
||||
if (!SafeProcessChannel(inst.get(), spL, spR, numSamples, &sehCode)) {
|
||||
// G3.3: plugin fault — mute this channel only, keep the bridge up.
|
||||
if (!crashedCh_[ch]) {
|
||||
crashedCh_[ch] = true;
|
||||
#ifdef _WIN32
|
||||
{
|
||||
HMODULE m = nullptr;
|
||||
char mod[MAX_PATH] = "?";
|
||||
@@ -477,6 +507,11 @@ void InstrumentEngineManager::renderAll(float* outputL, float* outputR, uint32_t
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
#else
|
||||
std::cerr << "[NativeBridge] G3.3: channel " << ch
|
||||
<< " plugin crashed in processAudioBlock — muted until reload"
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user