fix(processor): close S-VIEW-4 previewVelocity persistence loop
Add previewVelocity_ member to ReaSamplerProcessor; populate it in getState and restore it in setState so the field round-trips in the plugin, not just in the pure unit test. Clamp 1..127 at the deserialize read boundary in sample_map.cpp.
This commit is contained in:
@@ -197,6 +197,9 @@ tresult PLUGIN_API ReaSamplerProcessor::setState(IBStream* state) {
|
||||
channelMode_ = cs.channelMode;
|
||||
}
|
||||
applyOutputArrangement(cs.channelMode);
|
||||
// S-VIEW-4: restore the per-instance preview velocity. No mutex — setState is a load-time
|
||||
// call serialized by the host; there is no concurrent writer before Wave 2.
|
||||
previewVelocity_ = cs.previewVelocity;
|
||||
// Rebuild from the restored state (off-thread — setState is a load-time call).
|
||||
reloadFromBank();
|
||||
return kResultOk;
|
||||
@@ -217,6 +220,7 @@ tresult PLUGIN_API ReaSamplerProcessor::getState(IBStream* state) {
|
||||
std::lock_guard<std::mutex> lock(assignMarkerMutex_);
|
||||
state_out.lastConsumedAssignGeneration = lastConsumedAssignGeneration_; // S8 reader marker
|
||||
}
|
||||
state_out.previewVelocity = previewVelocity_; // S-VIEW-4: persist the preview strike velocity
|
||||
const std::vector<std::uint8_t> bytes = serializeComponentState(state_out);
|
||||
if (!bytes.empty()) {
|
||||
const tresult wr = state->write(const_cast<std::uint8_t*>(bytes.data()),
|
||||
|
||||
@@ -250,6 +250,12 @@ private:
|
||||
// NOT read on the audio thread.
|
||||
std::int64_t lastSeenBankGeneration_ = -1;
|
||||
|
||||
// S-VIEW-4 preview-trigger velocity (MIDI 1..127). Persisted in component state (v6) so the
|
||||
// user's chosen strike velocity survives a project save/reload. No concurrent writer before
|
||||
// Wave 2 (no editor knob yet) — setState and getState are the sole accessors, both on the
|
||||
// load/save thread (host-serialized). Default kPreviewVelocityDefault (64).
|
||||
std::uint8_t previewVelocity_ = kPreviewVelocityDefault;
|
||||
|
||||
// Latched from setupProcessing so setActive/reload can size against it. Read
|
||||
// off-thread only. 0.0 is explicitly invalid — setupProcessing sets the real host rate
|
||||
// before any audio, and reloadFromBank guards on it before use.
|
||||
|
||||
@@ -628,7 +628,11 @@ ComponentState deserializeComponentState(const std::vector<std::uint8_t>& bytes,
|
||||
if (!r.ok) return out; // truncated before/inside the marker -> empty (marker 0 holds)
|
||||
const std::uint8_t previewVel = r.u8();
|
||||
if (!r.ok) return out; // truncated before the velocity byte -> empty (mid default holds)
|
||||
out.previewVelocity = previewVel;
|
||||
// Clamp to the documented MIDI 1..127 range: a 0 byte (or any out-of-spec value from a
|
||||
// corrupt blob) falls back to the mid default rather than silencing the preview trigger.
|
||||
out.previewVelocity = (previewVel >= 1 && previewVel <= 127)
|
||||
? previewVel
|
||||
: kPreviewVelocityDefault;
|
||||
const std::uint32_t idLen = r.u32();
|
||||
out.selectionId = r.str(idLen);
|
||||
if (!r.ok) { out.selectionId.clear(); return out; } // truncated id -> empty
|
||||
|
||||
Reference in New Issue
Block a user