29#include "../Core/AudioBuffer.h"
30#include "../Core/AudioSpec.h"
31#include "../Core/DenormalGuard.h"
32#include "../Core/DspMath.h"
33#include "../Core/Hilbert.h"
34#include "../Core/StateBlob.h"
81 hilberts_.resize(numChannels_);
82 for (
auto& h : hilberts_) {
86 currentMix_ = mix_.load(std::memory_order_relaxed);
96 const int numCh = std::min(buffer.getNumChannels(), numChannels_);
97 const int numSamples = buffer.getNumSamples();
98 if (numSamples == 0 || numCh == 0)
return;
106 const T targetMix = mix_.load(std::memory_order_relaxed);
107 const T shiftHz = shift_.load(std::memory_order_relaxed);
113 const T mixInc = (targetMix - currentMix_) /
static_cast<T
>(numSamples);
116 const double w = (shiftHz * 2.0 * std::numbers::pi) / sampleRate_;
117 const T cos_w =
static_cast<T
>(std::cos(w));
118 const T sin_w =
static_cast<T
>(std::sin(w));
121 const T startCos =
static_cast<T
>(std::cos(phase_));
122 const T startSin =
static_cast<T
>(std::sin(phase_));
125 for (
int ch = 0; ch < numCh; ++ch)
127 T* data = buffer.getChannel(ch);
128 auto& hilbert = hilberts_[ch];
134 T smoothMix = currentMix_;
136 for (
int i = 0; i < numSamples; ++i)
141 auto h = hilbert.process(data[i]);
144 T shifted = h.real * u - h.imag * v;
147 data[i] = h.real + (shifted - h.real) * smoothMix;
150 T next_u = u * cos_w - v * sin_w;
151 T next_v = u * sin_w + v * cos_w;
159 currentMix_ = targetMix;
162 phase_ += w * numSamples;
165 constexpr double kTwoPi = 2.0 * std::numbers::pi;
166 phase_ = std::fmod(phase_, kTwoPi);
167 if (phase_ < 0.0) phase_ += kTwoPi;
176 for (
auto& h : hilberts_) {
190 if (!std::isfinite(hz))
return;
191 shift_.store(hz, std::memory_order_relaxed);
201 if (!std::isfinite(mix))
return;
202 mix_.store(std::clamp(mix, T(0), T(1)), std::memory_order_relaxed);
206 [[nodiscard]] T
getShift() const noexcept {
return shift_.load(std::memory_order_relaxed); }
209 [[nodiscard]] T
getMix() const noexcept {
return mix_.load(std::memory_order_relaxed); }
223 [[nodiscard]] std::vector<uint8_t>
getState()
const
228 w.
write(
"shift",
static_cast<float>(shift_.load(std::memory_order_relaxed)));
229 w.
write(
"mix",
static_cast<float>(mix_.load(std::memory_order_relaxed)));
244 double sampleRate_ = 44100.0;
245 int numChannels_ = 0;
250 std::atomic<T> shift_{ T(0) };
251 std::atomic<T> mix_{ T(1) };
254 T currentMix_{ T(1) };
256 std::vector<Hilbert<T>> hilberts_;
Non-owning view over audio channel data.
RAII scope guard to disable denormalised (subnormal) floating-point numbers.
Constant-Hz frequency shift optimized via Quadrature Oscillator.
static constexpr int getLatency() noexcept
Reports the processing latency in samples.
std::vector< uint8_t > getState() const
Serializes the parameter state (setup/UI threads; allocates).
void setMix(T mix) noexcept
Sets the dry/wet mix. Smoothed internally.
T getShift() const noexcept
void reset() noexcept
Resets internal filter states and phase accumulator.
void prepare(const AudioSpec &spec)
Prepares the frequency shifter state and allocates internal buffers.
T getMix() const noexcept
bool setState(const uint8_t *data, size_t size)
Restores parameters from a blob (tolerant; rejects foreign ids).
void setShift(T hz) noexcept
Sets the frequency shift amount in Hz.
void processBlock(AudioBufferView< T > buffer) noexcept
Processes audio in-place applying the frequency shift.
static constexpr int getLatencySamples() noexcept
FIR group-delay latency applied to both outputs, in samples.
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.
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.
constexpr bool isValid() const noexcept
Checks if the specification contains valid, processable parameters.
int numChannels
Number of audio channels (e.g., 1 = mono, 2 = stereo).
double sampleRate
Sample rate in Hz.