Restore the bank fold and usage publish to the resume path, guard setActive against repeats, and make the meter fold's bound literal
The resume also hands back to a full reload when the fold moves the loaded capture's decode source, so the refs table and the audio cannot skew.
This commit is contained in:
@@ -268,8 +268,7 @@ void ReaSamplerProcessor::publishUsage(const SampleRefs& refs,
|
||||
}
|
||||
|
||||
void ReaSamplerProcessor::publishBuiltLocked(std::unique_ptr<LoadedInstrument> built) {
|
||||
// REQUIRES reloadMutex_ held. Shared by reloadInstrument and rebuildVoiceEngine — the
|
||||
// one safety-critical swap dance (see the header's drain-slot proof).
|
||||
// REQUIRES reloadMutex_ held (see the header's drain-slot proof).
|
||||
const std::uint64_t seen = processGeneration_.load(std::memory_order_acquire);
|
||||
graveyard_.erase(
|
||||
std::remove_if(graveyard_.begin(), graveyard_.end(),
|
||||
@@ -347,9 +346,45 @@ bool ReaSamplerProcessor::resumeDormantInstrument() {
|
||||
// park. Rebuilding here would displace a correct instrument into the drain slot.
|
||||
if (live_.load(std::memory_order_acquire)) return true;
|
||||
if (!dormantSample_) return false;
|
||||
|
||||
// The activation is still where a bank change made with NO EDITOR OPEN is picked up:
|
||||
// pollBankSync, the only other route to either of the two calls below, runs off the
|
||||
// editor's sync tick and nothing else. Both are a GetProjExtState plus a parse — no disk
|
||||
// and no decode, which is what lets them stay on a path whose whole point is skipping
|
||||
// those two.
|
||||
const std::string selId = selectedSampleId();
|
||||
const std::vector<std::string> ids = referencedSampleIds(selId);
|
||||
SampleRefs refs;
|
||||
bool sourceMoved = false;
|
||||
{
|
||||
std::optional<std::string> banksJson =
|
||||
bridge_.readReasamplerExtState(kProjExtBanksKey);
|
||||
std::lock_guard<std::mutex> rl(refsMutex_);
|
||||
if (banksJson) {
|
||||
const SelectedSample* before = findRef(sampleRefs_, selId);
|
||||
const std::optional<SelectedSample> was =
|
||||
before ? std::optional<SelectedSample>(*before) : std::nullopt;
|
||||
refreshRefsFromBank(sampleRefs_, *banksJson, ids);
|
||||
const SelectedSample* now = findRef(sampleRefs_, selId);
|
||||
sourceMoved = !was || !now || !sameDecodeSource(*was, *now);
|
||||
}
|
||||
refs = sampleRefs_;
|
||||
}
|
||||
// A recapture that landed while this instance was inactive makes the park the WRONG audio,
|
||||
// and refreshing the refs without re-decoding would leave the table naming one file while
|
||||
// the voices play another. Hand back to the full reload, which decodes the new one.
|
||||
if (sourceMoved) return false;
|
||||
|
||||
// MOVED, not copied: the park exists for this one handoff, and keeping it would hold a
|
||||
// second copy of the PCM for the whole active lifetime.
|
||||
publishBuiltLocked(buildInstrumentLocked(std::move(*dormantSample_)));
|
||||
// second copy of the PCM for the whole active lifetime. Disengaged BEFORE the build so a
|
||||
// throwing build leaves nothing to resume — the next activation then takes the reload
|
||||
// rather than publishing an empty sample as permanent silence.
|
||||
SampleData resumed = std::move(*dormantSample_);
|
||||
dormantSample_.reset();
|
||||
publishBuiltLocked(buildInstrumentLocked(std::move(resumed)));
|
||||
// The prune-protection republish reloadInstrument owes on every publish: it is also what
|
||||
// heals an rsusage_ key whose write failed when this instance last set its state.
|
||||
publishUsage(refs, ids);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user