First steps on debugging of MixingConsole

pull/495/head
abscisys 2 years ago
parent 1d483dd4f7
commit 36546af851
  1. 2
      src/extra_features.h
  2. 7
      src/fx_components.cpp
  3. 3
      src/fx_engine.hpp
  4. 21
      src/fx_tube.cpp
  5. 3
      src/fx_tube.h
  6. 793
      src/mixing_console.hpp
  7. 11
      src/test/Makefile
  8. 55
      src/test/beta.cpp
  9. 4
      src/test/test_fx_rack.cpp
  10. 63
      src/test/test_mixing_console.cpp

@ -64,6 +64,8 @@ inline long long int getElapseTime(std::string marker = "")
#define LAP_TIME(marker) getElapseTime(marker) #define LAP_TIME(marker) getElapseTime(marker)
#define LOG_LAP_TIME(marker) { auto __d = getElapseTime(marker); if(__d > 0) std::cout << "Execution time for " << marker << ": " << __d << std::endl; } #define LOG_LAP_TIME(marker) { auto __d = getElapseTime(marker); if(__d > 0) std::cout << "Execution time for " << marker << ": " << __d << std::endl; }
#define DEBUG_VALUE(lbl, idx, v) std::cout << lbl << " " << idx << ": " << v << std::endl
#else #else
#define LAP_TIME(marker) #define LAP_TIME(marker)

@ -20,6 +20,7 @@ FastLFO::FastLFO(float32_t sampling_rate, float32_t min_frequency, float32_t max
InitialPhase(initial_phase), InitialPhase(initial_phase),
min_frequency_(min_frequency), min_frequency_(min_frequency),
max_frequency_(max_frequency), max_frequency_(max_frequency),
frequency_(0.0f),
y0_(0.0f), y0_(0.0f),
y1_(0.0f), y1_(0.0f),
iir_coefficient_(0.0f), iir_coefficient_(0.0f),
@ -628,9 +629,9 @@ float32_t softSaturator3(float32_t input, float32_t overdrive)
float32_t softSaturator4(float32_t input, float32_t saturator_factor) float32_t softSaturator4(float32_t input, float32_t saturator_factor)
{ {
float32_t x = input * (saturator_factor); float32_t x = input * saturator_factor;
float32_t abs_x = std::fabs(x); float32_t abs_x = std::abs(x);
float32_t sat_x = std::log(1.0 + abs_x) / std::log(1.0f + saturator_factor); float32_t sat_x = std::log(1.0f + abs_x) / std::log(1.0f + saturator_factor);
return x > 0 ? sat_x : -sat_x; return x > 0 ? sat_x : -sat_x;
} }

@ -121,7 +121,8 @@ public:
}; };
FxEngine(float32_t sampling_rate, float32_t max_lfo_frequency = 20.0f) : FxEngine(float32_t sampling_rate, float32_t max_lfo_frequency = 20.0f) :
FXBase(sampling_rate) FXBase(sampling_rate),
write_ptr_(0)
{ {
this->buffer_ = new T[size]; this->buffer_ = new T[size];
for(unsigned i = 0; i < LFOIndex::kLFOCount; ++i) this->lfo_[i] = enable_lfo ? new LFO(sampling_rate, 0.0f, max_lfo_frequency) : nullptr; for(unsigned i = 0; i < LFOIndex::kLFOCount; ++i) this->lfo_[i] = enable_lfo ? new LFO(sampling_rate, 0.0f, max_lfo_frequency) : nullptr;

@ -4,8 +4,9 @@
Tube::Tube(float32_t samplingRate) : Tube::Tube(float32_t samplingRate) :
FXElement(samplingRate), FXElement(samplingRate),
overdrive_(0.0f), overdrive_(1.0f),
saturator_factor_(0.0f) saturator_factor_(1.0f),
gain_factor_(1.0f)
{ {
this->setOverdrive(0.0f); this->setOverdrive(0.0f);
} }
@ -21,19 +22,29 @@ void Tube::reset()
void Tube::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) void Tube::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR)
{ {
outL = softSaturator4(inL, this->saturator_factor_); float32_t x = inL * this->saturator_factor_;
outR = softSaturator4(inR, this->saturator_factor_); float32_t abs_x = std::abs(x);
float32_t sat_x = std::log(1.0f + abs_x) * this->gain_factor_;
outL = inL > 0 ? sat_x : -sat_x;
x = inR * this->saturator_factor_;
abs_x = std::abs(x);
sat_x = std::log(1.0f + abs_x) * this->gain_factor_;
outR = inR > 0 ? sat_x : -sat_x;
} }
void Tube::setOverdrive(float32_t overdrive) void Tube::setOverdrive(float32_t overdrive)
{ {
static const float32_t N = 200.0f; static constexpr float32_t N = 200.0f;
overdrive = constrain(overdrive, 0.0f, 1.0f); overdrive = constrain(overdrive, 0.0f, 1.0f);
if(this->overdrive_ != overdrive) if(this->overdrive_ != overdrive)
{ {
this->overdrive_ = overdrive; this->overdrive_ = overdrive;
this->saturator_factor_ = 1.0f + N * overdrive; this->saturator_factor_ = 1.0f + N * overdrive;
this->gain_factor_ = 1.0f / std::log(1.0f + this->saturator_factor_);
} }
} }

@ -18,7 +18,7 @@
// //
#pragma once #pragma once
#include "fx_components.h" #include "fx.h"
class Tube : public FXElement class Tube : public FXElement
{ {
@ -37,4 +37,5 @@ public:
private: private:
float32_t overdrive_; float32_t overdrive_;
float32_t saturator_factor_; float32_t saturator_factor_;
float32_t gain_factor_;
}; };

