82 lines
2.7 KiB
C++
82 lines
2.7 KiB
C++
#pragma once
|
|
|
|
#include <JuceHeader.h>
|
|
#include "Params.h"
|
|
|
|
namespace serum
|
|
{
|
|
|
|
// ===========================================================================
|
|
// A single wavetable: 256 frames of 2048 samples each. Frames morph smoothly
|
|
// from a simple base shape to a complex one. Lookups interpolate bilinearly
|
|
// (across frames and within a frame). Tables are RAM-resident and generated
|
|
// lazily by the WavetableLibrary.
|
|
// ===========================================================================
|
|
class Wavetable
|
|
{
|
|
public:
|
|
static constexpr int kFrames = 256;
|
|
static constexpr int kTableSize = 2048;
|
|
|
|
Wavetable() = default;
|
|
|
|
juce::String name;
|
|
std::vector<std::vector<float>> frames; // [frame][sample]
|
|
|
|
bool isValid() const noexcept { return (int) frames.size() == kFrames; }
|
|
|
|
void clear();
|
|
|
|
// Build a table from a per-frame harmonic amplitude function.
|
|
// ampFn(frameIndex, harmonicNumber) -> amplitude (harmonic 1 = fundamental)
|
|
using HarmonicAmpFn = std::function<float (int, int)>;
|
|
void buildHarmonic (const juce::String& name, HarmonicAmpFn ampFn, int numHarmonics = 64);
|
|
|
|
// Read the table at a fractional frame position and a phase in [0,1).
|
|
float read (float framePos, float phase) const noexcept;
|
|
|
|
// Read with phase wrapped and clamped frame position.
|
|
float readSafe (float framePos, float phase) const noexcept
|
|
{
|
|
phase -= std::floor (phase);
|
|
return read (juce::jlimit (0.0f, (float) kFrames - 1.001f, framePos), phase);
|
|
}
|
|
|
|
// Copy raw samples of a frame into a destination buffer (for the GUI).
|
|
void copyFrame (int frameIndex, float* dest, int numSamples) const;
|
|
|
|
private:
|
|
static float lerp (float a, float b, float t) noexcept { return a + (b - a) * t; }
|
|
};
|
|
|
|
// ===========================================================================
|
|
// Lazily-built library of factory wavetables. Indices map to kWavetableNames.
|
|
// ===========================================================================
|
|
class WavetableLibrary
|
|
{
|
|
public:
|
|
const Wavetable& getTable (int index) const;
|
|
int size() const noexcept { return kNumWavetables; }
|
|
|
|
// Force generation of all tables (used at prepare time).
|
|
void prebuild();
|
|
|
|
private:
|
|
mutable std::array<Wavetable, kNumWavetables> tables;
|
|
mutable std::array<bool, kNumWavetables> built { { false } };
|
|
|
|
void buildTable (int index) const;
|
|
static Wavetable makeBasic();
|
|
static Wavetable makeSawPwm();
|
|
static Wavetable makeSquareSync();
|
|
static Wavetable makeTriangleFold();
|
|
static Wavetable makeVowel();
|
|
static Wavetable makeOrgan();
|
|
static Wavetable makeWarmSaw();
|
|
static Wavetable makeDigital();
|
|
static Wavetable makeGlass();
|
|
static Wavetable makeBass();
|
|
};
|
|
|
|
} // namespace serum
|