159 lines
5.9 KiB
C++
159 lines
5.9 KiB
C++
// deck_groups.cpp — see deck_groups.h. Pure data; no host types.
|
|
|
|
#include "core/instrument/ui/deck_groups.h"
|
|
|
|
#include <utility>
|
|
|
|
namespace reasampler::instrument::ui {
|
|
|
|
namespace {
|
|
int id(DeckParam p) { return static_cast<int>(p); }
|
|
double clamp(double v, double lo, double hi) { return v < lo ? lo : (v > hi ? hi : v); }
|
|
} // namespace
|
|
|
|
double deckBipolarFromNorm(double norm) { return clamp(norm, 0.0, 1.0) * 2.0 - 1.0; }
|
|
double deckNormFromBipolar(double value) { return clamp(value, -1.0, 1.0) * 0.5 + 0.5; }
|
|
|
|
std::vector<DeckGroupDesc> sampleDeckGroups(PlayMode playMode) {
|
|
std::vector<DeckGroupDesc> out;
|
|
{
|
|
DeckGroupDesc pitch;
|
|
pitch.id = kGroupPitch;
|
|
pitch.captionWidth = 38;
|
|
pitch.captionToggle = {id(DeckParam::kPitchEngine), 48};
|
|
pitch.cellIds = {id(DeckParam::kKeyTrack)};
|
|
out.push_back(std::move(pitch));
|
|
}
|
|
{
|
|
DeckGroupDesc penv;
|
|
penv.id = kGroupPitchEnv;
|
|
penv.captionWidth = 58;
|
|
penv.captionToggle = {id(DeckParam::kPitchEnvEnable), 32};
|
|
penv.cellIds = {id(DeckParam::kPitchEnvAttack),
|
|
id(DeckParam::kPitchEnvDecay),
|
|
id(DeckParam::kPitchEnvDepth)};
|
|
out.push_back(std::move(penv));
|
|
}
|
|
{
|
|
// Tone shaping left-to-right, then the three modulation depths that all target cutoff.
|
|
DeckGroupDesc filter;
|
|
filter.id = kGroupFilter;
|
|
filter.captionWidth = 46;
|
|
filter.captionToggle = {id(DeckParam::kFilterEnable), 32};
|
|
filter.cellIds = {id(DeckParam::kFilterMorph),
|
|
id(DeckParam::kFilterCutoff),
|
|
id(DeckParam::kFilterQ),
|
|
id(DeckParam::kFilterDrive),
|
|
id(DeckParam::kFilterModAmt),
|
|
id(DeckParam::kFilterVel),
|
|
id(DeckParam::kFilterKeyTrack)};
|
|
filter.rowToggle = {id(DeckParam::kFilterLaw), 44};
|
|
out.push_back(std::move(filter));
|
|
}
|
|
{
|
|
DeckGroupDesc fenv;
|
|
fenv.id = kGroupFilterEnv;
|
|
fenv.captionWidth = 66;
|
|
fenv.cellIds = {id(DeckParam::kFilterEnvAttack),
|
|
id(DeckParam::kFilterEnvHold),
|
|
id(DeckParam::kFilterEnvDecay),
|
|
id(DeckParam::kFilterEnvSustain),
|
|
id(DeckParam::kFilterEnvRelease)};
|
|
out.push_back(std::move(fenv));
|
|
}
|
|
{
|
|
DeckGroupDesc amp;
|
|
amp.id = kGroupAmpEnv;
|
|
amp.captionWidth = 78;
|
|
amp.captionToggle = {id(DeckParam::kPlayMode), 44};
|
|
if (playMode == PlayMode::Gate) {
|
|
amp.cellIds = {id(DeckParam::kAttack), id(DeckParam::kHold),
|
|
id(DeckParam::kDecay), id(DeckParam::kSustain),
|
|
id(DeckParam::kRelease)};
|
|
} else {
|
|
// Trigger, time-ordered left-to-right (Fade In / Length % / Fade Out — matches
|
|
// the drawn envelope), plus two blanks (see knob_deck.h's blank-cell contract).
|
|
amp.cellIds = {id(DeckParam::kTrigFadeIn), id(DeckParam::kTrigLength),
|
|
id(DeckParam::kTrigFadeOut), -1, -1};
|
|
}
|
|
out.push_back(std::move(amp));
|
|
}
|
|
{
|
|
DeckGroupDesc voice;
|
|
voice.id = kGroupVoice;
|
|
voice.captionWidth = 38;
|
|
voice.captionToggle = {id(DeckParam::kVoiceMode), 40};
|
|
voice.cellIds = {id(DeckParam::kVoiceCount)};
|
|
voice.rowToggle = {id(DeckParam::kMonoTrigger), 44};
|
|
out.push_back(std::move(voice));
|
|
}
|
|
{
|
|
DeckGroupDesc master;
|
|
master.id = kGroupMaster;
|
|
master.captionWidth = 46;
|
|
master.cellIds = {id(DeckParam::kMasterGain)};
|
|
out.push_back(std::move(master));
|
|
}
|
|
return out;
|
|
}
|
|
|
|
bool isLiveDeckParam(DeckParam id) {
|
|
switch (id) {
|
|
case DeckParam::kAttack:
|
|
case DeckParam::kHold:
|
|
case DeckParam::kDecay:
|
|
case DeckParam::kSustain:
|
|
case DeckParam::kRelease:
|
|
case DeckParam::kPitchEnvAttack:
|
|
case DeckParam::kPitchEnvDecay:
|
|
case DeckParam::kPitchEnvDepth:
|
|
case DeckParam::kFilterMorph:
|
|
case DeckParam::kFilterCutoff:
|
|
case DeckParam::kFilterQ:
|
|
case DeckParam::kFilterDrive:
|
|
case DeckParam::kFilterModAmt:
|
|
case DeckParam::kFilterKeyTrack:
|
|
case DeckParam::kFilterEnvAttack:
|
|
case DeckParam::kFilterEnvHold:
|
|
case DeckParam::kFilterEnvDecay:
|
|
case DeckParam::kFilterEnvSustain:
|
|
case DeckParam::kFilterEnvRelease:
|
|
return true;
|
|
// Listed rather than defaulted so a newly added control is a COMPILE error here (the
|
|
// -Wswitch gate is GCC/Clang; MSVC's C4062 is off at this project's warning level)
|
|
// instead of silently defaulting to non-live. Reasons live in the header.
|
|
case DeckParam::kPlayMode:
|
|
case DeckParam::kPitchEngine:
|
|
case DeckParam::kTrigLength:
|
|
case DeckParam::kTrigFadeIn:
|
|
case DeckParam::kTrigFadeOut:
|
|
case DeckParam::kPitchEnvEnable:
|
|
case DeckParam::kKeyTrack:
|
|
case DeckParam::kFilterEnable:
|
|
case DeckParam::kFilterVel:
|
|
case DeckParam::kFilterLaw:
|
|
case DeckParam::kVoiceCount:
|
|
case DeckParam::kVoiceMode:
|
|
case DeckParam::kMonoTrigger:
|
|
case DeckParam::kMasterGain:
|
|
case DeckParam::kCount: // not a control
|
|
return false;
|
|
}
|
|
return false; // unreachable for a valid enumerator; silences a warning.
|
|
}
|
|
|
|
bool liveCommitFor(LiveDragKind kind, int paramId, PlayMode playMode) {
|
|
switch (kind) {
|
|
case LiveDragKind::kDeckKnob:
|
|
return paramId >= 0 && paramId < static_cast<int>(DeckParam::kCount) &&
|
|
isLiveDeckParam(static_cast<DeckParam>(paramId));
|
|
case LiveDragKind::kEnvNode:
|
|
return playMode == PlayMode::Gate;
|
|
case LiveDragKind::kOther:
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
} // namespace reasampler::instrument::ui
|