Fixing FastLFO and tests suite for it

pull/495/head
abscisys 2 years ago
parent 3096a71598
commit 82c5f500fc
  1. 51
      src/fx_components.cpp
  2. 4
      src/test/Makefile
  3. 501
      src/test/beta.cpp
  4. 440
      src/test/beta_lowlevel.cpp
  5. 89
      src/test/test_cpp_performance.cpp
  6. 4
      src/test/test_fx_components.cpp
  7. 182
      src/test/test_fx_mixing_console_unitary.cpp

@ -92,27 +92,28 @@ float32_t FastLFO::getFrequency() const
void FastLFO::updateCoefficient()
{
float32_t frequency = this->unitary_frequency_ * 268.0f / 240.0f;
float32_t sign = 16.0f;
frequency -= 0.25f;
if(frequency < 0.0f)
{
frequency = -frequency;
}
else
{
if(frequency > 0.5f)
{
frequency -= 0.5f;
}
else
{
sign = -16.0f;
}
}
this->iir_coefficient_ = sign * frequency * (1.0f - 2.0f * frequency);
// float32_t frequency = this->unitary_frequency_ * 1.00669889338314f;
// float32_t sign = 16.0f;
// frequency -= 0.25f;
// if(frequency < 0.0f)
// {
// frequency = -frequency;
// }
// else
// {
// if(frequency > 0.5f)
// {
// frequency -= 0.5f;
// }
// else
// {
// sign = -16.0f;
// }
// }
// this->iir_coefficient_ = sign * frequency * (1.0f - 2.0f * frequency);
this->iir_coefficient_ = 2.0f * cos(Constants::M2PI * this->unitary_frequency_);
this->initial_amplitude_ = this->iir_coefficient_ * 0.25f;
this->reset();
@ -120,6 +121,8 @@ void FastLFO::updateCoefficient()
void FastLFO::reset()
{
static const float32_t epsilon = 1e-3;
this->sub_increment_ = 0.0f;
// computing cos(0) = sin(-PI/2)
@ -134,13 +137,15 @@ void FastLFO::reset()
float32_t p_i = Constants::M2PI * this->unitary_frequency_ / static_cast<float32_t>(this->nb_sub_increment_);
float32_t p = Constants::MPI_2;
float32_t t_p = this->InitialPhase;
const float32_t target = sin(this->InitialPhase);
if(t_p < p)
{
p -= Constants::M2PI;
}
while(p < t_p)
float32_t tuning = -3.0f;
while(p < t_p || abs(tuning - target) > epsilon)
{
this->process();
tuning = this->process();
p += p_i;
}
}

@ -88,8 +88,8 @@ $(OBJDIR)/%.o: ../%.cpp $(OBJDIR)
$(EXE): $(BINDIR) $(TST_OBJS) $(FX__OBJS)
$(LD) $(CXXFLAGS) $(call wildcard,$(TST_OBJS)) $(call wildcard,$(FX__OBJS)) -o $@ $(LIBS)
$(BETA): $(BINDIR) $(BETAOBJS) $(FX__OBJS)
$(LD) $(CXXFLAGS) $(BETAOBJS) $(call wildcard,$(FX__OBJS)) -o $@ $(LIBS)
$(BETA): $(BINDIR) $(BETAOBJS)
$(LD) $(CXXFLAGS) $(BETAOBJS) -o $@ $(LIBS)
clean:
rm -rf $(OBJDIR) $(BINDIR) $(OUTPUT_FOLDER)

@ -1,205 +1,386 @@
#include "test_fx_helper.h"
TEST(BetaTest, WavefileSamplesBoundariesTest)
#include <fstream>
#include <sstream>
#include <iomanip>
class FastLFODebugger
{
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();
public:
FastLFODebugger(float32_t sampling_rate, float32_t min_frequency, float32_t max_frequency, float32_t initial_phase, bool centered) :
SamplingFrequency(sampling_rate),
InitialPhase(initial_phase),
min_frequency_(min_frequency),
max_frequency_(max_frequency),
centered_(centered),
frequency_(0.0f),
nb_sub_increment_(1),
sub_increment_(0),
y0_(0.0f),
y1_(0.0f),
iir_coefficient_(0.0f),
initial_amplitude_(0.0f)
{
assert(this->min_frequency_ <= this->max_frequency_);
assert(this->max_frequency_ < sampling_rate / 2.0f);
size_t size;
float32_t** samples = readWaveFile(AUDIO_SOURCE_FILE, size);
this->setFrequency(this->min_frequency_);
}
size_t nb_errors = 0;
for(size_t i = 0; i < size; ++i)
~FastLFODebugger()
{
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);
}
ASSERT_EQ(0, nb_errors) << full_test_name << ".rawWaveSampleTest";
delete[] samples[0];
delete[] samples[1];
delete[] samples;
}
typedef MixingConsole<1> Mixer;
TEST(BetaTest, MixingConsoleShortBuffer)
{
static const float32_t SINPI_4 = std::sqrt(2.0f) / 2.0f;
inline float32_t getSamplingRate() const
{
return this->SamplingFrequency;
}
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();
void setNormalizedFrequency(float32_t normalized_frequency)
{
normalized_frequency = constrain(normalized_frequency, 0.0f, 1.0f);
if(this->normalized_frequency_ != normalized_frequency)
{
float32_t frequency = mapfloat(normalized_frequency, 0.0f, 1.0f, this->min_frequency_, this->max_frequency_);
this->normalized_frequency_ = normalized_frequency;
this->frequency_ = frequency;
this->unitary_frequency_ = this->frequency_ / this->getSamplingRate();
this->nb_sub_increment_ = (frequency >= 3.0f ? 1 : 300);
this->unitary_frequency_ *= this->nb_sub_increment_;
this->updateCoefficient(1.0f);
}
}
const size_t size = 10;
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, size);
float32_t getNormalizedFrequency() const
{
return this->normalized_frequency_;
}
mixer->setChannelLevel(0, 1.0f);
mixer->setPan(0, 0.5f);
void setFrequency(float32_t frequency)
{
frequency = constrain(frequency, this->min_frequency_, this->max_frequency_);
if(this->frequency_ != frequency)
{
float32_t normalized_frequency = mapfloat(frequency, this->min_frequency_, this->max_frequency_, 0.0f, 1.0f);
this->normalized_frequency_ = normalized_frequency;
this->frequency_ = frequency;
this->unitary_frequency_ = this->frequency_ / this->getSamplingRate();
this->nb_sub_increment_ = (frequency >= 3.0f ? 1 : 300);
this->unitary_frequency_ *= this->nb_sub_increment_;
this->updateCoefficient(1.0f);
}
}
mixer->setSendLevel(0, MixerOutput::MainOutput, 1.0f);
float32_t getFrequency() const
{
return this->frequency_;
}
float32_t inSamples[size];
for(size_t s = 0; s < size; ++s) inSamples[s] = getRandomValue();
float32_t outSamples[2][size];
memset(outSamples[0], 0, size * sizeof(float32_t));
memset(outSamples[1], 0, size * sizeof(float32_t));
void updateCoefficient(float32_t correction_ratio)
{
float32_t frequency = this->unitary_frequency_ * correction_ratio;
float32_t sign = 16.0f;
frequency -= 0.25f;
if(frequency < 0.0f)
{
frequency = -frequency;
}
else
{
if(frequency > 0.5f)
{
frequency -= 0.5f;
}
else
{
sign = -16.0f;
}
}
this->iir_coefficient_ = sign * frequency * (1.0f - 2.0f * frequency);
this->initial_amplitude_ = this->iir_coefficient_ * 0.25f;
this->reset(correction_ratio);
}
mixer->setInputSampleBuffer(0, inSamples);
ASSERT_EQ(0, FULL_INSPECT(mixer, true)) << full_test_name << " Mixer.setInputSampleBuffer";
void reset(float32_t correction_ratio = 1.0f)
{
// static const float32_t epsilon = 1e-7;
this->sub_increment_ = 0.0f;
// computing cos(0) = sin(-PI/2)
this->y1_ = this->initial_amplitude_;
this->y0_ = 0.5f;
// if(this->unitary_frequency_ == 0.0f)
// {
// return;
// }
// float32_t p_i = 2.0f * PI * this->unitary_frequency_ * correction_ratio / static_cast<float32_t>(this->nb_sub_increment_);
// float32_t p = PI / 2.0f;
// float32_t t_p = this->InitialPhase;
// if(t_p < p)
// {
// p -= 2.0f* PI;
// }
// float32_t current = 3.0f;
// while(abs(current, sin(this->InitialPhase)) > epsilon)
// {
// std::cout << "phase: " << p << std::endl;
// this->process();
// p += p_i;
// if(p > (6.0f * PI))
// cout << "ERROR: FLO is not precise enough" <<
// return;
// }
}
mixer->process(outSamples[0], outSamples[1]);
ASSERT_EQ(0, FULL_INSPECT(mixer, true)) << full_test_name << " Mixer.process";
for(size_t s = 0; s < size; ++s)
float32_t process()
{
EXPECT_FLOAT_EQ(outSamples[0][s], outSamples[1][s]);
EXPECT_FLOAT_EQ(outSamples[0][s], inSamples[s] * SINPI_4);
float32_t temp = this->y0_;
float32_t current = temp + 0.5f;
if(this->centered_)
{
current = current * 2.0f - 1.0f;
}
if(this->sub_increment_ == 0)
{
this->y0_ = this->iir_coefficient_ * this->y0_ - this->y1_;
this->y1_ = temp;
this->current_ = current;
return current;
}
this->sub_increment_++;
if(this->sub_increment_ >= this->nb_sub_increment_)
{
this->sub_increment_ = 0;
}
return mapfloat(this->sub_increment_, 0, this->nb_sub_increment_, this->current_, current);
}
delete mixer;
}
float32_t current() const
{
return this->current_;
}
TEST(BetaTest, MixingConsoleReverberatorShortBuffer)
private:
const float32_t SamplingFrequency;
const float32_t InitialPhase;
const float32_t min_frequency_;
const float32_t max_frequency_;
const bool centered_;
float32_t frequency_;
float32_t normalized_frequency_;
float32_t unitary_frequency_;
size_t nb_sub_increment_;
size_t sub_increment_;
float32_t y0_;
float32_t y1_;
float32_t iir_coefficient_;
float32_t initial_amplitude_;
float32_t current_;
};
void updateCorrectionStep(float32_t& sign, float32_t& correction_ratio_step, int direction)
{
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 size_t size = 10;
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, size);
mixer->setChannelLevel(0, 1.0f);
mixer->setPan(0, 0.5f);
mixer->getReverberator()->setInputGain(0.35f);
mixer->getReverberator()->setTime(0.69f);
mixer->getReverberator()->setDiffusion(0.7f);
mixer->getReverberator()->setLP(0.8f);
mixer->setSendLevel(0, MixerOutput::MainOutput, 0.4f);
mixer->setSendLevel(0, MixerOutput::FX_Reverberator, 1.0f);
mixer->setReturnLevel(MixerOutput::FX_Reverberator, MixerOutput::MainOutput, 0.6f);
float32_t inSamples[size];
for(size_t s = 0; s < size; ++s) inSamples[s] = getRandomValue();
float32_t outSamples[2][size];
memset(outSamples[0], 0, size * sizeof(float32_t));
memset(outSamples[1], 0, size * sizeof(float32_t));
mixer->setInputSampleBuffer(0, inSamples);
ASSERT_EQ(0, FULL_INSPECT(mixer, true)) << full_test_name << " Mixer.setInputSampleBuffer";
mixer->process(outSamples[0], outSamples[1]);
ASSERT_EQ(0, FULL_INSPECT(mixer, true)) << full_test_name << " Mixer.process";
if(sign == direction)
{
// does nothing
}
else if(sign == -direction)
{
sign = static_cast<float32_t>(direction);
correction_ratio_step /= 2.0f;
}
else
{
sign = static_cast<float32_t>(direction);
}
delete mixer;
if(direction > 0)
{
std::cout << "LFO is too slow - correction ratio step becomes: " << (sign * correction_ratio_step);
}
else if(direction < 0)
{
std::cout << "LFO is too fast - correction ratio step becomes: " << (sign * correction_ratio_step);
}
}
TEST(BetaTest, MixingConsoleDrySamplesBoundariesTest)
TEST(BetaTesta, FastLFO)
{
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();
size_t size;
float32_t** inSamples =readWaveFile(AUDIO_SOURCE_FILE, size);
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, size);
mixer->reset();
FULL_INSPECT2(mixer, true, "Mixer.reset");
mixer->setChannelLevel(0, 1.0f);
mixer->setPan(0, 0.5f);
mixer->setSendLevel(0, MixerOutput::MainOutput, 1.0f);
mixer->setInputSampleBuffer(0, inSamples[0]);
float32_t** outSamples = new float32_t*[2];
outSamples[0] = new float32_t[size];
outSamples[1] = new float32_t[size];
memset(outSamples[0], 0, size * sizeof(float32_t));
memset(outSamples[1], 0, size * sizeof(float32_t));
mixer->process(outSamples[0], outSamples[1]);
size_t nb_errors = 0;
for(size_t i = 0; i < size; ++i)
size_t NB = static_cast<size_t>(1.0f * SAMPLING_FREQUENCY);
const float32_t freq = 1.5f;
const float32_t init_phase = PI / 2.0f;
float32_t correction_ratio = 1.0f;
float32_t correction_ratio_step = 8.0f/ SAMPLING_FREQUENCY;
FastLFODebugger lfo1(SAMPLING_FREQUENCY, freq, 440.0f, init_phase, true);
lfo1.setFrequency(freq);
const float32_t epsilon = 1e-3;
int nbTrials = 100000;
float32_t maxDiff;
float32_t sign = 0.0f;
float32_t phase;
float32_t phase_increment;
size_t maxOK = 0;
float32_t best_correction = correction_ratio;
while(nbTrials > 0)
{
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);
maxDiff = 0.0f;
phase = init_phase;
correction_ratio += sign * correction_ratio_step;
std::cout << std::setprecision(9) << std::fixed << " - Testing correction_ratio: " << correction_ratio << std::endl;
lfo1.updateCoefficient(correction_ratio);
phase_increment = freq / SAMPLING_FREQUENCY;
for(size_t i = 0; i < NB; ++i)
{
float32_t v1 = lfo1.process();
float32_t v2 = sin(phase);
// std::cout << std::setprecision(9) << std::fixed << " + phase: " << phase << " // v1: " << v1 << " / v2: " << v2 << " => diff: " << (v2 - v1);
float32_t diff = abs(v1 - v2);
if(diff > maxDiff) maxDiff = diff;
// std::cout << " - OK: " << ((diff < epsilon) ? "Yes" : "No") << std::endl;
if(diff > epsilon)
{
if(maxOK < i)
{
maxOK = i + 1;
best_correction = correction_ratio;
}
int quater = 0;
if(phase > (PI / 2.0f)) ++quater;
if(phase > PI) ++quater;
if(phase > (3.0f * PI / 2.0f)) ++quater;
if(v1 < v2)
{
switch (quater)
{
case 0:
case 4:
// Sinus phase [0, PI / 2] => [0.00, 1.00]
// Sinus phase [3 * PI / 2, 2 * PI] => [-1.00, 0.00]
// lfo1 is too slow
updateCorrectionStep(sign, correction_ratio_step, +1);
break;
case 1:
case 3:
// Sinus phase [PI / 2, PI] => [1.00, 0.00]
// Sinus phase [PI, 3 * PI / 2] => [0.00, -1.00]
// lfo1 is too fast
updateCorrectionStep(sign, correction_ratio_step, -1);
break;
default:
FAIL() << "Issue on phase: " << phase;
break;
}
break;
}
else
{
switch (quater)
{
case 0:
case 4:
// Sinus phase [0, PI / 2] => [0.00, 1.00]
// Sinus phase [3 * PI / 2, 2 * PI] => [-1.00, 0.00]
// lfo1 is too fast
updateCorrectionStep(sign, correction_ratio_step, -1);
break;
case 1:
case 3:
// Sinus phase [PI / 2, PI] => [1.00, 0.00]
// Sinus phase [PI, 3 * PI / 2] => [0.00, -1.00]
// lfo1 is too slow
updateCorrectionStep(sign, correction_ratio_step, +1);
break;
default:
FAIL() << "Issue on phase: " << phase;
break;
}
break;
}
}
if(correction_ratio_step < 1e-9) FAIL() << "correction_ratio_step became too small. maxOK = " << maxOK << " with best_correction = " << best_correction;
phase += phase_increment;
if(phase > 2.0f * PI) phase -= 2.0f * PI;
}
--nbTrials;
}
ASSERT_EQ(0, nb_errors) << full_test_name << ".outputSampleTest";
if(nbTrials > -2)
std::cout << "Correct correction ratio = " << correction_ratio << " with maxDiff = " << maxDiff << std::endl;
else
std::cout << "No matching correction ratio" << std::endl;
delete[] inSamples[0];
delete[] inSamples[1];
delete[] inSamples;
std::cout << "maxOK = " << maxOK << " with best_correction = " << best_correction << std::endl;;
delete[] outSamples[0];
delete[] outSamples[1];
delete[] outSamples;
delete mixer;
}
// std::stringstream ssFst;
// std::stringstream ssSin;
TEST(BetaTest, MixingConsoleReverberatorSamplesBoundariesTest)
{
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();
size_t size;
float32_t** inSamples =readWaveFile(AUDIO_SOURCE_FILE, size);
// for(size_t i = 0; i < NB; ++i)
// {
// ssFst << lfo1.process() << (i == (NB - 1) ? "" : ", ");
// ssSin << sin(2.0f * PI * freq * i / SAMPLING_FREQUENCY + init_phase) << (i == (NB - 1) ? "" : ", ");
// }
float32_t** outSamples = new float32_t*[2];
outSamples[0] = new float32_t[size];
outSamples[1] = new float32_t[size];
memset(outSamples[0], 0, size * sizeof(float32_t));
memset(outSamples[1], 0, size * sizeof(float32_t));
// std::ofstream _fst(getResultFile(full_test_name + ".fst.data", true));
// _fst << ssFst.str();
// _fst.close();
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, size);
mixer->reset();
mixer->setChannelLevel(0, 1.0f);
mixer->setPan(0, 0.5f);
// std::ofstream _sin(getResultFile(full_test_name + ".sin.data", true));
// _sin << ssSin.str();
// _sin.close();
mixer->setSendLevel(0, MixerOutput::MainOutput, 0.4f);
mixer->setSendLevel(0, MixerOutput::FX_Reverberator, 1.0f);
mixer->setReturnLevel(MixerOutput::FX_Reverberator, MixerOutput::MainOutput, 0.6f);
mixer->getReverberator()->setMute(false);
mixer->getReverberator()->setInputGain(0.35);
mixer->getReverberator()->setTime(0.65);
mixer->getReverberator()->setDiffusion(0.8);
mixer->getReverberator()->setLP(0.7f);
// std::ofstream out(getResultFile(full_test_name + ".data.m", true));
// out << "# m file to tune FastLFO component" << std::endl << std::endl;
// out << "# Parameters:" << std::endl
// << "# + frequency: " << freq << "Hz" << std::endl
// << "# + # samples: " << NB << std::endl << std::endl;
mixer->setInputSampleBuffer(0, inSamples[0]);
mixer->process(outSamples[0], outSamples[1]);
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;
for(size_t i = 0; i < size; ++i)
{
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);
}
ASSERT_EQ(0, nb_errors) << full_test_name << ".outputSampleTest";
// out << "time = 0 : " << (NB - 1) << ";" << std::endl;
// out << "fst_lfo = load(\"-ascii\", \"" << full_test_name << ".fst.data\");" << std::endl;
// out << "sin_lfo = load(\"-ascii\", \"" << full_test_name << ".sin.data\");" << std::endl;
delete[] inSamples[0];
delete[] inSamples[1];
delete[] inSamples;
// out << std::endl << std::endl;
delete[] outSamples[0];
delete[] outSamples[1];
delete[] outSamples;
// out << "plot(time, fst_lfo, '-', time, sin_lfo, '-');" << std::endl;
// out << "title('LFO tuning');" << std::endl;
// out << "legend('FastLFODebugger', 'Sinus');" << std::endl;
delete mixer;
// out.close();
}
int main(int argc, char **argv)

