G0.4: save/restore preset quanh reload khi close GUI (captureState/restoreState, memorystream link truc tiep)
This commit is contained in:
Binary file not shown.
@@ -64,10 +64,11 @@ add_executable(daw_vst_bridge
|
|||||||
# is added to the bridge itself (same approach as the audiohost sample).
|
# is added to the bridge itself (same approach as the audiohost sample).
|
||||||
if(VST3_SDK_TARGET)
|
if(VST3_SDK_TARGET)
|
||||||
target_compile_definitions(daw_vst_bridge PRIVATE HAVE_VST3SDK=1)
|
target_compile_definitions(daw_vst_bridge PRIVATE HAVE_VST3SDK=1)
|
||||||
target_link_libraries(daw_vst_bridge PRIVATE ${VST3_SDK_TARGET} sdk_hosting)
|
target_link_libraries(daw_vst_bridge PRIVATE ${VST3_SDK_TARGET} sdk_hosting sdk_common)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_sources(daw_vst_bridge PRIVATE
|
target_sources(daw_vst_bridge PRIVATE
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/vst3sdk/public.sdk/source/vst/hosting/module_win32.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/vst3sdk/public.sdk/source/vst/hosting/module_win32.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/vst3sdk/public.sdk/source/common/memorystream.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ public:
|
|||||||
// it to dedupe repeated OPEN_GUI (frontend retry spam) — re-attaching a
|
// it to dedupe repeated OPEN_GUI (frontend retry spam) — re-attaching a
|
||||||
// view that is already attached corrupts plugins (Nexus createView→null).
|
// view that is already attached corrupts plugins (Nexus createView→null).
|
||||||
virtual bool hasAttachedView() const { return false; }
|
virtual bool hasAttachedView() const { return false; }
|
||||||
|
// G0.4: serialize/restore the plugin preset across instance reloads
|
||||||
|
// (GUI close/reopen). Non-VST engines: no-op (nothing to save).
|
||||||
|
virtual void captureState() {}
|
||||||
|
virtual void restoreState() {}
|
||||||
|
|
||||||
// Real-time Audio PCM Float32 rendering loop
|
// Real-time Audio PCM Float32 rendering loop
|
||||||
virtual void processAudioBlock(float* outputL, float* outputR, uint32_t numSamples) = 0;
|
virtual void processAudioBlock(float* outputL, float* outputR, uint32_t numSamples) = 0;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "INativeInstrument.h"
|
#include "INativeInstrument.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class Vst3Instrument : public INativeInstrument {
|
class Vst3Instrument : public INativeInstrument {
|
||||||
public:
|
public:
|
||||||
@@ -27,6 +28,10 @@ public:
|
|||||||
bool openGUI(void* parentWindowHandle) override;
|
bool openGUI(void* parentWindowHandle) override;
|
||||||
bool reloadForGUI() override;
|
bool reloadForGUI() override;
|
||||||
bool attachView(void* parentWindowHandle) override;
|
bool attachView(void* parentWindowHandle) override;
|
||||||
|
// G0.4: keep the preset across GUI reopen (reload() recreates the
|
||||||
|
// instance from scratch — without save/restore the plugin resets).
|
||||||
|
void captureState();
|
||||||
|
void restoreState();
|
||||||
void resizeView(int w, int h) override;
|
void resizeView(int w, int h) override;
|
||||||
bool hasAttachedView() const override;
|
bool hasAttachedView() const override;
|
||||||
void closeGUI() override;
|
void closeGUI() override;
|
||||||
@@ -47,6 +52,9 @@ private:
|
|||||||
bool hasAttachedOnce_;
|
bool hasAttachedOnce_;
|
||||||
bool reloading_; // guarded by InstrumentEngineManager::mu_ (set via setReloading)
|
bool reloading_; // guarded by InstrumentEngineManager::mu_ (set via setReloading)
|
||||||
uint32_t channel_ = 0;
|
uint32_t channel_ = 0;
|
||||||
|
// G0.4: serialized IComponent/IEditController state captured before reload.
|
||||||
|
std::vector<uint8_t> savedComponentState_;
|
||||||
|
std::vector<uint8_t> savedControllerState_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VST3_INSTRUMENT_H
|
#endif // VST3_INSTRUMENT_H
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "public.sdk/source/vst/hosting/processdata.h"
|
#include "public.sdk/source/vst/hosting/processdata.h"
|
||||||
#include "public.sdk/source/vst/hosting/eventlist.h"
|
#include "public.sdk/source/vst/hosting/eventlist.h"
|
||||||
#include "public.sdk/source/vst/hosting/parameterchanges.h"
|
#include "public.sdk/source/vst/hosting/parameterchanges.h"
|
||||||
|
#include "public.sdk/source/common/memorystream.h"
|
||||||
|
|
||||||
#include "pluginterfaces/vst/ivstaudioprocessor.h"
|
#include "pluginterfaces/vst/ivstaudioprocessor.h"
|
||||||
#include "pluginterfaces/vst/ivstcomponent.h"
|
#include "pluginterfaces/vst/ivstcomponent.h"
|
||||||
@@ -525,6 +526,59 @@ bool Vst3Instrument::openGUI(void* parentWindowHandle) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// G0.4: capture the plugin's full state (component + edit controller) into
|
||||||
|
// buffers so a GUI reopen can restore the preset after reload().
|
||||||
|
void Vst3Instrument::captureState() {
|
||||||
|
#ifndef HAVE_VST3SDK
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
auto* s = static_cast<Vst3HostState*>(state_);
|
||||||
|
if (!s) return;
|
||||||
|
savedComponentState_.clear();
|
||||||
|
savedControllerState_.clear();
|
||||||
|
Steinberg::MemoryStream stream;
|
||||||
|
if (s->component && s->component->getState(&stream) == kResultOk && stream.getSize() > 0) {
|
||||||
|
savedComponentState_.assign(stream.getData(), stream.getData() + stream.getSize());
|
||||||
|
std::cout << "[Vst3Instrument] state captured ch=" << channel_
|
||||||
|
<< " component=" << savedComponentState_.size() << "B" << std::endl;
|
||||||
|
}
|
||||||
|
if (s->controller && !s->controllerIsComponent &&
|
||||||
|
s->controller->getState(&stream) == kResultOk && stream.getSize() > 0) {
|
||||||
|
savedControllerState_.assign(stream.getData(), stream.getData() + stream.getSize());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// G0.4: restore the captured state onto the freshly loaded instance.
|
||||||
|
void Vst3Instrument::restoreState() {
|
||||||
|
#ifndef HAVE_VST3SDK
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
auto* s = static_cast<Vst3HostState*>(state_);
|
||||||
|
if (!s) return;
|
||||||
|
if (!savedComponentState_.empty()) {
|
||||||
|
Steinberg::MemoryStream stream;
|
||||||
|
stream.write(savedComponentState_.data(), (int32)savedComponentState_.size(), nullptr);
|
||||||
|
stream.seek(0, Steinberg::IBStream::kIBSeekSet, nullptr);
|
||||||
|
bool okComp = s->component && s->component->setState(&stream) == kResultOk;
|
||||||
|
if (!okComp) {
|
||||||
|
std::cerr << "[Vst3Instrument] setState(component) failed ch=" << channel_ << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "[Vst3Instrument] state restored ch=" << channel_
|
||||||
|
<< " component=" << savedComponentState_.size() << "B" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!savedControllerState_.empty()) {
|
||||||
|
Steinberg::MemoryStream stream;
|
||||||
|
stream.write(savedControllerState_.data(), (int32)savedControllerState_.size(), nullptr);
|
||||||
|
stream.seek(0, Steinberg::IBStream::kIBSeekSet, nullptr);
|
||||||
|
if (s->controller && s->controller->setState(&stream) != kResultOk) {
|
||||||
|
std::cerr << "[Vst3Instrument] setState(controller) failed ch=" << channel_ << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool Vst3Instrument::reloadForGUI() {
|
bool Vst3Instrument::reloadForGUI() {
|
||||||
#ifndef HAVE_VST3SDK
|
#ifndef HAVE_VST3SDK
|
||||||
return false;
|
return false;
|
||||||
@@ -539,9 +593,13 @@ bool Vst3Instrument::reloadForGUI() {
|
|||||||
// PHAN NAY PHAI chay tren worker thread — apartment cua channel song
|
// PHAN NAY PHAI chay tren worker thread — apartment cua channel song
|
||||||
// o day; chay tren thread tam thi apartment moi chet ngay sau do
|
// o day; chay tren thread tam thi apartment moi chet ngay sau do
|
||||||
// (reopen lan sau -> treo nhu bridge_like).
|
// (reopen lan sau -> treo nhu bridge_like).
|
||||||
|
// G0.4: reload() terminates + recreates the instance — capture the
|
||||||
|
// preset first, restore it after, so the GUI reopen keeps the sound.
|
||||||
|
captureState();
|
||||||
if (!reload()) return false;
|
if (!reload()) return false;
|
||||||
s = static_cast<Vst3HostState*>(state_);
|
s = static_cast<Vst3HostState*>(state_);
|
||||||
if (!s || !s->controller) return false;
|
if (!s || !s->controller) return false;
|
||||||
|
restoreState();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -707,7 +707,12 @@ static void post_close_gui(uint32_t ch, HWND hwnd) {
|
|||||||
// load/assign rebuilds it).
|
// load/assign rebuilds it).
|
||||||
std::lock_guard<std::mutex> lg(g_loadMutex);
|
std::lock_guard<std::mutex> lg(g_loadMutex);
|
||||||
try {
|
try {
|
||||||
|
// G0.4: reload() terminates + recreates the instance;
|
||||||
|
// capture the preset first, restore it after, so the
|
||||||
|
// sound survives a GUI close (reopen keeps it too).
|
||||||
|
i->captureState();
|
||||||
i->reload();
|
i->reload();
|
||||||
|
i->restoreState();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
std::cerr << "[NativeBridge] closeGUI reload EXCEPTION ch=" << ch
|
std::cerr << "[NativeBridge] closeGUI reload EXCEPTION ch=" << ch
|
||||||
<< " — plugin threw (createInstance)" << std::endl;
|
<< " — plugin threw (createInstance)" << std::endl;
|
||||||
|
|||||||
Reference in New Issue
Block a user