@ -33,471 +33,578 @@
#include "fx_dry.h" #include "fx_dry.h"
#include "fx_unit2.hpp" #include "fx_unit2.hpp"
template<size_t nb_inputs = 8> template<size_t nb_inputs>
class MixingConsole : public FXBase class MixingConsole : public FXBase
{ {
DISALLOW_COPY_AND_ASSIGN(MixingConsole); DISALLOW_COPY_AND_ASSIGN(MixingConsole);
public: public:
MixingConsole(float32_t sampling_rate, size_t buffer_size) : MixingConsole(float32_t sampling_rate, size_t buffer_size);
FXBase(sampling_rate), ~MixingConsole();
BufferSize(buffer_size)
{
for(size_t i = 0; i < nb_inputs; ++i)
{
this->input_sample_buffer_[StereoChannels::Left ][i] = new float32_t[this->BufferSize];
this->input_sample_buffer_[StereoChannels::Right][i] = new float32_t[this->BufferSize];
memset(this->input_sample_buffer_[StereoChannels::Left ][i], 0, this->BufferSize);
memset(this->input_sample_buffer_[StereoChannels::Right][i], 0, this->BufferSize);
}
memset(this->fx_, 0, MixerOutput::kFXCount * sizeof(FXElement*)); // Send section
void setChannelLevel(size_t in, float32_t lvl);
void setPan(size_t in, float32_t pan);
void setSendLevel(size_t in, MixerOutput fx, float32_t lvl);
void setInputSample(size_t in, float32_t sampleL, float32_t sampleR);
void setInputSampleBuffer(size_t in, float32_t* samples);
void setInputSampleBuffer(size_t in, float32_t* samplesL, float32_t* samplesR);
this->fx_[MixerOutput::FX_Tube] = this->tube_ = new FXUnit2<Tube>(sampling_rate); // Return section
this->fx_[MixerOutput::FX_Chorus] = this->chorus_ = new FXUnit2<Chorus>(sampling_rate); void setReturnLevel(MixerOutput ret, MixerOutput dest, float32_t lvl);
this->fx_[MixerOutput::FX_Flanger] = this->flanger_ = new FXUnit2<Flanger>(sampling_rate); void setReturnSample(MixerOutput ret, float32_t sampleL, float32_t sampleR);
this->fx_[MixerOutput::FX_Orbitone] = this->orbitone_ = new FXUnit2<Orbitone>(sampling_rate);
this->fx_[MixerOutput::FX_Phaser] = this->phaser_ = new FXUnit2<Phaser>(sampling_rate);
this->fx_[MixerOutput::FX_Delay] = this->delay_ = new FXUnit2<Delay>(sampling_rate);
this->fx_[MixerOutput::FX_PlateReverb] = this->plate_reverb_ = new FXUnit2<AudioEffectPlateReverb>(sampling_rate);
this->fx_[MixerOutput::FX_ShimmerReverb] = this->shimmer_reverb_ = new FXUnit2<ShimmerReverb>(sampling_rate);
this->fx_[MixerOutput::MainOutput] = this->dry_ = new FXUnit2<Dry>(sampling_rate);
this->init(); // Get FX
} FXElement* getFX(size_t fx);
FXUnit2<Tube>* getTube();
FXUnit2<Chorus>* getChorus();
FXUnit2<Flanger>* getFlanger();
FXUnit2<Orbitone>* getOrbitone();
FXUnit2<Phaser>* getPhaser();
FXUnit2<Delay>* getDelay();
FXUnit2<AudioEffectPlateReverb>* getPlateReverb();
FXUnit2<ShimmerReverb>* getShimmerReverb();
FXUnit2<Dry>* getDry();
~MixingConsole() // Processing
{ void init();
for(size_t i = 0; i < nb_inputs; ++i) void reset();
{ void processSample(float32_t& outL, float32_t& outR);
delete this->input_sample_buffer_[StereoChannels::Left ][i]; void prepare();
delete this->input_sample_buffer_[StereoChannels::Right][i]; void process(float32_t* outL, float32_t* outR);
}
for(size_t i = 0; i < MixerOutput::kFXCount; ++i) protected:
{ void updatePan(size_t in);
delete this->fx_[i]; void setLevel(size_t in, MixerOutput fx, float32_t lvl);
} void setSample(size_t in, float32_t sampleL, float32_t sampleR);
}
// Send section private:
const size_t BufferSize;
void setChannelLevel(size_t in, float32_t lvl) float32_t channel_level_[nb_inputs];
{ float32_t pan_[StereoChannels::kNumChannels + 1][nb_inputs];
assert(in < nb_inputs); float32_t* input_sample_buffer_[StereoChannels::kNumChannels][nb_inputs];
float32_t input_samples_[StereoChannels::kNumChannels][nb_inputs + MixerOutput::kFXCount - 1];
float32_t levels_[MixerOutput::kFXCount][nb_inputs + MixerOutput::kFXCount - 1];
lvl = constrain(lvl, 0.0f, 1.0f); FXElement* fx_[MixerOutput::kFXCount];
if(lvl == this->channel_level_[in]) return; FXUnit2<Tube>* tube_;
FXUnit2<Chorus>* chorus_;
FXUnit2<Flanger>* flanger_;
FXUnit2<Orbitone>* orbitone_;
FXUnit2<Phaser>* phaser_;
FXUnit2<Delay>* delay_;
FXUnit2<AudioEffectPlateReverb>* plate_reverb_;
FXUnit2<ShimmerReverb>* shimmer_reverb_;
FXUnit2<Dry>* dry_;
#if defined(DEBUG)
public:
void dump(std::ostream& out, const std::string& key = "") const;
#endif
};
this->channel_level_[in] = lvl;
this->updatePan();
}
void setPan(size_t in, float32_t pan) template<size_t nb_inputs>
MixingConsole<nb_inputs>::MixingConsole(float32_t sampling_rate, size_t buffer_size) :
FXBase(sampling_rate),
BufferSize(buffer_size)
{
for(size_t i = 0; i < nb_inputs; ++i)
{ {
assert(in < nb_inputs); this->input_sample_buffer_[StereoChannels::Left ][i] = new float32_t[this->BufferSize];
this->input_sample_buffer_[StereoChannels::Right][i] = new float32_t[this->BufferSize];
memset(this->input_sample_buffer_[StereoChannels::Left ][i], 0, this->BufferSize);
memset(this->input_sample_buffer_[StereoChannels::Right][i], 0, this->BufferSize);
}
pan = constrain(pan, 0.0f, 1.0f); memset(this->fx_, 0, MixerOutput::kFXCount * sizeof(FXElement*));
if(pan == this->pan_[StereoChannels::kNumChannels][in]) return;
this->pan_[StereoChannels::kNumChannels][in] = pan; this->fx_[MixerOutput::FX_Tube] = this->tube_ = new FXUnit2<Tube>(sampling_rate);
this->updatePan(in); this->fx_[MixerOutput::FX_Chorus] = this->chorus_ = new FXUnit2<Chorus>(sampling_rate);
} this->fx_[MixerOutput::FX_Flanger] = this->flanger_ = new FXUnit2<Flanger>(sampling_rate);
this->fx_[MixerOutput::FX_Orbitone] = this->orbitone_ = new FXUnit2<Orbitone>(sampling_rate);
this->fx_[MixerOutput::FX_Phaser] = this->phaser_ = new FXUnit2<Phaser>(sampling_rate);
this->fx_[MixerOutput::FX_Delay] = this->delay_ = new FXUnit2<Delay>(sampling_rate);
this->fx_[MixerOutput::FX_PlateReverb] = this->plate_reverb_ = new FXUnit2<AudioEffectPlateReverb>(sampling_rate);
this->fx_[MixerOutput::FX_ShimmerReverb] = this->shimmer_reverb_ = new FXUnit2<ShimmerReverb>(sampling_rate);
this->fx_[MixerOutput::MainOutput] = this->dry_ = new FXUnit2<Dry>(sampling_rate);
void setSendLevel(size_t in, MixerOutput fx, float32_t lvl) this->init();
{ }
assert(in < nb_inputs);
assert(fx < kFXCount);
this->setLevel(in, fx, lvl); template<size_t nb_inputs>
MixingConsole<nb_inputs>::~MixingConsole()
{
for(size_t i = 0; i < nb_inputs; ++i)
{
delete this->input_sample_buffer_[StereoChannels::Left ][i];
delete this->input_sample_buffer_[StereoChannels::Right][i];
} }
void setInputSample(size_t in, float32_t sampleL, float32_t sampleR) for(size_t i = 0; i < MixerOutput::kFXCount; ++i)
{ {
assert(in < nb_inputs); delete this->fx_[i];
this->setSample(in, sampleL, sampleR);
} }
}
void setInputSampleBuffer(size_t in, float32_t* samples) // Send section
{ template<size_t nb_inputs>
assert(in < nb_inputs); void MixingConsole<nb_inputs>::setChannelLevel(size_t in, float32_t lvl)
{
assert(in < nb_inputs);
if(samples != nullptr) lvl = constrain(lvl, 0.0f, 1.0f);
{ if(lvl == this->channel_level_[in]) return;
arm_scale_f32(samples, this->pan_[StereoChannels::Left ][in], this->input_sample_buffer_[StereoChannels::Left ][in], this->BufferSize);
arm_scale_f32(samples, this->pan_[StereoChannels::Right][in], this->input_sample_buffer_[StereoChannels::Right][in], this->BufferSize);
}
else
{
memset(this->input_sample_buffer_[StereoChannels::Left ][in], 0, this->BufferSize * sizeof(float32_t));
memset(this->input_sample_buffer_[StereoChannels::Right][in], 0, this->BufferSize * sizeof(float32_t));
}
}
void setInputSampleBuffer(size_t in, float32_t* samplesL, float32_t* samplesR) this->channel_level_[in] = lvl;
{ this->updatePan(in);
assert(in < nb_inputs); }
if(samplesL != nullptr)
{
memcpy(this->input_sample_buffer_[StereoChannels::Left ][in], samplesL, this->BufferSize * sizeof(float32_t));
}
else
{
memset(this->input_sample_buffer_[StereoChannels::Left ][in], 0, this->BufferSize * sizeof(float32_t));
}
if(samplesR != nullptr) template<size_t nb_inputs>
{ void MixingConsole<nb_inputs>::setPan(size_t in, float32_t pan)
memcpy(this->input_sample_buffer_[StereoChannels::Right][in], samplesR, this->BufferSize * sizeof(float32_t)); {
} assert(in < nb_inputs);
else
{
memset(this->input_sample_buffer_[StereoChannels::Right][in], 0, this->BufferSize * sizeof(float32_t));
}
}
// Return section pan = constrain(pan, 0.0f, 1.0f);
if(pan == this->pan_[StereoChannels::kNumChannels][in]) return;
void setReturnLevel(MixerOutput ret, MixerOutput dest, float32_t lvl) this->pan_[StereoChannels::kNumChannels][in] = pan;
{ this->updatePan(in);
assert(ret < (kFXCount - 1)); }
assert(dest < kFXCount);
if(ret == dest) template<size_t nb_inputs>
{ void MixingConsole<nb_inputs>::setSendLevel(size_t in, MixerOutput fx, float32_t lvl)
// An FX cannot feedback on itself {
return; assert(in < nb_inputs);
} assert(fx < kFXCount);
this->setLevel(nb_inputs + ret, dest, lvl); this->setLevel(in, fx, lvl);
} }
void setReturnSample(MixerOutput ret, float32_t sampleL, float32_t sampleR) template<size_t nb_inputs>
{ void MixingConsole<nb_inputs>::setInputSample(size_t in, float32_t sampleL, float32_t sampleR)
assert(ret < (kFXCount - 1)); {
assert(in < nb_inputs);
this->setSample(nb_inputs + ret, sampleL, sampleR); this->setSample(in, sampleL, sampleR);
} }
// Get FX template<size_t nb_inputs>
FXElement* getFX(size_t fx) void MixingConsole<nb_inputs>::setInputSampleBuffer(size_t in, float32_t* samples)
{ {
assert(fx < MixerOutput::kFXCount); assert(in < nb_inputs);
return this->fx_[fx];
}
FXUnit2<Tube>* getTube() if(samples != nullptr)
{ {
return this->tube_; arm_scale_f32(samples, this->pan_[StereoChannels::Left ][in], this->input_sample_buffer_[StereoChannels::Left ][in], this->BufferSize);
arm_scale_f32(samples, this->pan_[StereoChannels::Right][in], this->input_sample_buffer_[StereoChannels::Right][in], this->BufferSize);
} }
else
FXUnit2<Chorus>* getChorus()
{ {
return this->chorus_; memset(this->input_sample_buffer_[StereoChannels::Left ][in], 0, this->BufferSize * sizeof(float32_t));
memset(this->input_sample_buffer_[StereoChannels::Right][in], 0, this->BufferSize * sizeof(float32_t));
} }
}
FXUnit2<Flanger>* getFlanger() template<size_t nb_inputs>
void MixingConsole<nb_inputs>::setInputSampleBuffer(size_t in, float32_t* samplesL, float32_t* samplesR)
{
assert(in < nb_inputs);
if(samplesL != nullptr)
{ {
return this->flanger_; memcpy(this->input_sample_buffer_[StereoChannels::Left ][in], samplesL, this->BufferSize * sizeof(float32_t));
} }
else
FXUnit2<Orbitone>* getOrbitone()
{ {
return this->orbitone_; memset(this->input_sample_buffer_[StereoChannels::Left ][in], 0, this->BufferSize * sizeof(float32_t));
} }
FXUnit2<Phaser>* getPhaser() if(samplesR != nullptr)
{ {
return this->phaser_; memcpy(this->input_sample_buffer_[StereoChannels::Right][in], samplesR, this->BufferSize * sizeof(float32_t));
} }
else
FXUnit2<Delay>* getDelay()
{ {
return this->delay_; memset(this->input_sample_buffer_[StereoChannels::Right][in], 0, this->BufferSize * sizeof(float32_t));
} }
}
FXUnit2<AudioEffectPlateReverb>* getPlateReverb() // Return section
{ template<size_t nb_inputs>
return this->plate_reverb_; void MixingConsole<nb_inputs>::setReturnLevel(MixerOutput ret, MixerOutput dest, float32_t lvl)
} {
assert(ret < (kFXCount - 1));
assert(dest < kFXCount);
FXUnit2<ShimmerReverb>* getShimmerReverb() if(ret == dest)
{ {
return this->shimmer_reverb_; // An FX cannot feedback on itself
return;
} }
FXUnit2<Dry>* getDry() this->setLevel(nb_inputs + ret, dest, lvl);
{ }
return this->dry_;
}
// Processing template<size_t nb_inputs>
void MixingConsole<nb_inputs>::setReturnSample(MixerOutput ret, float32_t sampleL, float32_t sampleR)
{
assert(ret < (kFXCount - 1));
void init() this->setSample(nb_inputs + ret, sampleL, sampleR);
{ }
memset(this->channel_level_, 0, nb_inputs * sizeof(float32_t));
for(size_t i = 0; i <= StereoChannels::kNumChannels; ++i) memset(this->pan_[i], 0, nb_inputs * sizeof(float32_t));
for(size_t i = 0; i < MixerOutput::kFXCount; ++i) // Get FX
memset(this->levels_[i], 0, (nb_inputs + MixerOutput::kFXCount - 1) * sizeof(float32_t)); template<size_t nb_inputs>
FXElement* MixingConsole<nb_inputs>::getFX(size_t fx)
for(size_t i = 0; i < StereoChannels::kNumChannels; ++i) {
memset(this->input_samples_[i], 0, (nb_inputs + MixerOutput::kFXCount - 1) * sizeof(float32_t)); assert(fx < MixerOutput::kFXCount);
return this->fx_[fx];
}
this->reset(); template<size_t nb_inputs>
} FXUnit2<Tube>* MixingConsole<nb_inputs>::getTube()
{
return this->tube_;
}
template<size_t nb_inputs>
FXUnit2<Chorus>* MixingConsole<nb_inputs>::getChorus()
{
return this->chorus_;
}
template<size_t nb_inputs>
FXUnit2<Flanger>* MixingConsole<nb_inputs>::getFlanger()
{
return this->flanger_;
}
template<size_t nb_inputs>
FXUnit2<Orbitone>* MixingConsole<nb_inputs>::getOrbitone()
{
return this->orbitone_;
}
template<size_t nb_inputs>
FXUnit2<Phaser>* MixingConsole<nb_inputs>::getPhaser()
{
return this->phaser_;
}
void reset() template<size_t nb_inputs>
FXUnit2<Delay>* MixingConsole<nb_inputs>::getDelay()
{
return this->delay_;
}
template<size_t nb_inputs>
FXUnit2<AudioEffectPlateReverb>* MixingConsole<nb_inputs>::getPlateReverb()
{
return this->plate_reverb_;
}
template<size_t nb_inputs>
FXUnit2<ShimmerReverb>* MixingConsole<nb_inputs>::getShimmerReverb()
{
return this->shimmer_reverb_;
}
template<size_t nb_inputs>
FXUnit2<Dry>* MixingConsole<nb_inputs>::getDry()
{
return this->dry_;
}
// Processing
template<size_t nb_inputs>
void MixingConsole<nb_inputs>::init()
{
memset(this->channel_level_, 0, nb_inputs * sizeof(float32_t));
for(size_t i = 0; i <= StereoChannels::kNumChannels; ++i) memset(this->pan_[i], 0, nb_inputs * sizeof(float32_t));
for(size_t i = 0; i < MixerOutput::kFXCount; ++i)
memset(this->levels_[i], 0, (nb_inputs + MixerOutput::kFXCount - 1) * sizeof(float32_t));
for(size_t i = 0; i < StereoChannels::kNumChannels; ++i)
memset(this->input_samples_[i], 0, (nb_inputs + MixerOutput::kFXCount - 1) * sizeof(float32_t));
this->reset();
}
template<size_t nb_inputs>
void MixingConsole<nb_inputs>::reset()
{
for(size_t i = 0; i < nb_inputs; ++i)
{ {
for(size_t i = 0; i < nb_inputs; ++i) memset(this->input_sample_buffer_[StereoChannels::Left ][i], 0, this->BufferSize);
{ memset(this->input_sample_buffer_[StereoChannels::Right][i], 0, this->BufferSize);
memset(this->input_sample_buffer_[StereoChannels::Left ][i], 0, this->BufferSize); }
memset(this->input_sample_buffer_[StereoChannels::Right][i], 0, this->BufferSize);
}
for(size_t i = 0; i < MixerOutput::kFXCount; ++i) for(size_t i = 0; i < MixerOutput::kFXCount; ++i)
{ {
this->fx_[i]->reset(); this->fx_[i]->reset();
}
for(size_t i = 0; i < MixerOutput::MainOutput; ++i) if(i != MixerOutput::MainOutput)
{ {
this->setReturnSample(static_cast<MixerOutput>(i), 0.0f, 0.0f); this->setReturnSample(static_cast<MixerOutput>(i), 0.0f, 0.0f);
} }
} }
}
void processSample(float32_t& outL, float32_t& outR) template<size_t nb_inputs>
{ void MixingConsole<nb_inputs>::processSample(float32_t& outL, float32_t& outR)
float32_t fx_inputs_[MixerOutput::kFXCount][StereoChannels::kNumChannels]; {
float32_t fx_outputs_[MixerOutput::kFXCount][StereoChannels::kNumChannels]; constexpr size_t bufferSize = nb_inputs + MixerOutput::kFXCount - 1;
for(size_t i = 0; i < MixerOutput::kFXCount; ++i) float32_t fx_inputs_[MixerOutput::kFXCount][StereoChannels::kNumChannels];
float32_t fx_outputs_[MixerOutput::kFXCount][StereoChannels::kNumChannels];
for(size_t i = 0; i < MixerOutput::kFXCount; ++i)
{
// Compute the samples that will feed the MixerOutput and process MixerOutput
fx_inputs_[i][StereoChannels::Left ] = arm_weighted_sum_f32(this->input_samples_[StereoChannels::Left ], this->levels_[i], bufferSize);
fx_inputs_[i][StereoChannels::Right] = arm_weighted_sum_f32(this->input_samples_[StereoChannels::Right], this->levels_[i], bufferSize);
// Process the FX
this->fx_[i]->processSample(
fx_inputs_[i][StereoChannels::Left],
fx_inputs_[i][StereoChannels::Right],
fx_outputs_[i][StereoChannels::Left],
fx_outputs_[i][StereoChannels::Right]
);
if(i != MixerOutput::MainOutput)
{ {
// Compute the samples that will feed the MixerOutput and process MixerOutput // Feedback the resulting samples except for the main output
fx_inputs_[i][StereoChannels::Left ] = arm_weighted_sum_f32(this->input_samples_[StereoChannels::Left ], this->levels_[i], nb_inputs + MixerOutput::kFXCount - 1); this->setReturnSample(
fx_inputs_[i][StereoChannels::Right] = arm_weighted_sum_f32(this->input_samples_[StereoChannels::Right], this->levels_[i], nb_inputs + MixerOutput::kFXCount - 1); static_cast<MixerOutput>(i),
// Process the FX
this->fx_[i]->processSample(
fx_inputs_[i][StereoChannels::Left],
fx_inputs_[i][StereoChannels::Right],
fx_outputs_[i][StereoChannels::Left], fx_outputs_[i][StereoChannels::Left],
fx_outputs_[i][StereoChannels::Right] fx_outputs_[i][StereoChannels::Right]
); );
if(i != MixerOutput::MainOutput)
{
// Feedback the resulting samples except for the main output
this->setReturnSample(
static_cast<MixerOutput>(i),
fx_outputs_[i][StereoChannels::Left],
fx_outputs_[i][StereoChannels::Right]
);
}
} }
}
// Return this main output sample
outL = fx_inputs_[MixerOutput::MainOutput][StereoChannels::Left];
outR = fx_inputs_[MixerOutput::MainOutput][StereoChannels::Right];
}
// Return this main output sample template<size_t nb_inputs>
outL = fx_inputs_[MixerOutput::MainOutput][StereoChannels::Left]; void MixingConsole<nb_inputs>::prepare()
outR = fx_inputs_[MixerOutput::MainOutput][StereoChannels::Right]; {
for(size_t i = 0; i < MixerOutput::kFXCount; ++i)
{
this->fx_[i]->prepare();
} }
}
void prepare() template<size_t nb_inputs>
void MixingConsole<nb_inputs>::process(float32_t* outL, float32_t* outR)
{
this->prepare();
for(size_t s = 0; s < this->BufferSize; ++s)
{ {
for(size_t i = 0; i < MixerOutput::kFXCount; ++i) for(size_t in = 0; in < nb_inputs; ++in)
{ {
this->fx_[i]->prepare(); this->setSample(
in,
this->input_sample_buffer_[StereoChannels::Left ][in][s],
this->input_sample_buffer_[StereoChannels::Right][in][s]
);
} }
this->processSample(*outL, *outR);
++outL;
++outR;
} }
}
void process(float32_t* outL, float32_t* outR) template<size_t nb_inputs>
{ void MixingConsole<nb_inputs>::updatePan(size_t in)
this->prepare(); {
float32_t pan = mapfloat(this->pan_[StereoChannels::kNumChannels][in], 0.0f, 1.0f, 0.0, Constants::MPI_2);
this->pan_[StereoChannels::Left ][in] = arm_cos_f32(pan) * this->channel_level_[in];
this->pan_[StereoChannels::Right][in] = arm_sin_f32(pan) * this->channel_level_[in];
}
for(size_t s = 0; s < this->BufferSize; ++s) template<size_t nb_inputs>
{ void MixingConsole<nb_inputs>::setLevel(size_t in, MixerOutput fx, float32_t lvl)
for(size_t in = 0; in < nb_inputs; ++in) {
{ assert(in < (nb_inputs + MixerOutput::kFXCount - 1));
this->setSample( assert(fx < MixerOutput::kFXCount);
in,
this->input_sample_buffer_[StereoChannels::Left ][in][s],
this->input_sample_buffer_[StereoChannels::Right][in][s]
);
}
this->processSample(*outL, *outR); this->levels_[fx][in] = constrain(lvl, 0.0f, 1.0f);
++outL; }
++outR;
}
}
protected: template<size_t nb_inputs>
void updatePan(size_t in) void MixingConsole<nb_inputs>::setSample(size_t in, float32_t sampleL, float32_t sampleR)
{ {
float32_t pan = mapfloat(this->pan_[StereoChannels::kNumChannels][in], 0.0f, 1.0f, 0.0, Constants::MPI_2); assert(in < (nb_inputs + MixerOutput::kFXCount - 1));
this->pan_[StereoChannels::Left ][in] = arm_sin_f32(pan) * this->channel_level_[in]; this->input_samples_[StereoChannels::Left ][in] = sampleL;
this->pan_[StereoChannels::Right][in] = arm_cos_f32(pan) * this->channel_level_[in]; this->input_samples_[StereoChannels::Right][in] = sampleR;
} }
void setLevel(size_t in, MixerOutput fx, float32_t lvl)
{
assert(in < (nb_inputs + MixerOutput::kFXCount - 1));
assert(fx < MixerOutput::kFXCount);
this->levels_[fx][in] = constrain(lvl, 0.0f, 1.0f); #if defined(DEBUG)
}
void setSample(size_t in, float32_t sampleL, float32_t sampleR) #define SS_RESET(ss, prec, align) ss.str(""); ss.precision(prec); ss << align; ss << std::fixed
{ #define SS_SPACE(ss, spc, nb, align, sep) ss.fill(spc); ss.width(nb); ss << "" << sep
assert(in < (nb_inputs + MixerOutput::kFXCount - 1)); #define SS__TEXT(ss, spc, nb, align, sep, txt) ss << align; ss.fill(spc); ss.width(nb); ss << txt << sep
this->input_samples_[StereoChannels::Left ][in] = sampleL;
this->input_samples_[StereoChannels::Right][in] = sampleR;
}
private: template<size_t nb_inputs>
const size_t BufferSize; void MixingConsole<nb_inputs>::dump(std::ostream& out, const std::string& key) const
{
constexpr size_t space = 10;
constexpr size_t precision = 5;
float32_t channel_level_[nb_inputs]; std::stringstream ss;
float32_t pan_[StereoChannels::kNumChannels + 1][nb_inputs];
float32_t* input_sample_buffer_[StereoChannels::kNumChannels][nb_inputs];
float32_t input_samples_[StereoChannels::kNumChannels][nb_inputs + MixerOutput::kFXCount - 1];
float32_t levels_[MixerOutput::kFXCount][nb_inputs + MixerOutput::kFXCount - 1];
FXElement* fx_[MixerOutput::kFXCount]; out << "MixingConsole dump - START - " << key.c_str() << std::endl << std::endl;
FXUnit2<Tube>* tube_;
FXUnit2<Chorus>* chorus_;
FXUnit2<Flanger>* flanger_;
FXUnit2<Orbitone>* orbitone_;
FXUnit2<Phaser>* phaser_;
FXUnit2<Delay>* delay_;
FXUnit2<AudioEffectPlateReverb>* plate_reverb_;
FXUnit2<ShimmerReverb>* shimmer_reverb_;
FXUnit2<Dry>* dry_;
#if defined(DEBUG) out << "\t" << "Input levels & Pan:" << std::endl;
public: {
void dump(std::ostream& out, const std::string& key = "") const SS_RESET(ss, precision, std::left);
SS_SPACE(ss, ' ', space, std::left, '|');
SS__TEXT(ss, ' ', space, std::left, '|', "Level");
SS__TEXT(ss, ' ', space, std::left, '|', "Pan L");
SS__TEXT(ss, ' ', space, std::left, '|', "Pan R");
SS__TEXT(ss, ' ', space, std::left, '|', "Pan");
out << "\t" << ss.str() << std::endl;
SS_RESET(ss, precision, std::left);
SS_SPACE(ss, '-', space, std::left, '+');
SS_SPACE(ss, '-', space, std::left, '+');
SS_SPACE(ss, '-', space, std::left, '+');
SS_SPACE(ss, '-', space, std::left, '+');
SS_SPACE(ss, '-', space, std::left, '+');
out << "\t" << ss.str() << std::endl;
for(size_t i = 0; i < nb_inputs; ++i)
{
std::stringstream s;
s << "* Input ";
s << (i + 1);
SS_RESET(ss, precision, std::left);
SS__TEXT(ss, ' ', space, std::left, '|', s.str());
SS__TEXT(ss, ' ', space - 1, std::right, " |", this->channel_level_[i]);
SS__TEXT(ss, ' ', space - 1, std::right, " |", this->pan_[StereoChannels::Left][i]);
SS__TEXT(ss, ' ', space - 1, std::right, " |", this->pan_[StereoChannels::Right][i]);
SS__TEXT(ss, ' ', space - 1, std::right, " |", this->pan_[StereoChannels::kNumChannels][i]);
out << "\t" << ss.str() << std::endl;
}
}
out << std::endl;
out << "\t" << "Mixing Console input samples:" << std::endl;
{ {
std::stringstream ss; SS_RESET(ss, precision, std::left);
ss.fill(' '); SS_SPACE(ss, ' ', space, std::left, '|');
ss.precision(4);
ss << std::fixed;
out << "\t" << "MixingConsole dump - START - " << key.c_str() << std::endl;
out << "\t" << "Input levels & Pan:" << std::endl;
ss.str("");
ss << std::left;
ss << "\t";
ss.width(11);
ss << "";
ss.width(8);
ss << "Level";
ss.width(8);
ss << "Pan L";
ss.width(8);
ss << "Pan R";
ss.width(8);
ss << "Pan";
out << ss.str() << std::endl;
ss.str("");
for(size_t i = 0; i < nb_inputs; ++i) for(size_t i = 0; i < nb_inputs; ++i)
{ {
ss << std::left; std::stringstream s;
ss << "\t" << "* Input " << (i + 1) << ": "; s << "Input ";
s << (i + 1);
ss.precision(4);
ss << std::showpos; SS__TEXT(ss, ' ', space, std::left, '|', s.str());
ss << std::fixed;
ss.width(8);
ss << this->channel_level_[i];
ss.width(8);
ss << this->pan_[StereoChannels::Left][i];
ss.width(8);
ss << this->pan_[StereoChannels::Right][i];
ss.width(8);
ss << this->pan_[StereoChannels::kNumChannels][i];
ss << std::endl;
} }
out << ss.str() << std::endl; for(size_t i = 0; i < (MixerOutput::kFXCount - 1); ++i)
{
out << "\t" << "Mixing Console input samples:" << std::endl; std::string s = toString(static_cast<MixerOutput>(i));
ss.str(""); s.resize(space);
ss.fill(' '); SS__TEXT(ss, ' ', space, std::left, '|', s.c_str());
ss << std::left; }
ss << "\t"; out << "\t" << ss.str() << std::endl;
ss.width(11);
ss << ""; SS_RESET(ss, precision, std::left);
SS_SPACE(ss, '-', space, std::left, '+');
for(size_t i = 0; i < nb_inputs; ++i) for(size_t i = 0; i < nb_inputs; ++i)
{ {
ss << "Input " << (i + 1) << " "; SS_SPACE(ss, '-', space, std::left, '+');
} }
for(size_t i = 0; i < (MixerOutput::kFXCount - 1); ++i) for(size_t i = 0; i < (MixerOutput::kFXCount - 1); ++i)
{ {
ss.width(7); SS_SPACE(ss, '-', space, std::left, '+');
ss << toString(static_cast<MixerOutput>(i)) << " ";
} }
out << ss.str() << std::endl; out << "\t" << ss.str() << std::endl;
const char* LR = "LR"; const char* LR = "LR";
ss.str("");
for(size_t c = 0; c < StereoChannels::kNumChannels; ++c) for(size_t c = 0; c < StereoChannels::kNumChannels; ++c)
{ {
ss << std::left; std::stringstream s;
ss << "\t" << "* Input " << LR[c] << ": "; s << "* Input ";
ss.precision(4); s << LR[c];
ss << std::showpos;
ss << std::fixed; SS_RESET(ss, precision, std::left);
SS__TEXT(ss, ' ', space, std::left, '|', s.str());
for(size_t i = 0; i < (nb_inputs + MixerOutput::kFXCount - 1); ++i) for(size_t i = 0; i < (nb_inputs + MixerOutput::kFXCount - 1); ++i)
{ {
ss.width(8); SS__TEXT(ss, ' ', space - 1, std::right, " |", this->input_samples_[c][i]);
ss << this->input_samples_[c][i];
} }
ss << std::endl; out << "\t" << ss.str() << std::endl;
} }
out << ss.str() << std::endl; }
out << std::endl;
out << "\t" << "Mixing Console levels:" << std::endl;
ss.str(""); out << "\t" << "Mixing Console levels:" << std::endl;
ss << std::left; {
ss << "\t"; SS_RESET(ss, precision, std::left);
ss.width(11); SS_SPACE(ss, ' ', space, std::left, '|');
ss << " ";
for(size_t i = 0; i < nb_inputs; ++i) for(size_t i = 0; i < nb_inputs; ++i)
{ {
ss << "Input " << (i + 1) << " "; std::stringstream s;
s << "Input ";
s << (i + 1);
SS__TEXT(ss, ' ', space, std::left, '|', s.str());
} }
for(size_t i = 0; i < (MixerOutput::kFXCount - 1); ++i) for(size_t i = 0; i < (MixerOutput::kFXCount - 1); ++i)
{ {
ss.width(7); std::string s = toString(static_cast<MixerOutput>(i));
ss << toString(static_cast<MixerOutput>(i)) << " "; s.resize(space);
SS__TEXT(ss, ' ', space, std::left, '|', s.c_str());
} }
out << ss.str() << std::endl; out << "\t" << ss.str() << std::endl;
SS_RESET(ss, precision, std::left);
SS_SPACE(ss, '-', space, std::left, '+');
for(size_t i = 0; i < nb_inputs; ++i)
{
SS_SPACE(ss, '-', space, std::left, '+');
}
for(size_t i = 0; i < (MixerOutput::kFXCount - 1); ++i)
{
SS_SPACE(ss, '-', space, std::left, '+');
}
out << "\t" << ss.str() << std::endl;
ss.str("");
for(size_t c = 0; c < MixerOutput::kFXCount; ++c) for(size_t c = 0; c < MixerOutput::kFXCount; ++c)
{ {
ss << std::left; SS_RESET(ss, precision, std::left);
ss << "\t"; std::string s = toString(static_cast<MixerOutput>(c));
ss.width(9); s.resize(space);
ss << toString(static_cast<MixerOutput>(c)); SS__TEXT(ss, ' ', space, std::left, '|', s.c_str());
ss << ": ";
ss.precision(4);
ss << std::showpos;
ss << std::fixed;
for(size_t i = 0; i < (nb_inputs + MixerOutput::kFXCount - 1); ++i) for(size_t i = 0; i < (nb_inputs + MixerOutput::kFXCount - 1); ++i)
{ {
ss.width(8); SS__TEXT(ss, ' ', space - 1, std::right, " |", this->levels_[c][i]);
ss << this->levels_[c][i];
} }
ss << std::endl; out << "\t" << ss.str() << std::endl;
} }
out << ss.str() << std::endl;
out << "MixingConsole dump - END - " << key.c_str() << std::endl;
} }
out << std::endl;
out << "MixingConsole dump - END - " << key.c_str() << std::endl;
}
#define DUMP1(mixer, out) mixer->dump(cout)
#define DUMP2(mixer, out, tag) mixer->dump(cout, tag)
#else
#define DUMP1(mixer, out)
#define DUMP2(mixer, out, tag)
#endif #endif
};