@ -1,440 +0,0 @@
#include <gtest/gtest.h>
#include <iostream>
#include <iomanip>
#include "test_fx_helper.h"
#include "../fx_engine.hpp"
#define PRINT_EXEC(ctx, x) \
std::cout.fill(' '); \
std::cout.width(80); \
std::cout << std::left; \
std::cout.precision(6); \
std::cout << std::fixed; \
std::cout << #x; \
x \
{ \
float32_t v = 0.0f; \
ctx.write(v); \
std::cout << " // accumulator_: " << showpos << v; \
} \
std::cout << std::endl
#define TAIL , -1
typedef FxEngine<16384, Format::FORMAT_FLOAT32, true> Engine;
void processDebugReverberatorSample(
Engine& engine_, size_t index,
float32_t& lp_decay_1_, float32_t& lp_decay_2_,
float32_t inL, float32_t inR,
float32_t& outL, float32_t& outR)
{
// This is the Griesinger topology described in the Dattorro paper
// (4 AP diffusers on the input, then a loop of 2x 2AP+1Delay).
// Modulation is applied in the loop of the first diffuser AP for additional
// smearing; and to the two long delays for a slow shimmer/chorus effect.
typedef Engine::Reserve< 113,
Engine::Reserve< 162,
Engine::Reserve< 241,
Engine::Reserve< 399,
Engine::Reserve<1653,
Engine::Reserve<2038,
Engine::Reserve<3411,
Engine::Reserve<1913,
Engine::Reserve<1663,
Engine::Reserve<4782> > > > > > > > > > Memory;
Engine::DelayLine<Memory, 0> ap1;
Engine::DelayLine<Memory, 1> ap2;
Engine::DelayLine<Memory, 2> ap3;
Engine::DelayLine<Memory, 3> ap4;
Engine::DelayLine<Memory, 4> dap1a;
Engine::DelayLine<Memory, 5> dap1b;
Engine::DelayLine<Memory, 6> del1;
Engine::DelayLine<Memory, 7> dap2a;
Engine::DelayLine<Memory, 8> dap2b;
Engine::DelayLine<Memory, 9> del2;
Engine::Context c;
const float32_t kap = 0.8f;
const float32_t klp = 0.7f;
const float32_t krt = 0.75f;
const float32_t gain = 0.55f;
float32_t lp_1 = lp_decay_1_;
float32_t lp_2 = lp_decay_2_;
float32_t wet = 0.0f;
float32_t apout = 0.0f;
engine_.start(&c);
// Smear AP1 inside the loop.
PRINT_EXEC(c, c.interpolate(ap1, 10.0f, Engine::LFOIndex::LFO_1, 60.0f, 1.0f););
PRINT_EXEC(c, c.write(ap1, 100, 0.0f););
PRINT_EXEC(c, c.read(inL + inR, gain););
// Diffuse through 4 allpasses.
PRINT_EXEC(c, c.read(ap1 TAIL, kap););
PRINT_EXEC(c, c.writeAllPass(ap1, -kap););
PRINT_EXEC(c, c.read(ap2 TAIL, kap););
PRINT_EXEC(c, c.writeAllPass(ap2, -kap););
PRINT_EXEC(c, c.read(ap3 TAIL, kap););
PRINT_EXEC(c, c.writeAllPass(ap3, -kap););
PRINT_EXEC(c, c.read(ap4 TAIL, kap););
PRINT_EXEC(c, c.writeAllPass(ap4, -kap););
PRINT_EXEC(c, c.write(apout););
// Main reverb loop.
PRINT_EXEC(c, c.load(apout););
PRINT_EXEC(c, c.interpolate(del2, 4680.0f, Engine::LFOIndex::LFO_2, 100.0f, krt););
PRINT_EXEC(c, c.lp(lp_1, klp););
PRINT_EXEC(c, c.read(dap1a TAIL, -kap););
PRINT_EXEC(c, c.writeAllPass(dap1a, kap););
PRINT_EXEC(c, c.read(dap1b TAIL, kap););
PRINT_EXEC(c, c.writeAllPass(dap1b, -kap););
PRINT_EXEC(c, c.write(del1, 1.5f););
PRINT_EXEC(c, c.write(wet, 0.0f););
outL = wet;
PRINT_EXEC(c, c.load(apout););
// PRINT_EXEC(c, c.interpolate(del1, 4450.0f, Engine::LFOIndex::LFO_1, 50.0f, krt););
PRINT_EXEC(c, c.read(del1 TAIL, krt););
PRINT_EXEC(c, c.lp(lp_2, klp););
PRINT_EXEC(c, c.read(dap2a TAIL, kap););
PRINT_EXEC(c, c.writeAllPass(dap2a, -kap););
PRINT_EXEC(c, c.read(dap2b TAIL, -kap););
PRINT_EXEC(c, c.writeAllPass(dap2b, kap););
PRINT_EXEC(c, c.write(del2, 1.5f););
PRINT_EXEC(c, c.write(wet, 0.0f););
outR = wet;
lp_decay_1_ = lp_1;
lp_decay_2_ = lp_2;
std::cout << "Index # " << index << " - ( " << inL << ", " << inR << " ) ==> ( " << outL << ", " << outR << " )" << std::endl;
std::cout << std::endl << "***********************************************************************************************************" << std::endl << std::endl;
}
TEST(LowLevel, TestDiracReverberatorAlgo)
{
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();
Engine engine_(SAMPLING_FREQUENCY);
engine_.setLFOFrequency(Engine::LFOIndex::LFO_1, 0.5f);
engine_.setLFOFrequency(Engine::LFOIndex::LFO_2, 0.3f);
engine_.reset();
float32_t lp1 = 0.0f;
float32_t lp2 = 0.0f;
const size_t size = static_cast<float32_t>(SAMPLING_FREQUENCY) * 4;
float32_t* inSamples = new float32_t[size];
memset(inSamples, 0, size * sizeof(float32_t));
inSamples[0] = 1.0f;
float32_t* outSamplesL = new float32_t[size];
float32_t* outSamplesR = new float32_t[size];
memset(outSamplesL, 0, size * sizeof(float32_t));
memset(outSamplesR, 0, size * sizeof(float32_t));
for(size_t i = 0; i < size; ++i)
{
processDebugReverberatorSample(engine_, i, lp1, lp2, inSamples[i], inSamples[i], outSamplesL[i], outSamplesR[i]);
}
saveWaveFile(getResultFile(full_test_name + ".wav", true), outSamplesL, outSamplesR, size, SAMPLING_FREQUENCY, 16);
delete[] outSamplesL;
delete[] outSamplesR;
delete[] inSamples;
}
void processReverberatorSample(
Engine& engine_L_, Engine& engine_R_, size_t index,
float32_t& lp_decay_1_, float32_t& lp_decay_2_,
float32_t inL, float32_t inR,
float32_t& outL, float32_t& outR)
{
// This is the Griesinger topology described in the Dattorro paper
// (4 AP diffusers on the input, then a loop of 2x 2AP+1Delay).
// Modulation is applied in the loop of the first diffuser AP for additional
// smearing; and to the two long delays for a slow shimmer/chorus effect.
typedef Engine::Reserve< 113,
Engine::Reserve< 162,
Engine::Reserve< 241,
Engine::Reserve< 399,
Engine::Reserve<1653,
Engine::Reserve<2038,
Engine::Reserve<3411,
Engine::Reserve<1913,
Engine::Reserve<1663,
Engine::Reserve<4782> > > > > > > > > > Memory;
Engine::DelayLine<Memory, 0> ap1;
Engine::DelayLine<Memory, 1> ap2;
Engine::DelayLine<Memory, 2> ap3;
Engine::DelayLine<Memory, 3> ap4;
Engine::DelayLine<Memory, 4> dap1a;
Engine::DelayLine<Memory, 5> dap1b;
Engine::DelayLine<Memory, 6> del1;
Engine::DelayLine<Memory, 7> dap2a;
Engine::DelayLine<Memory, 8> dap2b;
Engine::DelayLine<Memory, 9> del2;
Engine::Context cL;
Engine::Context cR;
const float32_t kap = 0.8f;
const float32_t klp = 0.7f;
const float32_t krt = 0.75f;
const float32_t gain = 0.55f;
float32_t lp_1 = lp_decay_1_;
float32_t lp_2 = lp_decay_2_;
float32_t wet = 0.0f;
float32_t apout = 0.0f;
engine_L_.start(&cL);
engine_R_.start(&cR);
// Smear AP1 inside the loop.
cL.interpolate(ap1, 10.0f, Engine::LFOIndex::LFO_1, 60.0f, 1.0f);
cL.write(ap1, 100, 0.0f);
cL.read(inL, gain);
// Diffuse through 4 allpasses.
cL.read(ap1 TAIL, kap);
cL.writeAllPass(ap1, -kap);
cL.read(ap2 TAIL, kap);
cL.writeAllPass(ap2, -kap);
cL.read(ap3 TAIL, kap);
cL.writeAllPass(ap3, -kap);
cL.read(ap4 TAIL, kap);
cL.writeAllPass(ap4, -kap);
cL.write(apout);
// Main reverb loop.
cL.load(apout);
cL.interpolate(del2, 4680.0f, Engine::LFOIndex::LFO_2, 100.0f, krt);
cL.lp(lp_1, klp);
cL.read(dap1a TAIL, -kap);
cL.writeAllPass(dap1a, kap);
cL.read(dap1b TAIL, kap);
cL.writeAllPass(dap1b, -kap);
cL.write(del1, 1.5f);
cL.write(wet, 0.0f);
outL = wet;
// Smear AP1 inside the loop.
cR.interpolate(ap1, 10.0f, Engine::LFOIndex::LFO_1, 60.0f, 1.0f);
cR.write(ap1, 100, 0.0f);
cR.read(inL + inR, gain);
// Diffuse through 4 allpasses.
cR.read(ap1 TAIL, kap);
cR.writeAllPass(ap1, -kap);
cR.read(ap2 TAIL, kap);
cR.writeAllPass(ap2, -kap);
cR.read(ap3 TAIL, kap);
cR.writeAllPass(ap3, -kap);
cR.read(ap4 TAIL, kap);
cR.writeAllPass(ap4, -kap);
cR.write(apout);
// Main reverb loop.
cR.load(apout);
// cR.interpolate(del1, 4450.0f, Engine::LFOIndex::LFO_1, 50.0f, krt);
cR.read(del1 TAIL, krt);
cR.lp(lp_2, klp);
cR.read(dap2a TAIL, kap);
cR.writeAllPass(dap2a, -kap);
cR.read(dap2b TAIL, -kap);
cR.writeAllPass(dap2b, kap);
cR.write(del2, 1.5f);
cR.write(wet, 0.0f);
outR = wet;
lp_decay_1_ = lp_1;
lp_decay_2_ = lp_2;
}
TEST(LowLevel, TestStereoReverberatorAlgo)
{
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();
Engine engine_L_(SAMPLING_FREQUENCY);
Engine engine_R_(SAMPLING_FREQUENCY);
engine_L_.setLFOFrequency(Engine::LFOIndex::LFO_1, 0.5f);
engine_L_.setLFOFrequency(Engine::LFOIndex::LFO_2, 0.3f);
engine_L_.reset();
engine_R_.setLFOFrequency(Engine::LFOIndex::LFO_1, 0.5f);
engine_R_.setLFOFrequency(Engine::LFOIndex::LFO_2, 0.3f);
engine_R_.reset();
float32_t lp1 = 0.0f;
float32_t lp2 = 0.0f;
size_t size = 0;
float32_t** inSamples = readWaveFile(AUDIO_SOURCE_FILE, size);
float32_t* outSamplesL = new float32_t[size];
float32_t* outSamplesR = new float32_t[size];
memset(outSamplesL, 0, size * sizeof(float32_t));
memset(outSamplesR, 0, size * sizeof(float32_t));
for(size_t i = 0; i < size; ++i)
{
processReverberatorSample(engine_L_, engine_R_, i, lp1, lp2, inSamples[0][i], inSamples[1][i], outSamplesL[i], outSamplesR[i]);
}
saveWaveFile(getResultFile(full_test_name + ".wav", true), outSamplesL, outSamplesR, size, SAMPLING_FREQUENCY, 16);
delete[] outSamplesL;
delete[] outSamplesR;
delete[] inSamples[0];
delete[] inSamples[1];
delete[] inSamples;
}
void processReverberatorSample(
Engine& engine_, size_t index,
float32_t& lp_decay_1_, float32_t& lp_decay_2_,
float32_t inL, float32_t inR,
float32_t& outL, float32_t& outR)
{
// This is the Griesinger topology described in the Dattorro paper
// (4 AP diffusers on the input, then a loop of 2x 2AP+1Delay).
// Modulation is applied in the loop of the first diffuser AP for additional
// smearing; and to the two long delays for a slow shimmer/chorus effect.
typedef Engine::Reserve< 113,
Engine::Reserve< 162,
Engine::Reserve< 241,
Engine::Reserve< 399,
Engine::Reserve<1653,
Engine::Reserve<2038,
Engine::Reserve<3411,
Engine::Reserve<1913,
Engine::Reserve<1663,
Engine::Reserve<4782> > > > > > > > > > Memory;
Engine::DelayLine<Memory, 0> ap1;
Engine::DelayLine<Memory, 1> ap2;
Engine::DelayLine<Memory, 2> ap3;
Engine::DelayLine<Memory, 3> ap4;
Engine::DelayLine<Memory, 4> dap1a;
Engine::DelayLine<Memory, 5> dap1b;
Engine::DelayLine<Memory, 6> del1;
Engine::DelayLine<Memory, 7> dap2a;
Engine::DelayLine<Memory, 8> dap2b;
Engine::DelayLine<Memory, 9> del2;
Engine::Context c;
const float32_t kap = 0.8f;
const float32_t klp = 0.7f;
const float32_t krt = 0.75f;
const float32_t gain = 0.55f;
float32_t lp_1 = lp_decay_1_;
float32_t lp_2 = lp_decay_2_;
float32_t wet = 0.0f;
float32_t apout = 0.0f;
engine_.start(&c);
// Smear AP1 inside the loop.
c.interpolate(ap1, 10.0f, Engine::LFOIndex::LFO_1, 60.0f, 1.0f);
c.writeAndLoad(ap1, 100, 0.0f);
c.read(inL + inR, gain);
// Diffuse through 4 allpasses.
c.read(ap1 TAIL, kap);
c.writeAllPass(ap1, -kap);
c.read(ap2 TAIL, kap);
c.writeAllPass(ap2, -kap);
c.read(ap3 TAIL, kap);
c.writeAllPass(ap3, -kap);
c.read(ap4 TAIL, kap);
c.writeAllPass(ap4, -kap);
c.write(apout);
// Main reverb loop.
c.load(apout);
c.interpolate(del2, 4680.0f, Engine::LFOIndex::LFO_2, 100.0f, krt);
c.lp(lp_1, klp);
c.read(dap1a TAIL, -kap);
c.writeAllPass(dap1a, kap);
c.read(dap1b TAIL, kap);
c.writeAllPass(dap1b, -kap);
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);
c.read(dap2a TAIL, kap);
c.writeAllPass(dap2a, -kap);
c.read(dap2b TAIL, -kap);
c.writeAllPass(dap2b, kap);
c.write(del2, 2.0f);
c.writeAndLoad(wet, 0.0f);
outR = wet;
lp_decay_1_ = lp_1;
lp_decay_2_ = lp_2;
}
TEST(LowLevel, TestMonoReverberatorAlgo)
{
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();
Engine engine_(SAMPLING_FREQUENCY);
engine_.setLFOFrequency(Engine::LFOIndex::LFO_1, 0.5f);
engine_.setLFOFrequency(Engine::LFOIndex::LFO_2, 0.3f);
engine_.reset();
float32_t lp1 = 0.0f;
float32_t lp2 = 0.0f;
size_t size = 0;
float32_t** inSamples = readWaveFile(AUDIO_SOURCE_FILE, size);
float32_t* outSamplesL = new float32_t[size];
float32_t* outSamplesR = new float32_t[size];
memset(outSamplesL, 0, size * sizeof(float32_t));
memset(outSamplesR, 0, size * sizeof(float32_t));
for(size_t i = 0; i < size; ++i)
{
processReverberatorSample(engine_, i, lp1, lp2, inSamples[0][i], inSamples[1][i], outSamplesL[i], outSamplesR[i]);
}
saveWaveFile(getResultFile(full_test_name + ".wav", true), outSamplesL, outSamplesR, size, SAMPLING_FREQUENCY, 16);
delete[] outSamplesL;
delete[] outSamplesR;
delete[] inSamples[0];
delete[] inSamples[1];
delete[] inSamples;
}

