Skip to content

Commit

Permalink
Finish mixer node
Browse files Browse the repository at this point in the history
Mixer node gets pan and LFO on screen, LFO routable to level or pan, and all hooked up and ready to go.
  • Loading branch information
baconpaul authored Dec 28, 2024
1 parent ae15d22 commit 2395ec0
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 16 deletions.
5 changes: 1 addition & 4 deletions doc/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ SOURCE:
- Keytrack on/off, and if off ratio -> offset from 440hz
- 90%-100% of internal nyquist mute fades (maybe ship without this tho)

MIXER:
- LFO on Mixer Node to level or pan

MODULATION:
- Each item gets a modulation list from source set
- Monophonic Midi source
Expand All @@ -27,11 +24,11 @@ CLAP
- An output per OP wher each output is just the solo OP * Main ADSR (and zero if the OP is off)

GENERAL AND CLEANUPS
- LFO in Pulse and S&H need a tiny little LPF to avoid super-clicka on modulation nodes (but not ratio nodes)
- Ctrl/Knob quantizes on ratio to PO2
- We could have an envelope which trigers as always-gated on release
- AM is somehow not quiet right. Signal to zero seems 'no modulation' not 'no output'
- Don't send VU etc when editor not attached
- LFO in Pulse and S&H need a tiny little LPF to avoid super-clicka on modulation nodes (but not ratio nodes)
- Main DAHDSR at DAHD=0 SR=1 means voice lifetime is longest active op mixer DAHDSR and main DAHDSR bypassed


1 change: 1 addition & 0 deletions resources/factory_patches/Leads/Sorta Super Saw.sxsnp

Large diffs are not rendered by default.

27 changes: 22 additions & 5 deletions src/dsp/matrix_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,23 +167,27 @@ struct MixerNode : EnvelopeSupport<Patch::MixerNode>, LFOSupport<Patch::MixerNod
const MonoValues &monoValues;
const VoiceValues &voiceValues;

const float &level, &activeF, &pan, &lfoToLevel, &lfoToPan;
bool active{false};
const float &level, &activeF, &pan, &lfoToLevel, &lfoToPan, &lfoMulV;
bool active{false}, lfoMul{false};

MixerNode(const Patch::MixerNode &mn, OpSource &f, const MonoValues &mv, const VoiceValues &vv)
: monoValues(mv), voiceValues(vv), sr(mv), from(f), pan(mn.pan), level(mn.level),
activeF(mn.active), lfoToLevel(mn.lfoToLevel), lfoToPan(mn.lfoToPan),
EnvelopeSupport(mn, mv, vv), LFOSupport(mn, mv)
EnvelopeSupport(mn, mv, vv), LFOSupport(mn, mv), lfoMulV(mn.envLfoSum)
{
memset(output, 0, sizeof(output));
}

void attack()
{
lfoMul = lfoMulV > 0.5;
active = activeF > 0.5;
memset(output, 0, sizeof(output));
if (active)
{
envAttack();
lfoAttack();
}
}

void renderBlock()
Expand All @@ -195,13 +199,26 @@ struct MixerNode : EnvelopeSupport<Patch::MixerNode>, LFOSupport<Patch::MixerNod
float vSum alignas(16)[blockSize];

envProcess();
lfoProcess();

if (lfoMul)
{
mech::scale_by<blockSize>(env.outputCache, lfo.outputBlock);
}

for (int j = 0; j < blockSize; ++j)
{
// use mech blah
vSum[j] = level * env.outputCache[j] * from.output[j];
auto amp = level * env.outputCache[j];
// LFO is bipolar so
auto uniLFO = (lfo.outputBlock[j] + 1) * 0.5;
// attenuate amplitude by the LFO
amp *= (lfoToLevel * uniLFO) + (1 - lfoToLevel);
vSum[j] =
level * (env.outputCache[j] + lfoToLevel * lfo.outputBlock[j]) * from.output[j];
}

auto pn = pan;
auto pn = pan + lfoToPan * lfo.outputBlock[blockSize - 1];
if (pn != 0.f)
{
pn = (pn + 1) * 0.5;
Expand Down
13 changes: 10 additions & 3 deletions src/synth/patch.h
Original file line number Diff line number Diff line change
Expand Up @@ -569,19 +569,26 @@ struct Patch
.withName(name(idx) + " LFO to Pan")
.withGroupName(name(idx))
.withID(id(41, idx))
.withDefault(0))
.withDefault(0)),
envLfoSum(intMd()
.withName(name(idx) + " LFO Env Sum")
.withGroupName(name(idx))
.withID(id(42, idx))
.withRange(0, 1)
.withDefault(0)
.withUnorderedMapFormatting({{0, "+"}, {1, "x"}}))
{
}

std::string name(int idx) const { return "Op " + std::to_string(idx + 1) + " Mixer"; }
uint32_t id(int f, int idx) const { return idBase + idStride * idx + f; }

Param level, pan, lfoToLevel, lfoToPan;
Param level, pan, lfoToLevel, lfoToPan, envLfoSum;
Param active;

