Skip to content

Commit 92a7726

Browse files
authored
Update the rescan mechanism (#350)
Update the param rescan mechanism to 1: always use onMainThread and not the UI loop 2: Be way more parsimonious Reducing a multi-rescan macro patch load case introduced with super macros due to lingering design problems from 1.1 Assisted-By: Opus 4.7
1 parent 92d1a90 commit 92a7726

5 files changed

Lines changed: 64 additions & 49 deletions

File tree

src/presets/preset-manager.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,9 @@ void PresetManager::sendEntirePatchToAudio(Patch &patch, Synth::mainToAudioQueue
287287
msg.uiManagedPointer = macDat;
288288
mainToAudio.push(msg);
289289
}
290+
// The audio-side SEND_MACRO_NAME handler decides whether each name actually
291+
// changed and requests an INFO rescan only if so (atomic-OR coalesces the
292+
// burst into a single host call).
290293

291294
mainToAudio.push({Synth::MainToAudioMsg::STOP_AUDIO});
292295
for (const auto &p : patch.params)
@@ -296,8 +299,9 @@ void PresetManager::sendEntirePatchToAudio(Patch &patch, Synth::mainToAudioQueue
296299
}
297300
mainToAudio.push({Synth::MainToAudioMsg::START_AUDIO});
298301
mainToAudio.push({Synth::MainToAudioMsg::SEND_PATCH_IS_CLEAN, true});
302+
// SEND_POST_LOAD's audio handler now requests the VALUES rescan via
303+
// Synth::requestParamRescan, so no separate rescan message is needed here.
299304
mainToAudio.push({Synth::MainToAudioMsg::SEND_POST_LOAD, true});
300-
mainToAudio.push({Synth::MainToAudioMsg::SEND_REQUEST_RESCAN, true});
301305

302306
if (hostPar)
303307
{

src/synth/synth.cpp

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,10 @@ void Synth::processUIQueue(const clap_output_events_t *outq)
627627
doFullRefresh = false;
628628
didRefresh = true;
629629
}
630+
// Accumulate rescan flags across the whole drain so we issue one
631+
// requestParamRescan / request_callback at the end, regardless of how many
632+
// messages in this batch wanted a rescan.
633+
uint32_t pendingRescan{0};
630634
auto uiM = mainToAudio.pop();
631635
while (uiM.has_value())
632636
{
@@ -762,17 +766,18 @@ void Synth::processUIQueue(const clap_output_events_t *outq)
762766
if (idx < numMacros && uiM->uiManagedPointer)
763767
{
764768
auto &buf = patch.macroNames[idx];
765-
std::fill(buf.begin(), buf.end(), 0);
766-
strncpy(buf.data(), uiM->uiManagedPointer, buf.size() - 1);
767-
AudioToUIMsg out{AudioToUIMsg::SET_MACRO_NAME};
768-
out.paramId = idx;
769-
out.patchNamePointer = buf.data();
770-
audioToUi.push(out);
771-
772-
// Refresh host param info so the renamed macro picks up its display name.
773-
AudioToUIMsg rescan{AudioToUIMsg::DO_PARAM_RESCAN};
774-
rescan.paramId = CLAP_PARAM_RESCAN_INFO;
775-
audioToUi.push(rescan);
769+
// Only act on actual changes — avoids gratuitous INFO rescans on
770+
// preset loads where macro names match what the host already knows.
771+
if (std::strncmp(buf.data(), uiM->uiManagedPointer, buf.size()) != 0)
772+
{
773+
std::fill(buf.begin(), buf.end(), 0);
774+
strncpy(buf.data(), uiM->uiManagedPointer, buf.size() - 1);
775+
AudioToUIMsg out{AudioToUIMsg::SET_MACRO_NAME};
776+
out.paramId = idx;
777+
out.patchNamePointer = buf.data();
778+
audioToUi.push(out);
779+
pendingRescan |= RescanRequest::INFO;
780+
}
776781
}
777782
}
778783
break;
@@ -785,20 +790,15 @@ void Synth::processUIQueue(const clap_output_events_t *outq)
785790
case MainToAudioMsg::SEND_POST_LOAD:
786791
{
787792
postLoad();
793+
// Preset load just rewrote every param value — let the host re-read.
794+
pendingRescan |= RescanRequest::VALUES;
788795
}
789796
break;
790797
case MainToAudioMsg::SEND_PREP_FOR_STREAM:
791798
{
792799
prepForStream();
793800
}
794801
break;
795-
case MainToAudioMsg::SEND_REQUEST_RESCAN:
796-
{
797-
onMainRescanParams = true;
798-
audioToUi.push({AudioToUIMsg::DO_PARAM_RESCAN});
799-
clapHost->request_callback(clapHost);
800-
}
801-
break;
802802
case MainToAudioMsg::EDITOR_ATTACH_DETATCH:
803803
{
804804
isEditorAttached = uiM->paramId;
@@ -830,6 +830,10 @@ void Synth::processUIQueue(const clap_output_events_t *outq)
830830
}
831831
uiM = mainToAudio.pop();
832832
}
833+
834+
// One coalesced rescan request per drain pass.
835+
if (pendingRescan)
836+
requestParamRescan(pendingRescan);
833837
}
834838

835839
void Synth::reapplyControlSettings()
@@ -930,16 +934,26 @@ void Synth::resetSoloState()
930934