@ -1,6 +1,7 @@
OBJDIR := objects OBJDIR := objects
OUTPUT_FOLDER = results OUTPUT_FOLDER = results
EXE := all_test.bin EXE := all_test.bin
BETA := beta.bin
CXX := g++ CXX := g++
CXXFLAGS = -g -std=c++20 CXXFLAGS = -g -std=c++20
@ -14,7 +15,7 @@ INCLUDES = -I../../CMSIS_5/CMSIS/DSP/Include/ \
LD := g++ LD := g++
LIBS := -lm -lstdc++ -lgtest -lpthread LIBS := -lm -lstdc++ -lgtest -lpthread
TST_SRCS := $(filter-out waveplay.cpp, $(wildcard *.cpp)) TST_SRCS := $(filter-out waveplay.cpp, $(filter-out beta.cpp, $(wildcard *.cpp)))
FX__SRCS := ../fx.cpp FX__SRCS := ../fx.cpp
FX__SRCS += ../fx_components.cpp FX__SRCS += ../fx_components.cpp
FX__SRCS += ../fx_svf.cpp FX__SRCS += ../fx_svf.cpp
@ -38,6 +39,10 @@ test: $(EXE) $(OUTPUT_FOLDER)
rm -f $(OUTPUT_FOLDER)/* rm -f $(OUTPUT_FOLDER)/*
./$(EXE) ./$(EXE)
test-debug: $(EXE) $(OUTPUT_FOLDER)
rm -f $(OUTPUT_FOLDER)/*
valgrind --leak-check=full --leak-resolution=high --show-leak-kinds=all --xtree-leak=yes --show-mismatched-frees=yes --log-file=$(OUTPUT_FOLDER)/valgrind-analysis-results.txt ./$(EXE)
$(OBJDIR): $(OBJDIR):
mkdir -p $@ mkdir -p $@
@ -53,5 +58,9 @@ $(OBJDIR)/%.o: ../%.cpp $(OBJDIR)
$(EXE): $(TST_OBJS) $(FX__OBJS) $(EXE): $(TST_OBJS) $(FX__OBJS)
$(LD) $(CXXFLAGS) $(call wildcard,$(TST_OBJS)) $(call wildcard,$(FX__OBJS)) -o $@ $(LIBS) $(LD) $(CXXFLAGS) $(call wildcard,$(TST_OBJS)) $(call wildcard,$(FX__OBJS)) -o $@ $(LIBS)
$(BETA): $(FX__OBJS) beta.cpp
$(CXX) $(CXXFLAGS) $(DEFINES) $(INCLUDES) -c beta.cpp -o $(OBJDIR)/beta.o
$(LD) $(CXXFLAGS) $(call wildcard,$(OBJDIR)/beta.o) $(call wildcard,$(OBJDIR)/arm_functions.o) $(call wildcard,$(FX__OBJS)) -o $@ $(LIBS)
clean: clean:
rm -rf *.o $(OBJDIR) $(EXE) $(OUTPUT_FOLDER) rm -rf *.o $(OBJDIR) $(EXE) $(OUTPUT_FOLDER)

@ -0,0 +1,55 @@
#include "../mixing_console_constants.h"
#include "../mixing_console.hpp"
#include <iostream>
using namespace std;
typedef MixingConsole<8> Mixer;
int main()
{
Mixer* mixer = new Mixer(44100.0f, 4);
// DUMP2(mixer, cout, "Post creation");
mixer->reset();
DUMP2(mixer, cout, "Post creation");
mixer->setChannelLevel(0, 1.0f);
// DUMP2(mixer, cout, "Post setChannelLevel");
mixer->setPan(0, 0.5f);
// DUMP2(mixer, cout, "Post setPan");
float32_t samples[] = {0.0f, 0.0f, 0.0f, 0.0f};
mixer->setInputSampleBuffer(0, samples);
// DUMP2(mixer, cout, "Post setInputSampleBuffer");
mixer->setSendLevel(0, MixerOutput::MainOutput, 1.0f);
// DUMP2(mixer, cout, "Post setSendLevel - full dry");
float32_t outL[4];
float32_t outR[4];
mixer->process(outL, outR);
DUMP2(mixer, cout, "Post process");
cout.precision(5);
cout << std::fixed;
cout << "+ outL: " << outL[0] << " - " << outL[1] << endl;
cout << "+ outR: " << outR[0] << " - " << outR[1] << endl;
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);
// DUMP2(mixer, cout, "Post setSendLevel & setReturnLevel");
delete mixer;
return 0;
}

@ -45,8 +45,8 @@ void setupRack(FXRack* rack)
rack->getDelay()->setFlutterRate(0.15f); rack->getDelay()->setFlutterRate(0.15f);
rack->getDelay()->setFlutterAmount(0.75f); rack->getDelay()->setFlutterAmount(0.75f);
rack->getShimmerReverb()->setWetLevel(0.5f); rack->getShimmerReverb()->setWetLevel(0.6f);
rack->getShimmerReverb()->setInputGain(0.35f); rack->getShimmerReverb()->setInputGain(0.55f);
rack->getShimmerReverb()->setTime(0.89f); rack->getShimmerReverb()->setTime(0.89f);
rack->getShimmerReverb()->setDiffusion(0.75f); rack->getShimmerReverb()->setDiffusion(0.75f);
rack->getShimmerReverb()->setLP(0.8f); rack->getShimmerReverb()->setLP(0.8f);

@ -44,13 +44,13 @@ TEST(MixerOutputTest, toStringForDelay)
TEST(MixerOutputTest, toStringForPlateReverb) TEST(MixerOutputTest, toStringForPlateReverb)
{ {
auto v = toString(MixerOutput::FX_PlateReverb); auto v = toString(MixerOutput::FX_PlateReverb);
EXPECT_EQ(v, "PlateReverb"); EXPECT_EQ(v, "Plate Reverb");
} }
TEST(MixerOutputTest, toStringForShimmerReverb) TEST(MixerOutputTest, toStringForShimmerReverb)
{ {
auto v = toString(MixerOutput::FX_ShimmerReverb); auto v = toString(MixerOutput::FX_ShimmerReverb);
EXPECT_EQ(v, "ShimmerReverb"); EXPECT_EQ(v, "Shimmer Reverb");
} }
TEST(MixerOutputTest, toIndexTube) TEST(MixerOutputTest, toIndexTube)
@ -136,7 +136,7 @@ void setupMixingConsoleFX(Mixer* mixer)
mixer->getPlateReverb()->diffusion(0.65f); mixer->getPlateReverb()->diffusion(0.65f);
mixer->getPlateReverb()->level(1.0f); mixer->getPlateReverb()->level(1.0f);
mixer->getShimmerReverb()->setInputGain(0.35f); mixer->getShimmerReverb()->setInputGain(0.65f);
mixer->getShimmerReverb()->setTime(0.89f); mixer->getShimmerReverb()->setTime(0.89f);
mixer->getShimmerReverb()->setDiffusion(0.75f); mixer->getShimmerReverb()->setDiffusion(0.75f);
mixer->getShimmerReverb()->setLP(0.8f); mixer->getShimmerReverb()->setLP(0.8f);
@ -148,6 +148,8 @@ TEST(MixingConsole, DryProcessing)
constexpr size_t length = 2; constexpr size_t length = 2;
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, length); Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, length);
mixer->reset();
mixer->setSendLevel(0, MixerOutput::FX_Tube, 0.0f); mixer->setSendLevel(0, MixerOutput::FX_Tube, 0.0f);
mixer->setSendLevel(0, MixerOutput::FX_Chorus, 0.0f); mixer->setSendLevel(0, MixerOutput::FX_Chorus, 0.0f);
mixer->setSendLevel(0, MixerOutput::FX_Flanger, 0.0f); mixer->setSendLevel(0, MixerOutput::FX_Flanger, 0.0f);
@ -162,54 +164,77 @@ TEST(MixingConsole, DryProcessing)
mixer->setReturnLevel(static_cast<MixerOutput>(i), MixerOutput::MainOutput, 0.0f); mixer->setReturnLevel(static_cast<MixerOutput>(i), MixerOutput::MainOutput, 0.0f);
} }
mixer->setSendLevel(0, MixerOutput::MainOutput, 1.0f); mixer->setChannelLevel(0, 1.0f);
mixer->setPan(0, 0.5f); mixer->setPan(0, 0.5f);
mixer->setSendLevel(0, MixerOutput::MainOutput, 1.0f);
DUMP2(mixer, std::cout, "Post setup");
float32_t in[length] = {0.1, 0.2}; float32_t in[length] = {0.1, 0.2};
float32_t out[StereoChannels::kNumChannels][length]; float32_t out[StereoChannels::kNumChannels][length];
for(size_t i = 0; i < StereoChannels::kNumChannels; ++i) memset(out[i], 0, length * sizeof(float32_t)); for(size_t i = 0; i < StereoChannels::kNumChannels; ++i) memset(out[i], 0, length * sizeof(float32_t));
mixer->dump(std::cout);
mixer->setInputSampleBuffer(0, in); mixer->setInputSampleBuffer(0, in);
mixer->dump(std::cout); DUMP2(mixer, std::cout, "Post input injection");
mixer->process( mixer->process(
out[StereoChannels::Left ], out[StereoChannels::Left ],
out[StereoChannels::Right] out[StereoChannels::Right]
); );
mixer->dump(std::cout); DUMP2(mixer, std::cout, "Post processing");
EXPECT_EQ(out[StereoChannels::Left ][0], out[StereoChannels::Right][0]); EXPECT_EQ(out[StereoChannels::Left ][0], out[StereoChannels::Right][0]);
EXPECT_EQ(out[StereoChannels::Left ][1], out[StereoChannels::Right][1]); 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 ][0] - (sqrt(2.0f) / 20.0f)), epsilon);
EXPECT_LT(std::abs(out[StereoChannels::Left ][1] - (sqrt(2.0f) / 10.0f)), epsilon); EXPECT_LT(std::abs(out[StereoChannels::Left ][1] - (sqrt(2.0f) / 10.0f)), epsilon);
delete mixer;
}
TEST(MixingConsole, ShimmerProcessing)
{
constexpr float32_t epsilon = 1e-7;
constexpr size_t length = 2;
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, length);
mixer->reset();
mixer->setSendLevel(0, MixerOutput::MainOutput, 0.0f); mixer->setSendLevel(0, MixerOutput::MainOutput, 0.0f);
mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f); mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f);
mixer->setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 1.0f); mixer->setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 1.0f);
mixer->setChannelLevel(0, 1.0f);
mixer->setPan(0, 0.5f); mixer->setPan(0, 0.5f);
mixer->dump(std::cout); DUMP2(mixer, std::cout, "Post setup");
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); mixer->setInputSampleBuffer(0, in);
mixer->dump(std::cout); DUMP2(mixer, std::cout, "Post input injection #1");
mixer->process( mixer->process(
out[StereoChannels::Left ], out1[StereoChannels::Left ],
out[StereoChannels::Right] out1[StereoChannels::Right]
); );
mixer->dump(std::cout); DUMP2(mixer, std::cout, "Post processing #1");
float32_t out2[StereoChannels::kNumChannels][length];
mixer->reset(); mixer->reset();
mixer->dump(std::cout); DUMP2(mixer, std::cout, "Post reset");
float32_t out2[StereoChannels::kNumChannels][length];
mixer->setInputSampleBuffer(0, in); mixer->setInputSampleBuffer(0, in);
mixer->dump(std::cout); DUMP2(mixer, std::cout, "Post input injection #2");
mixer->process( mixer->process(
out2[StereoChannels::Left ], out2[StereoChannels::Left ],
out2[StereoChannels::Right] out2[StereoChannels::Right]
); );
mixer->dump(std::cout); DUMP2(mixer, std::cout, "Post processing #2");
EXPECT_EQ(out[StereoChannels::Left ][0], out2[StereoChannels::Left ][0]);
EXPECT_EQ(out[StereoChannels::Left ][1], out2[StereoChannels::Left ][1]); 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]);
delete mixer; delete mixer;
} }

Loading…
Cancel
Save