Skip to content

Commit

Permalink
Add infrastructure for waveforms; just add sin(x)^5 for now
Browse files Browse the repository at this point in the history
  • Loading branch information
baconpaul committed Dec 25, 2024
1 parent 8ecff81 commit 63a542a
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 25 deletions.
5 changes: 4 additions & 1 deletion src/dsp/op_source.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ struct alignas(16) OpSource : public EnvelopeSupport<Patch::SourceNode>,

bool keytrack{true};
const float &ratio, &activeV, &envToRatio, &lfoToRatio, &lfoByEnv; // in frequency multiple
const float &waveForm;
bool active{false};

// todo waveshape
Expand All @@ -53,7 +54,7 @@ struct alignas(16) OpSource : public EnvelopeSupport<Patch::SourceNode>,
OpSource(const Patch::SourceNode &sn, const MonoValues &mv, const VoiceValues &vv)
: monoValues(mv), voiceValues(vv), EnvelopeSupport(sn, mv, vv), LFOSupport(sn, mv),
ratio(sn.ratio), activeV(sn.active), envToRatio(sn.envToRatio), lfoToRatio(sn.lfoToRatio),
lfoByEnv(sn.envLfoSum)
lfoByEnv(sn.envLfoSum), waveForm(sn.waveForm)
{
reset();
}
Expand All @@ -67,6 +68,8 @@ struct alignas(16) OpSource : public EnvelopeSupport<Patch::SourceNode>,
phase = 4 << 27;
fbVal[0] = 0.f;
fbVal[1] = 0.f;
auto wf = (SinTable::WaveForm)std::round(waveForm);
st.setWaveForm(wf);
}

void zeroInputs()
Expand Down
72 changes: 56 additions & 16 deletions src/dsp/sintable.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,61 @@
#ifndef BACONPAUL_SIX_SINES_DSP_SINTABLE_H
#define BACONPAUL_SIX_SINES_DSP_SINTABLE_H

#include <cassert>
#include "configuration.h"
#include <sst/basic-blocks/simd/setup.h>

