Additional round of optimisations

pull/495/head
abscisys 2 years ago
parent 2a272801d3
commit f9f6f71835
  1. 32
      src/effect_platervbstereo.cpp
  2. 5
      src/fx.cpp
  3. 4
      src/fx.h
  4. 15
      src/fx_chorus.cpp
  5. 2
      src/fx_components.cpp
  6. 2
      src/fx_components.h
  7. 5
      src/fx_delay.cpp
  8. 52
      src/fx_engine.hpp
  9. 22
      src/fx_flanger.cpp
  10. 23
      src/fx_orbitone.cpp
  11. 63
      src/fx_phaser.cpp
  12. 17
      src/fx_phaser.h
  13. 22
      src/fx_rack.cpp
  14. 20
      src/fx_shimmer_reverb.cpp
  15. 4
      src/fx_tube.cpp
  16. 4
      src/fx_unit.hpp
  17. 6
      src/fx_unit2.hpp
  18. 2
      src/mixing_console.hpp
  19. 14
      src/test/Makefile
  20. 29
      src/test/beta.cpp
  21. 11
      src/test/beta_lowlevel.cpp
  22. 11
      src/test/cppcheck-suppression-list.txt
  23. BIN
      src/test/test3.wav
  24. 67
      src/test/test_cpp.cpp
  25. 2
      src/test/test_cpp_performance.cpp
  26. 4
      src/test/test_framework.cpp
  27. 275
      src/test/test_fxLevelTuning.cpp
  28. 3
      src/test/test_fx_components.cpp
  29. 24
      src/test/test_fx_helper.cpp
  30. 39
      src/test/test_fx_helper.h
  31. 386
      src/test/test_fx_mixing_console.cpp
  32. 75
      src/test/test_fx_plate_reverb.cpp
  33. 56
      src/test/test_fx_rack.cpp
  34. 130
      src/test/test_unitFXTuning.cpp
  35. 15
      src/test/wave.h
  36. 95
      src/test/wavein.cpp
  37. 4
      src/test/waveout.cpp

@ -84,11 +84,10 @@ const int16_t AudioWaveformSine[257] = {
};
AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) :
FXElement(samplerate)
FXElement(samplerate, 2.54f),
input_attn(0.5f),
in_allp_k(INP_ALLP_COEFF)
{
input_attn = 0.5f;
in_allp_k = INP_ALLP_COEFF;
memset(in_allp1_bufL, 0, sizeof(in_allp1_bufL));
memset(in_allp2_bufL, 0, sizeof(in_allp2_bufL));
memset(in_allp3_bufL, 0, sizeof(in_allp3_bufL));
@ -98,6 +97,8 @@ AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) :
in_allp3_idxL = 0;
in_allp4_idxL = 0;
in_allp_out_L = 0.0f;
memset(in_allp1_bufR, 0, sizeof(in_allp1_bufR));
memset(in_allp2_bufR, 0, sizeof(in_allp2_bufR));
memset(in_allp3_bufR, 0, sizeof(in_allp3_bufR));
@ -149,6 +150,9 @@ AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) :
master_lowpass_l = 0.0f;
master_lowpass_r = 0.0f;
rv_time_k = 0.0f;
rv_time_scaler = 0.0f;
lfo1_phase_acc = 0;
lfo1_adder = (UINT32_MAX + 1)/(samplerate * LFO1_FREQ_HZ);
lfo2_phase_acc = 0;
@ -173,14 +177,14 @@ void AudioEffectPlateReverb::reset()
memset(in_allp2_bufR, 0, sizeof(in_allp2_bufR));
memset(in_allp3_bufR, 0, sizeof(in_allp3_bufR));
memset(in_allp4_bufR, 0, sizeof(in_allp4_bufR));
memset(lp_allp1_buf, 0, sizeof(lp_allp1_buf));
memset(lp_allp2_buf, 0, sizeof(lp_allp2_buf));
memset(lp_allp3_buf, 0, sizeof(lp_allp3_buf));
memset(lp_allp4_buf, 0, sizeof(lp_allp4_buf));
memset(lp_dly1_buf, 0, sizeof(lp_dly1_buf));
memset(lp_dly2_buf, 0, sizeof(lp_dly2_buf));
memset(lp_dly3_buf, 0, sizeof(lp_dly3_buf));
memset(lp_dly4_buf, 0, sizeof(lp_dly4_buf));
memset(lp_allp1_buf, 0, sizeof(lp_allp1_buf));
memset(lp_allp2_buf, 0, sizeof(lp_allp2_buf));
memset(lp_allp3_buf, 0, sizeof(lp_allp3_buf));
memset(lp_allp4_buf, 0, sizeof(lp_allp4_buf));
memset(lp_dly1_buf, 0, sizeof(lp_dly1_buf));
memset(lp_dly2_buf, 0, sizeof(lp_dly2_buf));
memset(lp_dly3_buf, 0, sizeof(lp_dly3_buf));
memset(lp_dly4_buf, 0, sizeof(lp_dly4_buf));
}
void AudioEffectPlateReverb::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
@ -398,7 +402,7 @@ void AudioEffectPlateReverb::processSample(float32_t inL, float32_t inR, float32
temp1 = acc - master_lowpass_l;
master_lowpass_l += temp1 * master_lowpass_f;
outL = master_lowpass_l;
outL = master_lowpass_l * this->OutputLevelCorrector;
// Channel R
#ifdef TAP1_MODULATED
@ -442,7 +446,7 @@ void AudioEffectPlateReverb::processSample(float32_t inL, float32_t inR, float32
temp1 = acc - master_lowpass_r;
master_lowpass_r += temp1 * master_lowpass_f;
outR = master_lowpass_r;
outR = master_lowpass_r * this->OutputLevelCorrector;
}
void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t* inblockR, float32_t* rvbblockL, float32_t* rvbblockR, uint16_t len)

@ -14,8 +14,9 @@ float32_t FXBase::getSamplingRate() const
return this->SamplingRate;
}
FXElement::FXElement(float32_t sampling_rate) :
FXBase(sampling_rate)
FXElement::FXElement(float32_t sampling_rate, float32_t output_level_corrector) :
FXBase(sampling_rate),
OutputLevelCorrector(output_level_corrector)
{
}

@ -48,7 +48,9 @@ class FXElement : public FXBase
DISALLOW_COPY_AND_ASSIGN(FXElement);
protected:
FXElement(float32_t sampling_rate);
FXElement(float32_t sampling_rate, float32_t output_level_corrector = 1.0f);
const float32_t OutputLevelCorrector;
public:
virtual ~FXElement();

@ -6,7 +6,7 @@
#define LFO2_MAX_FREQ 0.35f
Chorus::Chorus(float32_t sampling_rate) :
FXElement(sampling_rate),
FXElement(sampling_rate, 1.18f),
engine_(sampling_rate, 0.0f),
rate_(0.0f),
depth_(0.0f),
@ -56,19 +56,18 @@ void Chorus::processSample(float32_t inL, float32_t inR, float32_t& outL, float3
float32_t wet;
// Sum L & R channel to send to chorus line.
c.read(inL, 0.5f);
c.read(inR, 0.5f);
c.write(line, 0.0f);
c.read(inL + inR, 0.5f);
c.writeAndLoad(line, 0.0f);
c.interpolate(line, sin_1 * this->fullscale_depth_ + 1200, 0.5f);
c.interpolate(line, sin_2 * this->fullscale_depth_ + 800, 0.5f);
c.write(wet, 0.0f);
outL = wet;
c.writeAndLoad(wet, 0.0f);
outL = wet * this->OutputLevelCorrector;
c.interpolate(line, cos_1 * this->fullscale_depth_ + 800, 0.5f);
c.interpolate(line, cos_2 * this->fullscale_depth_ + 1200, 0.5f);
c.write(wet, 0.0f);
outR = wet;
c.writeAndLoad(wet, 0.0f);
outR = wet * this->OutputLevelCorrector;
}
void Chorus::setRate(float32_t rate)

@ -498,7 +498,7 @@ float32_t PerlinNoiseGenerator::getRate() const
return this->rate_;
}
float32_t PerlinNoiseGenerator::getCurrent() const
float32_t PerlinNoiseGenerator::current() const
{
return this->current_;
}

@ -396,7 +396,7 @@ public:
void setRate(float32_t rate);
float32_t getRate() const;
float32_t getCurrent() const;
float32_t current() const;
virtual void reset() override;
float32_t process();

@ -50,7 +50,7 @@ void Delay::LowHighPassFilter::processSample(float32_t inL, float32_t inR, float
}
Delay::Delay(const float32_t sampling_rate, float32_t default_delay_time, float32_t default_flutter_level, float32_t default_feedback_level) :
FXElement(sampling_rate),
FXElement(sampling_rate, 3.46f),
MaxSampleDelayTime((MAX_DELAY_TIME + MAX_FLUTTER_DELAY_TIME) * sampling_rate * MAX_DELAY_TIME),
read_pos_L_(0),
read_pos_R_(0),
@ -133,6 +133,9 @@ void Delay::processSample(float32_t inL, float32_t inR, float32_t& outL, float32
{
this->read_pos_R_ -= this->MaxSampleDelayTime;
}
outL *= this->OutputLevelCorrector;
outR *= this->OutputLevelCorrector;
}
void Delay::setLeftDelayTime(float32_t delay_time)

