One undo-block opener for the whole tree: fourteen sites route through it, and the reclaim span can no longer swallow a user's act

The drain refuses a tick inside a foreign block; applyMode wakes the reclaimer
before it opens the span.
This commit is contained in:
2026-08-07 16:38:11 -04:00
parent b2f6b3f1d0
commit b7b93a7ac3
25 changed files with 561 additions and 313 deletions
+30 -29
View File
@@ -22,6 +22,7 @@
#include "core/wire/instrument_drop.h" // pure buildInstrumentDropPreset (.vstpreset image for a sampleId)
#include "shell/actions/instrument_drop_win.h" // shell loadInstrumentOntoTrack (FX add+apply, no own undo block)
#include "shell/persist/session.h" // ReaSamplerSession
#include "shell/undo/undo_block.h" // the ONE undo-block opener
#include "core/capture/wav_codec.h" // parseWavLayout (32f fast-path validator), buildFloat32Wav, hashWavContent
@@ -36,8 +37,6 @@
#define REAPERAPI_WANT_GetMediaSourceNumChannels
#define REAPERAPI_WANT_GetMediaSourceSampleRate
#define REAPERAPI_WANT_GetMediaSourceLength
#define REAPERAPI_WANT_Undo_BeginBlock2
#define REAPERAPI_WANT_Undo_EndBlock2
#define REAPERAPI_WANT_GetSelectedTrack
#include "reaper_plugin_functions.h"
@@ -362,14 +361,14 @@ void doImportFromMediaExplorer() {
// so any open VST3 browser instances refresh to show the new sound.
bool persisted = true; // true when nothing needed persisting (dedup)
if (r.added) {
Undo_BeginBlock2(nullptr);
g_session->bumpBankGeneration();
persisted = g_session->saveToActiveProject();
if (persisted)
Undo_EndBlock2(nullptr, "ReaSampler: import Media Explorer file into bank",
UNDO_STATE_MISCCFG);
else
Undo_EndBlock2(nullptr, "", 0);
{
UndoBlock undo(nullptr);
g_session->bumpBankGeneration();
persisted = g_session->saveToActiveProject();
if (persisted)
undo.recordPoint("ReaSampler: import Media Explorer file into bank",
UNDO_STATE_MISCCFG);
}
bankPanelRefresh();
}
ShowConsoleMsg(("ReaSampler ingest: " + r.message +
@@ -386,20 +385,21 @@ void doImportFromMediaExplorer() {
// Persist happens INSIDE the block and BEFORE the FX add so the new instance's
// setState -> reloadInstrument sees the just-persisted sample.
Undo_BeginBlock2(nullptr);
bool persisted = true; // true when nothing needed persisting (dedup)
if (r.added) {
g_session->bumpBankGeneration();
persisted = g_session->saveToActiveProject();
bool placed = false;
{
UndoBlock undo(nullptr);
if (r.added) {
g_session->bumpBankGeneration();
persisted = g_session->saveToActiveProject();
}
placed = loadInstrumentOntoTrack(target, preset);
// Anything else — the FX add/inject failed (already rolled back, no orphan), or
// the project was unsaved (persist no-op) — records no point at all.
if (placed && persisted)
undo.recordPoint("ReaSampler: import from Media Explorer into selected track",
UNDO_STATE_MISCCFG);
}
const bool placed = loadInstrumentOntoTrack(target, preset);
if (placed && persisted)
Undo_EndBlock2(nullptr, "ReaSampler: import from Media Explorer into selected track",
UNDO_STATE_MISCCFG);
else
// Either the FX add/inject failed (already rolled back, no orphan) or the
// project was unsaved (persist no-op): discard so no empty point is recorded.
Undo_EndBlock2(nullptr, "", 0);
bankPanelRefresh();
if (placed)
@@ -450,13 +450,14 @@ void ingestDroppedFiles(const std::vector<std::string>& absolutePaths) {
// One undo point for the whole drop, opened only if a NEW index entry was created.
if (importedNew > 0) {
Undo_BeginBlock2(nullptr);
g_session->bumpBankGeneration();
const bool persisted = g_session->saveToActiveProject();
if (persisted)
Undo_EndBlock2(nullptr, "ReaSampler: import dropped file(s)", UNDO_STATE_MISCCFG);
else
Undo_EndBlock2(nullptr, "", 0);
bool persisted = false;
{
UndoBlock undo(nullptr);
g_session->bumpBankGeneration();
persisted = g_session->saveToActiveProject();
if (persisted)
undo.recordPoint("ReaSampler: import dropped file(s)", UNDO_STATE_MISCCFG);
}
bankPanelRefresh();
const std::string msg =
"ReaSampler ingest: imported " + std::to_string(importedTotal) +