namespace baconpaul::six_sines
{
struct SinTable
{
enum WaveForm
{
SIN = 0, // these stream so you know....
SIN_FIFTH,

NUM_WAVEFORMS
};

static constexpr size_t nPoints{1 << 12};
float quadrantTable[4][nPoints + 1];
float dQuadrantTable[4][nPoints + 1];
float quadrantTable[NUM_WAVEFORMS][4][nPoints + 1];
float dQuadrantTable[NUM_WAVEFORMS][4][nPoints + 1];

float cubicHermiteCoefficients[4][nPoints];
float linterpCoefficients[2][nPoints];

SIMD_M128 simdQuad alignas(16)[4 * nPoints]; // for each quad it is q, q+1, dq + 1
SIMD_M128 simdCubic alignas(16)[nPoints]; // it is cq, cq+1, cdq, cd1+1
SIMD_M128
simdFullQuad alignas(16)[NUM_WAVEFORMS][4 * nPoints]; // for each quad it is q, q+1, dq + 1
SIMD_M128 *simdQuad;
SIMD_M128 simdCubic alignas(16)[nPoints]; // it is cq, cq+1, cdq, cd1+1

SinTable()
{
simdQuad = simdFullQuad[0];
memset(quadrantTable, 0, sizeof(quadrantTable));
memset(dQuadrantTable, 0, sizeof(dQuadrantTable));

// Waveform 0: Pure sine
for (int i = 0; i < nPoints + 1; ++i)
{
for (int Q = 0; Q < 4; ++Q)
{
auto s = sin((1.0 * i / (nPoints - 1) + Q) * M_PI / 2.0);
auto c = cos((1.0 * i / (nPoints - 1) + Q) * M_PI / 2.0);
quadrantTable[0][Q][i] = s;
dQuadrantTable[0][Q][i] = c / (nPoints - 1);
}
}

// Waveform 1: sin(x) ^ 5. Derivative is 5 sin(x)^4 cos(x)
for (int i = 0; i < nPoints + 1; ++i)
{
for (int j = 0; j < 4; ++j)
for (int Q = 0; Q < 4; ++Q)
{
auto s = sin((1.0 * i / (nPoints - 1) + j) * M_PI / 2.0);
auto c = cos((1.0 * i / (nPoints - 1) + j) * M_PI / 2.0);
quadrantTable[j][i] = s;
dQuadrantTable[j][i] = c / (nPoints - 1);
auto s = sin((1.0 * i / (nPoints - 1) + Q) * M_PI / 2.0);
auto c = cos((1.0 * i / (nPoints - 1) + Q) * M_PI / 2.0);
quadrantTable[1][Q][i] = s * s * s * s * s;
dQuadrantTable[1][Q][i] = 5 * s * s * s * s * c / (nPoints - 1);
}
}

Expand All @@ -64,16 +92,20 @@ struct SinTable
linterpCoefficients[1][i] = t;
}

// Load the SIMD buffers
for (int i = 0; i < nPoints; ++i)
{
for (int j = 0; j < 4; ++j)
for (int WF = 0; WF < NUM_WAVEFORMS; ++WF)
{
float r alignas(16)[4];
r[0] = quadrantTable[j][i];
r[1] = dQuadrantTable[j][i];
r[2] = quadrantTable[j][i + 1];
r[3] = dQuadrantTable[j][i + 1];
simdQuad[nPoints * j + i] = SIMD_MM(load_ps)(r);
for (int Q = 0; Q < 4; ++Q)
{
float r alignas(16)[4];
r[0] = quadrantTable[WF][Q][i];
r[1] = dQuadrantTable[WF][Q][i];
r[2] = quadrantTable[WF][Q][i + 1];
r[3] = dQuadrantTable[WF][Q][i + 1];
simdFullQuad[WF][nPoints * Q + i] = SIMD_MM(load_ps)(r);
}
}

{
Expand All @@ -87,6 +119,14 @@ struct SinTable
}
}

void setWaveForm(WaveForm wf)
{
auto stwf = size_t(wf);
if (stwf >= NUM_WAVEFORMS) // mostly remove ine during dev
stwf = 0;
simdQuad = simdFullQuad[stwf];
}

static constexpr double frToPhase{(1 << 26) / gSampleRate};
uint32_t dPhase(float fr)
{
Expand Down
19 changes: 16 additions & 3 deletions src/synth/patch.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "sst/basic-blocks/params/ParamMetadata.h"
#include "sst/basic-blocks/modulators/DAHDSREnvelope.h"
#include "synth/matrix_index.h"
#include "dsp/sintable.h"

namespace baconpaul::six_sines
{
Expand All @@ -46,7 +47,7 @@ struct Param
operator const float &() const { return value; }

uint64_t adhocFeatures{0};
enum AdHocFeatureValues
enum AdHocFeatureValues : uint64_t
{
ENVTIME = 1 << 0 // tag for ADSR envs we changed version 2-3
};
Expand Down Expand Up @@ -310,7 +311,16 @@ struct Patch
.withRange(0, 1)
.withDefault(0)
.withUnorderedMapFormatting({{0, "+"}, {1, "x"}})),

waveForm(intMd()
.withName(name(idx) + " Waveform")
.withGroupName(name(idx))
.withID(id(5, idx))
.withRange(0, SinTable::WaveForm::NUM_WAVEFORMS - 1)
.withDefault(0)
.withUnorderedMapFormatting({
{SinTable::WaveForm::SIN, "Sin"},
{SinTable::WaveForm::SIN_FIFTH, "Sin^5"},
})),
DAHDSRMixin(name(idx), id(100, idx), false), LFOMixin(name(idx), id(45, idx))
{
}
Expand All @@ -325,9 +335,12 @@ struct Patch
Param lfoToRatio;
Param envLfoSum;

Param waveForm;

std::vector<Param *> params()
{
std::vector<Param *> res{&ratio, &active, &envToRatio, &lfoToRatio, &envLfoSum};
std::vector<Param *> res{&ratio, &active, &envToRatio,
&lfoToRatio, &envLfoSum, &waveForm};
appendDAHDSRParams(res);
appendLFOParams(res);
return res;
Expand Down
5 changes: 5 additions & 0 deletions src/ui/patch-data-bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ struct PatchDiscrete : jdat::Discrete
SixSinesEditor &editor;
uint32_t pid;
Param *p{nullptr};
std::function<void()> onGuiSetValue{nullptr};

PatchDiscrete(SixSinesEditor &e, uint32_t id) : editor(e), pid(id)
{
if (e.patchCopy.paramMap.find(id) == e.patchCopy.paramMap.end())
Expand Down Expand Up @@ -126,6 +128,9 @@ struct PatchDiscrete : jdat::Discrete
p->value = f;
editor.uiToAudio.push({Synth::UIToAudioMsg::Action::SET_PARAM, pid, static_cast<float>(f)});
editor.flushOperator();

if (onGuiSetValue)
onGuiSetValue();
}
void setValueFromModel(const int &f) override { p->value = f; }
int getDefaultValue() const override
Expand Down
57 changes: 53 additions & 4 deletions src/ui/source-sub-panel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,42 @@
#include "source-sub-panel.h"
#include "patch-data-bindings.h"
#include "ui-constants.h"
#include "dsp/sintable.h" // for drawing

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

struct WavPainter : juce::Component
{
const Param &wf;
SinTable st;
WavPainter(const Param &w) : wf(w) {}

void paint(juce::Graphics &g)
{
st.setWaveForm((SinTable::WaveForm)std::round(wf.value));
uint32_t phase{0};
int nPixels{getWidth()};
auto dPhase = (1 << 27) / (nPixels - 1);
auto p = juce::Path();
for (int i = 0; i < nPixels; ++i)
{
auto sv = st.at(phase);
auto x = i;
auto y = (1 - (sv + 1) * 0.5) * getHeight();
if (i == 0)
p.startNewSubPath(x, y);
else
p.lineTo(x, y);
phase += dPhase;
}
g.setColour(juce::Colours::white);
g.strokePath(p, juce::PathStrokeType(1));
}
};

void SourceSubPanel::setSelectedIndex(size_t idx)
{
index = idx;
Expand Down Expand Up @@ -53,6 +83,17 @@ void SourceSubPanel::setSelectedIndex(size_t idx)
modTitle->setText("Depth");
addAndMakeVisible(*modTitle);

wavTitle = std::make_unique<RuledLabel>();
wavTitle->setText("Wave");
addAndMakeVisible(*wavTitle);

createComponent(editor, *this, sn.waveForm, wavButton, wavButtonD);
addAndMakeVisible(*wavButton);
wavButtonD->onGuiSetValue = [this]() { wavPainter->repaint(); };

wavPainter = std::make_unique<WavPainter>(sn.waveForm);
addAndMakeVisible(*wavPainter);

resized();
}

Expand All @@ -68,13 +109,21 @@ void SourceSubPanel::resized()

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

depx += xtraW;
depy += uicTitleLabelHeight;
positionKnobAndLabel(depx, depy, envToRatio, envToRatioL);
depy += uicLabeledKnobHeight + uicMargin;
depx += uicKnobSize + uicMargin;
positionKnobAndLabel(depx, depy, lfoToRatio, lfoToRatioL);

depx = r.getX() + 2 * uicMargin;
depy += uicLabeledKnobHeight + uicMargin;

positionTitleLabelAt(depx, depy, uicKnobSize * 2 + uicMargin, wavTitle);
depy += uicTitleLabelHeight;
wavButton->setBounds(depx, depy, uicKnobSize * 2 + uicMargin, uicLabelHeight);

depy += uicLabelHeight + uicMargin;
wavPainter->setBounds(depx, depy, uicKnobSize * 2 + uicMargin, uicLabelHeight * 2.5);
}
} // namespace baconpaul::six_sines::ui
8 changes: 7 additions & 1 deletion src/ui/source-sub-panel.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#define BACONPAUL_SIX_SINES_UI_SOURCE_SUB_PANEL_H

#include <juce_gui_basics/juce_gui_basics.h>
#include "sst/jucegui/components/JogUpDownButton.h"
#include "six-sines-editor.h"
#include "dahdsr-components.h"
#include "lfo-components.h"
Expand Down Expand Up @@ -50,7 +51,12 @@ struct SourceSubPanel : juce::Component,
std::unique_ptr<jcmp::MultiSwitch> lfoMul;
std::unique_ptr<PatchDiscrete> lfoMulD;

std::unique_ptr<RuledLabel> modTitle;
std::unique_ptr<jcmp::JogUpDownButton> wavButton;
std::unique_ptr<PatchDiscrete> wavButtonD;

std::unique_ptr<RuledLabel> modTitle, wavTitle;

std::unique_ptr<juce::Component> wavPainter;
};
} // namespace baconpaul::six_sines::ui
#endif // MAIN_SUB_PANEL_H

0 comments on commit 63a542a

Please sign in to comment.