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. 385
      src/mixing_console.hpp
  7. 11
      src/test/Makefile
  8. 55
      src/test/beta.cpp
  9. 4
      src/test/test_fx_rack.cpp
  10. 59
      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,13 +33,80 @@
#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);
~MixingConsole();
// 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);
// Return section
void setReturnLevel(MixerOutput ret, MixerOutput dest, float32_t lvl);
void setReturnSample(MixerOutput ret, float32_t sampleL, float32_t sampleR);
// 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();
// Processing
void init();
void reset();
void processSample(float32_t& outL, float32_t& outR);
void prepare();
void process(float32_t* outL, float32_t* outR);
protected:
void updatePan(size_t in);
void setLevel(size_t in, MixerOutput fx, float32_t lvl);
void setSample(size_t in, float32_t sampleL, float32_t sampleR);
private:
const size_t BufferSize;
float32_t channel_level_[nb_inputs];
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];
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
};
template<size_t nb_inputs>
MixingConsole<nb_inputs>::MixingConsole(float32_t sampling_rate, size_t buffer_size) :
FXBase(sampling_rate), FXBase(sampling_rate),
BufferSize(buffer_size) BufferSize(buffer_size)
{ {
@ -66,7 +133,8 @@ public:
this->init(); this->init();
} }
~MixingConsole() template<size_t nb_inputs>
MixingConsole<nb_inputs>::~MixingConsole()
{ {
for(size_t i = 0; i < nb_inputs; ++i) for(size_t i = 0; i < nb_inputs; ++i)
{ {
@ -81,8 +149,8 @@ public:
} }
// Send section // Send section
template<size_t nb_inputs>
void setChannelLevel(size_t in, float32_t lvl) void MixingConsole<nb_inputs>::setChannelLevel(size_t in, float32_t lvl)
{ {
assert(in < nb_inputs); assert(in < nb_inputs);
@ -90,10 +158,11 @@ public:
if(lvl == this->channel_level_[in]) return; if(lvl == this->channel_level_[in]) return;
this->channel_level_[in] = lvl; this->channel_level_[in] = lvl;
this->updatePan(); this->updatePan(in);
} }
void setPan(size_t in, float32_t pan) template<size_t nb_inputs>
void MixingConsole<nb_inputs>::setPan(size_t in, float32_t pan)
{ {
assert(in < nb_inputs); assert(in < nb_inputs);
@ -105,7 +174,8 @@ public:
this->updatePan(in); this->updatePan(in);
} }
void setSendLevel(size_t in, MixerOutput fx, float32_t lvl) template<size_t nb_inputs>
void MixingConsole<nb_inputs>::setSendLevel(size_t in, MixerOutput fx, float32_t lvl)
{ {
assert(in < nb_inputs); assert(in < nb_inputs);
assert(fx < kFXCount); assert(fx < kFXCount);
@ -113,14 +183,16 @@ public:
this->setLevel(in, fx, lvl); this->setLevel(in, fx, lvl);
} }
void setInputSample(size_t in, 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(in < nb_inputs); assert(in < nb_inputs);
this->setSample(in, sampleL, sampleR); this->setSample(in, sampleL, sampleR);
} }
void setInputSampleBuffer(size_t in, float32_t* samples) template<size_t nb_inputs>
void MixingConsole<nb_inputs>::setInputSampleBuffer(size_t in, float32_t* samples)
{ {
assert(in < nb_inputs); assert(in < nb_inputs);
@ -136,7 +208,8 @@ public:
} }
} }
void setInputSampleBuffer(size_t in, float32_t* samplesL, float32_t* samplesR) template<size_t nb_inputs>
void MixingConsole<nb_inputs>::setInputSampleBuffer(size_t in, float32_t* samplesL, float32_t* samplesR)
{ {
assert(in < nb_inputs); assert(in < nb_inputs);
if(samplesL != nullptr) if(samplesL != nullptr)
@ -159,8 +232,8 @@ public:
} }
// Return section // Return section
template<size_t nb_inputs>
void setReturnLevel(MixerOutput ret, MixerOutput dest, float32_t lvl) void MixingConsole<nb_inputs>::setReturnLevel(MixerOutput ret, MixerOutput dest, float32_t lvl)
{ {
assert(ret < (kFXCount - 1)); assert(ret < (kFXCount - 1));
assert(dest < kFXCount); assert(dest < kFXCount);
@ -174,7 +247,8 @@ public:
this->setLevel(nb_inputs + ret, dest, lvl); this->setLevel(nb_inputs + ret, dest, lvl);
} }
void setReturnSample(MixerOutput ret, float32_t sampleL, float32_t sampleR) template<size_t nb_inputs>
void MixingConsole<nb_inputs>::setReturnSample(MixerOutput ret, float32_t sampleL, float32_t sampleR)
{ {
assert(ret < (kFXCount - 1)); assert(ret < (kFXCount - 1));
@ -182,60 +256,70 @@ public:
} }
// Get FX // Get FX
FXElement* getFX(size_t fx) template<size_t nb_inputs>
FXElement* MixingConsole<nb_inputs>::getFX(size_t fx)
{ {
assert(fx < MixerOutput::kFXCount); assert(fx < MixerOutput::kFXCount);
return this->fx_[fx]; return this->fx_[fx];
} }
FXUnit2<Tube>* getTube() template<size_t nb_inputs>
FXUnit2<Tube>* MixingConsole<nb_inputs>::getTube()
{ {
return this->tube_; return this->tube_;
} }
FXUnit2<Chorus>* getChorus() template<size_t nb_inputs>
FXUnit2<Chorus>* MixingConsole<nb_inputs>::getChorus()
{ {
return this->chorus_; return this->chorus_;
} }
FXUnit2<Flanger>* getFlanger() template<size_t nb_inputs>
FXUnit2<Flanger>* MixingConsole<nb_inputs>::getFlanger()
{ {
return this->flanger_; return this->flanger_;
} }
FXUnit2<Orbitone>* getOrbitone() template<size_t nb_inputs>
FXUnit2<Orbitone>* MixingConsole<nb_inputs>::getOrbitone()
{ {
return this->orbitone_; return this->orbitone_;
} }
FXUnit2<Phaser>* getPhaser() template<size_t nb_inputs>
FXUnit2<Phaser>* MixingConsole<nb_inputs>::getPhaser()
{ {
return this->phaser_; return this->phaser_;
} }
FXUnit2<Delay>* getDelay() template<size_t nb_inputs>
FXUnit2<Delay>* MixingConsole<nb_inputs>::getDelay()
{ {
return this->delay_; return this->delay_;
} }
FXUnit2<AudioEffectPlateReverb>* getPlateReverb() template<size_t nb_inputs>
FXUnit2<AudioEffectPlateReverb>* MixingConsole<nb_inputs>::getPlateReverb()
{ {
return this->plate_reverb_; return this->plate_reverb_;
} }
FXUnit2<ShimmerReverb>* getShimmerReverb() template<size_t nb_inputs>
FXUnit2<ShimmerReverb>* MixingConsole<nb_inputs>::getShimmerReverb()
{ {
return this->shimmer_reverb_; return this->shimmer_reverb_;
} }
FXUnit2<Dry>* getDry() template<size_t nb_inputs>
FXUnit2<Dry>* MixingConsole<nb_inputs>::getDry()
{ {
return this->dry_; return this->dry_;
} }
// Processing // Processing
template<size_t nb_inputs>
void init() void MixingConsole<nb_inputs>::init()
{ {
memset(this->channel_level_, 0, nb_inputs * sizeof(float32_t)); 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 <= StereoChannels::kNumChannels; ++i) memset(this->pan_[i], 0, nb_inputs * sizeof(float32_t));
@ -249,7 +333,8 @@ public:
this->reset(); this->reset();
} }
void 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)
{ {
@ -260,24 +345,26 @@ public:
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)
{ {
constexpr size_t bufferSize = nb_inputs + MixerOutput::kFXCount - 1;
float32_t fx_inputs_[MixerOutput::kFXCount][StereoChannels::kNumChannels]; float32_t fx_inputs_[MixerOutput::kFXCount][StereoChannels::kNumChannels];
float32_t fx_outputs_[MixerOutput::kFXCount][StereoChannels::kNumChannels]; float32_t fx_outputs_[MixerOutput::kFXCount][StereoChannels::kNumChannels];
for(size_t i = 0; i < MixerOutput::kFXCount; ++i) for(size_t i = 0; i < MixerOutput::kFXCount; ++i)
{ {
// Compute the samples that will feed the MixerOutput and process MixerOutput // 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], nb_inputs + MixerOutput::kFXCount - 1); 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], nb_inputs + MixerOutput::kFXCount - 1); fx_inputs_[i][StereoChannels::Right] = arm_weighted_sum_f32(this->input_samples_[StereoChannels::Right], this->levels_[i], bufferSize);
// Process the FX // Process the FX
this->fx_[i]->processSample( this->fx_[i]->processSample(
@ -303,7 +390,8 @@ public:
outR = fx_inputs_[MixerOutput::MainOutput][StereoChannels::Right]; outR = fx_inputs_[MixerOutput::MainOutput][StereoChannels::Right];
} }
void prepare() template<size_t nb_inputs>
void MixingConsole<nb_inputs>::prepare()
{ {
for(size_t i = 0; i < MixerOutput::kFXCount; ++i) for(size_t i = 0; i < MixerOutput::kFXCount; ++i)
{ {
@ -311,7 +399,8 @@ public:
} }
} }
void process(float32_t* outL, float32_t* outR) template<size_t nb_inputs>
void MixingConsole<nb_inputs>::process(float32_t* outL, float32_t* outR)
{ {
this->prepare(); this->prepare();
@ -332,15 +421,16 @@ public:
} }
} }
protected: template<size_t nb_inputs>
void updatePan(size_t in) void MixingConsole<nb_inputs>::updatePan(size_t in)
{ {
float32_t pan = mapfloat(this->pan_[StereoChannels::kNumChannels][in], 0.0f, 1.0f, 0.0, Constants::MPI_2); float32_t pan = mapfloat(this->pan_[StereoChannels::kNumChannels][in], 0.0f, 1.0f, 0.0, Constants::MPI_2);
this->pan_[StereoChannels::Left ][in] = arm_sin_f32(pan) * this->channel_level_[in]; this->pan_[StereoChannels::Left ][in] = arm_cos_f32(pan) * this->channel_level_[in];
this->pan_[StereoChannels::Right][in] = arm_cos_f32(pan) * this->channel_level_[in]; this->pan_[StereoChannels::Right][in] = arm_sin_f32(pan) * this->channel_level_[in];
} }
void setLevel(size_t in, MixerOutput fx, float32_t lvl) template<size_t nb_inputs>
void MixingConsole<nb_inputs>::setLevel(size_t in, MixerOutput fx, float32_t lvl)
{ {
assert(in < (nb_inputs + MixerOutput::kFXCount - 1)); assert(in < (nb_inputs + MixerOutput::kFXCount - 1));
assert(fx < MixerOutput::kFXCount); assert(fx < MixerOutput::kFXCount);
@ -348,156 +438,173 @@ protected:
this->levels_[fx][in] = constrain(lvl, 0.0f, 1.0f); this->levels_[fx][in] = constrain(lvl, 0.0f, 1.0f);
} }
void setSample(size_t in, float32_t sampleL, float32_t sampleR) template<size_t nb_inputs>
void MixingConsole<nb_inputs>::setSample(size_t in, float32_t sampleL, float32_t sampleR)
{ {
assert(in < (nb_inputs + MixerOutput::kFXCount - 1)); assert(in < (nb_inputs + MixerOutput::kFXCount - 1));
this->input_samples_[StereoChannels::Left ][in] = sampleL; this->input_samples_[StereoChannels::Left ][in] = sampleL;
this->input_samples_[StereoChannels::Right][in] = sampleR; this->input_samples_[StereoChannels::Right][in] = sampleR;
} }
private:
const size_t BufferSize;
float32_t channel_level_[nb_inputs]; #if defined(DEBUG)
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]; #define SS_RESET(ss, prec, align) ss.str(""); ss.precision(prec); ss << align; ss << std::fixed
FXUnit2<Tube>* tube_; #define SS_SPACE(ss, spc, nb, align, sep) ss.fill(spc); ss.width(nb); ss << "" << sep
FXUnit2<Chorus>* chorus_; #define SS__TEXT(ss, spc, nb, align, sep, txt) ss << align; ss.fill(spc); ss.width(nb); ss << txt << sep
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) template<size_t nb_inputs>
public: void MixingConsole<nb_inputs>::dump(std::ostream& out, const std::string& key) const
void dump(std::ostream& out, const std::string& key = "") const
{ {
constexpr size_t space = 10;
constexpr size_t precision = 5;
std::stringstream ss; std::stringstream ss;
ss.fill(' ');
ss.precision(4);
ss << std::fixed;
out << "\t" << "MixingConsole dump - START - " << key.c_str() << std::endl; out << "MixingConsole dump - START - " << key.c_str() << std::endl << std::endl;
out << "\t" << "Input levels & Pan:" << std::endl; out << "\t" << "Input levels & Pan:" << std::endl;
{
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;
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_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]);
ss.precision(4); out << "\t" << ss.str() << std::endl;
ss << std::showpos;
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; }
out << std::endl;
out << "\t" << "Mixing Console input samples:" << std::endl; out << "\t" << "Mixing Console input samples:" << std::endl;
ss.str(""); {
ss.fill(' '); SS_RESET(ss, precision, std::left);
ss << std::left; SS_SPACE(ss, ' ', space, std::left, '|');
ss << "\t"; for(size_t i = 0; i < nb_inputs; ++i)
ss.width(11); {
ss << ""; 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)
{
std::string s = toString(static_cast<MixerOutput>(i));
s.resize(space);
SS__TEXT(ss, ' ', space, std::left, '|', s.c_str());
}
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) 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]; }
out << "\t" << ss.str() << std::endl;
} }
ss << std::endl;
} }
out << ss.str() << std::endl; out << std::endl;
out << "\t" << "Mixing Console levels:" << std::endl; out << "\t" << "Mixing Console levels:" << std::endl;
ss.str(""); {
ss << std::left; SS_RESET(ss, precision, std::left);
ss << "\t"; SS_SPACE(ss, ' ', space, std::left, '|');
ss.width(11); for(size_t i = 0; i < nb_inputs; ++i)
ss << " "; {
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)
{
std::string s = toString(static_cast<MixerOutput>(i));
s.resize(space);
SS__TEXT(ss, ' ', space, std::left, '|', s.c_str());
}
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) 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;
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 << std::endl;
out << "MixingConsole dump - END - " << key.c_str() << 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);

@ -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