140 lines
4.7 KiB
C++
140 lines
4.7 KiB
C++
#pragma once
|
|
#include <JuceHeader.h>
|
|
#include <functional> // <-- for std::function used by WaveShaper
|
|
#include <memory>
|
|
#include <cmath>
|
|
#include "NeuralSharedParams.h"
|
|
#include "BlepOsc.h"
|
|
#include "WavetableOsc.h"
|
|
|
|
//==============================================================================
|
|
// A single polyBLEP oscillator voice with per-voice ADSR, filter ADSR,
|
|
// flanger (delayline), simple delay, chorus, reverb, distortion, EQ, master.
|
|
class NeuralSynthVoice : public juce::MPESynthesiserVoice
|
|
{
|
|
public:
|
|
explicit NeuralSynthVoice (NeuralSharedParams& sharedParams);
|
|
|
|
// JUCE voice API
|
|
void prepare (const juce::dsp::ProcessSpec& spec);
|
|
void renderNextBlock (juce::AudioBuffer<float>& outputBuffer,
|
|
int startSample, int numSamples) override;
|
|
|
|
void noteStarted() override;
|
|
void noteStopped (bool allowTailOff) override;
|
|
void notePitchbendChanged() override;
|
|
|
|
void notePressureChanged() override {}
|
|
void noteTimbreChanged() override {}
|
|
void noteKeyStateChanged() override {}
|
|
|
|
private:
|
|
struct MorphLFO
|
|
{
|
|
void prepare (double sr) { sampleRate = juce::jmax (1.0, sr); updateIncrement(); }
|
|
void reset() { phase = 0.0f; }
|
|
void setRate (float hz) { rate = juce::jlimit (0.0f, 30.0f, hz); updateIncrement(); }
|
|
void setShape (int idx) { shape = juce::jlimit (0, 3, idx); }
|
|
float process()
|
|
{
|
|
float value = 0.0f;
|
|
|
|
switch (shape)
|
|
{
|
|
case 1: value = 1.0f - 4.0f * std::abs(phase - 0.5f); break; // Triangle
|
|
case 2: value = 2.0f * phase - 1.0f; break; // Ramp up
|
|
case 3: value = 1.0f - 2.0f * phase; break; // Ramp down
|
|
default: value = std::sin (juce::MathConstants<float>::twoPi * phase); break; // Sine
|
|
}
|
|
|
|
phase += phaseInc;
|
|
if (phase >= 1.0f)
|
|
phase -= 1.0f;
|
|
|
|
return value;
|
|
}
|
|
|
|
private:
|
|
void updateIncrement()
|
|
{
|
|
phaseInc = (float) (rate / (float) sampleRate);
|
|
if (phaseInc < 0.0f) phaseInc = 0.0f;
|
|
}
|
|
|
|
double sampleRate { 44100.0 };
|
|
float rate { 1.0f };
|
|
float phase { 0.0f };
|
|
float phaseInc { 0.0f };
|
|
int shape { 0 };
|
|
};
|
|
|
|
//=== Processing chain (without oscillator) ===============================
|
|
using DelayLine = juce::dsp::DelayLine<float,
|
|
juce::dsp::DelayLineInterpolationTypes::Linear>;
|
|
using IIR = juce::dsp::IIR::Filter<float>;
|
|
using Gain = juce::dsp::Gain<float>;
|
|
using WaveShaper = juce::dsp::WaveShaper<float, std::function<float(float)>>; // <-- fix
|
|
using Chorus = juce::dsp::Chorus<float>;
|
|
using Reverb = juce::dsp::Reverb;
|
|
using Limiter = juce::dsp::Limiter<float>;
|
|
|
|
enum ChainIndex
|
|
{
|
|
flangerIndex = 0,
|
|
delayIndex,
|
|
chorusIndex,
|
|
reverbIndex,
|
|
distortionPreGain,
|
|
distortionIndex,
|
|
distortionPostLPF,
|
|
eqLowIndex,
|
|
eqMidIndex,
|
|
eqHighIndex,
|
|
masterIndex,
|
|
limiterIndex
|
|
};
|
|
|
|
using Chain = juce::dsp::ProcessorChain<
|
|
DelayLine, // flanger
|
|
DelayLine, // simple delay
|
|
Chorus, // chorus
|
|
Reverb, // reverb
|
|
Gain, // distortion pre-gain (drive)
|
|
WaveShaper, // distortion waveshaper
|
|
IIR, // tone / post-EQ for distortion
|
|
IIR, // EQ low
|
|
IIR, // EQ mid
|
|
IIR, // EQ high
|
|
Gain, // master gain
|
|
Limiter // safety limiter
|
|
>;
|
|
|
|
private:
|
|
NeuralSharedParams& shared;
|
|
|
|
juce::dsp::ProcessSpec spec {};
|
|
|
|
// ==== Oscillators ======================================================
|
|
BlepOsc osc; // polyBLEP oscillator
|
|
WT::Osc wtOsc; // wavetable oscillator (shared bank)
|
|
MorphLFO morphLfo;
|
|
int currentWtBankIndex { -1 };
|
|
WT::Osc wtOsc2; // secondary wavetable oscillator
|
|
MorphLFO morphLfo2;
|
|
int currentWtBankIndex2 { -1 };
|
|
|
|
// ==== Envelopes & Filter ===============================================
|
|
juce::ADSR adsr;
|
|
juce::ADSR filterAdsr;
|
|
juce::dsp::StateVariableTPTFilter<float> svf;
|
|
|
|
// ==== Chain (FX, EQ, master, limiter) ==================================
|
|
Chain chain;
|
|
|
|
// ==== Scratch buffer (properly allocated) ===============================
|
|
juce::AudioBuffer<float> tempBuffer;
|
|
juce::dsp::AudioBlock<float> tempBlock;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NeuralSynthVoice)
|
|
};
|