116 lines
6.0 KiB
C++
116 lines
6.0 KiB
C++
// deck_groups.h — WHICH groups the Sample face's knob deck carries and in what order, plus
|
|
// the control-id space they are built from. Pure data: knob_deck lays out whatever descriptors
|
|
// it is handed, and this module decides what those descriptors are, so the deck's signal-flow
|
|
// ordering is provable without a host.
|
|
|
|
#pragma once
|
|
|
|
#include <vector>
|
|
|
|
#include "core/instrument/engine/play_params.h" // PlayMode (the AMP group's Gate/Trigger face)
|
|
#include "core/instrument/ui/knob_deck.h" // DeckGroupDesc
|
|
|
|
namespace reasampler::instrument::ui {
|
|
|
|
// Deck control ids. Opaque to knob_deck, resolved by the shell's hit-test and value binding.
|
|
// Runtime-only — nothing persists them, so the ordering here is free to change.
|
|
enum class DeckParam {
|
|
kPlayMode = 0, // Gate | Trigger toggle
|
|
kPitchEngine, // Varispeed | Preserve toggle
|
|
kAttack, // AHDSR attack (Gate) / —
|
|
kHold, // AHDSR hold (Gate)
|
|
kDecay, // AHDSR decay (Gate)
|
|
kSustain, // AHDSR sustain (Gate)
|
|
kRelease, // AHDSR release (Gate)
|
|
kTrigLength, // Trigger %-length
|
|
kTrigFadeIn, // Trigger fade-in
|
|
kTrigFadeOut, // Trigger fade-out
|
|
kPitchEnvEnable, // AD pitch envelope on|off
|
|
kPitchEnvAttack, // AD pitch attack
|
|
kPitchEnvDecay, // AD pitch decay
|
|
kPitchEnvDepth, // AD pitch depth in +/- semitones
|
|
kKeyTrack, // key-tracking 0..200% (lives on InstrumentParams, not PlaySeconds)
|
|
// Filter. The four control positions map through filter_params' own laws; the three
|
|
// depths are bipolar and centred at zero.
|
|
kFilterEnable, // filter on|off caption toggle
|
|
kFilterMorph, // morph position: high-pass .. low-pass
|
|
kFilterCutoff, // cutoff, log across the audio band
|
|
kFilterQ, // resonance
|
|
kFilterDrive, // in-loop drive depth
|
|
kFilterModAmt, // filter envelope -> cutoff, +/-100%
|
|
kFilterVel, // velocity -> cutoff, +/-100%
|
|
kFilterKeyTrack, // note -> cutoff, 0..200%
|
|
kFilterLaw, // morph law row toggle: HP-BP-LP | HP-notch-LP
|
|
kFilterEnvAttack,
|
|
kFilterEnvHold,
|
|
kFilterEnvDecay,
|
|
kFilterEnvSustain,
|
|
kFilterEnvRelease,
|
|
// Deck-only controls: processor-side per-instance params — routed to the processor
|
|
// setters, never through the parameter set.
|
|
kVoiceCount, // polyphony bound (1..32) — a stepped knob in the VOICE group
|
|
kVoiceMode, // Poly | Mono caption toggle (VOICE group)
|
|
kMonoTrigger, // Retrig | Legato row toggle (VOICE group; live only in Mono)
|
|
kMasterGain, // post-mixer master gain knob (-inf..+24 dB taper, MASTER group)
|
|
kCount
|
|
};
|
|
|
|
// Deck group ids. Unscoped so the shell's caption switch reads against the plain `id` int
|
|
// knob_deck carries.
|
|
enum DeckGroupId {
|
|
kGroupPitch = 0,
|
|
kGroupPitchEnv,
|
|
kGroupFilter,
|
|
kGroupFilterEnv,
|
|
kGroupAmpEnv,
|
|
kGroupVoice,
|
|
kGroupMaster,
|
|
};
|
|
|
|
// The deck's groups, left to right, in SIGNAL-FLOW order: pitch -> filter -> amp, then the
|
|
// two instance-wide groups. `playMode` picks the AMP group's face, via knob_deck's blank-cell
|
|
// reservation (knob_deck.h) so a mode flip never reflows the neighbouring groups.
|
|
std::vector<DeckGroupDesc> sampleDeckGroups(PlayMode playMode);
|
|
|
|
// Whether control `id` is delivered LIVE — straight to the voices that are already sounding —
|
|
// rather than through an instrument reload. The line is drawn at continuously-valued playback
|
|
// controls, so this is a routing decision at the editor's commit site rather than a property
|
|
// of any one knob; moving a control across the line is a change here and nowhere else.
|
|
//
|
|
// THE home for why each excluded control is excluded. Five continuous controls are outside the
|
|
// live set, plus every discrete toggle:
|
|
// - the discrete toggles (play mode, pitch engine, filter enable/law, pitch-envelope enable)
|
|
// name a different sound rather than a different setting of one;
|
|
// - the three capture-anchored overrides (root, loop span, start frame) name positions in
|
|
// the decoded PCM;
|
|
// - kKeyTrack and kFilterVel feed values a voice latches at note-on by design (the pitch
|
|
// ratio and the velocity-curve result), so live delivery would retune or re-gain a note
|
|
// already struck;
|
|
// - kTrigLength resolves playEnd_, a fact about the note. kTrigFadeIn/kTrigFadeOut are pure
|
|
// amplitude shape and would be live-able in principle, but they live in `sample.play` and
|
|
// are baked into SampleData at build time — the engine rebuild copies that verbatim, so
|
|
// only a reload can deliver them without widening LiveValues. They fold into the AHD
|
|
// alongside Gate's, at which point they inherit its routing; until then they reload.
|
|
// Consequence, stated plainly: a Trigger-mode instance gets NO live delivery on its amplitude
|
|
// controls. Only the filter and pitch-envelope knobs move a sounding Trigger one-shot.
|
|
bool isLiveDeckParam(DeckParam id);
|
|
|
|
// The editor drag kinds that can commit live, in this pure module's own vocabulary (the
|
|
// shell's DragKind maps onto it) so the WHOLE routing decision — not just the predicate — is
|
|
// testable without a host.
|
|
enum class LiveDragKind { kOther, kDeckKnob, kEnvNode };
|
|
|
|
// Whether a drag of `kind` commits live. A deck knob is live per isLiveDeckParam (negative ids
|
|
// are the shell's processor-side sentinels and out-of-range ids are not controls, so neither
|
|
// reaches the enum); an envelope-node drag is live only in Gate, where it edits the AHDSR —
|
|
// in Trigger the same drag rewrites the play span, which is not a live control.
|
|
bool liveCommitFor(LiveDragKind kind, int paramId, PlayMode playMode);
|
|
|
|
// The deck's BIPOLAR knob law: 0.5 of the knob's travel is zero depth, the ends are -1 and
|
|
// +1. Exact inverses, and exact at the centre detent (0.5 -> 0 -> 0.5), so a knob parked at
|
|
// centre can never persist a hair of modulation. Out-of-range norm clamps to the endpoints.
|
|
double deckBipolarFromNorm(double norm);
|
|
double deckNormFromBipolar(double value);
|
|
|
|
} // namespace reasampler::instrument::ui
|