fix(vst): pin output bus to stereo (mode is decode-only) killing the hard-right pan; auto-default channel mode from the loaded capture (state v9)
This commit is contained in:
@@ -102,12 +102,11 @@ public:
|
||||
Steinberg::tresult PLUGIN_API process(
|
||||
Steinberg::Vst::ProcessData& data) override;
|
||||
|
||||
// S7 channel-mode bus negotiation. The instrument has ONE canonical output arrangement
|
||||
// determined by its per-instance channel mode (mono -> kMono, stereo -> kStereo). We
|
||||
// accept the host's proposal only when it matches that arrangement; otherwise we reject
|
||||
// (kResultFalse) but keep the mode's arrangement, so getBusArrangement / getBusInfo always
|
||||
// report the mode's channel count and REAPER routes accordingly. A runtime mode change
|
||||
// updates the output bus + calls restartComponent(kIoChanged) to trigger re-negotiation.
|
||||
// Output-bus negotiation. The instrument has ONE canonical output arrangement: a FIXED
|
||||
// stereo bus (GA fix — the channel mode is a decode policy, never a bus fact; mono mode
|
||||
// renders dual-mono through it). We accept the host's proposal only when it is a single
|
||||
// stereo output; otherwise we reject (kResultFalse) but keep our stereo arrangement, so
|
||||
// getBusArrangement / getBusInfo always report 2 channels and the host routes accordingly.
|
||||
Steinberg::tresult PLUGIN_API setBusArrangements(
|
||||
Steinberg::Vst::SpeakerArrangement* inputs, Steinberg::int32 numIns,
|
||||
Steinberg::Vst::SpeakerArrangement* outputs, Steinberg::int32 numOuts) override;
|
||||
@@ -184,11 +183,14 @@ public:
|
||||
// (the editor toggle) and read off-thread by getState/reloadFromBank; guarded by
|
||||
// channelModeMutex_. NEVER read on the audio thread — process() renders against the host's
|
||||
// negotiated output channel count, and reloadFromBank bakes the mode into the decode.
|
||||
// GA fix: the mode is a DECODE policy only (downmix vs L/R split). The output bus is a
|
||||
// FIXED stereo bus — mono mode renders dual-mono through it (centered) — so a mode change
|
||||
// never renegotiates host I/O (the mono<->stereo bus flip's live pin remap was the
|
||||
// hard-right-pan defect).
|
||||
ChannelMode channelMode();
|
||||
// Sets the mode. When it CHANGES, updates the output bus arrangement (mono->kMono /
|
||||
// stereo->kStereo) and asks the host to re-negotiate I/O via restartComponent(kIoChanged),
|
||||
// then reloads the instrument so the next block decodes the new channel count. A no-op set
|
||||
// (same mode) does neither. UI thread only.
|
||||
// Sets the mode from the EDITOR TOGGLE (a deliberate user choice): latches the mode
|
||||
// EXPLICIT (the GA auto-default stops fighting it), and on a CHANGE reloads the instrument
|
||||
// so the next block decodes the new channel count. UI thread only.
|
||||
void setChannelMode(ChannelMode mode);
|
||||
|
||||
// The per-instance preview-trigger velocity (S-VIEW-4, MIDI 1..127). Read/written on the
|
||||
@@ -234,11 +236,6 @@ public:
|
||||
void previewNoteOff(int note);
|
||||
|
||||
private:
|
||||
// Apply `mode` to the output audio bus's SpeakerArrangement (kMono / kStereo). Called from
|
||||
// initialize (topology) and setChannelMode (runtime change). Does NOT re-negotiate — the
|
||||
// caller drives restartComponent when appropriate.
|
||||
void applyOutputArrangement(ChannelMode mode);
|
||||
|
||||
// Phase S drain retirement (FA1-review Major #2): if process() has published that the
|
||||
// CURRENT drain instrument is fully idle (every engine voice + the preview card silent),
|
||||
// move it out of the drain slot into the graveyard and prune — so an edited-away snapshot
|
||||
@@ -330,8 +327,12 @@ private:
|
||||
// The per-instance channel mode (S7). Off-thread only (UI + getState + reloadFromBank);
|
||||
// guarded against a getState/editor race. Default Mono preserves pre-S7 behavior. NOT read
|
||||
// on the audio thread — process renders against the host's negotiated output channel count.
|
||||
// channelModeExplicit_ (GA, persisted v9): false = the mode is an un-touched default that
|
||||
// reloadFromBank may auto-default from the loaded capture's channel count; true = the user
|
||||
// deliberately toggled the mode (setChannelMode latches it) and it is never fought.
|
||||
std::mutex channelModeMutex_;
|
||||
ChannelMode channelMode_ = ChannelMode::Mono;
|
||||
bool channelModeExplicit_ = false;
|
||||
|
||||
// The last assignment-request generation this instance CONSUMED (S8 reader). Persisted in
|
||||
// component state (v5) so a re-open does not re-apply a request the user already got and
|
||||
|
||||
Reference in New Issue
Block a user