DSPark 1.8.0
Header-only C++20 DSP for real-time and offline audio
Loading...
Searching...
No Matches
ClipperShape.h
1// DSPark - Professional Audio DSP Framework
2// Copyright (c) 2026 Cristian Moresi - MIT License
3
4#pragma once
5
14#include "../DspMath.h"
15#include "RationalKnee.h"
16#include <algorithm>
17#include <array>
18#include <cmath>
19#include <numbers>
20
21namespace dspark::detail
22{
23enum class ClipperCurve
24{
25 Hard,
26 Tanh,
27 Sine,
31};
32
34template <ClipperCurve Curve, FloatType T>
35[[nodiscard]] constexpr T clipperSmallSignalSlope() noexcept
36{
37 if constexpr (Curve == ClipperCurve::Sine)
38 return fastSinPolynomial<T>[0];
39 else
40 return T(1);
41}
42
44template <ClipperCurve Curve, FloatType T>
45[[nodiscard]] inline std::array<T, 2> clipperLinearLimits(T ceiling) noexcept
46{
47 static_assert(Curve == ClipperCurve::GoldenRatio || Curve == ClipperCurve::SymmetricKnee ||
49 if constexpr (Curve == ClipperCurve::SymmetricKnee)
50 return {-T(0.9) * ceiling, T(0.9) * ceiling};
51 else if constexpr (Curve == ClipperCurve::AsymmetricKnee)
52 return {-T(0.78) * ceiling, T(0.96) * ceiling};
53 else
54 {
55 const T limit = ceiling / T(1.6180339887498948482);
56 return {-limit, limit};
57 }
58}
59
61template <ClipperCurve Curve, FloatType T>
62[[nodiscard]] inline T clipperShape(T sample, T ceiling) noexcept
63{
64 if constexpr (Curve == ClipperCurve::Hard)
65 return std::clamp(sample, -ceiling, ceiling);
66 else if constexpr (Curve == ClipperCurve::Tanh)
67 return ceiling * std::tanh(sample / ceiling);
68 else if constexpr (Curve == ClipperCurve::Sine)
69 {
70 constexpr T halfPi = static_cast<T>(std::numbers::pi * 0.5);
71 return ceiling * fastSin(std::clamp(sample / ceiling, -halfPi, halfPi));
72 }
73 else if constexpr (Curve == ClipperCurve::GoldenRatio)
74 {
75 constexpr T phi = static_cast<T>(1.6180339887498948482);
76 const T threshold = ceiling / phi;
77 const T absSample = std::abs(sample);
78 if (absSample <= threshold)
79 return sample;
80 const T sign = std::copysign(T(1), sample);
81 return sign * rationalKneeMagnitude(absSample, threshold, ceiling);
82 }
83 else
84 {
85 const auto limits = clipperLinearLimits<Curve>(ceiling);
86 const T threshold = sample >= T(0) ? limits[1] : -limits[0];
87 return std::copysign(rationalKneeMagnitude(std::abs(sample), threshold, ceiling), sample);
88 }
89}
90} // namespace dspark::detail
std::array< T, 2 > clipperLinearLimits(T ceiling) noexcept
Exact linear-region endpoints of a rational clipping curve.
T clipperShape(T sample, T ceiling) noexcept
Shared transfer functions; no state or implicit antialiasing.
T rationalKneeMagnitude(T magnitude, T knee, T ceiling) noexcept
Positive magnitude of the original Clipper rational soft knee.
constexpr T clipperSmallSignalSlope() noexcept
Exact small-signal slope of the implemented stateless curve.
T fastSin(T x) noexcept
Fast sine approximation (degree-9 odd minimax polynomial).
Definition DspMath.h:248
constexpr T halfPi
Pi / 2 (1.57079...). Quarter period; sin/cos phase offset.
Definition DspMath.h:54