#pragma once #include #include enum class DistortionType { SoftClip = 0, HardClip, Foldback, Overdrive, NumTypes }; class Distortion { public: void prepare(double /*sr*/) {} void setParameters(DistortionType type, float amount, float symmetry, float tone) { distType = type; distAmount = amount; distSymmetry = symmetry; distTone = tone; dryWet = 1.0f; } float process(float input) { float driven = input * (1.0f + distAmount * 9.0f); float wet = 0.0f; switch (distType) { case DistortionType::SoftClip: wet = std::tanh(driven); break; case DistortionType::HardClip: { float threshold = 1.0f / (1.0f + distAmount * 9.0f); wet = std::clamp(driven, -threshold, threshold); break; } case DistortionType::Foldback: { float threshold = 1.0f + distAmount * 3.0f; wet = driven; while (wet > threshold || wet < -threshold) { if (wet > threshold) wet = 2.0f * threshold - wet; else if (wet < -threshold) wet = -2.0f * threshold - wet; else break; } if (threshold > 0.0f) wet /= threshold; break; } case DistortionType::Overdrive: { float t = driven; if (t > 1.0f) t = 1.0f; else if (t < -1.0f) t = -1.0f; wet = t * (1.5f - 0.5f * t * t); break; } default: wet = driven; break; } // Asymmetry: bias the signal before/after shaping for even-harmonic grit wet += distSymmetry * 0.5f; // Tone: one-pole low-pass to tame harsh high harmonics float lpCoeff = distTone * 0.9f + 0.05f; toneState += lpCoeff * (wet - toneState); wet = toneState; if (distAmount < 0.001f && std::abs(distSymmetry) < 0.001f) return input; return input + (wet - input) * dryWet; } private: DistortionType distType = DistortionType::SoftClip; float distAmount = 0.0f; float distSymmetry = 0.0f; float distTone = 1.0f; float dryWet = 1.0f; float toneState = 0.0f; };