refactor(source): move every implementation into its module directory

- 36 files move into the module whose AGENTS.md already claimed them:
  Engine/, Synth/, Modulation/, Params/, Plugin/, GUI/, EffectUnits/, Resources/
- Source/engine, modulation, params, plugin and synth become Engine,
  Modulation, Params, Plugin and Synth, matching the directories that already
  hold code
- ExactCompare.h stays at the Source/ root as the one shared header
- SERUMALT_INCLUDE_DIRS adds one include directory per module, so the 31
  parent-relative includes become plain names with no path prefix
- the module AGENTS.md files list owned files instead of describing a move
  that had not happened, and README.md and AGENTS.md describe the real tree

Verified: the harness passes CTest, the Linux VST3 and Standalone link, the
Windows cross-build passes its module checks, each configure exposes only its
own targets, no first-party warning line appears, and the generated Windows
manifest is unchanged.
This commit is contained in:
biggy committed 2026-10-06 09:17:49 +02:00
1 parent facd5c5b5e
commit 4b0db50271
70 files changed
+115 -111

No files matched your search

+2 -2
View File
@@ -2,7 +2,7 @@
## Owned files
- Related rack implementation: `../FXProcessor.h`, `../FXProcessor.cpp`
- FXProcessor.h, FXProcessor.cpp
- Biquad.h
- Hyper.h, Hyper.cpp
- Chorus.h, Chorus.cpp
@@ -27,7 +27,7 @@
## IF-THEN
- IF a unit needs a delay line THEN allocate it in `prepare()` at the full required length and only read and write it in `process`.
- Include the existing rack interface via `../FXProcessor.h`; no source relocation is implied by this guidance.
- Include the rack interface via `FXProcessor.h`.
## Examples
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "../FXProcessor.h"
#include "FXProcessor.h"
namespace serum
{
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "../FXProcessor.h"
#include "FXProcessor.h"
namespace serum
{
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "../FXProcessor.h"
#include "FXProcessor.h"
namespace serum
{
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "../FXProcessor.h"
#include "FXProcessor.h"
#include "Biquad.h"
namespace serum
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "../FXProcessor.h"
#include "FXProcessor.h"
#include "Biquad.h"
namespace serum
+113
View File
@@ -0,0 +1,113 @@
#include "FXProcessor.h"
#include "EffectUnits/Hyper.h"
#include "EffectUnits/Chorus.h"
#include "EffectUnits/Flanger.h"
#include "EffectUnits/Phaser.h"
#include "EffectUnits/Distortion.h"
#include "EffectUnits/EQ.h"
#include "EffectUnits/Compressor.h"
#include "EffectUnits/Delay.h"
#include "EffectUnits/Reverb.h"
namespace serum
{
FXProcessor::FXProcessor()
{
for (auto& slotUnits : units)
{
slotUnits[0] = std::make_unique<HyperUnit>();
slotUnits[1] = std::make_unique<ChorusUnit>();
slotUnits[2] = std::make_unique<FlangerUnit>();
slotUnits[3] = std::make_unique<PhaserUnit>();
slotUnits[4] = std::make_unique<DistortionUnit>();
slotUnits[5] = std::make_unique<EQUnit>();
slotUnits[6] = std::make_unique<CompressorUnit>();
slotUnits[7] = std::make_unique<DelayUnit>();
slotUnits[8] = std::make_unique<ReverbUnit>();
}
}
FXProcessor::~FXProcessor() = default;
void FXProcessor::prepare (double sampleRate, int maxBlockSize)
{
for (auto& slotUnits : units)
for (auto& unit : slotUnits)
unit->prepare (sampleRate, maxBlockSize);
wet.setSize (2, maxBlockSize, false, false, true);
reset();
}
void FXProcessor::reset()
{
for (auto& slotUnits : units)
for (auto& unit : slotUnits)
unit->reset();
activeTypes.fill ((int) FxType::Off);
wet.clear();
}
juce::String FXProcessor::fxTypeName (int type)
{
switch ((FxType) type)
{
case FxType::Off: return "Off";
case FxType::Hyper: return "Hyper";
case FxType::Chorus: return "Chorus";
case FxType::Flanger: return "Flanger";
case FxType::Phaser: return "Phaser";
case FxType::Distortion: return "Distortion";
case FxType::EQ: return "EQ";
case FxType::Compressor: return "Compressor";
case FxType::Delay: return "Delay";
case FxType::Reverb: return "Reverb";
case FxType::Count: return {};
default: return {};
}
}
void FXProcessor::process (juce::AudioBuffer<float>& buffer, const FxSlotParams* slots, int numSlots)
{
// The rack is stereo end to end; a mono buffer would read a channel that is not there.
jassert (buffer.getNumChannels() >= 2);
if (buffer.getNumChannels() < 2)
return;
const int n = buffer.getNumSamples();
jassert (n <= wet.getNumSamples());
if (n <= 0)
return;
for (int s = 0; s < juce::jmin (numSlots, kNumFxSlots); ++s)
{
const FxSlotParams& slot = slots[s];
const int unitIdx = slot.type - 1;
if (unitIdx < 0 || unitIdx >= kNumEffectTypes)
{
activeTypes[(size_t) s] = (int) FxType::Off;
continue;
}
auto& unit = *units[(size_t) s][(size_t) unitIdx];
if (activeTypes[(size_t) s] != slot.type)
{
unit.reset();
activeTypes[(size_t) s] = slot.type;
}
wet.copyFrom (0, 0, buffer, 0, 0, n);
wet.copyFrom (1, 0, buffer, 1, 0, n);
unit.process (wet.getWritePointer (0), wet.getWritePointer (1), n, slot.p);
const float mix = juce::jlimit (0.0f, 1.0f, slot.mix);
for (int ch = 0; ch < 2; ++ch)
{
float* out = buffer.getWritePointer (ch);
const float* effect = wet.getReadPointer (ch);
for (int i = 0; i < n; ++i)
out[i] = out[i] * (1.0f - mix) + effect[i] * mix;
}
}
}
} // namespace serum
+56
View File
@@ -0,0 +1,56 @@
#pragma once
#include <JuceHeader.h>
#include "Params.h"
namespace serum
{
// ===========================================================================
// Base class for a stereo effect unit. Each unit processes a full-wet buffer.
// ===========================================================================
class FXUnit
{
public:
virtual ~FXUnit() = default;
virtual void prepare (double sampleRate, int maxBlockSize) = 0;
virtual void reset() = 0;
virtual void process (float* l, float* r, int numSamples, const float p[4]) = 0;
};
// ===========================================================================
// Snapshot of one FX slot.
// ===========================================================================
struct FxSlotParams
{
int type = (int) FxType::Off;
float mix = 0.0f;
float p[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
};
// ===========================================================================
// Reorderable effects rack. Slots are processed in list order; reordering is
// simply swapping FxSlotParams entries. Nine effect unit implementations are
// preconstructed per slot with independent DSP history.
// ===========================================================================
class FXProcessor
{
public:
FXProcessor();
~FXProcessor();
void prepare (double sampleRate, int maxBlockSize);
void reset();
void process (juce::AudioBuffer<float>& buffer, const FxSlotParams* slots, int numSlots);
static juce::String fxTypeName (int type);
private:
static constexpr int kNumEffectTypes = (int) FxType::Count - 1;
std::array<std::array<std::unique_ptr<FXUnit>, kNumEffectTypes>, kNumFxSlots> units;
std::array<int, kNumFxSlots> activeTypes {};
juce::AudioBuffer<float> wet;
};
} // namespace serum
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "../FXProcessor.h"
#include "FXProcessor.h"
namespace serum
{
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "../FXProcessor.h"
#include "FXProcessor.h"
#include "Biquad.h"
namespace serum
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "../FXProcessor.h"
#include "FXProcessor.h"
namespace serum
{
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "../FXProcessor.h"
#include "FXProcessor.h"
namespace serum
{