From 154cf690cb38b990e6b8a242b6e0155828d58b26 Mon Sep 17 00:00:00 2001 From: abscisys Date: Fri, 23 Dec 2022 18:59:20 +0100 Subject: [PATCH] Finalizing the Phase before testing --- src/Makefile | 2 +- src/fx_phaser.cpp | 123 ++++++++++++++++++++++++++++++++++++++++------ src/fx_phaser.h | 40 ++++++++++++--- src/fx_rack.cpp | 1 + src/fx_rack.h | 1 + 5 files changed, 142 insertions(+), 25 deletions(-) diff --git a/src/Makefile b/src/Makefile index 40d59c7..6e0e621 100644 --- a/src/Makefile +++ b/src/Makefile @@ -10,7 +10,7 @@ OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \ mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \ sysexfileloader.o performanceconfig.o perftimer.o \ effect_compressor.o effect_platervbstereo.o \ - fx.o fx_tape_delay.o fx_shimmer_reverb.o fx_rack.o \ + fx.o fx_phaser.o fx_tape_delay.o fx_shimmer_reverb.o fx_rack.o \ uibuttons.o midipin.o OPTIMIZE = -O3 diff --git a/src/fx_phaser.cpp b/src/fx_phaser.cpp index 1ff06e3..1dc360d 100644 --- a/src/fx_phaser.cpp +++ b/src/fx_phaser.cpp @@ -2,17 +2,19 @@ #include -PhaserStage::PhaserStage(float32_t sampling_rate, float32_t frequency, float32_t q) : +PhaserParameter::PhaserParameter(float32_t sampling_rate, float32_t frequency, float32_t q) : FXBase(sampling_rate), frequency_(frequency), q_(q) { - memset(this->z1, 0, 2 * sizeof(float32_t)); - memset(this->z2, 0, 2 * sizeof(float32_t)); this->computeCoefficients(); } -void PhaserStage::computeCoefficients() +PhaserParameter::~PhaserParameter() +{ +} + +void PhaserParameter::computeCoefficients() { float32_t w0 = 2.0f * PI * this->getFrequency() / this->getSamplingRate(); float32_t alpha = sin(w0) / (2.0f * this->q_); @@ -23,36 +25,125 @@ void PhaserStage::computeCoefficients() this->b2 = this->a2; } +void PhaserParameter::setFrequency(float32_t frequency) +{ + this->frequency_ = constrain(frequency, 0.1, 10.0); + this->computeCoefficients(); +} + +float32_t PhaserParameter::getFrequency() const +{ + return this->frequency_; +} + +void PhaserParameter::setQ(float32_t q) +{ + this->q_ = constrain(q, 0.5f, 10.0f); + this->computeCoefficients(); +} + +float32_t PhaserParameter::getQ() const +{ + return this->q_; +} + + + +// PhaserStage implementation +PhaserStage::PhaserStage(float32_t sampling_rate, PhaserParameter* params) : + FXBase(sampling_rate), + params_(params) +{ + memset(this->z1, 0, 2 * sizeof(float32_t)); + memset(this->z2, 0, 2 * sizeof(float32_t)); +} + void PhaserStage::process(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) { - outL = (this->a0 * inL + this->a1 * this->z1[0] + this->a2 * this->z2[0]) / this->a0; + outL = (this->params_->a0 * inL + this->params_->a1 * this->z1[0] + this->params_->a2 * this->z2[0]) / this->params_->a0; this->z2[0] = this->z1[0]; this->z2[0] = inL; - outR = (this->a0 * inR + this->a1 * this->z1[1] + this->a2 * this->z2[1]) / this->a0; + outR = (this->params_->a0 * inR + this->params_->a1 * this->z1[1] + this->params_->a2 * this->z2[1]) / this->params_->a0; this->z2[1] = this->z1[1]; this->z2[1] = inR; } -void PhaserStage::setFrequency(float32_t frequency) + + +// Phaser implementation +Phaser::Phaser(float32_t sampling_rate, float32_t frequency, float32_t q) : + FX(sampling_rate), + params_(sampling_rate, frequency, q), + phase_(0.0f), + phase_increment_(0.0f) { - this->frequency_ = constrain(frequency, 0.0, 10.0); - this->computeCoefficients(); + this->phase_increment_ = 2.0f * PI * frequency / this->getSamplingRate(); + for(unsigned i = 0; i < NUM_PHASER_STAGES; ++i) + { + this->stages_[i] = new PhaserStage(sampling_rate, &this->params_); + } } -float32_t PhaserStage::getFrequency() const +Phaser::~Phaser() { - return this->frequency_; + for(unsigned i = 0; i < NUM_PHASER_STAGES; ++i) + { + delete this->stages_[i]; + } } -void PhaserStage::setQ(float32_t q) +void Phaser::process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) { - this->q_ = constrain(q, 0.1f, 1.0f); - this->computeCoefficients(); + float sampleL; + float sampleR; + for(unsigned i = 0; i < nSamples; ++i) + { + // Process the input sample through each stage of the phaser + sampleL = *left_input; + sampleR = *right_input; + for(unsigned s = 0; s < NUM_PHASER_STAGES; ++s) + { + this->stages_[s]->process(sampleL, sampleR, sampleL, sampleR); + } + + // Modulate the output of the phaser using the LFO + *left_output = sampleL * (0.5f + 0.5f * cos(this->phase_)); + *right_output = sampleR * (0.5f + 0.5f * cos(this->phase_));; + + // Update the phase of the LFO + this->phase_ += this->phase_increment_; + if(this->phase_ > 2.0f * PI) { + this->phase_ -= 2.0 * PI; + } + + // Move to next input sample + ++left_input; + ++right_input; + + // Move to next output sample + ++left_output; + ++right_output; + } } -float32_t PhaserStage::getQ() const +void Phaser::setFrequency(float32_t frequency) { - return this->q_; + this->params_.setFrequency(frequency); + this->phase_increment_ = 2.0f * PI * frequency / this->getSamplingRate(); +} + +float32_t Phaser::getFrequency() const +{ + return this->params_.getFrequency(); } +void Phaser::setQ(float32_t q) +{ + this->params_.setQ(q); +} + +float32_t Phaser::getQ() const +{ + return this->params_.getQ(); +} diff --git a/src/fx_phaser.h b/src/fx_phaser.h index 657a79f..c1e91ab 100644 --- a/src/fx_phaser.h +++ b/src/fx_phaser.h @@ -20,14 +20,16 @@ #include "fx.h" -class PhaserStage : public FXBase +class PhaserStage; + +class PhaserParameter : public FXBase { - DISALLOW_COPY_AND_ASSIGN(PhaserStage); + friend class PhaserStage; + DISALLOW_COPY_AND_ASSIGN(PhaserParameter); public: - PhaserStage(float32_t sampling_rate, float32_t frequency = 0.5f, float32_t q = 1.0f); - - void process(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR); + PhaserParameter(float32_t sampling_rate, float32_t frequency = 0.5f, float32_t q = 1.0f); + virtual ~PhaserParameter(); void setFrequency(float32_t frequency); inline float32_t getFrequency() const; @@ -42,7 +44,20 @@ private: float32_t q_; // Q factor for the filters float32_t a0, a1, a2, b1, b2; // Coefficients for the stage's filter - float32_t z1[2], z2[2]; // State variables for the stage's filter +}; + +class PhaserStage : public FXBase +{ + DISALLOW_COPY_AND_ASSIGN(PhaserStage); + +public: + PhaserStage(float32_t sampling_rate, PhaserParameter* params); + + void process(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR); + +private: + PhaserParameter* params_; // All paremters of the phaser including the inner coefficients + float32_t z1[2], z2[2]; // State variables for the stage's filter }; #define NUM_PHASER_STAGES 6 @@ -52,11 +67,20 @@ class Phaser : public FX DISALLOW_COPY_AND_ASSIGN(Phaser); public: - Phaser(float32_t sampling_rate, float32_t frequency, float32_t q); + Phaser(float32_t sampling_rate, float32_t frequency = 0.5f, float32_t q = 1.0f); virtual ~Phaser(); virtual void process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples) override; + void setFrequency(float32_t frequency); + inline float32_t getFrequency() const; + + void setQ(float32_t q); + inline float32_t getQ() const; + private: - PhaserStage stages_[NUM_PHASER_STAGES]; + PhaserParameter params_; + float32_t phase_; // Current phase of the LFO + float32_t phase_increment_; // Amount to increment the phase at each sample + PhaserStage* stages_[NUM_PHASER_STAGES]; }; \ No newline at end of file diff --git a/src/fx_rack.cpp b/src/fx_rack.cpp index bab4864..3778984 100644 --- a/src/fx_rack.cpp +++ b/src/fx_rack.cpp @@ -45,6 +45,7 @@ FXRack::FXRack(float32_t sampling_rate) : FX(sampling_rate), fx_chain_() { + this->registerFX(new Phaser(sampling_rate)); this->registerFX(new TapeDelay(sampling_rate)); this->registerFX(new ShimmerReverb(sampling_rate)); } diff --git a/src/fx_rack.h b/src/fx_rack.h index 74fe77d..d425a1d 100644 --- a/src/fx_rack.h +++ b/src/fx_rack.h @@ -20,6 +20,7 @@ #pragma once #include "fx.h" +#include "fx_phaser.h" #include "fx_tape_delay.h" #include "fx_shimmer_reverb.h"