Skip to content

Commit

Permalink
Low Frequency KeyTrack option (#205)
Browse files Browse the repository at this point in the history
Keytrack now has a toggle to either be in the
audible (midi keybed) or low frequency (0-10hz)
range, with the slider adjusting accordingly.

Closes #203
  • Loading branch information
baconpaul authored Feb 2, 2025
1 parent 92ee0d2 commit 802ce60
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 18 deletions.
16 changes: 12 additions & 4 deletions src/dsp/op_source.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ struct alignas(16) OpSource : public EnvelopeSupport<Patch::SourceNode>,

bool keytrack{true};
const float &ratio, &activeV, &envToRatio, &lfoToRatio, &envToRatioFine,
&lfoToRatioFine; // in frequency multiple
const float &waveForm, &kt, &ktv, &startPhase, &octTranspose; // in octaves;
&lfoToRatioFine; // in frequency multiple
const float &waveForm, &kt, &ktv, &ktlo, &ktlov, &startPhase, &octTranspose; // in octaves;
bool active{false};
bool unisonParticipatesPan{true}, unisonParticipatesTune{true};
bool operatorOutputsToMain{true}, operatorOutputsToOp{true};
Expand All @@ -64,6 +64,7 @@ struct alignas(16) OpSource : public EnvelopeSupport<Patch::SourceNode>,
LFOSupport(sn, mv), ModulationSupport(sn, this, mv, vv), ratio(sn.ratio),
activeV(sn.active), envToRatio(sn.envToRatio), lfoToRatio(sn.lfoToRatio),
waveForm(sn.waveForm), kt(sn.keyTrack), ktv(sn.keyTrackValue),
ktlo(sn.keyTrackValueIsLow), ktlov(sn.keyTrackLowFrequencyValue),
startPhase(sn.startingPhase), octTranspose(sn.octTranspose),
lfoToRatioFine(sn.lfoToRatioFine), envToRatioFine(sn.envToRatioFine)
{
Expand Down Expand Up @@ -169,8 +170,15 @@ struct alignas(16) OpSource : public EnvelopeSupport<Patch::SourceNode>,
}
else
{
// Consciously do *not* retune absolute mode oscillators
baseFrequency = 440 * monoValues.twoToTheX.twoToThe(ktv / 12);
if (ktlo > 0.5)
{
baseFrequency = ktlov; // its just in hertz
}
else
{
// Consciously do *not* retune absolute mode oscillators
baseFrequency = 440 * monoValues.twoToTheX.twoToThe(ktv / 12);
}
}
}

