#pragma once #include #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> 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; 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 tables; mutable std::array 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