145 lines
4.3 KiB
C++
145 lines
4.3 KiB
C++
#ifndef SYNTH_ENGINE_H
|
|
#define SYNTH_ENGINE_H
|
|
|
|
#include <stdint.h>
|
|
#include <vector>
|
|
#include <utility>
|
|
|
|
#if defined(ARDUINO_ARCH_RP2040)
|
|
#include <pico/mutex.h>
|
|
class SynthMutex {
|
|
public:
|
|
SynthMutex() { mutex_init(&mtx); }
|
|
void lock() { mutex_enter_blocking(&mtx); }
|
|
void unlock() { mutex_exit(&mtx); }
|
|
private:
|
|
mutex_t mtx;
|
|
};
|
|
template <typename Mutex>
|
|
class SynthLockGuard {
|
|
public:
|
|
explicit SynthLockGuard(Mutex& m) : m_mutex(m) { m_mutex.lock(); }
|
|
~SynthLockGuard() { m_mutex.unlock(); }
|
|
SynthLockGuard(const SynthLockGuard&) = delete;
|
|
SynthLockGuard& operator=(const SynthLockGuard&) = delete;
|
|
private:
|
|
Mutex& m_mutex;
|
|
};
|
|
#else
|
|
#include <mutex>
|
|
using SynthMutex = std::mutex;
|
|
template <typename Mutex>
|
|
using SynthLockGuard = std::lock_guard<Mutex>;
|
|
#endif
|
|
|
|
/**
|
|
* @class SynthEngine
|
|
* @brief A portable, platform-agnostic synthesizer engine.
|
|
*
|
|
* This class contains the core digital signal processing (DSP) logic.
|
|
* It has no dependencies on any specific hardware, OS, or audio API.
|
|
* It works by filling a provided buffer with 16-bit signed audio samples.
|
|
*
|
|
* The oscillator uses a 32-bit unsigned integer as a phase accumulator,
|
|
* which is highly efficient and avoids floating-point math in the audio loop,
|
|
* making it ideal for the RP2040.
|
|
*/
|
|
class SynthEngine {
|
|
public:
|
|
enum Waveform {
|
|
SAWTOOTH,
|
|
SQUARE,
|
|
SINE
|
|
};
|
|
|
|
/**
|
|
* @brief Constructs the synthesizer engine.
|
|
* @param sampleRate The audio sample rate in Hz (e.g., 44100).
|
|
*/
|
|
~SynthEngine();
|
|
SynthEngine(uint32_t sampleRate);
|
|
|
|
/**
|
|
* @brief Fills a buffer with audio samples. This is the main audio callback.
|
|
* @param buffer Pointer to the output buffer to be filled.
|
|
* @param numFrames The number of audio frames (samples) to generate.
|
|
*/
|
|
void process(int16_t* buffer, uint32_t numFrames);
|
|
|
|
/**
|
|
* @brief Sets the frequency of the oscillator.
|
|
* @param freq The frequency in Hz.
|
|
*/
|
|
void setFrequency(float freq);
|
|
|
|
/**
|
|
* @brief Sets the output volume.
|
|
* @param vol Volume from 0.0 (silent) to 1.0 (full).
|
|
*/
|
|
void setVolume(float vol);
|
|
|
|
/**
|
|
* @brief Sets the oscillator's waveform.
|
|
* @param form The waveform to use.
|
|
*/
|
|
void setWaveform(Waveform form);
|
|
|
|
/**
|
|
* @brief Opens or closes the sound gate.
|
|
* @param isOpen True to produce sound, false for silence.
|
|
*/
|
|
void setGate(bool isOpen);
|
|
|
|
/**
|
|
* @brief Gets the current frequency of the oscillator.
|
|
* @return The frequency in Hz.
|
|
*/
|
|
float getFrequency() const;
|
|
|
|
// --- Grid Synth ---
|
|
struct GridCell {
|
|
enum Type { EMPTY, FIXED_OSCILLATOR, INPUT_OSCILLATOR, WAVETABLE, NOISE, LFO, GATE_INPUT, ADSR_ATTACK, ADSR_DECAY, ADSR_SUSTAIN, ADSR_RELEASE, FORK, WIRE, LPF, HPF, VCA, BITCRUSHER, DISTORTION, RECTIFIER, PITCH_SHIFTER, GLITCH, OPERATOR, DELAY, REVERB, SINK };
|
|
enum Op { OP_ADD, OP_MUL, OP_SUB, OP_DIV, OP_MIN, OP_MAX };
|
|
|
|
Type type = EMPTY;
|
|
float param = 0.5f; // 0.0 to 1.0
|
|
int rotation = 0; // 0:N, 1:E, 2:S, 3:W (Output direction)
|
|
float value = 0.0f; // Current output sample
|
|
float next_value = 0.0f; // For double-buffering in processGridStep
|
|
float phase = 0.0f; // For Oscillator, Noise state
|
|
uint32_t phase_accumulator = 0; // For Oscillators (Fixed point optimization)
|
|
};
|
|
|
|
static const int GRID_W = 12;
|
|
static const int GRID_H = 12;
|
|
|
|
static const size_t MAX_SERIALIZED_GRID_SIZE = 1024;
|
|
size_t exportGrid(uint8_t* buffer);
|
|
int importGrid(const uint8_t* buffer, size_t size);
|
|
void loadPreset(int preset);
|
|
void rebuildProcessingOrder();
|
|
void clearGrid();
|
|
|
|
GridCell grid[GRID_W][GRID_H];
|
|
SynthMutex gridMutex;
|
|
|
|
// Helper to process one sample step of the grid
|
|
float processGridStep();
|
|
|
|
private:
|
|
uint32_t _sampleRate;
|
|
uint32_t _phase; // Phase accumulator for the oscillator.
|
|
uint32_t _increment; // Phase increment per sample, determines frequency.
|
|
float _volume;
|
|
Waveform _waveform;
|
|
float _freqToPhaseInc; // Pre-calculated constant for frequency to phase increment conversion
|
|
bool _isGateOpen;
|
|
uint32_t _rngState;
|
|
std::vector<std::pair<int, int>> _processing_order;
|
|
void rebuildProcessingOrder_locked();
|
|
|
|
// Internal random number generator
|
|
float _random();
|
|
};
|
|
|
|
#endif // SYNTH_ENGINE_H
|