27#include "../Core/DspMath.h"
28#include "../Core/AudioSpec.h"
29#include "../Core/AudioBuffer.h"
30#include "../Core/StateBlob.h"
60 if (!(sampleRate > 0.0))
return;
61 sampleRate_ = sampleRate;
75 if (buffer.getNumChannels() >= 2)
76 process(buffer.getChannel(0), buffer.getChannel(1), buffer.getNumSamples());
87 if (!std::isfinite(width))
return;
88 width_.store(std::max(T(0), width), std::memory_order_relaxed);
92 [[nodiscard]] T
getWidth() const noexcept {
return width_.load(std::memory_order_relaxed); }
104 if (cutoffHz > 0.0 && std::isfinite(cutoffHz))
106 bassMonoCutoff_.store(cutoffHz, std::memory_order_relaxed);
109 bassMonoEnabled_.store(enabled, std::memory_order_release);
118 void process(T* left, T* right,
int numSamples)
noexcept
121 const T currentWidth = width_.load(std::memory_order_relaxed);
122 const bool bassMono = bassMonoEnabled_.load(std::memory_order_acquire);
126 const T coeff = bassMonoCoeff_.load(std::memory_order_relaxed);
134 for (
int i = 0; i < numSamples; ++i)
139 T mid = (l + r) * T(0.5);
140 T side = (l - r) * T(0.5) * currentWidth;
144 sideState_ += coeff * (sideLpIn - sideState_) + antiDenormal_;
145 sideState_ -= antiDenormal_;
146 side = sideLpIn - sideState_;
148 left[i] = mid + side;
149 right[i] = mid - side;
155 for (
int i = 0; i < numSamples; ++i)
157 T mid = (left[i] + right[i]) * T(0.5);
158 T side = (left[i] - right[i]) * T(0.5) * currentWidth;
160 left[i] = mid + side;
161 right[i] = mid - side;
174 [[nodiscard]] std::vector<uint8_t>
getState()
const
177 w.
write(
"width", width_.load(std::memory_order_relaxed));
178 w.
write(
"bassMono", bassMonoEnabled_.load(std::memory_order_relaxed));
179 w.
write(
"bassCutoff",
static_cast<float>(bassMonoCutoff_.load(std::memory_order_relaxed)));
190 static_cast<double>(r.
read(
"bassCutoff", 100.0f)));
197 if (sampleRate_ > 0.0)
200 T coeff =
static_cast<T
>(1.0 - std::exp(-std::numbers::pi * 2.0 * cutoff / sampleRate_));
201 bassMonoCoeff_.store(coeff, std::memory_order_relaxed);
206 double sampleRate_ = 48000.0;
209 std::atomic<T> width_ { T(1) };
210 std::atomic<bool> bassMonoEnabled_ {
false };
211 std::atomic<double> bassMonoCutoff_ { 100.0 };
212 std::atomic<T> bassMonoCoeff_ { T(0) };
218 static constexpr T antiDenormal_ =
static_cast<T
>(1e-15);
Non-owning view over audio channel data.
Tolerant reader: missing keys yield defaults, unknown keys are skipped.
float read(const char *key, float defaultValue) const
Reads a float, or defaultValue when the key is absent.
bool isValid() const noexcept
uint32_t processorId() const noexcept
Serializes key/value parameters into a versioned blob.
std::vector< uint8_t > blob() const
Finalizes and returns the blob.
void write(const char *key, float value)
Writes a float parameter.
High-performance stereo image processor with phase-aligned bass mono.
void setWidth(T width) noexcept
Sets the overall stereo width factor.
void processBlock(AudioBufferView< T > buffer) noexcept
Processes an AudioBufferView in-place.
void process(T *left, T *right, int numSamples) noexcept
Process a full block of audio. Optimized for SIMD vectorization.
void prepare(const AudioSpec &spec) noexcept
Prepares from AudioSpec (unified API).
std::vector< uint8_t > getState() const
Serializes the parameter state (setup/UI threads; allocates).
T getWidth() const noexcept
Returns current width setting.
void prepare(double sampleRate) noexcept
Prepares the processor and resets internal states.
void setBassMono(bool enabled, double cutoffHz=100.0) noexcept
Toggles Bass Mono and updates the crossover frequency.
void updateBassMonoCoeff(double cutoff) noexcept
bool setState(const uint8_t *data, size_t size)
Restores parameters from a blob (tolerant; rejects foreign ids).
void reset() noexcept
Clears the internal filter states to prevent artifact ringing.
Main namespace for the DSPark framework.
constexpr uint32_t stateId(const char(&tag)[5]) noexcept
Builds a FOURCC processor id, e.g. dspark::stateId("COMP").
Describes the audio environment for a DSP processor.