Expand Down
36 changes: 30 additions & 6 deletions src/synth/patch.h
Original file line number Diff line number Diff line change
Expand Up @@ -498,13 +498,26 @@ struct Patch : pats::PatchBase<Patch, Param>
.withGroupName(name(idx))
.withID(id(6, idx))
.withDefault(true)),
keyTrackValueIsLow(boolMd()
.withName(name(idx) + " Keytrack Frequency is Low Frequency")
.withGroupName(name(idx))
.withID(id(17, idx))
.withDefault(false)),
keyTrackValue(floatMd()
.withName(name(idx) + " Absolute Frequency at Ratio=1")
.withGroupName(name(idx))
.withDefault(0)
.withRange(-70, 70)
.withSemitoneZeroAt400Formatting()
.withID(id(7, idx))),
keyTrackLowFrequencyValue(
floatMd()
.withName(name(idx) + " Keytrack Frequency at Ratio=1 (Low Frequency)")
.withGroupName(name(idx))
.withRange(0, 10)
.withLinearScaleFormatting("Hz")
.withID(id(18, idx))
.withDefault(1)),
startingPhase(floatMd()
.withName(name(idx) + " Phase")
.withGroupName(name(idx))
Expand Down Expand Up @@ -586,7 +599,7 @@ struct Patch : pats::PatchBase<Patch, Param>

Param waveForm;

Param keyTrack, keyTrackValue;
Param keyTrack, keyTrackValue, keyTrackLowFrequencyValue, keyTrackValueIsLow;

Param startingPhase, octTranspose;

Expand All @@ -596,11 +609,22 @@ struct Patch : pats::PatchBase<Patch, Param>

std::vector<Param *> params()
{
std::vector<Param *> res{&ratio, &active, &envToRatio,
&lfoToRatio, &waveForm, &keyTrack,
&keyTrackValue, &startingPhase, &octTranspose,
&envToRatioFine, &lfoToRatioFine, &unisonParticipation,
&unisonToMain, &unisonToOpOut};
std::vector<Param *> res{&ratio,
&active,
&envToRatio,
&lfoToRatio,
&waveForm,
&keyTrack,
&keyTrackLowFrequencyValue,
&keyTrackValueIsLow,
&keyTrackValue,
&startingPhase,
&octTranspose,
&envToRatioFine,
&lfoToRatioFine,
&unisonParticipation,
&unisonToMain,
&unisonToOpOut};
for (int i = 0; i < numModsPer; ++i)
res.push_back(&modtarget[i]);
appendDAHDSRParams(res);
Expand Down
37 changes: 30 additions & 7 deletions src/ui/source-sub-panel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,19 +145,27 @@ void SourceSubPanel::setSelectedIndex(size_t idx)
addAndMakeVisible(*keyTrack);
traverse(keyTrack);

createComponent(editor, *this, sn.keyTrackValueIsLow, keyTrackLow, keyTrackLowD);
keyTrackLow->setLabel("Lo");
addAndMakeVisible(*keyTrackLow);
traverse(keyTrackLow);

createComponent(editor, *this, sn.keyTrackValue, keyTrackValue, keyTrackValueD);
addAndMakeVisible(*keyTrackValue);
keyTrackValueLL = std::make_unique<jcmp::Label>();
keyTrackValueLL->setText("f");
addAndMakeVisible(*keyTrackValueLL);
traverse(keyTrackValue);

createRescaledComponent(editor, *this, sn.keyTrackLowFrequencyValue, keyTrackLowValue,
keyTrackLowValueD);
addChildComponent(*keyTrackLowValue);

auto op = [w = juce::Component::SafePointer(this)]()
{
if (w)
w->setEnabledState();
};

keyTrackD->onGuiSetValue = op;
keyTrackLowD->onGuiSetValue = op;
editor.componentRefreshByID[sn.keyTrack.meta.id] = op;

createComponent(editor, *this, sn.octTranspose, tsposeButton, tsposeButtonD);
Expand Down Expand Up @@ -214,7 +222,6 @@ void SourceSubPanel::resized()

auto ktl = jlo::VList().withWidth(uicKnobSize * 2 + uicMargin + 36).withAutoGap(uicMargin);
ktl.add(titleLabelGaplessLayout(keyTrackTitle));
;

auto sktcol = jlo::HList().withAutoGap(uicMargin).withHeight(uicLabeledKnobHeight);

Expand All @@ -226,7 +233,14 @@ void SourceSubPanel::resized()

auto c2 = jlo::VList().withWidth(uicKnobSize + 18).withAutoGap(uicMargin);
c2.add(jlo::Component(*keyTrack).withHeight(uicLabelHeight));
c2.add(sideLabelSlider(keyTrackValueLL, keyTrackValue));

// We have to get a bit crunched to get this in
namespace jlo = sst::jucegui::layouts;
auto ul = jlo::HList().withHeight(uicLabelHeight);
ul.add(jlo::Component(*keyTrackLow).withWidth(20));
ul.addGap(1);
ul.add(jlo::Component(*keyTrackValue).insetBy(0, 2).expandToFill());
c2.add(ul);
sktcol.add(c2);

ktl.add(sktcol);
Expand All @@ -240,15 +254,24 @@ void SourceSubPanel::resized()

lo.doLayout();

// The keytrack low can sub in for the keytrack
keyTrackLowValue->setBounds(keyTrackValue->getBounds());

layoutModulation(p);
}

void SourceSubPanel::setEnabledState()
{
auto &sn = editor.patchCopy.sourceNodes[index];
auto ekt = sn.keyTrack.value < 0.5;
keyTrackValue->setEnabled(ekt);
keyTrackValueLL->setEnabled(ekt);
auto ktl = sn.keyTrackValueIsLow > 0.5;
keyTrackValue->setEnabled(ekt && !ktl);
keyTrackValue->setVisible(!ktl);

keyTrackLowValue->setEnabled(ekt && ktl);
keyTrackLowValue->setVisible(ktl);

keyTrackLow->setEnabled(ekt);
tsposeButton->setEnabled(!ekt);

unisonBehaviorB->setEnabled(editor.patchCopy.output.unisonCount > 1);
Expand Down
7 changes: 6 additions & 1 deletion src/ui/source-sub-panel.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,16 @@ struct SourceSubPanel : juce::Component,
std::unique_ptr<jcmp::ToggleButton> keyTrack;
std::unique_ptr<PatchDiscrete> keyTrackD;

std::unique_ptr<jcmp::ToggleButton> keyTrackLow;
std::unique_ptr<PatchDiscrete> keyTrackLowD;

std::unique_ptr<jcmp::TextPushButton> unisonBehaviorB;

std::unique_ptr<jcmp::HSliderFilled> keyTrackValue;
std::unique_ptr<PatchContinuous> keyTrackValueD;
std::unique_ptr<jcmp::Label> keyTrackValueLL;

std::unique_ptr<jcmp::HSliderFilled> keyTrackLowValue;
std::unique_ptr<PatchContinuous::cubic_t> keyTrackLowValueD;

std::unique_ptr<jcmp::HSliderFilled> startingPhase;
std::unique_ptr<PatchContinuous> startingPhaseD;
Expand Down

0 comments on commit 802ce60

Please sign in to comment.