M5: capture editor state -> preset_b64 khi đóng GUI native (JuceFxLoop ghi <job>.preset.json + /fx-gui/close poll)
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
@@ -79,6 +80,23 @@ std::string extractChainJson(const std::string& s) {
|
||||
return s.substr(p, i - p + 1);
|
||||
}
|
||||
|
||||
// M5: base64 encode (RFC 4648) cho editor state capture -> file preset.
|
||||
static std::string base64Encode(const std::string& in) {
|
||||
static const char* tbl =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
std::string out;
|
||||
out.reserve(((in.size() + 2) / 3) * 4);
|
||||
for (size_t i = 0; i < in.size(); i += 3) {
|
||||
unsigned a = (unsigned char)in[i];
|
||||
unsigned b = i + 1 < in.size() ? (unsigned char)in[i + 1] : 0;
|
||||
unsigned c = i + 2 < in.size() ? (unsigned char)in[i + 2] : 0;
|
||||
out += tbl[a >> 2];
|
||||
out += tbl[((a & 3) << 4) | (b >> 4)];
|
||||
out += i + 1 < in.size() ? tbl[((b & 15) << 2) | (c >> 6)] : '=';
|
||||
out += i + 2 < in.size() ? tbl[c & 63] : '=';
|
||||
}
|
||||
return out;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int run_juce_fx_loop(const std::string& jobPath, const std::string& shmName,
|
||||
@@ -232,6 +250,37 @@ int run_juce_fx_loop(const std::string& jobPath, const std::string& shmName,
|
||||
engine.requestEditor(slot, act, w, h);
|
||||
std::cerr << "[JuceFxLoop] ctrl " << key << " slot=" << slot
|
||||
<< " w=" << w << " h=" << h << std::endl;
|
||||
// M5: capture state editor (GUI đóng → preset về project như
|
||||
// WM_FXGUI_CAPTURE cũ). PumpEditorQueue (GUI tick 30ms) thực thi
|
||||
// Capture → captured[slot] (raw). Ctrl thread đợi tối đa 3s rồi
|
||||
// base64 + ghi file JSON cạnh job: <jobPath>.preset.json
|
||||
// {slot, preset_b64}. Python /fx-gui/close poll file này (xoá file
|
||||
// cũ trước — chỉ đọc file MỚI cho capture lần này).
|
||||
if (act == JuceFxEngine::EditorAction::Capture) {
|
||||
const std::string capFile = jobPath + ".preset.json";
|
||||
std::remove(capFile.c_str());
|
||||
std::string raw;
|
||||
for (int i = 0; i < 300 && raw.empty(); ++i) {
|
||||
sleepMs(10);
|
||||
if (!ipc->h.running || ipc->h.state != FXRT_STATE_READY)
|
||||
break;
|
||||
raw = engine.takeCapturedState(slot);
|
||||
}
|
||||
if (!raw.empty()) {
|
||||
const std::string b64 = base64Encode(raw);
|
||||
std::ofstream f(capFile, std::ios::binary);
|
||||
f << "{\"slot\":" << slot << ",\"preset_b64\":\""
|
||||
<< b64 << "\"}" << std::endl;
|
||||
std::cerr << "[JuceFxLoop] capture slot=" << slot
|
||||
<< " -> " << capFile << " (" << raw.size()
|
||||
<< " bytes, " << b64.size() << " b64)"
|
||||
<< std::endl;
|
||||
} else {
|
||||
std::cerr << "[JuceFxLoop] capture slot=" << slot
|
||||
<< " rỗng — plugin không có state" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
sleepMs(2);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user