@ -59,6 +59,33 @@ TEST(CppPerformance, LFOPerformance_ComplexLFO_FastLFO)
EXPECT_GE(d1, d2);
}
TEST(CppPerformance, LFOPerformance_InterpolatedSineOscillator_FastLFO)
{
const size_t NB = 10000000;
float32_t freq = 0.1f;
InterpolatedSineOscillator lfo1(SAMPLING_FREQUENCY, 0.0f, 10.0f, Constants::MPI_2);
FastLFO lfo2(SAMPLING_FREQUENCY, 0.0f, 10.0f);
lfo1.setFrequency(freq);
LAP_TIME("lfo1");
for(size_t i = 0; i < NB; ++i)
{
lfo1.process();
}
auto d1 = LAP_TIME("lfo1");
lfo2.setFrequency(freq);
LAP_TIME("lfo2");
for(size_t i = 0; i < NB; ++i)
{
lfo2.process();
}
auto d2 = LAP_TIME("lfo2");
EXPECT_GE(d1, d2);
}
TEST(CppPerformance, FastLFOTuning)
{
const testing::TestInfo* test_info = testing::UnitTest::GetInstance()->current_test_info();
@ -91,3 +118,65 @@ TEST(CppPerformance, FastLFOTuning)
}
out.close();
}
TEST(CppPerformance, FastLFOTuningOctave)
{
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();
size_t NB = static_cast<size_t>(1.0f * SAMPLING_FREQUENCY);
float32_t freq = 1.5f;
FastLFO lfo1(SAMPLING_FREQUENCY, freq, 440.0f);
lfo1.setFrequency(freq);
InterpolatedSineOscillator lfo2(SAMPLING_FREQUENCY, freq, 440.0f);
lfo2.setFrequency(freq);
ComplexLFO lfo3(SAMPLING_FREQUENCY, freq, 440.0f);
lfo3.setFrequency(freq);
std::stringstream ssLFO1;
std::stringstream ssLFO2;
std::stringstream ssLFO3;
for(size_t i = 0; i < NB; ++i)
{
ssLFO1 << lfo1.process() << (i == (NB - 1) ? "" : ", ");
ssLFO2 << lfo2.process() << (i == (NB - 1) ? "" : ", ");
ssLFO3 << lfo3.process() << (i == (NB - 1) ? "" : ", ");
}
std::ofstream _lfo1(getResultFile(full_test_name + ".fast.data", true));
_lfo1 << ssLFO1.str();
_lfo1.close();
std::ofstream _lfo2(getResultFile(full_test_name + ".intr.data", true));
_lfo2 << ssLFO2.str();
_lfo2.close();
std::ofstream _lfo3(getResultFile(full_test_name + ".cplx.data", true));
_lfo3 << ssLFO3.str();
_lfo3.close();
std::ofstream out(getResultFile(full_test_name + ".data.m", true));
out << "# m file to tune FastLFO component" << std::endl << std::endl;
out << "# Parameters:" << std::endl
<< "# + frequency: " << freq << "Hz" << std::endl
<< "# + # samples: " << NB << std::endl << std::endl;
out << "time = 0 : " << (NB - 1) << ";" << std::endl;
out << "fast_lfo = load(\"-ascii\", \"" << full_test_name << ".fast.data\");" << std::endl;
out << "intr_lfo = load(\"-ascii\", \"" << full_test_name << ".intr.data\");" << std::endl;
out << "cplx_lfo = load(\"-ascii\", \"" << full_test_name << ".cplx.data\");" << std::endl;
out << std::endl << std::endl;
out << "plot(time, fast_lfo, '-', time, intr_lfo, '-', cplx_lfo, '-');" << std::endl;
out << "title('LFO tuning');" << std::endl;
out << "legend('FastLFO', 'InterpolatedSineOscillator', 'ComplexLFO');" << std::endl;
out.close();
}