931935
void Synth::onMainThread()
932936
{
933-
bool ex{true}, re{false};
934-
if (onMainRescanParams.compare_exchange_strong(ex, re))
935-
{
936-
auto pe = static_cast<const clap_host_params_t *>(
937-
clapHost->get_extension(clapHost, CLAP_EXT_PARAMS));
938-
if (pe)
939-
{
940-
pe->rescan(clapHost, CLAP_PARAM_RESCAN_VALUES | CLAP_PARAM_RESCAN_TEXT);
941-
}
942-
}
937+
auto flags = onMainRescanFlags.exchange(0, std::memory_order_acquire);
938+
if (flags == 0 || !clapHost)
939+
return;
940+
auto pe =
941+
static_cast<const clap_host_params_t *>(clapHost->get_extension(clapHost, CLAP_EXT_PARAMS));
942+
if (!pe)
943+
return;
944+
// CLAP says INFO is mutually exclusive with VALUES; issue separately.
945+
if (flags & RescanRequest::VALUES)
946+
pe->rescan(clapHost, CLAP_PARAM_RESCAN_VALUES);
947+
if (flags & RescanRequest::INFO)
948+
pe->rescan(clapHost, CLAP_PARAM_RESCAN_INFO);
949+
}
950+
951+
void Synth::requestParamRescan(uint32_t flags)
952+
{
953+
if (flags == 0 || !clapHost)
954+
return;
955+
onMainRescanFlags.fetch_or(flags, std::memory_order_release);
956+
clapHost->request_callback(clapHost);
943957
}
944958

945959
} // namespace baconpaul::six_sines

src/synth/synth.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,6 @@ struct Synth
339339
UPDATE_CPU_USAGE,
340340
SET_PATCH_NAME,
341341
SET_PATCH_DIRTY_STATE,
342-
DO_PARAM_RESCAN, // paramId optionally carries CLAP_PARAM_RESCAN_*
343-
// flags; 0 falls back to VALUES|TEXT
344342

345343
SEND_SAMPLE_RATE,
346344
SET_DAW_EXTRA_STATE,
@@ -366,7 +364,6 @@ struct Synth
366364
SEND_PATCH_AUTHOR,
367365
SEND_PATCH_IS_CLEAN,
368366
SEND_POST_LOAD,
369-
SEND_REQUEST_RESCAN,
370367
EDITOR_ATTACH_DETATCH, // paramid is true for attach and false for detach
371368
SEND_PREP_FOR_STREAM,
372369
PANIC_STOP_VOICES,
@@ -379,6 +376,20 @@ struct Synth
379376
const char *uiManagedPointer{nullptr};
380377
const void *dawExtraStatePointer{nullptr};
381378
};
379+
380+
// Rescan request flags accumulated in onMainRescanFlags. Bit positions match
381+
// CLAP's CLAP_PARAM_RESCAN_* so onMainThread can map them with no translation.
382+
// The indirection lets non-CLAP layers stay CLAP-header-clean.
383+
enum RescanRequest : uint32_t
384+
{
385+
VALUES = 1 << 0,
386+
INFO = 1 << 2,
387+
ALL = VALUES | INFO
388+
};
389+
390+
// Thread-safe; accumulates flags and asks the host to call us back on the main
391+
// thread, where onMainThread() will issue the actual clap rescans.
392+
void requestParamRescan(uint32_t flags);
382393
using audioToUIQueue_t = sst::cpputils::SimpleRingBuffer<AudioToUIMsg, 1024 * 16>;
383394
using mainToAudioQueue_T = sst::cpputils::SimpleRingBuffer<MainToAudioMsg, 1024 * 64>;
384395
audioToUIQueue_t audioToUi;
@@ -422,7 +433,7 @@ struct Synth
422433
}
423434
}
424435

425-
std::atomic<bool> onMainRescanParams{false};
436+
std::atomic<uint32_t> onMainRescanFlags{0};
426437
void onMainThread();
427438

428439
void reapplyControlSettings();

src/ui/macro-sub-panel.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,8 @@ void MacroSubPanel::commitName()
378378
msg.paramId = static_cast<uint32_t>(index);
379379
msg.uiManagedPointer = buf.data();
380380
editor.mainToAudio.push(msg);
381+
// The audio-side SEND_MACRO_NAME handler diffs against the current name and
382+
// requests an INFO rescan via Synth::requestParamRescan when it actually changes.
381383

382384
if (editor.macroPanel && index < editor.macroPanel->labels.size() &&
383385
editor.macroPanel->labels[index])

src/ui/six-sines-editor.cpp

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -361,22 +361,6 @@ void SixSinesEditor::idle()
361361
presetDataBinding->setDirtyState(patchCopy.dirty);
362362
presetButton->repaint();
363363
}
364-
else if (aum->action == Synth::AudioToUIMsg::DO_PARAM_RESCAN)
365-
{
366-
if (!clapParamsExtension)
367-
clapParamsExtension = static_cast<const clap_host_params_t *>(
368-
clapHost->get_extension(clapHost, CLAP_EXT_PARAMS));
369-
if (clapParamsExtension)
370-
{
371-
// RESCAN_INFO is mutually exclusive with VALUES/TEXT — honour an
372-
// explicit flag in paramId when set, default otherwise.
373-
auto flags = aum->paramId != 0
374-
? aum->paramId
375-
: (uint32_t)(CLAP_PARAM_RESCAN_VALUES | CLAP_PARAM_RESCAN_TEXT);
376-
clapParamsExtension->rescan(clapHost, flags);
377-
clapParamsExtension->request_flush(clapHost);
378-
}
379-
}
380364
else if (aum->action == Synth::AudioToUIMsg::SEND_SAMPLE_RATE)
381365
{
382366
engineSR = aum->value2;

0 commit comments

Comments
 (0)