@ -1,18 +1,11 @@
#pragma once
#if defined(DEBUG)
#include <iostream>
#include <cmath>
#endif
#include <algorithm>
#include <climits>
#include <cassert>
#include "fx_components.h"
#define STEP_UP(x) x
enum Format
{
FORMAT_12_BIT,
@ -214,14 +207,14 @@ public:
this->accumulator_ = value;
}
inline void read(float32_t value, float32_t scale)
inline void read(float32_t value)
{
this->accumulator_ += value * scale;
this->accumulator_ += value;
}
inline void read(float32_t value)
inline void read(float32_t value, float32_t scale)
{
this->accumulator_ += value;
this->accumulator_ += value * scale;
}
inline void write(float32_t& value)
@ -235,10 +228,24 @@ public:
this->accumulator_ *= scale;
}
inline void writeAndLoad(float32_t& value, float32_t newValue)
{
value = this->accumulator_;
this->load(newValue);
}
template <typename D>
inline void write(D& d, int32_t offset, float32_t scale)
inline void directWrite(float32_t value, D& d)
{
this->load(value);
this->writeAndLoad(d, 0, 0.0f);
}
template <typename D>
inline void write(D& d, int32_t offset)
{
assert((D::base + D::length) <= size);
T w = DataType<format>::compress(this->accumulator_);
if(offset == -1)
{
@ -248,15 +255,34 @@ public:
{
this->buffer_[(this->write_ptr_ + D::base + offset) & MASK] = w;
}
}
template <typename D>
inline void write(D& d, int32_t offset, float32_t scale)
{
this->write(d, offset);
this->accumulator_ *= scale;
}
template <typename D>
inline void writeAndLoad(D& d, int32_t offset, float32_t newValue)
{
this->write(d, offset);
this->load(newValue);
}
template <typename D>
inline void write(D& d, float32_t scale)
{
this->write(d, 0, scale);
}
template <typename D>
inline void writeAndLoad(D& d, float32_t newValue)
{
this->writeAndLoad(d, 0, newValue);
}
template <typename D>
inline void writeAllPass(D& d, int32_t offset, float32_t scale)
{
@ -373,7 +399,7 @@ public:
{
for(unsigned i = 0; i < LFOIndex::kLFOCount; ++i)
{
c->lfo_value_[i] = STEP_UP(this->lfo_[i]->process());
c->lfo_value_[i] = this->lfo_[i]->process();
}
}
}

@ -1,9 +1,7 @@
#include "fx_flanger.h"
#include <cmath>
Flanger::Flanger(float32_t sampling_rate, float32_t rate, float32_t depth, float32_t feedback) :
FXElement(sampling_rate),
FXElement(sampling_rate, 1.17f),
MaxDelayLineSize(static_cast<unsigned>(MAX_FLANGER_DELAY * sampling_rate)),
write_index_(0)
{
@ -40,7 +38,7 @@ void Flanger::reset()
{
memset(this->delay_lineL_, 0, this->MaxDelayLineSize * sizeof(float32_t));
memset(this->delay_lineR_, 0, this->MaxDelayLineSize * sizeof(float32_t));
memset(this->feedback_samples_, 0, 2 * sizeof(float32_t));
memset(this->feedback_samples_, 0, StereoChannels::kNumChannels * sizeof(float32_t));
this->write_index_ = 0;
for(unsigned i = 0; i < LFOIndex::kLFOCount; ++i)
@ -52,8 +50,8 @@ void Flanger::reset()
void Flanger::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{
// Write sample and any feedback into delay buffers
this->delay_lineL_[this->write_index_] = inL + this->feedback_samples_[0];
this->delay_lineR_[this->write_index_] = inR + this->feedback_samples_[1];
this->delay_lineL_[this->write_index_] = inL + this->feedback_samples_[StereoChannels::Left ];
this->delay_lineR_[this->write_index_] = inR + this->feedback_samples_[StereoChannels::Right];
++this->write_index_;
if(this->write_index_ >= this->MaxDelayLineSize)
@ -86,8 +84,8 @@ void Flanger::processSample(float32_t inL, float32_t inR, float32_t& outL, float
}
// Calculate linear interpolation point for left channel
int currentL = (int)delayReadHeadL;
int nextL = currentL + 1;
int32_t currentL = static_cast<int32_t>(delayReadHeadL);
int32_t nextL = currentL + 1;
float32_t fractionL = delayReadHeadL - currentL;
if(nextL >= static_cast<int>(this->MaxDelayLineSize))
{
@ -95,8 +93,8 @@ void Flanger::processSample(float32_t inL, float32_t inR, float32_t& outL, float
}
// Calculate linear interpolation point for right channel
int currentR = (int)delayReadHeadR;
int nextR = currentR + 1;
int32_t currentR = static_cast<int32_t>(delayReadHeadR);
int32_t nextR = currentR + 1;
float32_t fractionR = delayReadHeadR - currentR;
if(nextR >= static_cast<int>(this->MaxDelayLineSize))
{
@ -111,8 +109,8 @@ void Flanger::processSample(float32_t inL, float32_t inR, float32_t& outL, float
this->feedback_samples_[StereoChannels::Left ] = delay_sample_l * this->feedback_;
this->feedback_samples_[StereoChannels::Right] = delay_sample_r * this->feedback_;
outL = delay_sample_l;
outR = delay_sample_r;
outL = delay_sample_l * this->OutputLevelCorrector;
outR = delay_sample_r * this->OutputLevelCorrector;
}
void Flanger::setRate(float32_t rate)

@ -1,12 +1,10 @@
#include "fx_orbitone.h"
#include <cmath>
#define LFO_SLOW_MAX_FREQUENCY 1.0f
#define LFO_FAST_MAX_FREQUENCY 8.8f
Orbitone::Orbitone(float32_t sampling_rate, float32_t rate, float32_t depth) :
FXElement(sampling_rate),
FXElement(sampling_rate, 1.8f),
engine_(sampling_rate, 0.0f),
depth_(0.0f),
fullscale_depth_(0.0f)
@ -47,8 +45,8 @@ void Orbitone::reset()
void Orbitone::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{
typedef Engine::Reserve<2047, Engine::Reserve<2047> > Memory;
Engine::DelayLine<Memory, 0> line_l;
Engine::DelayLine<Memory, 1> line_r;
Engine::DelayLine<Memory, StereoChannels::Left > line_l;
Engine::DelayLine<Memory, StereoChannels::Right> line_r;
Engine::Context c;
this->engine_.start(&c);
@ -70,23 +68,20 @@ void Orbitone::processSample(float32_t inL, float32_t inR, float32_t& outL, floa
float32_t wet = 0.0f;
// Sum L & R channel to send to chorus line.
c.read(inL, 1.0f);
c.write(line_l, 0.0f);
c.read(inR, 1.0f);
c.write(line_r, 0.0f);
c.directWrite(inL, line_l);
c.directWrite(inR, line_r);
c.interpolate(line_l, mod_1 + 1024, 0.33f);
c.interpolate(line_l, mod_2 + 1024, 0.33f);
c.interpolate(line_r, mod_3 + 1024, 0.33f);
c.write(wet, 0.0f);
outL = wet;
c.writeAndLoad(wet, 0.0f);
outL = wet * this->OutputLevelCorrector;
c.interpolate(line_r, mod_1 + 1024, 0.33f);
c.interpolate(line_r, mod_2 + 1024, 0.33f);
c.interpolate(line_l, mod_3 + 1024, 0.33f);
c.write(wet, 0.0f);
outR = wet;
c.writeAndLoad(wet, 0.0f);
outR = wet * this->OutputLevelCorrector;
}
void Orbitone::setRate(float32_t rate)

@ -1,11 +1,7 @@
#include "fx_phaser.h"
#include <algorithm>
#include <cmath>
Phaser::AllpassDelay::AllpassDelay() :
FXElement(0.0f),
a1_(0.0f)
FXElement(0.0f)
{
this->reset();
}
@ -16,32 +12,37 @@ Phaser::AllpassDelay::~AllpassDelay()
void Phaser::AllpassDelay::reset()
{
memset(this->z_, 0, 2 * sizeof(float32_t));
memset(this->a1_, 0, StereoChannels::kNumChannels * sizeof(float32_t));
memset(this->z_, 0, StereoChannels::kNumChannels * sizeof(float32_t));
}
void Phaser::AllpassDelay::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{
outL = inL * -this->a1_ + this->z_[0];
this->z_[0] = outL * this->a1_ + inL;
outL = inL * -this->a1_[StereoChannels::Left ] + this->z_[StereoChannels::Left ];
this->z_[StereoChannels::Left ] = outL * this->a1_[StereoChannels::Left ] + inL;
outR = inR * -this->a1_ + this->z_[1];
this->z_[1] = outR * this->a1_ + inR;
outR = inR * -this->a1_[StereoChannels::Right] + this->z_[StereoChannels::Right];
this->z_[StereoChannels::Right] = outR * this->a1_[StereoChannels::Right] + inR;
}
void Phaser::AllpassDelay::setDelay(float32_t delay)
void Phaser::AllpassDelay::setDelay(float32_t delayL, float32_t delayR)
{
this->a1_ = (1.0f - delay) / (1.0f + delay);
this->a1_[StereoChannels::Left ] = (1.0f - delayL) / (1.0f + delayL);
this->a1_[StereoChannels::Right] = (1.0f - delayR) / (1.0f + delayR);
}
Phaser::Phaser(float32_t sampling_rate, float32_t rate, float32_t depth, float32_t feedback, unsigned nb_stages) :
FXElement(sampling_rate),
lfo_(sampling_rate, 0.0f, 2.5f),
depth_(0.0f),
gain_(1.0f),
feedback_(0.0f),
dmin_(0.0f),
dmax_(0.0f)
{
this->lfo_[StereoChannels::Left ] = new LFO(sampling_rate, 0.0f, 2.5f);
this->lfo_[StereoChannels::Right] = new LFO(sampling_rate, 0.0f, 2.5f, Constants::MPI_2);
this->setRate(rate);
this->setDepth(depth);
this->setFeedback(feedback);
@ -53,36 +54,42 @@ Phaser::Phaser(float32_t sampling_rate, float32_t rate, float32_t depth, float32
Phaser::~Phaser()
{
delete this->lfo_[StereoChannels::Left ];
delete this->lfo_[StereoChannels::Right];
}
void Phaser::reset()
{
memset(this->z_, 0, 2 * sizeof(float32_t));
memset(this->z_, 0, StereoChannels::kNumChannels * sizeof(float32_t));
for(unsigned i = 0; i < MAX_NB_PHASES; ++i)
{
this->stages_[i].reset();
}
this->lfo_.reset();
this->lfo_[StereoChannels::Left ]->reset();
this->lfo_[StereoChannels::Right]->reset();
}
void Phaser::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{
float32_t d = this->dmin_ + (this->dmax_ - this->dmin_) * ((1.0f + this->lfo_.process()) / 2.0f);
float32_t dL = this->dmin_ + (this->dmax_ - this->dmin_) * ((1.0f + this->lfo_[StereoChannels::Left ]->process()) / 2.0f);
float32_t dR = this->dmin_ + (this->dmax_ - this->dmin_) * ((1.0f + this->lfo_[StereoChannels::Right]->process()) / 2.0f);
float32_t sampleL = inL + this->feedback_ * this->z_[0];
float32_t sampleR = inR + this->feedback_ * this->z_[1];
float32_t sampleL = inL + this->feedback_ * this->z_[StereoChannels::Left ];
float32_t sampleR = inR + this->feedback_ * this->z_[StereoChannels::Right];
for(unsigned i = 0; i < this->nb_stages_; ++i)
{
this->stages_[i].setDelay(d);
this->stages_[i].setDelay(dL, dR);
this->stages_[i].processSample(sampleL, sampleR, sampleL, sampleR);
}
this->z_[0] = sampleL;
this->z_[1] = sampleR;
this->z_[StereoChannels::Left ] = sampleL;
this->z_[StereoChannels::Right] = sampleR;
outL = inL + this->z_[StereoChannels::Left ] * this->depth_;
outR = inR + this->z_[StereoChannels::Right] * this->depth_;
outL *= this->gain_;
outR *= this->gain_;
}
void Phaser::setFrequencyRange(float32_t min_frequency, float32_t max_frequency)
@ -94,21 +101,23 @@ void Phaser::setFrequencyRange(float32_t min_frequency, float32_t max_frequency)
void Phaser::setRate(float32_t rate)
{
rate = constrain(rate, 0.0f, 1.0f);
this->lfo_.setNormalizedFrequency(rate);
this->lfo_[StereoChannels::Left ]->setNormalizedFrequency(rate);
this->lfo_[StereoChannels::Right]->setNormalizedFrequency(rate);
}
inline float32_t Phaser::getRate() const
float32_t Phaser::getRate() const
{
return this->lfo_.getNormalizedFrequency();
return this->lfo_[StereoChannels::Left]->getNormalizedFrequency();
}
void Phaser::setDepth(float32_t depth)
{
depth = constrain(depth, 0.0f, 1.0f);
this->depth_ = depth;
this->gain_ = this->OutputLevelCorrector / (1.0f + depth);
}
inline float32_t Phaser::getDepth() const
float32_t Phaser::getDepth() const
{
return this->depth_;
}
@ -119,7 +128,7 @@ void Phaser::setFeedback(float32_t feedback)
this->feedback_ = feedback;
}
inline float32_t Phaser::getFeedback() const
float32_t Phaser::getFeedback() const
{
return this->feedback_;
}

@ -35,13 +35,13 @@ public:
AllpassDelay();
virtual ~AllpassDelay();
virtual void reset();
virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR);
virtual void reset() override;
virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override;
void setDelay(float32_t delay);
void setDelay(float32_t delayL, float32_t delayR);
private:
float32_t a1_;
float32_t a1_[StereoChannels::kNumChannels];
float32_t z_[StereoChannels::kNumChannels];
IMPLEMENT_DUMP(
@ -99,8 +99,9 @@ public:
unsigned getNbStages() const;
private:
LFO lfo_;
LFO* lfo_[StereoChannels::kNumChannels];
float32_t depth_;
float32_t gain_;
float32_t feedback_;
float32_t dmin_;
float32_t dmax_;
@ -142,7 +143,8 @@ private:
if(deepInspection)
{
this->lfo_.dump(out, deepInspection, tag + ".lfo_");
this->lfo_[StereoChannels::Left ]->dump(out, deepInspection, tag + ".lfo_[ L ]");
this->lfo_[StereoChannels::Right]->dump(out, deepInspection, tag + ".lfo_[ R ]");
for(unsigned i = 0; i < MAX_NB_PHASES; ++i)
{
this->stages_[i].dump(out, deepInspection, tag + ".stages_[ " + std::to_string(i) + " ]");
@ -161,7 +163,8 @@ private:
if(deepInspection)
{
nb_errors += this->lfo_.inspect(inspector, deepInspection, tag + ".lfo_");
nb_errors += this->lfo_[StereoChannels::Left ]->inspect(inspector, deepInspection, tag + ".lfo_[ L ]");
nb_errors += this->lfo_[StereoChannels::Right]->inspect(inspector, deepInspection, tag + ".lfo_[ R ]");
for(unsigned i = 0; i < MAX_NB_PHASES; ++i)
{
nb_errors += this->stages_[i].inspect(inspector, deepInspection, tag + ".stages_[ " + std::to_string(i) + " ]");

@ -41,10 +41,9 @@ FXRack::~FXRack()
inline void FXRack::reset()
{
auto end = this->fx_chain_.end();
for(FXChain::iterator it = this->fx_chain_.begin(); it != end; it++)
for(FXElement* fx : this->fx_chain_)
{
(*it)->reset();;
fx->reset();
}
}
@ -61,19 +60,14 @@ inline void FXRack::processSample(float32_t inL, float32_t inR, float32_t& outL,
void FXRack::process(float32_t* left_input, float32_t* right_input, float32_t* left_output, float32_t* right_output, size_t nSamples)
{
float32_t sampleInL;
float32_t sampleInR;
float32_t sampleOutL;
float32_t sampleOutR;
for(unsigned i = 0; i < nSamples; ++i)
{
sampleInL = *left_input;
sampleInR = *right_input;
sampleOutL = 0.0f;
sampleOutR = 0.0f;
float32_t sampleInL = *left_input;
float32_t sampleInR = *right_input;
float32_t sampleOutL = 0.0f;
float32_t sampleOutR = 0.0f;
if(this->isEnable())
if(this->isEnable())
{
this->processSample(sampleInL, sampleInR, sampleOutL, sampleOutR);
@ -86,7 +80,7 @@ void FXRack::process(float32_t* left_input, float32_t* right_input, float32_t* l
*left_output = sampleInL;
*right_output = sampleInR;
}
// Move inputs by 1 sample
++left_input;
++right_input;

@ -1,14 +1,12 @@
#include "fx_shimmer_reverb.h"
#include <cmath>
#include <algorithm>
#define TAIL , -1
ShimmerReverb::ShimmerReverb(float32_t sampling_rate) :
FXElement(sampling_rate),
engine_(sampling_rate),
input_gain_(-1.0f),
reverb_time_(0.0f),
diffusion_(-1.0f),
lp_(-1.0f),
lp_decay_1_(0.0f),
@ -18,8 +16,11 @@ ShimmerReverb::ShimmerReverb(float32_t sampling_rate) :
this->engine_.setLFOFrequency(Engine::LFOIndex::LFO_2, 0.3f);
this->setInputGain(1.0f);
this->setLP(0.7f);
this->setTime(0.7f);
this->setDiffusion(0.625f);
this->setLP(0.7f);
this->reset();
}
ShimmerReverb::~ShimmerReverb()
@ -75,7 +76,7 @@ void ShimmerReverb::processSample(float32_t inL, float32_t inR, float32_t& outL,
// Smear AP1 inside the loop.
c.interpolate(ap1, 10.0f, Engine::LFOIndex::LFO_1, 60.0f, 1.0f);
c.write(ap1, 100, 0.0f);
c.writeAndLoad(ap1, 100, 0.0f);
c.read(inL + inR, gain);
// Diffuse through 4 allpasses.
@ -97,21 +98,20 @@ void ShimmerReverb::processSample(float32_t inL, float32_t inR, float32_t& outL,
c.writeAllPass(dap1a, kap);
c.read(dap1b TAIL, kap);
c.writeAllPass(dap1b, -kap);
c.write(del1, 1.5f);
c.write(wet, 0.0f);
c.write(del1, 2.0f);
c.writeAndLoad(wet, 0.0f);
outL = wet;
c.load(apout);
// c.interpolate(del1, 4450.0f, Engine::LFOIndex::LFO_1, 50.0f, krt);
c.read(del1 TAIL, krt);
c.lp(lp_2, klp);
c.read(dap2a TAIL, kap);
c.writeAllPass(dap2a, -kap);
c.read(dap2b TAIL, -kap);
c.writeAllPass(dap2b, kap);
c.write(del2, 1.5f);
c.write(wet, 0.0f);
c.write(del2, 2.0f);
c.writeAndLoad(wet, 0.0f);
outR = wet;

@ -1,7 +1,5 @@
#include "fx_tube.h"
#include <cmath>
Tube::Tube(float32_t samplingRate) :
FXElement(samplingRate),
overdrive_(1.0f),
@ -44,7 +42,7 @@ void Tube::setOverdrive(float32_t overdrive)
{
this->overdrive_ = overdrive;
this->saturator_factor_ = 1.0f + N * overdrive;
this->gain_factor_ = 1.0f / std::log(1.0f + this->saturator_factor_);
this->gain_factor_ = this->OutputLevelCorrector / std::log(1.0f + this->saturator_factor_);
}
}

@ -81,7 +81,7 @@ public:
{
}
void reset()
void reset() override
{
if(!this->is_reset_)
{
@ -90,7 +90,7 @@ public:
}
}
void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override
{
if(!this->isEnable() || this->getWetLevel() == 0.0f)
{

@ -36,7 +36,7 @@ public:
virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) = 0;
void setMute(bool mute = false)
inline void setMute(bool mute = false)
{
this->mute_ = mute;
}
@ -68,7 +68,7 @@ public:
{
}
void reset()
inline void reset() override
{
if(!this->is_reset_)
{
@ -77,7 +77,7 @@ public:
}
}
void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
inline void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override
{
if(this->isMute())
{

@ -68,7 +68,7 @@ public:
// Processing
inline void init();
inline void reset();
inline void reset() override;
inline void processSample(float32_t& outL, float32_t& outR);
void process(float32_t* outL, float32_t* outR);

@ -5,13 +5,19 @@ OUTPUT_FOLDER := results
EXE := $(BINDIR)/all_tests.bin
BETA := $(BINDIR)/beta.bin
CXX := g++
CXXFLAGS = -g -std=c++20 -MMD -MP
CXX = g++
CXXFLAGS = -g -Wall -std=c++20 -MMD -MP
DEFINES = -DCPU=x86 -DDEBUG -DOUTPUT_FOLDER="\"$(OUTPUT_FOLDER)\""
INCLUDES = -I../../CMSIS_5/CMSIS/DSP/Include/ \
-I../../CMSIS_5/CMSIS/Core/Include/ \
-I../../Synth_Dexed/src/
CPPCHECK = cppcheck
CHECKFLAGS = -q -j 8 --enable=all --force --language=c++ \
$(INCLUDES) --platform=unix64 \
--error-exitcode=0 \
--suppressions-list=cppcheck-suppression-list.txt
-include $(TST_OBJS:.o=.d)
-include $(FX__OBJS:.o=.d)
@ -48,6 +54,10 @@ all: $(EXE) test
build: $(EXE)
cpp-check: $(FX__SRCS) $(TST_SRCS) $(BETASRCS)
flawfinder ../../src
$(CPPCHECK) $(CHECKFLAGS) $^
test: $(EXE) $(OUTPUT_FOLDER)
rm -rf $(OUTPUT_FOLDER)/*
./$(EXE)

@ -1,9 +1,4 @@
#include <gtest/gtest.h>
#include <cmath>
#include <iostream>
#include "test_fx_helper.h"
#include "../mixing_console.hpp"
TEST(BetaTest, WavefileSamplesBoundariesTest)
{
@ -21,7 +16,7 @@ TEST(BetaTest, WavefileSamplesBoundariesTest)
nb_errors += fullInspector(full_test_name + ".rawWaveSampleTest", samples[0][i], -1.0f, 1.0f, true);
nb_errors += fullInspector(full_test_name + ".rawWaveSampleTest", samples[1][i], -1.0f, 1.0f, true);
}
EXPECT_EQ(0, nb_errors) << full_test_name << ".rawWaveSampleTest";
ASSERT_EQ(0, nb_errors) << full_test_name << ".rawWaveSampleTest";
delete[] samples[0];
delete[] samples[1];
@ -54,14 +49,14 @@ TEST(BetaTest, MixingConsoleShortBuffer)
memset(outSamples[1], 0, size * sizeof(float32_t));
mixer->setInputSampleBuffer(0, inSamples);
EXPECT_EQ(0, FULL_INSPECT(mixer, true));
ASSERT_EQ(0, FULL_INSPECT(mixer, true)) << full_test_name << " Mixer.setInputSampleBuffer";
mixer->process(outSamples[0], outSamples[1]);
EXPECT_EQ(0, FULL_INSPECT(mixer, true));
ASSERT_EQ(0, FULL_INSPECT(mixer, true)) << full_test_name << " Mixer.process";
for(size_t s = 0; s < size; ++s)
{
EXPECT_EQ(outSamples[0][s], outSamples[1][s]);
EXPECT_EQ(outSamples[0][s], inSamples[s] * SINPI_4);
EXPECT_FLOAT_EQ(outSamples[0][s], outSamples[1][s]);
EXPECT_FLOAT_EQ(outSamples[0][s], inSamples[s] * SINPI_4);
}
delete mixer;
@ -96,12 +91,10 @@ TEST(BetaTest, MixingConsoleShimmerShortBuffer)
memset(outSamples[1], 0, size * sizeof(float32_t));
mixer->setInputSampleBuffer(0, inSamples);
EXPECT_EQ(0, FULL_INSPECT(mixer, true));
// FAST_DUMP(mixer, std::cerr, full_test_name + ".setInputSampleBuffer");
ASSERT_EQ(0, FULL_INSPECT(mixer, true)) << full_test_name << " Mixer.setInputSampleBuffer";
mixer->process(outSamples[0], outSamples[1]);
EXPECT_EQ(0, FULL_INSPECT(mixer, true));
// FAST_DUMP(mixer, std::cerr, full_test_name + ".process");
ASSERT_EQ(0, FULL_INSPECT(mixer, true)) << full_test_name << " Mixer.process";
delete mixer;
}
@ -140,7 +133,7 @@ TEST(BetaTest, MixingConsoleDrySamplesBoundariesTest)
nb_errors += fullInspector(full_test_name + ".outputSampleTest", inSamples[0][i], -1.0f, 1.0f, true);
nb_errors += fullInspector(full_test_name + ".outputSampleTest", inSamples[1][i], -1.0f, 1.0f, true);
}
EXPECT_EQ(0, nb_errors) << full_test_name << ".outputSampleTest";
ASSERT_EQ(0, nb_errors) << full_test_name << ".outputSampleTest";
delete[] inSamples[0];
delete[] inSamples[1];
@ -186,8 +179,8 @@ TEST(BetaTest, MixingConsoleShimmerSamplesBoundariesTest)
mixer->setInputSampleBuffer(0, inSamples[0]);
mixer->process(outSamples[0], outSamples[1]);
FAST_DUMP(mixer, std::cerr, full_test_name);
//EXPECT_EQ(0, FULL_INSPECT2(mixer, true, full_test_name + "Mixer.process")) << full_test_name << "Mixer.process";
ASSERT_EQ(0, FULL_INSPECT2(mixer, true, full_test_name + "Mixer.process")) << full_test_name << " Mixer.process";
saveWaveFile(getResultFile(full_test_name + ".wav", true), outSamples[0], outSamples[1], size, static_cast<unsigned>(SAMPLING_FREQUENCY), 16);
size_t nb_errors = 0;
@ -196,7 +189,7 @@ FAST_DUMP(mixer, std::cerr, full_test_name);
nb_errors += fullInspector(full_test_name + ".outputSampleTest", inSamples[0][i], -1.0f, 1.0f, true);
nb_errors += fullInspector(full_test_name + ".outputSampleTest", inSamples[1][i], -1.0f, 1.0f, true);
}
EXPECT_EQ(0, nb_errors) << full_test_name << ".outputSampleTest";
ASSERT_EQ(0, nb_errors) << full_test_name << ".outputSampleTest";
delete[] inSamples[0];
delete[] inSamples[1];

@ -357,7 +357,7 @@ void processShimmerSample(
// Smear AP1 inside the loop.
c.interpolate(ap1, 10.0f, Engine::LFOIndex::LFO_1, 60.0f, 1.0f);
c.write(ap1, 100, 0.0f);
c.writeAndLoad(ap1, 100, 0.0f);
c.read(inL + inR, gain);
// Diffuse through 4 allpasses.
@ -379,12 +379,11 @@ void processShimmerSample(
c.writeAllPass(dap1a, kap);
c.read(dap1b TAIL, kap);
c.writeAllPass(dap1b, -kap);
c.write(del1, 1.5f);
c.write(wet, 0.0f);
c.write(del1, 2.0f);
c.writeAndLoad(wet, 0.0f);
outL = wet;
c.load(apout);
c.read(del1 TAIL, krt);
c.lp(lp_2, klp);
@ -392,8 +391,8 @@ void processShimmerSample(
c.writeAllPass(dap2a, -kap);
c.read(dap2b TAIL, -kap);
c.writeAllPass(dap2b, kap);
c.write(del2, 1.5f);
c.write(wet, 0.0f);
c.write(del2, 2.0f);
c.writeAndLoad(wet, 0.0f);
outR = wet;

@ -0,0 +1,11 @@
*:../../CMSIS_5/*
toomanyconfigs:*
noExplicitConstructor:*
unusedFunction:*
missingIncludeSystem:*
unmatchedSuppression:*
// unexplained exceptions
syntaxError:beta.cpp:52
syntaxError:test_fx_mixing_console.cpp:207
internalAstError:test_cpp_performance.cpp:22

Binary file not shown.

@ -1,67 +0,0 @@
#include <gtest/gtest.h>
#include "../fx_components.h"
int nb = 0;
int NbIteration() {
nb++;
return 3;
}
TEST(Cpp, NbCallsInUpperBoudariesInForLoop)
{
for(int i = 0; i < NbIteration(); ++i)
{
// Does something
}
EXPECT_EQ(nb, 4);
}
#define CLASS_INIT(clazz) clazz::StaticInit()
class StaticCtorTest
{
private:
static int n_;
public:
int i_;
static int StaticInit()
{
static int i = 0;
i++;
StaticCtorTest::n_ = 2;
return i;
}
StaticCtorTest() : i_(0)
{
static int init = CLASS_INIT(StaticCtorTest);
static int NB = 0;
EXPECT_EQ(init, 1);
this->i_ = ++NB;
EXPECT_EQ(StaticCtorTest::n_, 2);
}
~StaticCtorTest()
{
}
};
int StaticCtorTest::n_ = 0;
TEST(Cpp, StaticCtorTest)
{
StaticCtorTest obj1;
StaticCtorTest obj2;
StaticCtorTest obj3;
EXPECT_EQ(obj1.i_, 1);
EXPECT_EQ(obj2.i_, 2);
EXPECT_EQ(obj3.i_, 3);
}

@ -29,7 +29,7 @@ TEST(CppPerformance, LFOPerformance_ComplexLFO_InterpolatedSineOscillator)
}
auto d2 = LAP_TIME("lfo2");
EXPECT_GE(d1, d2);
EXPECT_LE(d1, d2);
}
TEST(CppPerformance, LFOPerformance_ComplexLFO_FastLFO)

@ -17,5 +17,5 @@ TEST(Framework, TestWaveIn)
nb_errors += fullInspector("R", samples[StereoChannels::Right][i], -1.0f, 1.0f, true);
}
EXPECT_EQ(nb_errors, 0);
}
ASSERT_EQ(nb_errors, 0) << "readWaveFile returns NaN of out of bounds samples: " << nb_errors << " out of " << size;
}

@ -0,0 +1,275 @@
#include "test_fx_helper.h"
#include "../fx_tube.h"
#include "../fx_chorus.h"
#include "../fx_flanger.h"
#include "../fx_orbitone.h"
#include "../fx_phaser.h"
#include "../fx_delay.h"
#include "../effect_platervbstereo.h"
#include "../fx_shimmer_reverb.h"
TEST(LevelTuning, Tube)
{
Tube fx(SAMPLING_FREQUENCY);
fx.reset();
fx.setOverdrive(0.75f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
float32_t sumIn = 0.0f;
float32_t sumOut = 0.0f;
size_t nb_errors = 0;
AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR,
sumIn += inL * inL;
fx.processSample(inL, inR, outL, outR);
sumOut += outL * outL;
nb_errors += std::abs(outL) > 1.0f ? 1 : 0;
nb_errors += std::abs(outR) > 1.0f ? 1 : 0;
);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
float32_t ratio = std::sqrt(sumOut / sumIn);
ASSERT_EQ(nb_errors, 0) << "Sample value error for Tube";
EXPECT_GE(ratio, 0.9f);
EXPECT_LE(1.0f / ratio, 1.1f);
}
TEST(LevelTuning, Chorus)
{
Chorus fx(SAMPLING_FREQUENCY);
fx.reset();
fx.setRate(0.4f);
fx.setDepth(0.5f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
float32_t sumIn = 0.0f;
float32_t sumOut = 0.0f;
size_t nb_errors = 0;
AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR,
sumIn += inL * inL;
fx.processSample(inL, inR, outL, outR);
sumOut += outL * outL;
nb_errors += std::abs(outL) > 1.0f ? 1 : 0;
nb_errors += std::abs(outR) > 1.0f ? 1 : 0;
);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
float32_t ratio = std::sqrt(sumOut / sumIn);
ASSERT_EQ(nb_errors, 0) << "Sample value error for Chorus";
EXPECT_LE(ratio, 1.0f);
EXPECT_GE(ratio, 0.9f);
EXPECT_LE(1.0f / ratio, 1.1f);
}
TEST(LevelTuning, Flanger)
{
Flanger fx(SAMPLING_FREQUENCY);
fx.reset();
fx.setRate(0.03f);
fx.setDepth(0.75f);
fx.setFeedback(0.5f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
float32_t sumIn = 0.0f;
float32_t sumOut = 0.0f;
size_t nb_errors = 0;
AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR,
sumIn += inL * inL;
fx.processSample(inL, inR, outL, outR);
sumOut += outL * outL;
nb_errors += std::abs(outL) > 1.0f ? 1 : 0;
nb_errors += std::abs(outR) > 1.0f ? 1 : 0;
);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
float32_t ratio = std::sqrt(sumOut / sumIn);
ASSERT_EQ(nb_errors, 0) << "Sample value error for Flanger";
EXPECT_LE(ratio, 1.0f);
EXPECT_GE(ratio, 0.9f);
EXPECT_LE(1.0f / ratio, 1.1f);
}
TEST(LevelTuning, Orbitone)
{
Orbitone fx(SAMPLING_FREQUENCY);
fx.reset();
fx.setRate(0.4f);
fx.setDepth(0.5f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
float32_t sumIn = 0.0f;
float32_t sumOut = 0.0f;
size_t nb_errors = 0;
AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR,
sumIn += inL * inL;
fx.processSample(inL, inR, outL, outR);
sumOut += outL * outL;
nb_errors += std::abs(outL) > 1.0f ? 1 : 0;
nb_errors += std::abs(outR) > 1.0f ? 1 : 0;
);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
float32_t ratio = std::sqrt(sumOut / sumIn);
ASSERT_EQ(nb_errors, 0) << "Sample value error for Orbitone";
EXPECT_LE(ratio, 1.0f);
EXPECT_GE(ratio, 0.9f);
EXPECT_LE(1.0f / ratio, 1.1f);
}
TEST(LevelTuning, Phaser)
{
Phaser fx(SAMPLING_FREQUENCY);
fx.reset();
fx.setRate(0.1f);
fx.setDepth(1.0f);
fx.setFeedback(0.5f);
fx.setNbStages(12);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
float32_t sumIn = 0.0f;
float32_t sumOut = 0.0f;
size_t nb_errors = 0;
AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR,
sumIn += inL * inL;
fx.processSample(inL, inR, outL, outR);
sumOut += outL * outL;
nb_errors += std::abs(outL) > 1.0f ? 1 : 0;
nb_errors += std::abs(outR) > 1.0f ? 1 : 0;
);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
float32_t ratio = std::sqrt(sumOut / sumIn);
ASSERT_EQ(nb_errors, 0) << "Sample value error for Phaser";
EXPECT_LE(ratio, 1.0f);
EXPECT_GE(ratio, 0.9f);
EXPECT_LE(1.0f / ratio, 1.1f);
}
TEST(LevelTuning, Delay)
{
Delay fx(SAMPLING_FREQUENCY);
fx.reset();
fx.setLeftDelayTime(0.15f);
fx.setLeftDelayTime(0.2f);
fx.setFeedback(0.35f);
fx.setFlutterRate(0.0f);
fx.setFlutterAmount(0.0f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
float32_t sumIn = 0.0f;
float32_t sumOut = 0.0f;
size_t nb_errors = 0;
AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR,
sumIn += inL * inL;
fx.processSample(inL, inR, outL, outR);
sumOut += outL * outL;
nb_errors += std::abs(outL) > 1.0f ? 1 : 0;
nb_errors += std::abs(outR) > 1.0f ? 1 : 0;
);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
float32_t ratio = std::sqrt(sumOut / sumIn);
ASSERT_EQ(nb_errors, 0) << "Sample value error for Delay";
EXPECT_LE(ratio, 1.0f);
EXPECT_GE(ratio, 0.9f);
EXPECT_LE(1.0f / ratio, 1.1f);
}
TEST(LevelTuning, PlateReverb)
{
AudioEffectPlateReverb fx(SAMPLING_FREQUENCY);
fx.reset();
fx.set_bypass(false);
fx.size(0.7f);
fx.hidamp(0.5f);
fx.lodamp(0.5f);
fx.lowpass(0.3f);
fx.diffusion(0.65f);
fx.level(1.0f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
float32_t sumIn = 0.0f;
float32_t sumOut = 0.0f;
size_t nb_errors = 0;
AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR,
sumIn += inL * inL;
fx.processSample(inL, inR, outL, outR);
sumOut += outL * outL;
nb_errors += std::abs(outL) > 1.0f ? 1 : 0;
nb_errors += std::abs(outR) > 1.0f ? 1 : 0;
);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
float32_t ratio = std::sqrt(sumOut / sumIn);
ASSERT_EQ(nb_errors, 0) << "Sample value error for PlateReverb";
EXPECT_GE(ratio, 0.9f);
EXPECT_LE(1.0f / ratio, 1.1f);
}
TEST(LevelTuning, ShimmerReverb)
{
ShimmerReverb fx(SAMPLING_FREQUENCY);
fx.reset();
fx.setInputGain(0.35f);
fx.setTime(0.89f);
fx.setDiffusion(0.75f);
fx.setLP(0.8f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
float32_t sumIn = 0.0f;
float32_t sumOut = 0.0f;
size_t nb_errors = 0;
AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR,
sumIn += inL * inL;
fx.processSample(inL, inR, outL, outR);
sumOut += outL * outL;
nb_errors += std::abs(outL) > 1.0f ? 1 : 0;
nb_errors += std::abs(outR) > 1.0f ? 1 : 0;
);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
float32_t ratio = std::sqrt(sumOut / sumIn);
ASSERT_EQ(nb_errors, 0) << "Sample value error for ShimmerReverb";
EXPECT_GE(ratio, 0.9f);
EXPECT_LE(1.0f / ratio, 1.1f);
}

@ -7,7 +7,6 @@
#include "../fx_rack.h"
#include "../effect_platervbstereo.h"
#include "../mixing_console.hpp"
#define MAX_SVF_SAMPLES 10000000
#define MAX_NB_ERRORS 100
@ -146,5 +145,5 @@ TEST(CppOptimization, FastLFOPrecisionTest)
max_delta = std::max(max_delta, std::abs(v1 - v2));
}
// EXPECT_GT(epsilon, max_delta);
EXPECT_GT(epsilon, max_delta);
}

@ -1,6 +1,5 @@
#include "test_fx_helper.h"
#include <iostream>
#include <filesystem>
std::string getScenarioName(int scenario)
@ -21,7 +20,7 @@ std::string getScenarioName(int scenario)
if(fxTube)
{
if(!first) ss << ", ";
// if(!first) ss << ", ";
ss << "Tube";
first = false;
}
@ -72,7 +71,7 @@ std::string getScenarioName(int scenario)
{
if(!first) ss << ", ";
ss << "Shim";
first = false;
// first = false;
}
ss << " ]";
@ -130,3 +129,22 @@ float32_t getRandomValue()
return dist(gen);
}
float32_t** loadAudioTest(size_t& size, WaveHeader* hdr)
{
float32_t** samples = readWaveFile(AUDIO_SOURCE_FILE, size, hdr);
assert(samples != nullptr);
return samples;
}
void freeAudioSamples(float32_t** samples, size_t size)
{
assert(samples != nullptr);
for(size_t i = 0; i < size; ++i)
{
delete[] samples[i];
}
delete[] samples;
}

@ -7,10 +7,44 @@
#include "wave.h"
#include "../fx.h"
#define AUDIO_SOURCE_FILE "test2.wav"
#define AUDIO_SOURCE_FILE "test3.wav"
#define SAMPLING_FREQUENCY 44100.0f
#define PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name)\
const testing::TestInfo* test_info = testing::UnitTest::GetInstance()->current_test_info();\
std::string full_test_name = test_info->test_case_name();\
full_test_name += ".";\
full_test_name += test_info->name();\
WaveHeader hdr;\
size_t size;\
float32_t** inSamples = loadAudioTest(size, &hdr);\
float32_t** outSamples = new float32_t*[2];\
outSamples[0] = new float32_t[size]; memset(outSamples[0], 0, size * sizeof(float32_t));\
outSamples[1] = new float32_t[size]; memset(outSamples[1], 0, size * sizeof(float32_t))
#define CLEANUP_AUDIO_TEST(inSamples, outSamples)\
freeAudioSamples(inSamples, 2);\
freeAudioSamples(outSamples, 2)
#define AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR, code)\
for(size_t i = 0; i < size; ++i)\
{\
float32_t inL = inSamples[0][i];\
float32_t inR = inSamples[1][i];\
float32_t outL;\
float32_t outR;\
code\
outSamples[0][i] = outL;\
outSamples[1][i] = outR;\
} //
#define SIMPLE_AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR, fx)\
AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR, fx.processSample(inL, inR, outL, outR);)
#define SAVE_AUDIO_RESULTS(filename, samples, size)\
saveWaveFile(getResultFile(filename + ".wav", true), samples[0], samples[1], size, static_cast<unsigned>(SAMPLING_FREQUENCY), 16)
#define Active(scenarioKey, FxID) ((scenarioKey & (1 << FxID)) == (1 << FxID))
std::string getScenarioName(int scenario);
@ -37,3 +71,6 @@ std::string getResultFile(const std::string& filename, bool createPath);
float32_t getRandomValue();
class FXScenarioTest : public testing::TestWithParam<int> {};
float32_t** loadAudioTest(size_t& size, WaveHeader* hdr);
void freeAudioSamples(float32_t** samples, size_t size);

@ -13,7 +13,7 @@ TEST_P(MixingConsoleScenarioTest, MixerOutputTest)
MixerOutput v = this->GetParam();
std::string str = toString(v);
MixerOutput mo = toIndex(str.c_str());
EXPECT_EQ(v, mo);
ASSERT_EQ(v, mo);
}
INSTANTIATE_TEST_SUITE_P(MixerOutputTest, MixingConsoleScenarioTest, testing::Range(MixerOutput::OutputStart, MixerOutput::kFXCount));
@ -83,51 +83,163 @@ void setupMixingConsoleFX(Mixer* mixer, int scenarioId)
mixer->setChannelLevel(0, 1.0f);
mixer->setPan(0, 0.5f);
size_t nbActiveFX = 0;
MixerOutput previousActivatedFX = MixerOutput::MainOutput;
if(bFX_Tube)
{
nbActiveFX++;
if(nbActiveFX == 1)
{
mixer->setSendLevel(0, MixerOutput::FX_Tube, 1.0f);
previousActivatedFX = MixerOutput::FX_Tube;
}
else
{
mixer->setReturnLevel(previousActivatedFX, MixerOutput::FX_Tube, 1.0f);
}
}
if(bFX_Chorus)
{
nbActiveFX++;
if(nbActiveFX == 1)
{
mixer->setSendLevel(0, MixerOutput::FX_Chorus, 1.0f);
previousActivatedFX = MixerOutput::FX_Chorus;
}
else
{
mixer->setReturnLevel(previousActivatedFX, MixerOutput::FX_Chorus, 1.0f);
}
}
if(bFX_Flanger)
{
nbActiveFX++;
if(nbActiveFX == 1)
{
mixer->setSendLevel(0, MixerOutput::FX_Flanger, 1.0f);
previousActivatedFX = MixerOutput::FX_Flanger;
}
else
{
mixer->setReturnLevel(previousActivatedFX, MixerOutput::FX_Flanger, 1.0f);
}
}
if(bFX_Orbitone)
{
nbActiveFX++;
if(nbActiveFX == 1)
{
mixer->setSendLevel(0, MixerOutput::FX_Orbitone, 1.0f);
previousActivatedFX = MixerOutput::FX_Orbitone;
}
else
{
mixer->setReturnLevel(previousActivatedFX, MixerOutput::FX_Orbitone, 1.0f);
}
}
if(bFX_Phaser)
{
nbActiveFX++;
if(nbActiveFX == 1)
{
mixer->setSendLevel(0, MixerOutput::FX_Phaser, 1.0f);
previousActivatedFX = MixerOutput::FX_Phaser;
}
else
{
mixer->setReturnLevel(previousActivatedFX, MixerOutput::FX_Phaser, 1.0f);
}
}
if(bFX_Delay)
{
nbActiveFX++;
if(nbActiveFX == 1)
{
mixer->setSendLevel(0, MixerOutput::FX_Delay, 1.0f);
previousActivatedFX = MixerOutput::FX_Delay;
}
else
{
mixer->setReturnLevel(previousActivatedFX, MixerOutput::FX_Delay, 1.0f);
}
}
if(bFX_PlateReverb)
{
nbActiveFX++;
if(nbActiveFX == 1)
{
mixer->setSendLevel(0, MixerOutput::FX_PlateReverb, 1.0f);
previousActivatedFX = MixerOutput::FX_PlateReverb;
}
else
{
mixer->setReturnLevel(previousActivatedFX, MixerOutput::FX_PlateReverb, 1.0f);
}
}
if(bFX_ShimmerReverb)
{
nbActiveFX++;
if(nbActiveFX == 1)
{
mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f);
previousActivatedFX = MixerOutput::FX_ShimmerReverb;
}
else
{
mixer->setReturnLevel(previousActivatedFX, MixerOutput::FX_ShimmerReverb, 1.0f);
}
}
}
TEST(MixingConsole, ZeroSamplesTest)
{
const size_t length = 4;
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, length);
EXPECT_EQ(0, FULL_INSPECT(mixer, true));
Mixer mixer(SAMPLING_FREQUENCY, length);
ASSERT_EQ(0, FULL_INSPECT((&mixer), true));
mixer->reset();
EXPECT_EQ(0, FULL_INSPECT(mixer, true));
mixer.reset();
ASSERT_EQ(0, FULL_INSPECT((&mixer), true));
setupMixingConsoleFX(mixer);
EXPECT_EQ(0, FULL_INSPECT(mixer, true));
setupMixingConsoleFX(&mixer);
ASSERT_EQ(0, FULL_INSPECT((&mixer), true));
mixer->setChannelLevel(0, 1.0f);
EXPECT_EQ(0, FULL_INSPECT(mixer, true));
mixer.setChannelLevel(0, 1.0f);
ASSERT_EQ(0, FULL_INSPECT((&mixer), true));
mixer->setPan(0, 0.5f);
EXPECT_EQ(0, FULL_INSPECT(mixer, true));
mixer.setPan(0, 0.5f);
ASSERT_EQ(0, FULL_INSPECT((&mixer), true));
float32_t samples[] = {0.0f, 0.0f, 0.0f, 0.0f};
mixer->setInputSampleBuffer(0, samples);
EXPECT_EQ(0, FULL_INSPECT(mixer, true));
mixer.setInputSampleBuffer(0, samples);
ASSERT_EQ(0, FULL_INSPECT((&mixer), true));
mixer->setSendLevel(0, MixerOutput::MainOutput, 1.0f);
EXPECT_EQ(0, FULL_INSPECT(mixer, true));
mixer.setSendLevel(0, MixerOutput::MainOutput, 1.0f);
ASSERT_EQ(0, FULL_INSPECT((&mixer), true));
float32_t outL[4];
float32_t outR[4];
mixer->process(outL, outR);
EXPECT_EQ(0, FULL_INSPECT(mixer, true));
mixer->setSendLevel(0, MixerOutput::FX_Tube, 1.0f);
mixer->setSendLevel(0, MixerOutput::FX_Delay, 1.0f);
mixer->setSendLevel(0, MixerOutput::FX_PlateReverb, 1.0f);
mixer->setReturnLevel(MixerOutput::FX_Tube, MixerOutput::FX_Orbitone, 1.0f);
mixer->setReturnLevel(MixerOutput::FX_Orbitone, MixerOutput::MainOutput, 0.5f);
mixer->setReturnLevel(MixerOutput::FX_Orbitone, MixerOutput::FX_PlateReverb, 1.0f);
mixer->setReturnLevel(MixerOutput::FX_Delay, MixerOutput::MainOutput, 0.5f);
mixer->setReturnLevel(MixerOutput::FX_PlateReverb, MixerOutput::MainOutput, 0.5f);
EXPECT_EQ(0, FULL_INSPECT(mixer, true));
delete mixer;
mixer.process(outL, outR);
ASSERT_EQ(0, FULL_INSPECT((&mixer), true));
mixer.setSendLevel(0, MixerOutput::FX_Tube, 1.0f);
mixer.setSendLevel(0, MixerOutput::FX_Delay, 1.0f);
mixer.setSendLevel(0, MixerOutput::FX_PlateReverb, 1.0f);
mixer.setReturnLevel(MixerOutput::FX_Tube, MixerOutput::FX_Orbitone, 1.0f);
mixer.setReturnLevel(MixerOutput::FX_Orbitone, MixerOutput::MainOutput, 0.5f);
mixer.setReturnLevel(MixerOutput::FX_Orbitone, MixerOutput::FX_PlateReverb, 1.0f);
mixer.setReturnLevel(MixerOutput::FX_Delay, MixerOutput::MainOutput, 0.5f);
mixer.setReturnLevel(MixerOutput::FX_PlateReverb, MixerOutput::MainOutput, 0.5f);
ASSERT_EQ(0, FULL_INSPECT((&mixer), true));
}
TEST(MixingConsole, DryProcessing)
@ -135,47 +247,45 @@ TEST(MixingConsole, DryProcessing)
const float32_t epsilon = 1e-7;
const size_t length = 2;
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, length);
mixer->reset();
Mixer mixer(SAMPLING_FREQUENCY, length);
mixer.reset();
mixer->setSendLevel(0, MixerOutput::FX_Tube, 0.0f);
mixer->setSendLevel(0, MixerOutput::FX_Chorus, 0.0f);
mixer->setSendLevel(0, MixerOutput::FX_Flanger, 0.0f);
mixer->setSendLevel(0, MixerOutput::FX_Orbitone, 0.0f);
mixer->setSendLevel(0, MixerOutput::FX_Phaser, 0.0f);
mixer->setSendLevel(0, MixerOutput::FX_Delay, 0.0f);
mixer->setSendLevel(0, MixerOutput::FX_PlateReverb, 0.0f);
mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 0.0f);
mixer.setSendLevel(0, MixerOutput::FX_Tube, 0.0f);
mixer.setSendLevel(0, MixerOutput::FX_Chorus, 0.0f);
mixer.setSendLevel(0, MixerOutput::FX_Flanger, 0.0f);
mixer.setSendLevel(0, MixerOutput::FX_Orbitone, 0.0f);
mixer.setSendLevel(0, MixerOutput::FX_Phaser, 0.0f);
mixer.setSendLevel(0, MixerOutput::FX_Delay, 0.0f);
mixer.setSendLevel(0, MixerOutput::FX_PlateReverb, 0.0f);
mixer.setSendLevel(0, MixerOutput::FX_ShimmerReverb, 0.0f);
for(unsigned i = MixerOutput::OutputStart; i < (MixerOutput::kFXCount - 1); ++i)
for(size_t i = MixerOutput::OutputStart; i < (MixerOutput::kFXCount - 1); ++i)
{
mixer->setReturnLevel(static_cast<MixerOutput>(i), MixerOutput::MainOutput, 0.0f);
mixer.setReturnLevel(static_cast<MixerOutput>(i), MixerOutput::MainOutput, 0.0f);
}
mixer->setChannelLevel(0, 1.0f);
mixer->setPan(0, 0.5f);
mixer->setSendLevel(0, MixerOutput::MainOutput, 1.0f);
EXPECT_EQ(0, INSPECT(mixer, fullInspector));
mixer.setChannelLevel(0, 1.0f);
mixer.setPan(0, 0.5f);
mixer.setSendLevel(0, MixerOutput::MainOutput, 1.0f);
ASSERT_EQ(0, INSPECT((&mixer), fullInspector));
float32_t in[length] = {0.1, 0.2};
float32_t out[StereoChannels::kNumChannels][length];
for(size_t i = 0; i < StereoChannels::kNumChannels; ++i) memset(out[i], 0, length * sizeof(float32_t));
mixer->setInputSampleBuffer(0, in);
EXPECT_EQ(0, INSPECT(mixer, fullInspector));
mixer.setInputSampleBuffer(0, in);
ASSERT_EQ(0, INSPECT((&mixer), fullInspector));
mixer->process(
mixer.process(
out[StereoChannels::Left ],
out[StereoChannels::Right]
);
EXPECT_EQ(0, INSPECT(mixer, fullInspector));
ASSERT_EQ(0, INSPECT((&mixer), fullInspector));
EXPECT_EQ(out[StereoChannels::Left ][0], out[StereoChannels::Right][0]);
EXPECT_EQ(out[StereoChannels::Left ][1], out[StereoChannels::Right][1]);
EXPECT_LT(std::abs(out[StereoChannels::Left ][0] - (sqrt(2.0f) / 20.0f)), epsilon);
EXPECT_LT(std::abs(out[StereoChannels::Left ][1] - (sqrt(2.0f) / 10.0f)), epsilon);
delete mixer;
EXPECT_FLOAT_EQ(out[StereoChannels::Left ][0], out[StereoChannels::Right][0]);
EXPECT_FLOAT_EQ(out[StereoChannels::Left ][1], out[StereoChannels::Right][1]);
EXPECT_NEAR(out[StereoChannels::Left ][0], sqrt(2.0f) / 20.0f, epsilon);
EXPECT_NEAR(out[StereoChannels::Left ][1], sqrt(2.0f) / 10.0f, epsilon);
}
TEST(MixingConsole, ShimmerProcessing)
@ -183,63 +293,61 @@ TEST(MixingConsole, ShimmerProcessing)
const float32_t epsilon = 1e-7;
const size_t length = 2;
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, length);
mixer->reset();
Mixer mixer(SAMPLING_FREQUENCY, length);
mixer.reset();
mixer->setSendLevel(0, MixerOutput::MainOutput, 0.0f);
mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f);
mixer->setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 1.0f);
mixer->setChannelLevel(0, 1.0f);
mixer->setPan(0, 0.5f);
EXPECT_EQ(0, INSPECT(mixer, fullInspector));
mixer.setSendLevel(0, MixerOutput::MainOutput, 0.0f);
mixer.setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f);
mixer.setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 1.0f);
mixer.setChannelLevel(0, 1.0f);
mixer.setPan(0, 0.5f);
ASSERT_EQ(0, INSPECT((&mixer), fullInspector));
float32_t in[length] = {0.1, 0.2};
float32_t out1[StereoChannels::kNumChannels][length];
for(size_t i = 0; i < StereoChannels::kNumChannels; ++i) memset(out1[i], 0, length * sizeof(float32_t));
mixer->setInputSampleBuffer(0, in);
EXPECT_EQ(0, INSPECT(mixer, fullInspector));
mixer.setInputSampleBuffer(0, in);
ASSERT_EQ(0, INSPECT((&mixer), fullInspector));
mixer->process(
mixer.process(
out1[StereoChannels::Left ],
out1[StereoChannels::Right]
);
EXPECT_EQ(0, INSPECT(mixer, fullInspector));
ASSERT_EQ(0, INSPECT((&mixer), fullInspector));
mixer->reset();
EXPECT_EQ(0, INSPECT(mixer, fullInspector));
mixer.reset();
ASSERT_EQ(0, INSPECT((&mixer), fullInspector));
float32_t out2[StereoChannels::kNumChannels][length];
mixer->setInputSampleBuffer(0, in);
EXPECT_EQ(0, INSPECT(mixer, fullInspector));
mixer.setInputSampleBuffer(0, in);
ASSERT_EQ(0, INSPECT((&mixer), fullInspector));
mixer->process(
mixer.process(
out2[StereoChannels::Left ],
out2[StereoChannels::Right]
);
EXPECT_EQ(0, INSPECT(mixer, fullInspector));
EXPECT_EQ(out1[StereoChannels::Left ][0], out2[StereoChannels::Left ][0]);
EXPECT_EQ(out1[StereoChannels::Right][0], out2[StereoChannels::Right][0]);
EXPECT_EQ(out1[StereoChannels::Left ][1], out2[StereoChannels::Left ][1]);
EXPECT_EQ(out1[StereoChannels::Right][1], out2[StereoChannels::Right][1]);
ASSERT_EQ(0, INSPECT((&mixer), fullInspector));
delete mixer;
EXPECT_NEAR(out1[StereoChannels::Left ][0], out2[StereoChannels::Left ][0], epsilon);
EXPECT_NEAR(out1[StereoChannels::Right][0], out2[StereoChannels::Right][0], epsilon);
EXPECT_NEAR(out1[StereoChannels::Left ][1], out2[StereoChannels::Left ][1], epsilon);
EXPECT_NEAR(out1[StereoChannels::Right][1], out2[StereoChannels::Right][1], epsilon);
}
TEST(MixingConsole, ShimmerNoiseProcessing)
{
const size_t length = 1024;
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, length);
mixer->reset();
Mixer mixer(SAMPLING_FREQUENCY, length);
mixer.reset();
mixer->setSendLevel(0, MixerOutput::MainOutput, 0.0f);
mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f);
mixer->setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 1.0f);
mixer->setChannelLevel(0, 1.0f);
mixer->setPan(0, 0.5f);
EXPECT_EQ(0, INSPECT(mixer, fullInspector));
mixer.setSendLevel(0, MixerOutput::MainOutput, 0.0f);
mixer.setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f);
mixer.setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 1.0f);
mixer.setChannelLevel(0, 1.0f);
mixer.setPan(0, 0.5f);
ASSERT_EQ(0, INSPECT((&mixer), fullInspector));
float32_t in[length];
for(size_t i = 0; i < length; ++i) in[i] = getRandomValue();
@ -247,68 +355,46 @@ TEST(MixingConsole, ShimmerNoiseProcessing)
float32_t out[StereoChannels::kNumChannels][length];
for(size_t i = 0; i < StereoChannels::kNumChannels; ++i) memset(out[i], 0, length * sizeof(float32_t));
mixer->setInputSampleBuffer(0, in);
EXPECT_EQ(0, INSPECT(mixer, fullInspector));
mixer.setInputSampleBuffer(0, in);
ASSERT_EQ(0, INSPECT((&mixer), fullInspector));
mixer->process(
mixer.process(
out[StereoChannels::Left ],
out[StereoChannels::Right]
);
EXPECT_EQ(0, INSPECT(mixer, fullInspector));
delete mixer;
ASSERT_EQ(0, INSPECT((&mixer), fullInspector));
}
TEST(MixingConsole, StandardUsageProcessing)
{
const testing::TestInfo* test_info = testing::UnitTest::GetInstance()->current_test_info();
std::string full_test_name = test_info->test_case_name();
full_test_name += ".";
full_test_name += test_info->name();
const unsigned nbRepeats = 2;
size_t size;
float32_t** samples = readWaveFile(AUDIO_SOURCE_FILE, size);
float32_t* sampleOutL = new float32_t[size * nbRepeats];
float32_t* sampleOutR = new float32_t[size * nbRepeats];
memset(sampleOutL, 0, size * nbRepeats * sizeof(float32_t));
memset(sampleOutR, 0, size * nbRepeats * sizeof(float32_t));
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, size);
setupMixingConsoleFX(mixer);
mixer->getTube()->setOverdrive(0.15f);
mixer->setSendLevel(0, MixerOutput::FX_Tube, 1.0f);
mixer->setSendLevel(0, MixerOutput::FX_Phaser, 1.0f);
// mixer->setReturnLevel(MixerOutput::FX_Tube, MixerOutput::MainOutput, 1.0f);
// mixer->setSendLevel(0, MixerOutput::FX_Chorus, 1.0f);
// mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f);
mixer->setReturnLevel(MixerOutput::FX_Tube, MixerOutput::FX_Chorus, 1.0f);
mixer->setReturnLevel(MixerOutput::FX_Chorus, MixerOutput::FX_ShimmerReverb, 1.0f);
mixer->setReturnLevel(MixerOutput::FX_Phaser, MixerOutput::FX_Delay, 1.0f);
mixer->setSendLevel(0, MixerOutput::MainOutput, 0.25f);
mixer->setReturnLevel(MixerOutput::FX_Tube, MixerOutput::MainOutput, 0.1f);
mixer->setReturnLevel(MixerOutput::FX_Chorus, MixerOutput::MainOutput, 0.15f);
mixer->setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 0.3f);
mixer->setReturnLevel(MixerOutput::FX_Delay, MixerOutput::MainOutput, 0.3f);
for(unsigned j = 0; j < nbRepeats; ++j)
{
mixer->setInputSampleBuffer(0, samples[0], samples[1]);
mixer->process(sampleOutL + j * size, sampleOutR + j * size);
EXPECT_EQ(0, INSPECT(mixer, fullInspector));
}
saveWaveFile(getResultFile(full_test_name + ".wav", true), sampleOutL, sampleOutR, nbRepeats * size, static_cast<unsigned>(SAMPLING_FREQUENCY), 16);
delete mixer;
delete[] samples[0];
delete[] samples[1];
delete[] samples;
delete[] sampleOutL;
delete[] sampleOutR;
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
Mixer mixer(SAMPLING_FREQUENCY, size);
setupMixingConsoleFX(&mixer);
mixer.getTube()->setOverdrive(0.15f);
mixer.setSendLevel(0, MixerOutput::FX_Tube, 1.0f);
mixer.setSendLevel(0, MixerOutput::FX_Phaser, 1.0f);
// mixer.setReturnLevel(MixerOutput::FX_Tube, MixerOutput::MainOutput, 1.0f);
// mixer.setSendLevel(0, MixerOutput::FX_Chorus, 1.0f);
// mixer.setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f);
mixer.setReturnLevel(MixerOutput::FX_Tube, MixerOutput::FX_Chorus, 1.0f);
mixer.setReturnLevel(MixerOutput::FX_Chorus, MixerOutput::FX_ShimmerReverb, 1.0f);
mixer.setReturnLevel(MixerOutput::FX_Phaser, MixerOutput::FX_Delay, 1.0f);
mixer.setSendLevel(0, MixerOutput::MainOutput, 0.25f);
mixer.setReturnLevel(MixerOutput::FX_Tube, MixerOutput::MainOutput, 0.1f);
mixer.setReturnLevel(MixerOutput::FX_Chorus, MixerOutput::MainOutput, 0.15f);
mixer.setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 0.3f);
mixer.setReturnLevel(MixerOutput::FX_Delay, MixerOutput::MainOutput, 0.3f);
mixer.setInputSampleBuffer(0, inSamples[0], inSamples[1]);
mixer.process(outSamples[0], outSamples[1]);
ASSERT_EQ(0, INSPECT((&mixer), fullInspector));
saveWaveFile(getResultFile(full_test_name + ".wav", true), outSamples[0], outSamples[1], size, static_cast<unsigned>(SAMPLING_FREQUENCY), 16);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
}
// TEST_P(FXScenarioTest, FXProcessingScenario)
@ -326,23 +412,21 @@ TEST(MixingConsole, StandardUsageProcessing)
// memset(sampleOutL, 0, size * nbRepeats * sizeof(float32_t));
// memset(sampleOutR, 0, size * nbRepeats * sizeof(float32_t));
// Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, size);
// Mixer mixer(SAMPLING_FREQUENCY, size);
// setupMixingConsoleFX(mixer);
// setupMixingConsoleFX(&mixer);
// int scenarioId = this->GetParam();
// setupMixingConsoleFXForScenario(mixer, scenarioId);
// setupMixingConsoleFXForScenario((&mixer), scenarioId);
// for(unsigned j = 0; j < nbRepeats; ++j)
// for(size_t j = 0; j < nbRepeats; ++j)
// {
// mixer->setInputSampleBuffer(0, samples[0], samples[1]);
// mixer->process(sampleOutL + j * size, sampleOutR + j * size);
// EXPECT_EQ(0, INSPECT(mixer, fullInspector));
// mixer.setInputSampleBuffer(0, samples[0], samples[1]);
// mixer.process(sampleOutL + j * size, sampleOutR + j * size);
// EXPECT_EQ(0, INSPECT((&mixer), fullInspector));
// }
// saveWaveFile(getResultFile(full_test_name + ".wav"), sampleOutL, sampleOutR, nbRepeats * size, static_cast<unsigned>(SAMPLING_FREQUENCY), 16);
// delete mixer;
// delete[] samples[0];
// delete[] samples[1];
// delete[] samples;

@ -6,65 +6,34 @@
TEST(FXPlateReverb, Migration)
{
const testing::TestInfo* test_info = testing::UnitTest::GetInstance()->current_test_info();
std::string full_test_name = test_info->test_case_name();
full_test_name += ".";
full_test_name += test_info->name();
const unsigned nbRepeats = 4;
AudioEffectPlateReverb* reverb = new AudioEffectPlateReverb(SAMPLING_FREQUENCY);
reverb->set_bypass(false);
reverb->size(0.7f);
reverb->hidamp(0.5f);
reverb->lodamp(0.5f);
reverb->lowpass(0.3f);
reverb->diffusion(0.65f);
reverb->level(1.0f);
size_t size;
float32_t** samples = readWaveFile(AUDIO_SOURCE_FILE, size);
float32_t* sampleOutL = new float32_t[size * nbRepeats];
float32_t* sampleOutR = new float32_t[size * nbRepeats];
memset(sampleOutL, 0, size * nbRepeats * sizeof(float32_t));
memset(sampleOutR, 0, size * nbRepeats * sizeof(float32_t));
unsigned index = 0;
for(unsigned i = 0; i < nbRepeats; ++i)
AudioEffectPlateReverb reverb(SAMPLING_FREQUENCY);
reverb.set_bypass(false);
reverb.size(0.7f);
reverb.hidamp(0.5f);
reverb.lodamp(0.5f);
reverb.lowpass(0.3f);
reverb.diffusion(0.65f);
reverb.level(1.0f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
for(size_t i = 0; i < size; ++i)
{
for(unsigned j = 0; j < size; ++j)
{
reverb->processSample(samples[0][j], samples[1][j], sampleOutL[index], sampleOutR[index]);
++index;
}
reverb.processSample(inSamples[0][i], inSamples[1][i], outSamples[0][i], outSamples[1][i]);
}
saveWaveFile(getResultFile(full_test_name + ".PlateReverb-new.wav", true), sampleOutL, sampleOutR, nbRepeats * size, static_cast<unsigned>(SAMPLING_FREQUENCY), 16);
saveWaveFile(getResultFile(full_test_name + ".PlateReverb-new.wav", true), outSamples[0], outSamples[1], size, static_cast<unsigned>(SAMPLING_FREQUENCY), 16);
unsigned indexOut = 0;
for (unsigned i = 0; i < nbRepeats; ++i)
size_t index = 0;
size_t len = size;
while(len > 0)
{
unsigned len = size;
unsigned indexIn = 0;
size_t grainSize = (len < 1024 ? len : 1024);
while(len > 0)
{
unsigned grainSize = (len < 1024 ? len : 1024);
reverb->doReverb(samples[0] + indexIn, samples[1] + indexIn, sampleOutL + indexOut, sampleOutR + indexOut, grainSize);
indexIn += grainSize;
indexOut += grainSize;
len -= grainSize;
}
reverb.doReverb(inSamples[0] + index, inSamples[1] + index, outSamples[0] + index, outSamples[1] + index, grainSize);
index += grainSize;
len -= grainSize;
}
saveWaveFile(getResultFile(full_test_name + ".PlateReverb-legacy.wav", true), sampleOutL, sampleOutR, nbRepeats * size, static_cast<unsigned>(SAMPLING_FREQUENCY), 16);
delete[] sampleOutL;
delete[] sampleOutR;
delete[] samples[0];
delete[] samples[1];
delete[] samples;
saveWaveFile(getResultFile(full_test_name + ".PlateReverb-legacy.wav", true), outSamples[0], outSamples[1], size, static_cast<unsigned>(SAMPLING_FREQUENCY), 16);
delete reverb;
CLEANUP_AUDIO_TEST(inSamples, outSamples);
}

@ -1,6 +1,3 @@
#include <gtest/gtest.h>
#include <cmath>
#include "test_fx_helper.h"
#include "../fx_rack.h"
@ -32,7 +29,7 @@ void setupRack(FXRack* rack, int scenario)
rack->getOrbitone()->setEnable(Active(scenario, FXSwitch::FX__Orbitone));
rack->getOrbitone()->setWetLevel(0.8f);
rack->getOrbitone()->setRate(0.4f);
rack->getOrbitone()->setDepth(0.5f);
rack->getOrbitone()->setDepth(0.7f);
rack->getPhaser()->setEnable(Active(scenario, FXSwitch::FX__Phaser));
rack->getPhaser()->setWetLevel(1.0f);
@ -59,57 +56,32 @@ void setupRack(FXRack* rack, int scenario)
TEST_P(FXScenarioTest, FXRackResetAllScenarios)
{
FXRack *rack = new FXRack(SAMPLING_FREQUENCY);
FXRack rack(SAMPLING_FREQUENCY);
int fxSwitch = this->GetParam();
rack->setEnable(true);
setupRack(rack, fxSwitch);
rack->reset();
delete rack;
rack.setEnable(true);
setupRack(&rack, fxSwitch);
rack.reset();
}
TEST_P(FXScenarioTest, ScenarioProcessing)
{
const testing::TestInfo* test_info = testing::UnitTest::GetInstance()->current_test_info();
std::string full_test_name = test_info->test_case_name();
full_test_name += ".";
full_test_name += test_info->name();
const unsigned nbRepeats = 1;
size_t size;
float32_t** samples = readWaveFile(AUDIO_SOURCE_FILE, size);
float32_t* sampleOutL = new float32_t[size * nbRepeats];
float32_t* sampleOutR = new float32_t[size * nbRepeats];
memset(sampleOutL, 0, size * nbRepeats * sizeof(float32_t));
memset(sampleOutR, 0, size * nbRepeats * sizeof(float32_t));
FXRack *rack = new FXRack(SAMPLING_FREQUENCY);
int fxSwitch = this->GetParam();
rack->setEnable(true);
setupRack(rack, fxSwitch);
rack->reset();
string name = getScenarioName(fxSwitch);
for(unsigned i = 0; i < nbRepeats; ++i)
{
rack->process(samples[0], samples[1], sampleOutL + i * size, sampleOutR + i * size, size);
}
FXRack rack(SAMPLING_FREQUENCY);
rack.setEnable(true);
setupRack(&rack, fxSwitch);
rack.reset();
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
rack.process(inSamples[0], inSamples[1], outSamples[0], outSamples[1], size);
stringstream ss;
ss << full_test_name << "-fx-rack" << name << ".wav";
saveWaveFile(getResultFile(ss.str(), true), sampleOutL, sampleOutR, nbRepeats * size, static_cast<unsigned>(SAMPLING_FREQUENCY), 16);
delete[] samples[0];
delete[] samples[1];
delete[] samples;
delete[] sampleOutL;
delete[] sampleOutR;
saveWaveFile(getResultFile(ss.str(), true), outSamples[0], outSamples[1], size, static_cast<unsigned>(SAMPLING_FREQUENCY), 16);
delete rack;
CLEANUP_AUDIO_TEST(inSamples, outSamples);
}
INSTANTIATE_TEST_SUITE_P(FXRack, FXScenarioTest, testing::Range(0, 1 << (FXSwitch::FX__ShimmerReverb + 1)));

@ -0,0 +1,130 @@
#include "test_fx_helper.h"
#include "../fx_dry.h"
#include "../fx_tube.h"
#include "../fx_chorus.h"
#include "../fx_flanger.h"
#include "../fx_orbitone.h"
#include "../fx_phaser.h"
#include "../fx_delay.h"
#include "../effect_platervbstereo.h"
#include "../fx_shimmer_reverb.h"
TEST(UnitFXTuning, Dry)
{
Dry fx(SAMPLING_FREQUENCY);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
SIMPLE_AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR, fx);
SAVE_AUDIO_RESULTS(full_test_name, outSamples, size);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
}
TEST(UnitFXTuning, Tube)
{
Tube fx(SAMPLING_FREQUENCY);
fx.setOverdrive(0.5f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
SIMPLE_AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR, fx);
SAVE_AUDIO_RESULTS(full_test_name, outSamples, size);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
}
TEST(UnitFXTuning, Chorus)
{
Chorus fx(SAMPLING_FREQUENCY);
fx.setRate(0.4f);
fx.setDepth(0.7f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
SIMPLE_AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR, fx);
SAVE_AUDIO_RESULTS(full_test_name, outSamples, size);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
}
TEST(UnitFXTuning, Flanger)
{
Flanger fx(SAMPLING_FREQUENCY);
fx.setRate(0.03f);
fx.setDepth(0.75f);
fx.setFeedback(0.5f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
SIMPLE_AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR, fx);
SAVE_AUDIO_RESULTS(full_test_name, outSamples, size);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
}
TEST(UnitFXTuning, Orbitone)
{
Orbitone fx(SAMPLING_FREQUENCY);
fx.setRate(0.4f);
fx.setDepth(0.7f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
SIMPLE_AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR, fx);
SAVE_AUDIO_RESULTS(full_test_name, outSamples, size);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
}
TEST(UnitFXTuning, Phaser)
{
Phaser fx(SAMPLING_FREQUENCY);
fx.setRate(0.1f);
fx.setDepth(1.0f);
fx.setFeedback(0.5f);
fx.setNbStages(12);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
SIMPLE_AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR, fx);
SAVE_AUDIO_RESULTS(full_test_name, outSamples, size);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
}
TEST(UnitFXTuning, Delay)
{
Delay fx(SAMPLING_FREQUENCY);
fx.setLeftDelayTime(0.25f);
fx.setLeftDelayTime(0.40f);
fx.setFeedback(0.55f);
fx.setFlutterRate(0.01f);
fx.setFlutterAmount(0.05f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
SIMPLE_AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR, fx);
SAVE_AUDIO_RESULTS(full_test_name, outSamples, size);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
}
TEST(UnitFXTuning, PlateReverb)
{
AudioEffectPlateReverb fx(SAMPLING_FREQUENCY);
fx.set_bypass(false);
fx.size(0.7f);
fx.hidamp(0.5f);
fx.lodamp(0.5f);
fx.lowpass(0.3f);
fx.diffusion(0.65f);
fx.level(1.0f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
SIMPLE_AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR, fx);
SAVE_AUDIO_RESULTS(full_test_name, outSamples, size);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
}
TEST(UnitFXTuning, ShimmerReverb)
{
ShimmerReverb fx(SAMPLING_FREQUENCY);
fx.setInputGain(0.65f);
fx.setTime(0.89f);
fx.setDiffusion(0.75f);
fx.setLP(0.8f);
PREPARE_AUDIO_TEST(size, inSamples, outSamples, full_test_name);
SIMPLE_AUDIO_LOOP(inSamples, outSamples, size, inL, inR, outL, outR, fx);
SAVE_AUDIO_RESULTS(full_test_name, outSamples, size);
CLEANUP_AUDIO_TEST(inSamples, outSamples);
}

@ -3,6 +3,7 @@
#include <stdint.h>
#include <arm_math.h>
#include <string>
#include <iostream>
inline uint32_t id2int(const char id[4])
{
@ -57,15 +58,21 @@ struct WaveHeaderFMT {
};
struct WaveHeaderDATA {
char subchunk2Id[4];
ChunkID subchunk2Id;
uint32_t subchunk2Size;
};
float32_t** readWaveFile(const std::string& fileName, size_t& size);
std::ostream& operator<<(std::ostream& out, const ChunkID& id);
std::ostream& operator<<(std::ostream& out, const WaveHeader& hdr);
std::ostream& operator<<(std::ostream& out, const WaveHeaderRIFF& riff);
std::ostream& operator<<(std::ostream& out, const WaveHeaderFMT& fmt);
std::ostream& operator<<(std::ostream& out, const WaveHeaderDATA& data);
float32_t** readWaveFile(const std::string& fileName, size_t& size, WaveHeader* hdr = nullptr);
void saveWaveFile(const std::string& fileName,
float32_t* LChannel,
float32_t* RChannel,
const float32_t* LChannel,
const float32_t* RChannel,
size_t size,
int sampleRate,
int bitsPerSample);

@ -10,6 +10,72 @@
#define ASSERT_NORMALIZED(x)
#endif
std::ostream& operator<<(std::ostream& out, const WaveHeader& hdr)
{
out << "WaveHeader" << std::endl;
out << " + chunkId : " << hdr.chunkId << std::endl;
out << " + chunkSize : " << hdr.chunkSize << std::endl;
out << " + format : " << hdr.format << std::endl;
out << " + subchunk1Id : " << hdr.subchunk1Id << std::endl;
out << " + subchunk1Size : " << hdr.subchunk1Size << std::endl;
out << " + audioFormat : " << hdr.audioFormat << std::endl;
out << " + numChannels : " << hdr.numChannels << std::endl;
out << " + sampleRate : " << hdr.sampleRate << std::endl;
out << " + byteRate : " << hdr.byteRate << std::endl;
out << " + blockAlign : " << hdr.blockAlign << std::endl;
out << " + bitsPerSample : " << hdr.bitsPerSample << std::endl;
out << " + subchunk2Id : " << hdr.subchunk2Id << std::endl;
out << " + subchunk2Size : " << hdr.subchunk2Size << std::endl;
return out;
}
std::ostream& operator<<(std::ostream& out, const ChunkID& id)
{
out << "'"
<< id.ID[0]
<< id.ID[1]
<< id.ID[2]
<< id.ID[3]
<< "'";
return out;
}
std::ostream& operator<<(std::ostream& out, const WaveHeaderRIFF& riff)
{
out << "WaveHeaderRIFF" << std::endl;
out << " + chunkId : " << riff.chunkId << std::endl;
out << " + chunkSize : " << riff.chunkSize << std::endl;
out << " + format : " << riff.format << std::endl;
return out;
}
std::ostream& operator<<(std::ostream& out, const WaveHeaderFMT& fmt)
{
out << "WaveHeaderFMT" << std::endl;
out << " + subchunk1Id : " << fmt.subchunk1Id << std::endl;
out << " + subchunk1Size : " << fmt.subchunk1Size << std::endl;
out << " + audioFormat : " << fmt.audioFormat << std::endl;
out << " + numChannels : " << fmt.numChannels << std::endl;
out << " + sampleRate : " << fmt.sampleRate << std::endl;
out << " + byteRate : " << fmt.byteRate << std::endl;
out << " + blockAlign : " << fmt.blockAlign << std::endl;
out << " + bitsPerSample : " << fmt.bitsPerSample << std::endl;
return out;
}
std::ostream& operator<<(std::ostream& out, const WaveHeaderDATA& data)
{
out << "WaveHeaderDATA" << std::endl;
out << " + subchunk2Id : " << data.subchunk2Id << std::endl;
out << " + subchunk2Size : " << data.subchunk2Size << std::endl;
return out;
}
template<typename T>
bool readChunk(std::ifstream& in, uint32_t id, T& chunk)
{
@ -33,7 +99,7 @@ bool readChunk(std::ifstream& in, uint32_t id, T& chunk)
return false;
}
float32_t** readWaveFile(const std::string& fileName, size_t& size)
float32_t** readWaveFile(const std::string& fileName, size_t& size, WaveHeader* hdr)
{
std::ifstream file(fileName, std::ios::binary);
if(!file)
@ -75,12 +141,28 @@ float32_t** readWaveFile(const std::string& fileName, size_t& size)
return nullptr;
}
size = data.subchunk2Size / (fmt.bitsPerSample / 8);
if(hdr != nullptr)
{
hdr->chunkId = riff.chunkId;
hdr->chunkSize = riff.chunkSize;
hdr->format = riff.format;
hdr->subchunk1Id = fmt.subchunk1Id;
hdr->subchunk1Size = fmt.subchunk1Size;
hdr->audioFormat = fmt.audioFormat;
hdr->numChannels = fmt.numChannels;
hdr->sampleRate = fmt.sampleRate;
hdr->byteRate = fmt.byteRate;
hdr->blockAlign = fmt.blockAlign;
hdr->bitsPerSample = fmt.bitsPerSample;
hdr->subchunk2Id = data.subchunk2Id;
hdr->subchunk2Size = data.subchunk2Size;
}
size = data.subchunk2Size / fmt.blockAlign;
float32_t* LChannel = new float32_t[size];
float32_t* RChannel = new float32_t[size];
unsigned increment = fmt.numChannels;
unsigned i = 0;
size_t i = 0;
while(!file.eof() && i < size)
{
if(fmt.bitsPerSample == 8)
@ -153,10 +235,7 @@ float32_t** readWaveFile(const std::string& fileName, size_t& size)
return nullptr;
}
// ASSERT_NORMALIZED(LChannel[i]);
// ASSERT_NORMALIZED(RChannel[i]);
i += increment;
++i;
}
assert(i == size);

@ -5,8 +5,8 @@
#include <cstring>
void saveWaveFile(const std::string& fileName,
float32_t* LChannel,
float32_t* RChannel,
const float32_t* LChannel,
const float32_t* RChannel,
size_t size,
int sampleRate,
int bitsPerSample)

Loading…
Cancel
Save