@ -133,8 +133,8 @@ TEST(CppOptimization, FastLFOPrecisionTest)
const float32_t epsilon = 1e-3;
ComplexLFO lfo1(SAMPLING_FREQUENCY, 0.0f, 10.0f);
FastLFO lfo2(SAMPLING_FREQUENCY, 0.0f, 10.0f);
ComplexLFO lfo1(SAMPLING_FREQUENCY, 0.0f, 10.0f, 0.0f, true);
FastLFO lfo2(SAMPLING_FREQUENCY, 0.0f, 10.0f, 0.0f, true);
lfo1.setFrequency(freq);
lfo2.setFrequency(freq);
float32_t max_delta = 0.0f;

@ -0,0 +1,182 @@
#include "test_fx_helper.h"
#include "../mixing_console.hpp"
typedef MixingConsole<1> Mixer;
TEST(MixingConsole, ShortBuffer)
{
static const float32_t SINPI_4 = std::sqrt(2.0f) / 2.0f;
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 size_t size = 10;
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, size);
mixer->setChannelLevel(0, 1.0f);
mixer->setPan(0, 0.5f);
mixer->setSendLevel(0, MixerOutput::MainOutput, 1.0f);
float32_t inSamples[size];
for(size_t s = 0; s < size; ++s) inSamples[s] = getRandomValue();
float32_t outSamples[2][size];
memset(outSamples[0], 0, size * sizeof(float32_t));
memset(outSamples[1], 0, size * sizeof(float32_t));
mixer->setInputSampleBuffer(0, inSamples);
ASSERT_EQ(0, FULL_INSPECT(mixer, true)) << full_test_name << " Mixer.setInputSampleBuffer";
mixer->process(outSamples[0], outSamples[1]);
ASSERT_EQ(0, FULL_INSPECT(mixer, true)) << full_test_name << " Mixer.process";
for(size_t s = 0; s < size; ++s)
{
EXPECT_FLOAT_EQ(outSamples[0][s], outSamples[1][s]);
EXPECT_FLOAT_EQ(outSamples[0][s], inSamples[s] * SINPI_4);
}
delete mixer;
}
TEST(MixingConsole, ReverberatorShortBuffer)
{
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 size_t size = 10;
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, size);
mixer->setChannelLevel(0, 1.0f);
mixer->setPan(0, 0.5f);
mixer->getReverberator()->setInputGain(0.35f);
mixer->getReverberator()->setTime(0.69f);
mixer->getReverberator()->setDiffusion(0.7f);
mixer->getReverberator()->setLP(0.8f);
mixer->setSendLevel(0, MixerOutput::MainOutput, 0.4f);
mixer->setSendLevel(0, MixerOutput::FX_Reverberator, 1.0f);
mixer->setReturnLevel(MixerOutput::FX_Reverberator, MixerOutput::MainOutput, 0.6f);
float32_t inSamples[size];
for(size_t s = 0; s < size; ++s) inSamples[s] = getRandomValue();
float32_t outSamples[2][size];
memset(outSamples[0], 0, size * sizeof(float32_t));
memset(outSamples[1], 0, size * sizeof(float32_t));
mixer->setInputSampleBuffer(0, inSamples);
ASSERT_EQ(0, FULL_INSPECT(mixer, true)) << full_test_name << " Mixer.setInputSampleBuffer";
mixer->process(outSamples[0], outSamples[1]);
ASSERT_EQ(0, FULL_INSPECT(mixer, true)) << full_test_name << " Mixer.process";
delete mixer;
}
TEST(MixingConsole, DrySamplesBoundariesTest)
{
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();
size_t size;
float32_t** inSamples =readWaveFile(AUDIO_SOURCE_FILE, size);
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, size);
mixer->reset();
FULL_INSPECT2(mixer, true, "Mixer.reset");
mixer->setChannelLevel(0, 1.0f);
mixer->setPan(0, 0.5f);
mixer->setSendLevel(0, MixerOutput::MainOutput, 1.0f);
mixer->setInputSampleBuffer(0, inSamples[0]);
float32_t** outSamples = new float32_t*[2];
outSamples[0] = new float32_t[size];
outSamples[1] = new float32_t[size];
memset(outSamples[0], 0, size * sizeof(float32_t));
memset(outSamples[1], 0, size * sizeof(float32_t));
mixer->process(outSamples[0], outSamples[1]);
size_t nb_errors = 0;
for(size_t i = 0; i < size; ++i)
{
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);
}
ASSERT_EQ(0, nb_errors) << full_test_name << ".outputSampleTest";
delete[] inSamples[0];
delete[] inSamples[1];
delete[] inSamples;
delete[] outSamples[0];
delete[] outSamples[1];
delete[] outSamples;
delete mixer;
}
TEST(MixingConsole, ReverberatorSamplesBoundariesTest)
{
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();
size_t size;
float32_t** inSamples =readWaveFile(AUDIO_SOURCE_FILE, size);
float32_t** outSamples = new float32_t*[2];
outSamples[0] = new float32_t[size];
outSamples[1] = new float32_t[size];
memset(outSamples[0], 0, size * sizeof(float32_t));
memset(outSamples[1], 0, size * sizeof(float32_t));
Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, size);
mixer->reset();
mixer->setChannelLevel(0, 1.0f);
mixer->setPan(0, 0.5f);
mixer->setSendLevel(0, MixerOutput::MainOutput, 0.4f);
mixer->setSendLevel(0, MixerOutput::FX_Reverberator, 1.0f);
mixer->setReturnLevel(MixerOutput::FX_Reverberator, MixerOutput::MainOutput, 0.6f);
mixer->getReverberator()->setMute(false);
mixer->getReverberator()->setInputGain(0.35);
mixer->getReverberator()->setTime(0.65);
mixer->getReverberator()->setDiffusion(0.8);
mixer->getReverberator()->setLP(0.7f);
mixer->setInputSampleBuffer(0, inSamples[0]);
mixer->process(outSamples[0], outSamples[1]);
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;
for(size_t i = 0; i < size; ++i)
{
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);
}
ASSERT_EQ(0, nb_errors) << full_test_name << ".outputSampleTest";
delete[] inSamples[0];
delete[] inSamples[1];
delete[] inSamples;
delete[] outSamples[0];
delete[] outSamples[1];
delete[] outSamples;
delete mixer;
}
Loading…
Cancel
Save