PITCH/RATE deck: Rate and Pitch knobs compounded into one read increment, on a three-state commit predicate and payload v16
This commit is contained in:
@@ -69,14 +69,16 @@ scattered `#ifdef`s in the VST shell, except the one described below).
|
||||
(`DEF_CLASS2` / `INLINE_UID` / `FUID` from `pluginfactory.h` + `funknown.h`).
|
||||
|
||||
**The three commit tiers (Θ-W3).** An edit reaches the audio by exactly one of three routes, and
|
||||
which route a control takes is decided once, by the pure `isLiveDeckParam` / `liveCommitFor` pair
|
||||
which route a control takes is decided once, by the pure `deckParamCommit` / `liveCommitFor` pair
|
||||
(`core/instrument/ui/deck_groups`) that the editor's `dragCommitsLive` only maps onto — see
|
||||
`core/instrument/CLAUDE.md`'s "Live parameter delivery" for the rule and its rationale.
|
||||
1. **Full reload** — `reloadInstrument`: bridge read, WAV re-decode, fresh engine, snapshot swap.
|
||||
2. **Engine rebuild** — `rebuildVoiceEngine`: same drain-slot swap around the already-decoded
|
||||
`SampleData`. Voice count / mode / mono trigger.
|
||||
3. **Live** — `publishLiveParams` (and `masterGain_`, the original of the shape): a lock-free
|
||||
publish the audio thread observes at block boundaries. No rebuild, no snapshot, no disk.
|
||||
publish the audio thread observes at block boundaries. No rebuild, no snapshot, no disk. The
|
||||
pure predicate splits this tier by WHO READS the published value (`Live` vs `NoteOnLatched`);
|
||||
the route out of the editor is the same one either way.
|
||||
|
||||
The editor's `commitLive` is the tier-3 peer of `commitAndReload`; why it still writes the
|
||||
parameter set is recorded at its declaration in `reasampler_editor.h`, and why `liveParams_` is
|
||||
|
||||
@@ -211,6 +211,16 @@ std::string ReaSamplerEditor::deckValueLabel(int id) const {
|
||||
snprintf(buf, sizeof(buf), "%+.1fst", play.pitchEnv.peakSemitones); break;
|
||||
case ParamControl::kKeyTrack:
|
||||
snprintf(buf, sizeof(buf), "%.0f%%", params_.keyTrack * 100.0); break;
|
||||
case ParamControl::kRate: {
|
||||
// One decimal below 100 % only: the taper is linear in semitones, so the lower half
|
||||
// spends 50 percentage points on the same twelve semitones the upper half spends
|
||||
// 100 on — a whole percent is twice as coarse a step down there.
|
||||
const double pct = play.playRate * 100.0;
|
||||
snprintf(buf, sizeof(buf), pct < 100.0 ? "%.1f%%" : "%.0f%%", pct);
|
||||
break;
|
||||
}
|
||||
case ParamControl::kPitch:
|
||||
snprintf(buf, sizeof(buf), "%+.1fst", play.pitchOffsetSemitones); break;
|
||||
case ParamControl::kVoiceCount:
|
||||
snprintf(buf, sizeof(buf), "%d", voiceCount_); break;
|
||||
case ParamControl::kMasterGain:
|
||||
|
||||
@@ -73,6 +73,8 @@ void ReaSamplerEditor::paintDeck(LICE_IBitmap* bmp, const FaceLayout& fl) {
|
||||
case ParamControl::kTrigHold: return "Hold";
|
||||
case ParamControl::kTrigDecay: return "Decay";
|
||||
case ParamControl::kKeyTrack: return "Key Trk";
|
||||
case ParamControl::kRate: return "Rate";
|
||||
case ParamControl::kPitch: return "Pitch";
|
||||
case ParamControl::kPitchEnvAttack: return "P.Att";
|
||||
case ParamControl::kPitchEnvHold: return "P.Hold";
|
||||
case ParamControl::kPitchEnvDecay: return "P.Dec";
|
||||
@@ -109,7 +111,7 @@ void ReaSamplerEditor::paintDeck(LICE_IBitmap* bmp, const FaceLayout& fl) {
|
||||
const char* caption = "";
|
||||
switch (g.id) {
|
||||
case kGroupAmpEnv: caption = "AMP ENVELOPE"; break;
|
||||
case kGroupPitch: caption = "PITCH"; break;
|
||||
case kGroupPitch: caption = "PITCH/RATE"; break;
|
||||
case kGroupPitchEnv: caption = "PITCH ENV"; break;
|
||||
case kGroupFilter: caption = "FILTER"; break;
|
||||
case kGroupFilterEnv: caption = "FILTER ENV"; break;
|
||||
|
||||
@@ -190,7 +190,10 @@ bool ReaSamplerEditor::dragCommitsLive(DragKind kind, int paramId) const {
|
||||
const LiveDragKind k = kind == DragKind::kDeckKnob ? LiveDragKind::kDeckKnob
|
||||
: kind == DragKind::kEnvNode ? LiveDragKind::kEnvNode
|
||||
: LiveDragKind::kOther;
|
||||
return instrument::ui::liveCommitFor(k, paramId);
|
||||
// Live and NoteOnLatched take the SAME route out of here — one publish, no reload — so the
|
||||
// shell's question is only "does this reload?". Which voices then read the published value
|
||||
// is the engine's business (deck_groups.h).
|
||||
return instrument::ui::liveCommitFor(k, paramId) != instrument::ui::LiveCommit::Reload;
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::closeCurvePopup() {
|
||||
|
||||
@@ -276,14 +276,14 @@ private:
|
||||
// instrument off the audio thread. UI thread only.
|
||||
void commitAndReload();
|
||||
|
||||
// The live peer of commitAndReload for a continuously-valued control (isLiveDeckParam):
|
||||
// The live peer of commitAndReload for a continuously-valued control (deckParamCommit):
|
||||
// the same parameter-set write — so a saved project carries the edit exactly as before —
|
||||
// followed by a live publish instead of a rebuild, so the note already sounding follows
|
||||
// the knob. Does not repaint; callers already do. UI thread only.
|
||||
void commitLive();
|
||||
|
||||
// Whether an in-flight drag commits live rather than through a reload. A deck knob is
|
||||
// live per isLiveDeckParam; an envelope-node drag is live in EITHER mode — see
|
||||
// live per deckParamCommit; an envelope-node drag is live in EITHER mode — see
|
||||
// liveCommitFor (deck_groups.h) for why.
|
||||
bool dragCommitsLive(DragKind kind, int paramId = -1) const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user