#pragma once #include "../SynthVoice.h" void NeuralSynthVoice::renderDistortion( int numSamples, int numCh, juce::dsp::AudioBlock &block) { // ================================================================ // Distortion + tone (post LPF/Peak) // ================================================================ const float driveDb = shared.distortionDrive ? shared.distortionDrive->load() : 0.0f; const float bias = juce::jlimit (-1.0f, 1.0f, shared.distortionBias ? shared.distortionBias->load() : 0.0f); const float toneHz = juce::jlimit (100.0f, 8000.0f, shared.distortionTone ? shared.distortionTone->load() : 3000.0f); const int shape = (int) std::lround (juce::jlimit (0.0f, 2.0f, shared.distortionShape ? shared.distortionShape->load() : 0.0f)); const float mix = shared.distortionMix ? shared.distortionMix->load() : 0.0f; auto& pre = chain.get(); auto& sh = chain.get(); auto& tone = chain.get(); pre.setGainDecibels (driveDb); // Explicit std::function target (works on MSVC) if (shape == 0) sh.functionToUse = std::function{ [bias](float x) noexcept { return std::tanh (x + bias); } }; else if (shape == 1) sh.functionToUse = std::function{ [bias](float x) noexcept { return juce::jlimit (-1.0f, 1.0f, x + bias); } }; else sh.functionToUse = std::function{ [bias](float x) noexcept { return std::atan (x + bias) * (2.0f / juce::MathConstants::pi); } }; tone.coefficients = juce::dsp::IIR::Coefficients::makePeakFilter ( spec.sampleRate, toneHz, 0.707f, juce::Decibels::decibelsToGain (shared.highGainDbls ? shared.highGainDbls->load() : 0.0f)); if (shared.distortionOn && shared.distortionOn->load() > 0.5f) { // Wet/dry blend around the shaper juce::AudioBuffer dryCopy (tempBuffer.getNumChannels(), numSamples); for (int ch = 0; ch < numCh; ++ch) dryCopy.copyFrom (ch, 0, tempBuffer, ch, 0, numSamples); // pre -> shaper -> tone pre.process (juce::dsp::ProcessContextReplacing (block)); sh.process (juce::dsp::ProcessContextReplacing (block)); tone.process (juce::dsp::ProcessContextReplacing (block)); const float wet = mix, dry = 1.0f - mix; for (int ch = 0; ch < numCh; ++ch) { auto* d = dryCopy.getReadPointer (ch); auto* w = tempBuffer.getWritePointer (ch); for (int i = 0; i < numSamples; ++i) w[i] = dry * d[i] + wet * w[i]; } } }