std::vector<Param *> params()
{
std::vector<Param *> res{&level, &active, &pan, &lfoToLevel, &lfoToPan};
std::vector<Param *> res{&level, &active, &pan, &lfoToLevel, &lfoToPan, &envLfoSum};
appendDAHDSRParams(res);
appendLFOParams(res);
return res;
Expand Down
52 changes: 49 additions & 3 deletions src/ui/mixer-sub-panel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

namespace baconpaul::six_sines::ui
{
MixerSubPanel::MixerSubPanel(SixSinesEditor &e) : HasEditor(e){};
MixerSubPanel::MixerSubPanel(SixSinesEditor &e) : HasEditor(e) { setSelectedIndex(0); };
MixerSubPanel::~MixerSubPanel() {}

void MixerSubPanel::setSelectedIndex(int idx)
Expand All @@ -27,14 +27,60 @@ void MixerSubPanel::setSelectedIndex(int idx)

removeAllChildren();

setupDAHDSR(editor, editor.patchCopy.mixerNodes[idx]);
auto &sn = editor.patchCopy.mixerNodes[idx];
setupDAHDSR(editor, sn);
setupLFO(editor, sn);

createComponent(editor, *this, sn.envLfoSum, lfoMul, lfoMulD);
addAndMakeVisible(*lfoMul);
lfoMul->direction = jcmp::MultiSwitch::VERTICAL;

createComponent(editor, *this, sn.lfoToLevel, lfoToLevel, lfoToLevelD);
addAndMakeVisible(*lfoToLevel);
lfoToLevelL = std::make_unique<jcmp::Label>();
lfoToLevelL->setText(std::string() + u8"\U00002192" + "Lev");
addAndMakeVisible(*lfoToLevelL);

createComponent(editor, *this, sn.lfoToPan, lfoToPan, lfoToPanD);
addAndMakeVisible(*lfoToPan);
lfoToPanL = std::make_unique<jcmp::Label>();
lfoToPanL->setText(std::string() + u8"\U00002192" + "Pan");
addAndMakeVisible(*lfoToPanL);

panTitle = std::make_unique<RuledLabel>();
panTitle->setText("Pan");
createComponent(editor, *this, sn.pan, pan, panD);
panL = std::make_unique<jcmp::Label>();
panL->setText("Pan");
addAndMakeVisible(*panTitle);
addAndMakeVisible(*pan);
addAndMakeVisible(*panL);

resized();
}

void MixerSubPanel::resized()
{
auto p = getLocalBounds().reduced(uicMargin, 0);
layoutDAHDSRAt(p.getX(), p.getY());
auto pn = layoutDAHDSRAt(p.getX(), p.getY());
auto gh = (pn.getHeight() - 2 * uicPowerButtonSize) / 2;
lfoMul->setBounds(pn.getX() + uicMargin, pn.getY() + gh, uicPowerButtonSize,
2 * uicPowerButtonSize);
pn = pn.translated(2 * uicMargin + uicPowerButtonSize, 0);
auto r = layoutLFOAt(pn.getX(), p.getY(), uicMargin + uicKnobSize);

positionKnobAndLabel(r.getX() - uicKnobSize, r.getY() + uicTitleLabelHeight, lfoToLevel,
lfoToLevelL);
positionKnobAndLabel(r.getX() - uicKnobSize,
r.getY() + uicTitleLabelHeight + uicLabeledKnobHeight + uicMargin,
lfoToPan, lfoToPanL);

auto depx = r.getX() + 2 * uicMargin;
auto depy = r.getY();
positionTitleLabelAt(depx, depy, uicKnobSize + uicMargin, panTitle);

depy += uicTitleLabelHeight;
positionKnobAndLabel(depx, depy, pan, panL);
}

} // namespace baconpaul::six_sines::ui
23 changes: 22 additions & 1 deletion src/ui/mixer-sub-panel.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@
#include <juce_gui_basics/juce_gui_basics.h>
#include "six-sines-editor.h"
#include "dahdsr-components.h"
#include "lfo-components.h"

namespace baconpaul::six_sines::ui
{
struct MixerSubPanel : juce::Component, HasEditor, DAHDSRComponents<MixerSubPanel, Patch::MixerNode>
struct MixerSubPanel : juce::Component,
HasEditor,
DAHDSRComponents<MixerSubPanel, Patch::MixerNode>,
LFOComponents<MixerSubPanel, Patch::MixerNode>
{
MixerSubPanel(SixSinesEditor &);
~MixerSubPanel();
Expand All @@ -33,6 +37,23 @@ struct MixerSubPanel : juce::Component, HasEditor, DAHDSRComponents<MixerSubPane

size_t index{0};
void setSelectedIndex(int i);

std::unique_ptr<jcmp::MultiSwitch> lfoMul;
std::unique_ptr<PatchDiscrete> lfoMulD;

std::unique_ptr<jcmp::Knob> lfoToLevel;
std::unique_ptr<PatchContinuous> lfoToLevelD;
std::unique_ptr<jcmp::Label> lfoToLevelL;

std::unique_ptr<jcmp::Knob> lfoToPan;
std::unique_ptr<PatchContinuous> lfoToPanD;
std::unique_ptr<jcmp::Label> lfoToPanL;

std::unique_ptr<RuledLabel> panTitle;

std::unique_ptr<jcmp::Knob> pan;
std::unique_ptr<PatchContinuous> panD;
std::unique_ptr<jcmp::Label> panL;
};
} // namespace baconpaul::six_sines::ui
#endif // MIXER_SUB_PANE_H

0 comments on commit 2395ec0

Please sign in to comment.