chore: land janitor round 1 and graft integration

Round 1 findings and fixes, all previously uncommitted:
- FXProcessor per-slot DSP history repair (HEAD does not compile without it)
- SynthVoice::getModulationValue, editor control-lock guard
- ExactCompare.h naming the deliberate exact float comparisons
- KnobLookAndFeel replacing the never-installed SerumLookAndFeel
- 55 first-party compiler warnings to 0
- AGENT.md renamed to AGENTS.md across Source/
- graft repository context graph and its hooks
- JANITOR_TASKS.md and UI_UX_AUDIT.md records
This commit is contained in:
biggy committed 2026-10-06 08:50:45 +02:00
1 parent 5c942cad0c
commit e4cea300db
63 files changed
+2360 -805

No files matched your search

+29 -16
View File
@@ -1,4 +1,5 @@
#include "LFO.h"
#include "ExactCompare.h"
namespace serum
{
@@ -40,7 +41,7 @@ void LFO::setParams (float rateNorm, bool s, float b, int shp, float ph,
// Only restart the delay/fade timing when those knobs actually change,
// so repeated block-rate setParams calls don't keep resetting the LFO.
if (delay != prevDelayParam || fade != prevFadeParam)
if (changed (delay, prevDelayParam) || changed (fade, prevFadeParam))
{
delayCounter = delaySeconds * sr;
fadeCounter = 0.0;
@@ -62,39 +63,51 @@ void LFO::setShapeData (const std::vector<float>& data, int steps)
? juce::jlimit (-1.0f, 1.0f, data[i]) : 0.0f;
}
float LFO::shapeValue() noexcept
float lfoShapeValue (float phase, LfoShape shape, int steps,
const float* data, int dataSize, float sampleHoldValue) noexcept
{
const float p = getPhase();
switch ((LfoShape) shape)
const int numSteps = juce::jlimit (2, LFO::kShapePoints, steps);
const int numData = data != nullptr ? juce::jlimit (0, LFO::kShapePoints, dataSize) : 0;
auto point = [data, numData] (int index) noexcept
{
return numData > 0 ? data[(size_t) juce::jlimit (0, numData - 1, index)] : 0.0f;
};
switch (shape)
{
case LfoShape::Sine:
return std::sin (p * juce::MathConstants<float>::twoPi);
return std::sin (phase * juce::MathConstants<float>::twoPi);
case LfoShape::Triangle:
return 1.0f - 4.0f * std::abs (p - 0.5f);
return 1.0f - 4.0f * std::abs (phase - 0.5f);
case LfoShape::Saw:
return 2.0f * p - 1.0f;
return 2.0f * phase - 1.0f;
case LfoShape::Square:
return (p < 0.5f) ? 1.0f : -1.0f;
return (phase < 0.5f) ? 1.0f : -1.0f;
case LfoShape::SampleHold:
return holdValue;
return sampleHoldValue;
case LfoShape::StepSeq:
{
const int idx = juce::jlimit (0, shapeSteps - 1, (int) (p * shapeSteps));
return shapeBuffer[(size_t) idx];
}
return point (juce::jlimit (0, numSteps - 1, (int) (phase * (float) numSteps)));
case LfoShape::Freehand:
{
const float pos = p * (float) (shapeSteps - 1);
const float pos = phase * (float) (numSteps - 1);
const int i0 = (int) pos;
const int i1 = juce::jmin (i0 + 1, shapeSteps - 1);
const int i1 = juce::jmin (i0 + 1, numSteps - 1);
const float frac = pos - (float) i0;
return shapeBuffer[(size_t) i0] * (1.0f - frac) + shapeBuffer[(size_t) i1] * frac;
return point (i0) * (1.0f - frac) + point (i1) * frac;
}
case LfoShape::Count:
default:
return 0.0f;
}
}
float LFO::shapeValue() noexcept
{
return lfoShapeValue (getPhase(), (LfoShape) shape, shapeSteps,
shapeBuffer.data(), (int) shapeBuffer.size(), holdValue);
}
float LFO::process() noexcept
{
return advance (1);