86 assert(tableSize >= 4);
93 tableSize = std::clamp(tableSize, 4, 1 << 20);
94 if (!(xMax > T(0))) xMax = T(8);
96 tableSize_ = tableSize;
97 xMax_ = std::max(xMax, T(0.001));
98 invRange_ = T(1) / (T(2) * xMax_);
102 table_.resize(
static_cast<size_t>(tableSize) + 3);
104 for (
int i = 0; i < tableSize; ++i)
106 T x = -xMax_ + T(2) * xMax_ *
static_cast<T
>(i) /
static_cast<T
>(tableSize - 1);
107 table_[
static_cast<size_t>(i + 1)] = func(x);
111 table_[0] = table_[1];
112 table_[
static_cast<size_t>(tableSize + 1)] = table_[
static_cast<size_t>(tableSize)];
113 table_[
static_cast<size_t>(tableSize + 2)] = table_[
static_cast<size_t>(tableSize)];
134 return std::clamp(x, -threshold, threshold);
145 if (x > T(1))
return T(2.0 / 3.0);
146 if (x < T(-1))
return T(-2.0 / 3.0);
147 return x - (x * x * x) / T(3);
158 return x >= T(0) ? std::tanh(x * T(1.2)) : std::tanh(x * T(0.8));
170 [[nodiscard]]
inline T
process(T input, T preGain = T(1), T postGain = T(1)) const noexcept
177 T driven = std::max(-xMax_, std::min(xMax_, input * preGain));
180 T pos = (driven + xMax_) * invRange_ *
static_cast<T
>(tableSize_ - 1);
182 int idx =
static_cast<int>(pos);
183 T frac = pos -
static_cast<T
>(idx);
186 const T* t = table_.data() + idx + 1;
203 void process(T* __restrict data,
int numSamples, T preGain = T(1), T postGain = T(1)) const noexcept
205 for (
int i = 0; i < numSamples; ++i)
206 data[i] =
process(data[i], preGain, postGain);
219 oversampler_->prepare(spec);
229 assert(factor >= 1 && (factor & (factor - 1)) == 0);
233 oversampler_ = std::make_unique<Oversampling<T>>(factor);
237 oversamplingFactor_ = oversampler_->getFactor();
239 oversampler_->prepare(spec_);
243 oversamplingFactor_ = 1;
244 oversampler_.reset();
258 if (oversamplingFactor_ > 1 && oversampler_)
260 auto upView = oversampler_->upsample(buffer);
261 for (
int ch = 0; ch < upView.getNumChannels(); ++ch)
263 process(upView.getChannel(ch), upView.getNumSamples(), preGain, postGain);
265 oversampler_->downsample(buffer);
278 if (oversampler_) oversampler_->reset();
282 [[nodiscard]]
bool isReady() const noexcept {
return tableSize_ > 0; }
294 return (oversampler_ && oversamplingFactor_ > 1) ? oversampler_->getLatency() : 0;
298 std::vector<T> table_;
301 T invRange_ = T(1) / T(16);
304 std::unique_ptr<Oversampling<T>> oversampler_;
305 int oversamplingFactor_ = 1;
Owning audio buffer and non-owning view for real-time DSP processing.
Describes the audio processing environment (sample rate, block size, channels).
Core mathematical utilities for digital signal processing.
Fractional-position interpolation for delay lines, tables and buffers.
Power-of-two oversampling with polyphase half-band FIR filters.
Non-owning view over audio channel data.
int getNumSamples() const noexcept
Returns the number of samples per channel.
int getNumChannels() const noexcept
Returns the number of channels in this view.
T * getChannel(int ch) const noexcept
Returns a pointer to the sample data for the given channel.
Zero-latency lookup-table waveshaper with RT-safe gain modulation.
void buildTanh(int tableSize=4096)
Builds a normalized tanh (soft clip) table.
int getLatency() const noexcept
Reports the processing latency in samples.
void buildSoftClip(int tableSize=4096)
Builds a cubic soft-clip table.
int getTableSize() const noexcept
T process(T input, T preGain=T(1), T postGain=T(1)) const noexcept
Processes a single sample through the waveshaper with Hermite interpolation.
void buildAsymmetric(int tableSize=4096)
Builds an asymmetric clipping table for even-harmonic generation.
void prepare(const AudioSpec &spec)
Prepares the waveshaper for oversampled block processing.
void buildHardClip(T threshold=T(0.8), int tableSize=4096)
Builds a hard-clip table.
WaveshapeTable()
Constructor. Initializes a safe passthrough table to prevent RT crashes.
bool isReady() const noexcept
void buildFromFunction(std::function< T(T)> func, int tableSize=4096, T xMax=T(8))
Builds the lookup table from an arbitrary transfer function.
void setOversampling(int factor)
Enables oversampling.
void processBlock(AudioBufferView< T > buffer, T preGain=T(1), T postGain=T(1)) noexcept
Processes a buffer view with optional oversampling.
void process(T *__restrict data, int numSamples, T preGain=T(1), T postGain=T(1)) const noexcept
Processes a buffer in-place.
T getInputRange() const noexcept
Returns the half-range of the table's input domain.
int getOversamplingFactor() const noexcept
Main namespace for the DSPark framework.
T interpolateHermite(T y0, T y1, T y2, T y3, T frac) noexcept
4-point, 3rd-order Hermite interpolation (optimized x-form).
Describes the audio environment for a DSP processor.
double sampleRate
Sample rate in Hz.