diff --git a/src/debug.hpp b/src/debug.hpp index 339e0ca..b0f845b 100644 --- a/src/debug.hpp +++ b/src/debug.hpp @@ -81,6 +81,11 @@ public:\ code\ } +#define DUMP(clazz, out) clazz->dump(out, true, "") +#define DUMP2(clazz, out, tag) clazz->dump(out, true, tag) +#define FAST_DUMP(clazz, out, tag) clazz->dump(out, false, "") +#define FAST_DUMP2(clazz, out, tag) clazz->dump(out, false, tag) + #define IMPLEMENT_INSPECT(code) \ public:\ virtual size_t inspect(ValueInpector inspector, bool deepInspection = true, const std::string& tag = "") const override\ @@ -89,7 +94,9 @@ public:\ } #define INSPECT(obj, inspector) obj->inspect(inspector, true) -#define INSPECT2(obj, inspector, deepInspection) obj->inpect(inspector, deepInspection) +#define INSPECT2(obj, inspector, deepInspection) obj->inspect(inspector, deepInspection) +#define FULL_INSPECT(obj, deepInspection) obj->inspect(fullInspector, deepInspection) +#define FULL_INSPECT2(obj, deepInspection, tag) obj->inspect(fullInspector, deepInspection, tag) #else @@ -97,7 +104,14 @@ public:\ #define IMPLEMENT_DUMP(code) #define IMPLEMENT_INSPECT(code) +#define DUMP(clazz, out) +#define DUMP2(clazz, out, tag) +#define FAST_DUMP(clazz, out, tag) +#define FAST_DUMP2(clazz, out, tag) + #define INSPECT(obj, inspector) #define INSPECT2(obj, inspector, deepInspection) +#define FULL_INSPECT(obj, deepInspection) +#define FULL_INSPECT2(obj, deepInspection, tag) #endif \ No newline at end of file diff --git a/src/fx_delay.cpp b/src/fx_delay.cpp index 199c4db..c408070 100644 --- a/src/fx_delay.cpp +++ b/src/fx_delay.cpp @@ -88,12 +88,15 @@ void Delay::reset() void Delay::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) { static const float32_t max_delay_time = MAX_DELAY_TIME * this->getSamplingRate(); - float32_t jitter_ratio = this->jitter_generator_.process(); float32_t jitter_delay_time = 0.0f; - if(jitter_ratio != 0.0f) + if(this->jitter_amount_ != 0.0f) { - jitter_ratio *= this->jitter_amount_; - jitter_delay_time = MAX_FLUTTER_DELAY_TIME * jitter_ratio * this->getSamplingRate(); + float32_t jitter_ratio = this->jitter_generator_.process(); + if(jitter_ratio != 0.0f) + { + jitter_ratio *= this->jitter_amount_; + jitter_delay_time = MAX_FLUTTER_DELAY_TIME * jitter_ratio * this->getSamplingRate(); + } } // this->filter_.setCutoffChangeRatio(jitter_ratio); diff --git a/src/fx_delay.h b/src/fx_delay.h index f1fe2b2..c81dee3 100644 --- a/src/fx_delay.h +++ b/src/fx_delay.h @@ -22,8 +22,6 @@ #include "fx_components.h" #include "fx_svf.h" -#include - class Delay : public FXElement { DISALLOW_COPY_AND_ASSIGN(Delay); diff --git a/src/mixing_console.hpp b/src/mixing_console.hpp index 1c4c9c5..25287b4 100644 --- a/src/mixing_console.hpp +++ b/src/mixing_console.hpp @@ -383,7 +383,7 @@ template void MixingConsole::setSendLevel(size_t in, MixerOutput fx, float32_t lvl) { assert(in < nb_inputs); - assert(fx < kFXCount); + assert(fx < MixerOutput::kFXCount); this->setLevel(in, fx, lvl); } @@ -440,8 +440,8 @@ void MixingConsole::setInputSampleBuffer(size_t in, float32_t* sample template void MixingConsole::setReturnLevel(MixerOutput ret, MixerOutput dest, float32_t lvl) { - assert(ret < (kFXCount - 1)); - assert(dest < kFXCount); + assert(ret < (MixerOutput::kFXCount - 1)); + assert(dest < MixerOutput::kFXCount); if(ret == dest) { @@ -455,7 +455,7 @@ void MixingConsole::setReturnLevel(MixerOutput ret, MixerOutput dest, template void MixingConsole::setReturnSample(MixerOutput ret, float32_t sampleL, float32_t sampleR) { - assert(ret < (kFXCount - 1)); + assert(ret < (MixerOutput::kFXCount - 1)); this->setSample(nb_inputs + ret, sampleL, sampleR); } diff --git a/src/test/Makefile b/src/test/Makefile index 3258619..58ab5ac 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -16,7 +16,6 @@ INCLUDES = -I../../CMSIS_5/CMSIS/DSP/Include/ \ LD := g++ LIBS := -lm -lstdc++ -lgtest -lpthread -TST_SRCS := $(filter-out waveplay.cpp, $(filter-out beta.cpp, $(wildcard *.cpp))) FX__SRCS := ../fx.cpp FX__SRCS += ../fx_components.cpp FX__SRCS += ../fx_svf.cpp @@ -31,17 +30,28 @@ FX__SRCS += ../fx_shimmer_reverb.cpp FX__SRCS += ../fx_dry.cpp FX__SRCS += ../fx_rack.cpp -TST_OBJS = $(TST_SRCS:%.cpp=$(OBJDIR)/%.o) +TST_SRCS := $(filter-out waveplay.cpp, $(filter-out beta.cpp, $(wildcard *.cpp))) + +BETASRCS := beta.cpp +BETASRCS += arm_functions.cpp +BETASRCS += wavein.cpp +BETASRCS += waveout.cpp +BETASRCS += test_fx_helper.cpp + FX__OBJS = $(patsubst ../%, $(OBJDIR)/%, $(FX__SRCS:.cpp=.o)) +TST_OBJS = $(TST_SRCS:%.cpp=$(OBJDIR)/%.o) +BETAOBJS = $(BETASRCS:%.cpp=$(OBJDIR)/%.o) all: $(EXE) test +bin: $(EXE) + test: $(EXE) $(OUTPUT_FOLDER) - rm -f $(OUTPUT_FOLDER)/* + rm -rf $(OUTPUT_FOLDER)/* ./$(EXE) test-debug: $(EXE) $(OUTPUT_FOLDER) - rm -f $(OUTPUT_FOLDER)/* + rm -rf $(OUTPUT_FOLDER)/* valgrind --leak-check=full --leak-resolution=high --show-leak-kinds=all --xtree-leak=yes --show-mismatched-frees=yes --error-limit=no --log-file=$(OUTPUT_FOLDER)/valgrind-analysis-results.txt ./$(EXE) $(OBJDIR): @@ -59,9 +69,8 @@ $(OBJDIR)/%.o: ../%.cpp $(OBJDIR) $(EXE): $(TST_OBJS) $(FX__OBJS) $(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) +$(BETA): $(BETAOBJS) beta.cpp + $(LD) $(CXXFLAGS) $(BETAOBJS) $(call wildcard,$(FX__OBJS)) -o $@ $(LIBS) clean: rm -rf *.o $(OBJDIR) $(EXE) $(OUTPUT_FOLDER) diff --git a/src/test/beta.cpp b/src/test/beta.cpp index 8e20cb9..a83dba0 100644 --- a/src/test/beta.cpp +++ b/src/test/beta.cpp @@ -1,55 +1,216 @@ -#include "../mixing_console_constants.h" +#include +#include +#include + +#include "test_fx_helper.h" #include "../mixing_console.hpp" -#include +TEST(BetaTest, WavefileSamplesBoundariesTest) +{ + 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(); -using namespace std; + size_t size; + float32_t** samples = readWaveFile(AUDIO_SOURCE_FILE, size); -typedef MixingConsole<8> Mixer; + size_t nb_errors = 0; + for(size_t i = 0; i < size; ++i) + { + nb_errors += fullInspector(full_test_name + ".rawWaveSampleTest", samples[0][i], -1.0f, 1.0f, true); + nb_errors += fullInspector(full_test_name + ".rawWaveSampleTest", samples[1][i], -1.0f, 1.0f, true); + } + EXPECT_EQ(0, nb_errors) << full_test_name << ".rawWaveSampleTest"; -int main() + delete[] samples[0]; + delete[] samples[1]; + delete[] samples; +} + +typedef MixingConsole<1> Mixer; + +TEST(BetaTest, MixingConsoleShortBuffer) { - Mixer* mixer = new Mixer(44100.0f, 4); - // DUMP2(mixer, cout, "Post creation"); + static const float32_t SINPI_4 = std::sqrt(2.0f) / 2.0f; - mixer->reset(); - DUMP2(mixer, cout, "Post creation"); + 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); - // DUMP2(mixer, cout, "Post setChannelLevel"); + 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); + EXPECT_EQ(0, FULL_INSPECT(mixer, true)); + mixer->process(outSamples[0], outSamples[1]); + EXPECT_EQ(0, FULL_INSPECT(mixer, true)); + for(size_t s = 0; s < size; ++s) + { + EXPECT_EQ(outSamples[0][s], outSamples[1][s]); + EXPECT_EQ(outSamples[0][s], inSamples[s] * SINPI_4); + } + + delete mixer; +} + +TEST(BetaTest, MixingConsoleShimmerShortBuffer) +{ + 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); - // 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->getShimmerReverb()->setInputGain(0.35f); + mixer->getShimmerReverb()->setTime(0.69f); + mixer->getShimmerReverb()->setDiffusion(0.7f); + mixer->getShimmerReverb()->setLP(0.8f); + + mixer->setSendLevel(0, MixerOutput::MainOutput, 0.4f); + mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f); + mixer->setReturnLevel(MixerOutput::FX_ShimmerReverb, 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); + EXPECT_EQ(0, FULL_INSPECT(mixer, true)); + // FAST_DUMP(mixer, std::cerr, full_test_name + ".setInputSampleBuffer"); + + mixer->process(outSamples[0], outSamples[1]); + EXPECT_EQ(0, FULL_INSPECT(mixer, true)); + // FAST_DUMP(mixer, std::cerr, full_test_name + ".process"); + + delete mixer; +} + +TEST(BetaTest, MixingConsoleDrySamplesBoundariesTest) +{ + 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); - // 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->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); + } + EXPECT_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(BetaTest, MixingConsoleShimmerSamplesBoundariesTest) +{ + 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->setSendLevel(0, MixerOutput::FX_Tube, 1.0f); - mixer->setSendLevel(0, MixerOutput::FX_Delay, 1.0f); - mixer->setSendLevel(0, MixerOutput::FX_PlateReverb, 1.0f); + 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->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"); + 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_ShimmerReverb, 1.0f); + mixer->setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 0.6f); + + mixer->getShimmerReverb()->setMute(false); + mixer->getShimmerReverb()->setInputGain(0.35); + mixer->getShimmerReverb()->setTime(0.65); + mixer->getShimmerReverb()->setDiffusion(0.8); + mixer->getShimmerReverb()->setLP(0.7f); + + mixer->setInputSampleBuffer(0, inSamples[0]); + mixer->process(outSamples[0], outSamples[1]); +FAST_DUMP(mixer, std::cerr, full_test_name); + //EXPECT_EQ(0, FULL_INSPECT2(mixer, true, full_test_name + "Mixer.process")) << full_test_name << "Mixer.process"; + saveWaveFile(getResultFile(full_test_name + ".wav", true), outSamples[0], outSamples[1], size, static_cast(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); + } + EXPECT_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; +} - return 0; -} \ No newline at end of file +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/test/test_cpp.cpp b/src/test/test_cpp.cpp index 224d8e6..1d6c836 100644 --- a/src/test/test_cpp.cpp +++ b/src/test/test_cpp.cpp @@ -1,8 +1,6 @@ #include #include "../fx_components.h" -#include -#include int nb = 0; diff --git a/src/test/test_cpp_performance.cpp b/src/test/test_cpp_performance.cpp index 5435728..d1d3e3e 100644 --- a/src/test/test_cpp_performance.cpp +++ b/src/test/test_cpp_performance.cpp @@ -61,9 +61,13 @@ TEST(CppPerformance, LFOPerformance_ComplexLFO_FastLFO) TEST(CppPerformance, FastLFOTuning) { - float32_t freq = 5.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(); + size_t NB = static_cast(1.0f * SAMPLING_FREQUENCY); + float32_t freq = 5.0f; FastLFO lfo1(SAMPLING_FREQUENCY, freq, 440.0f); lfo1.setFrequency(freq); @@ -71,8 +75,8 @@ TEST(CppPerformance, FastLFOTuning) ComplexLFO lfo2(SAMPLING_FREQUENCY, freq, 440.0f); lfo2.setFrequency(freq); - std::ofstream out(getResultFile("CppPerformance.FastLFOTuning-data.csv")); - setupOuputStreamFocCSV(out); + std::ofstream out(getResultFile(full_test_name + ".FastLFOTuning-data.csv", true)); + setupOuputStreamForCSV(out); out << "index;FastLFO;ComplexLFO" << std::endl; for(size_t i = 0; i < NB; ++i) { diff --git a/src/test/test_framework.cpp b/src/test/test_framework.cpp index bc2d3af..4eeddc7 100644 --- a/src/test/test_framework.cpp +++ b/src/test/test_framework.cpp @@ -1,14 +1,13 @@ #include #include "test_fx_helper.h" -#include "wave.h" #include "../debug.hpp" #include "../fx_base.h" TEST(Framework, TestWaveIn) { - unsigned size; + size_t size; float32_t** samples = readWaveFile(AUDIO_SOURCE_FILE, size); size_t nb_errors = 0; diff --git a/src/test/test_fx_components.cpp b/src/test/test_fx_components.cpp index e32894d..d6d625f 100644 --- a/src/test/test_fx_components.cpp +++ b/src/test/test_fx_components.cpp @@ -2,13 +2,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include "wave.h" #include "test_fx_helper.h" @@ -21,6 +14,11 @@ TEST(FXComponent, LFO) { + 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 float32_t freq = 10.0f; LFO lfo(SAMPLING_FREQUENCY, 0.0f, freq); @@ -28,9 +26,9 @@ TEST(FXComponent, LFO) float32_t rate = 0.0f; float32_t rate_increment = freq / 2.0f / SAMPLING_FREQUENCY; - std::ofstream out(getResultFile("FXComponent.LFO.csv")); - setupOuputStreamFocCSV(out); - out << fixed << showpoint; + std::ofstream out(getResultFile(full_test_name + ".FXComponent.LFO.csv", true)); + setupOuputStreamForCSV(out); + out << std::fixed << std::showpoint; out << "index;LFO" << std::endl; for(unsigned i = 0; i < size; ++i) diff --git a/src/test/test_fx_helper.cpp b/src/test/test_fx_helper.cpp index 6ea3c0c..cdd4ad7 100644 --- a/src/test/test_fx_helper.cpp +++ b/src/test/test_fx_helper.cpp @@ -1,5 +1,8 @@ #include "test_fx_helper.h" +#include +#include + std::string getScenarioName(int scenario) { std::stringstream ss; @@ -78,27 +81,52 @@ std::string getScenarioName(int scenario) } -void setupOuputStreamFocCSV(std::ostream& out) +void setupOuputStreamForCSV(std::ostream& out) { - struct comma_separator : numpunct + struct comma_separator : std::numpunct { virtual char do_decimal_point() const override { return ','; } }; - out.imbue(locale(out.getloc(), new comma_separator)); - out << fixed << showpoint; + out.imbue(std::locale(out.getloc(), new comma_separator)); + out << std::fixed << std::showpoint; +} + +bool createFolderStructure(std::string& path) +{ + try + { + std::filesystem::path file_path(path); + if(!std::filesystem::exists(file_path.parent_path())) + { + std::filesystem::create_directories(file_path.parent_path()); + } + + return true; + } + catch(const std::exception& e) + { + std::cerr << e.what() << '\n'; + return false; + } } -std::string getResultFile(const std::string& filename) +std::string getResultFile(const std::string& filename, bool createPath) { - return std::string(OUTPUT_FOLDER) + "/" + filename; + std::string f = std::string(OUTPUT_FOLDER) + "/" + filename; + if(createPath) + { + createFolderStructure(f); + } + + return f; } float32_t getRandomValue() { - static random_device rd; - static mt19937 gen(rd()); - static uniform_real_distribution dist(-1.0f, 1.0f); + static std::random_device rd; + static std::mt19937 gen(rd()); + static std::uniform_real_distribution dist(-1.0f, 1.0f); return dist(gen); } diff --git a/src/test/test_fx_helper.h b/src/test/test_fx_helper.h index 2f68dfa..4f6f2c5 100644 --- a/src/test/test_fx_helper.h +++ b/src/test/test_fx_helper.h @@ -4,10 +4,10 @@ #include #include +#include "wave.h" #include "../fx.h" -#include "../mixing_console_constants.h" -#define AUDIO_SOURCE_FILE "test2.wav" +#define AUDIO_SOURCE_FILE "test.wav" #define SAMPLING_FREQUENCY 44100.0f @@ -24,12 +24,15 @@ enum FXSwitch FX__Phaser, FX__Delay, FX__ShimmerReverb, - FX__PlateReverb + FX__PlateReverb, + __kFXCount }; -void setupOuputStreamFocCSV(std::ostream& out); +void setupOuputStreamForCSV(std::ostream& out); -std::string getResultFile(const string& filename); +bool createFolderStructure(std::string& path); + +std::string getResultFile(const std::string& filename, bool createPath); float32_t getRandomValue(); diff --git a/src/test/test_mixing_console.cpp b/src/test/test_fx_mixing_console.cpp similarity index 67% rename from src/test/test_mixing_console.cpp rename to src/test/test_fx_mixing_console.cpp index 5b5bc47..caf476f 100644 --- a/src/test/test_mixing_console.cpp +++ b/src/test/test_fx_mixing_console.cpp @@ -1,245 +1,353 @@ -#include -#include - -#include "test_fx_helper.h" -#include "wave.h" - -#include "../mixing_console.hpp" - -class MixingConsoleScenarioTest : public testing::TestWithParam {}; - -TEST_P(MixingConsoleScenarioTest, MixerOutputTest) -{ - MixerOutput v = this->GetParam(); - std::string str = toString(v); - MixerOutput mo = toIndex(str.c_str()); - EXPECT_EQ(v, mo); -} - -INSTANTIATE_TEST_SUITE_P(MixerOutputTest, MixingConsoleScenarioTest, testing::Range(MixerOutput::OutputStart, MixerOutput::kFXCount)); - -typedef MixingConsole<8> Mixer; - -void setupMixingConsoleFX(Mixer* mixer) -{ - mixer->getTube()->setMute(false); - mixer->getTube()->setOverdrive(0.25f); - - mixer->getChorus()->setMute(false); - mixer->getChorus()->setRate(0.4f); - mixer->getChorus()->setDepth(0.5f); - - mixer->getFlanger()->setMute(false); - mixer->getFlanger()->setRate(0.03f); - mixer->getFlanger()->setDepth(0.75f); - mixer->getFlanger()->setFeedback(0.5f); - - mixer->getOrbitone()->setMute(false); - mixer->getOrbitone()->setRate(0.4f); - mixer->getOrbitone()->setDepth(0.5f); - - mixer->getPhaser()->setMute(false); - mixer->getPhaser()->setRate(0.1f); - mixer->getPhaser()->setDepth(1.0f); - mixer->getPhaser()->setFeedback(0.5f); - mixer->getPhaser()->setNbStages(12); - - mixer->getDelay()->setMute(false); - mixer->getDelay()->setLeftDelayTime(0.5f); - mixer->getDelay()->setLeftDelayTime(0.7f); - mixer->getDelay()->setFeedback(0.7f); - mixer->getDelay()->setFlutterRate(0.7f); - mixer->getDelay()->setFlutterAmount(0.7f); - - mixer->getPlateReverb()->setMute(false); - mixer->getPlateReverb()->set_bypass(false); - mixer->getPlateReverb()->size(0.7f); - mixer->getPlateReverb()->hidamp(0.5f); - mixer->getPlateReverb()->lodamp(0.5f); - mixer->getPlateReverb()->lowpass(0.3f); - mixer->getPlateReverb()->diffusion(0.65f); - mixer->getPlateReverb()->level(1.0f); - - mixer->getShimmerReverb()->setMute(false); - mixer->getShimmerReverb()->setInputGain(0.65f); - mixer->getShimmerReverb()->setTime(0.89f); - mixer->getShimmerReverb()->setDiffusion(0.75f); - mixer->getShimmerReverb()->setLP(0.8f); -} - -TEST(MixingConsole, DryProcessing) -{ - const float32_t epsilon = 1e-7; - const size_t length = 2; - - Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, length); - mixer->reset(); - - mixer->setSendLevel(0, MixerOutput::FX_Tube, 0.0f); - mixer->setSendLevel(0, MixerOutput::FX_Chorus, 0.0f); - mixer->setSendLevel(0, MixerOutput::FX_Flanger, 0.0f); - mixer->setSendLevel(0, MixerOutput::FX_Orbitone, 0.0f); - mixer->setSendLevel(0, MixerOutput::FX_Phaser, 0.0f); - mixer->setSendLevel(0, MixerOutput::FX_Delay, 0.0f); - mixer->setSendLevel(0, MixerOutput::FX_PlateReverb, 0.0f); - mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 0.0f); - - for(unsigned i = MixerOutput::OutputStart; i < (MixerOutput::kFXCount - 1); ++i) - { - mixer->setReturnLevel(static_cast(i), MixerOutput::MainOutput, 0.0f); - } - - mixer->setChannelLevel(0, 1.0f); - mixer->setPan(0, 0.5f); - mixer->setSendLevel(0, MixerOutput::MainOutput, 1.0f); - EXPECT_EQ(0, INSPECT(mixer, fullInspector)); - - float32_t in[length] = {0.1, 0.2}; - float32_t out[StereoChannels::kNumChannels][length]; - for(size_t i = 0; i < StereoChannels::kNumChannels; ++i) memset(out[i], 0, length * sizeof(float32_t)); - - mixer->setInputSampleBuffer(0, in); - EXPECT_EQ(0, INSPECT(mixer, fullInspector)); - - mixer->process( - out[StereoChannels::Left ], - out[StereoChannels::Right] - ); - EXPECT_EQ(0, INSPECT(mixer, fullInspector)); - - EXPECT_EQ(out[StereoChannels::Left ][0], out[StereoChannels::Right][0]); - EXPECT_EQ(out[StereoChannels::Left ][1], out[StereoChannels::Right][1]); - EXPECT_LT(std::abs(out[StereoChannels::Left ][0] - (sqrt(2.0f) / 20.0f)), epsilon); - EXPECT_LT(std::abs(out[StereoChannels::Left ][1] - (sqrt(2.0f) / 10.0f)), epsilon); - - delete mixer; -} - -TEST(MixingConsole, ShimmerProcessing) -{ - const float32_t epsilon = 1e-7; - const size_t length = 2; - - Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, length); - mixer->reset(); - - mixer->setSendLevel(0, MixerOutput::MainOutput, 0.0f); - mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f); - mixer->setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 1.0f); - mixer->setChannelLevel(0, 1.0f); - mixer->setPan(0, 0.5f); - EXPECT_EQ(0, INSPECT(mixer, fullInspector)); - - - float32_t in[length] = {0.1, 0.2}; - float32_t out1[StereoChannels::kNumChannels][length]; - for(size_t i = 0; i < StereoChannels::kNumChannels; ++i) memset(out1[i], 0, length * sizeof(float32_t)); - - mixer->setInputSampleBuffer(0, in); - EXPECT_EQ(0, INSPECT(mixer, fullInspector)); - - mixer->process( - out1[StereoChannels::Left ], - out1[StereoChannels::Right] - ); - EXPECT_EQ(0, INSPECT(mixer, fullInspector)); - - mixer->reset(); - EXPECT_EQ(0, INSPECT(mixer, fullInspector)); - - float32_t out2[StereoChannels::kNumChannels][length]; - mixer->setInputSampleBuffer(0, in); - EXPECT_EQ(0, INSPECT(mixer, fullInspector)); - - mixer->process( - out2[StereoChannels::Left ], - out2[StereoChannels::Right] - ); - EXPECT_EQ(0, INSPECT(mixer, fullInspector)); - - EXPECT_EQ(out1[StereoChannels::Left ][0], out2[StereoChannels::Left ][0]); - EXPECT_EQ(out1[StereoChannels::Right][0], out2[StereoChannels::Right][0]); - EXPECT_EQ(out1[StereoChannels::Left ][1], out2[StereoChannels::Left ][1]); - EXPECT_EQ(out1[StereoChannels::Right][1], out2[StereoChannels::Right][1]); - - delete mixer; -} - -TEST(MixingConsole, ShimmerNoiseProcessing) -{ - const size_t length = 1024; - - Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, length); - mixer->reset(); - - mixer->setSendLevel(0, MixerOutput::MainOutput, 0.0f); - mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f); - mixer->setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 1.0f); - mixer->setChannelLevel(0, 1.0f); - mixer->setPan(0, 0.5f); - EXPECT_EQ(0, INSPECT(mixer, fullInspector)); - - float32_t in[length]; - for(size_t i = 0; i < length; ++i) in[i] = getRandomValue(); - - float32_t out[StereoChannels::kNumChannels][length]; - for(size_t i = 0; i < StereoChannels::kNumChannels; ++i) memset(out[i], 0, length * sizeof(float32_t)); - - mixer->setInputSampleBuffer(0, in); - EXPECT_EQ(0, INSPECT(mixer, fullInspector)); - - mixer->process( - out[StereoChannels::Left ], - out[StereoChannels::Right] - ); - EXPECT_EQ(0, INSPECT(mixer, fullInspector)); - - delete mixer; -} - -TEST(MixingConsole, SimpleProcessing) -{ - const unsigned nbRepeats = 2; - unsigned size; - float32_t** samples = readWaveFile(AUDIO_SOURCE_FILE, size); - float32_t* sampleOutL = new float32_t[size * nbRepeats]; - float32_t* sampleOutR = new float32_t[size * nbRepeats]; - memset(sampleOutL, 0, size * nbRepeats * sizeof(float32_t)); - memset(sampleOutR, 0, size * nbRepeats * sizeof(float32_t)); - - Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, size); - - setupMixingConsoleFX(mixer); - - mixer->getTube()->setOverdrive(0.15f); - mixer->setSendLevel(0, MixerOutput::FX_Tube, 1.0f); - mixer->setSendLevel(0, MixerOutput::FX_Phaser, 1.0f); - // mixer->setReturnLevel(MixerOutput::FX_Tube, MixerOutput::MainOutput, 1.0f); - // mixer->setSendLevel(0, MixerOutput::FX_Chorus, 1.0f); - // mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f); - mixer->setReturnLevel(MixerOutput::FX_Tube, MixerOutput::FX_Chorus, 1.0f); - mixer->setReturnLevel(MixerOutput::FX_Chorus, MixerOutput::FX_ShimmerReverb, 1.0f); - mixer->setReturnLevel(MixerOutput::FX_Phaser, MixerOutput::FX_Delay, 1.0f); - - mixer->setSendLevel(0, MixerOutput::MainOutput, 0.25f); - mixer->setReturnLevel(MixerOutput::FX_Tube, MixerOutput::MainOutput, 0.1f); - mixer->setReturnLevel(MixerOutput::FX_Chorus, MixerOutput::MainOutput, 0.15f); - mixer->setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 0.3f); - mixer->setReturnLevel(MixerOutput::FX_Delay, MixerOutput::MainOutput, 0.3f); - - for(unsigned j = 0; j < nbRepeats; ++j) - { - mixer->setInputSampleBuffer(0, samples[0], samples[1]); - mixer->process(sampleOutL + j * size, sampleOutR + j * size); - EXPECT_EQ(0, INSPECT(mixer, fullInspector)); - } - saveWaveFile(getResultFile("result-mixing-console.wav"), sampleOutL, sampleOutR, nbRepeats * size, static_cast(SAMPLING_FREQUENCY), 16); - - delete mixer; - - delete[] samples[0]; - delete[] samples[1]; - delete[] samples; - delete[] sampleOutL; - delete[] sampleOutR; -} +#include +#include + +#include "test_fx_helper.h" +#include "wave.h" + +#include "../mixing_console.hpp" + +class MixingConsoleScenarioTest : public testing::TestWithParam {}; + +TEST_P(MixingConsoleScenarioTest, MixerOutputTest) +{ + MixerOutput v = this->GetParam(); + std::string str = toString(v); + MixerOutput mo = toIndex(str.c_str()); + EXPECT_EQ(v, mo); +} + +INSTANTIATE_TEST_SUITE_P(MixerOutputTest, MixingConsoleScenarioTest, testing::Range(MixerOutput::OutputStart, MixerOutput::kFXCount)); + +typedef MixingConsole<8> Mixer; + +void setupMixingConsoleFX(Mixer* mixer) +{ + mixer->getTube()->setMute(false); + mixer->getTube()->setOverdrive(0.25f); + + mixer->getChorus()->setMute(false); + mixer->getChorus()->setRate(0.4f); + mixer->getChorus()->setDepth(0.5f); + + mixer->getFlanger()->setMute(false); + mixer->getFlanger()->setRate(0.03f); + mixer->getFlanger()->setDepth(0.75f); + mixer->getFlanger()->setFeedback(0.5f); + + mixer->getOrbitone()->setMute(false); + mixer->getOrbitone()->setRate(0.4f); + mixer->getOrbitone()->setDepth(0.5f); + + mixer->getPhaser()->setMute(false); + mixer->getPhaser()->setRate(0.1f); + mixer->getPhaser()->setDepth(1.0f); + mixer->getPhaser()->setFeedback(0.5f); + mixer->getPhaser()->setNbStages(12); + + mixer->getDelay()->setMute(false); + mixer->getDelay()->setLeftDelayTime(0.5f); + mixer->getDelay()->setLeftDelayTime(0.7f); + mixer->getDelay()->setFeedback(0.7f); + mixer->getDelay()->setFlutterRate(0.7f); + mixer->getDelay()->setFlutterAmount(0.7f); + + mixer->getPlateReverb()->setMute(false); + mixer->getPlateReverb()->set_bypass(false); + mixer->getPlateReverb()->size(0.7f); + mixer->getPlateReverb()->hidamp(0.5f); + mixer->getPlateReverb()->lodamp(0.5f); + mixer->getPlateReverb()->lowpass(0.3f); + mixer->getPlateReverb()->diffusion(0.65f); + mixer->getPlateReverb()->level(1.0f); + + mixer->getShimmerReverb()->setMute(false); + mixer->getShimmerReverb()->setInputGain(0.65f); + mixer->getShimmerReverb()->setTime(0.89f); + mixer->getShimmerReverb()->setDiffusion(0.75f); + mixer->getShimmerReverb()->setLP(0.8f); +} + +#define ACTIVE_FX(scenarioId, fx) const bool b ## fx = ((scenarioId & MixerOutput::fx) == MixerOutput::fx) + +void setupMixingConsoleFX(Mixer* mixer, int scenarioId) +{ + ACTIVE_FX(scenarioId, FX_Tube); + ACTIVE_FX(scenarioId, FX_Chorus); + ACTIVE_FX(scenarioId, FX_Flanger); + ACTIVE_FX(scenarioId, FX_Orbitone); + ACTIVE_FX(scenarioId, FX_Phaser); + ACTIVE_FX(scenarioId, FX_Delay); + ACTIVE_FX(scenarioId, FX_PlateReverb); + ACTIVE_FX(scenarioId, FX_ShimmerReverb); + + mixer->setChannelLevel(0, 1.0f); + mixer->setPan(0, 0.5f); + + +} + +TEST(MixingConsole, ZeroSamplesTest) +{ + const size_t length = 4; + Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, length); + EXPECT_EQ(0, FULL_INSPECT(mixer, true)); + + mixer->reset(); + EXPECT_EQ(0, FULL_INSPECT(mixer, true)); + + setupMixingConsoleFX(mixer); + EXPECT_EQ(0, FULL_INSPECT(mixer, true)); + + mixer->setChannelLevel(0, 1.0f); + EXPECT_EQ(0, FULL_INSPECT(mixer, true)); + + mixer->setPan(0, 0.5f); + EXPECT_EQ(0, FULL_INSPECT(mixer, true)); + + float32_t samples[] = {0.0f, 0.0f, 0.0f, 0.0f}; + mixer->setInputSampleBuffer(0, samples); + EXPECT_EQ(0, FULL_INSPECT(mixer, true)); + + mixer->setSendLevel(0, MixerOutput::MainOutput, 1.0f); + EXPECT_EQ(0, FULL_INSPECT(mixer, true)); + + float32_t outL[4]; + float32_t outR[4]; + mixer->process(outL, outR); + EXPECT_EQ(0, FULL_INSPECT(mixer, true)); + + mixer->setSendLevel(0, MixerOutput::FX_Tube, 1.0f); + mixer->setSendLevel(0, MixerOutput::FX_Delay, 1.0f); + mixer->setSendLevel(0, MixerOutput::FX_PlateReverb, 1.0f); + + mixer->setReturnLevel(MixerOutput::FX_Tube, MixerOutput::FX_Orbitone, 1.0f); + mixer->setReturnLevel(MixerOutput::FX_Orbitone, MixerOutput::MainOutput, 0.5f); + mixer->setReturnLevel(MixerOutput::FX_Orbitone, MixerOutput::FX_PlateReverb, 1.0f); + mixer->setReturnLevel(MixerOutput::FX_Delay, MixerOutput::MainOutput, 0.5f); + mixer->setReturnLevel(MixerOutput::FX_PlateReverb, MixerOutput::MainOutput, 0.5f); + EXPECT_EQ(0, FULL_INSPECT(mixer, true)); + + delete mixer; +} + +TEST(MixingConsole, DryProcessing) +{ + const float32_t epsilon = 1e-7; + const size_t length = 2; + + Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, length); + mixer->reset(); + + mixer->setSendLevel(0, MixerOutput::FX_Tube, 0.0f); + mixer->setSendLevel(0, MixerOutput::FX_Chorus, 0.0f); + mixer->setSendLevel(0, MixerOutput::FX_Flanger, 0.0f); + mixer->setSendLevel(0, MixerOutput::FX_Orbitone, 0.0f); + mixer->setSendLevel(0, MixerOutput::FX_Phaser, 0.0f); + mixer->setSendLevel(0, MixerOutput::FX_Delay, 0.0f); + mixer->setSendLevel(0, MixerOutput::FX_PlateReverb, 0.0f); + mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 0.0f); + + for(unsigned i = MixerOutput::OutputStart; i < (MixerOutput::kFXCount - 1); ++i) + { + mixer->setReturnLevel(static_cast(i), MixerOutput::MainOutput, 0.0f); + } + + mixer->setChannelLevel(0, 1.0f); + mixer->setPan(0, 0.5f); + mixer->setSendLevel(0, MixerOutput::MainOutput, 1.0f); + EXPECT_EQ(0, INSPECT(mixer, fullInspector)); + + float32_t in[length] = {0.1, 0.2}; + float32_t out[StereoChannels::kNumChannels][length]; + for(size_t i = 0; i < StereoChannels::kNumChannels; ++i) memset(out[i], 0, length * sizeof(float32_t)); + + mixer->setInputSampleBuffer(0, in); + EXPECT_EQ(0, INSPECT(mixer, fullInspector)); + + mixer->process( + out[StereoChannels::Left ], + out[StereoChannels::Right] + ); + EXPECT_EQ(0, INSPECT(mixer, fullInspector)); + + EXPECT_EQ(out[StereoChannels::Left ][0], out[StereoChannels::Right][0]); + EXPECT_EQ(out[StereoChannels::Left ][1], out[StereoChannels::Right][1]); + EXPECT_LT(std::abs(out[StereoChannels::Left ][0] - (sqrt(2.0f) / 20.0f)), epsilon); + EXPECT_LT(std::abs(out[StereoChannels::Left ][1] - (sqrt(2.0f) / 10.0f)), epsilon); + + delete mixer; +} + +TEST(MixingConsole, ShimmerProcessing) +{ + const float32_t epsilon = 1e-7; + const size_t length = 2; + + Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, length); + mixer->reset(); + + mixer->setSendLevel(0, MixerOutput::MainOutput, 0.0f); + mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f); + mixer->setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 1.0f); + mixer->setChannelLevel(0, 1.0f); + mixer->setPan(0, 0.5f); + EXPECT_EQ(0, INSPECT(mixer, fullInspector)); + + float32_t in[length] = {0.1, 0.2}; + float32_t out1[StereoChannels::kNumChannels][length]; + for(size_t i = 0; i < StereoChannels::kNumChannels; ++i) memset(out1[i], 0, length * sizeof(float32_t)); + + mixer->setInputSampleBuffer(0, in); + EXPECT_EQ(0, INSPECT(mixer, fullInspector)); + + mixer->process( + out1[StereoChannels::Left ], + out1[StereoChannels::Right] + ); + EXPECT_EQ(0, INSPECT(mixer, fullInspector)); + + mixer->reset(); + EXPECT_EQ(0, INSPECT(mixer, fullInspector)); + + float32_t out2[StereoChannels::kNumChannels][length]; + mixer->setInputSampleBuffer(0, in); + EXPECT_EQ(0, INSPECT(mixer, fullInspector)); + + mixer->process( + out2[StereoChannels::Left ], + out2[StereoChannels::Right] + ); + EXPECT_EQ(0, INSPECT(mixer, fullInspector)); + + EXPECT_EQ(out1[StereoChannels::Left ][0], out2[StereoChannels::Left ][0]); + EXPECT_EQ(out1[StereoChannels::Right][0], out2[StereoChannels::Right][0]); + EXPECT_EQ(out1[StereoChannels::Left ][1], out2[StereoChannels::Left ][1]); + EXPECT_EQ(out1[StereoChannels::Right][1], out2[StereoChannels::Right][1]); + + delete mixer; +} + +TEST(MixingConsole, ShimmerNoiseProcessing) +{ + const size_t length = 1024; + + Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, length); + mixer->reset(); + + mixer->setSendLevel(0, MixerOutput::MainOutput, 0.0f); + mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f); + mixer->setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 1.0f); + mixer->setChannelLevel(0, 1.0f); + mixer->setPan(0, 0.5f); + EXPECT_EQ(0, INSPECT(mixer, fullInspector)); + + float32_t in[length]; + for(size_t i = 0; i < length; ++i) in[i] = getRandomValue(); + + float32_t out[StereoChannels::kNumChannels][length]; + for(size_t i = 0; i < StereoChannels::kNumChannels; ++i) memset(out[i], 0, length * sizeof(float32_t)); + + mixer->setInputSampleBuffer(0, in); + EXPECT_EQ(0, INSPECT(mixer, fullInspector)); + + mixer->process( + out[StereoChannels::Left ], + out[StereoChannels::Right] + ); + EXPECT_EQ(0, INSPECT(mixer, fullInspector)); + + delete mixer; +} + +TEST(MixingConsole, StandardUsageProcessing) +{ + const testing::TestInfo* test_info = testing::UnitTest::GetInstance()->current_test_info(); + std::string full_test_name = test_info->test_case_name(); + full_test_name += "."; + full_test_name += test_info->name(); + + const unsigned nbRepeats = 2; + size_t size; + float32_t** samples = readWaveFile(AUDIO_SOURCE_FILE, size); + float32_t* sampleOutL = new float32_t[size * nbRepeats]; + float32_t* sampleOutR = new float32_t[size * nbRepeats]; + memset(sampleOutL, 0, size * nbRepeats * sizeof(float32_t)); + memset(sampleOutR, 0, size * nbRepeats * sizeof(float32_t)); + + Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, size); + + setupMixingConsoleFX(mixer); + + mixer->getTube()->setOverdrive(0.15f); + mixer->setSendLevel(0, MixerOutput::FX_Tube, 1.0f); + mixer->setSendLevel(0, MixerOutput::FX_Phaser, 1.0f); + // mixer->setReturnLevel(MixerOutput::FX_Tube, MixerOutput::MainOutput, 1.0f); + // mixer->setSendLevel(0, MixerOutput::FX_Chorus, 1.0f); + // mixer->setSendLevel(0, MixerOutput::FX_ShimmerReverb, 1.0f); + mixer->setReturnLevel(MixerOutput::FX_Tube, MixerOutput::FX_Chorus, 1.0f); + mixer->setReturnLevel(MixerOutput::FX_Chorus, MixerOutput::FX_ShimmerReverb, 1.0f); + mixer->setReturnLevel(MixerOutput::FX_Phaser, MixerOutput::FX_Delay, 1.0f); + + mixer->setSendLevel(0, MixerOutput::MainOutput, 0.25f); + mixer->setReturnLevel(MixerOutput::FX_Tube, MixerOutput::MainOutput, 0.1f); + mixer->setReturnLevel(MixerOutput::FX_Chorus, MixerOutput::MainOutput, 0.15f); + mixer->setReturnLevel(MixerOutput::FX_ShimmerReverb, MixerOutput::MainOutput, 0.3f); + mixer->setReturnLevel(MixerOutput::FX_Delay, MixerOutput::MainOutput, 0.3f); + + for(unsigned j = 0; j < nbRepeats; ++j) + { + mixer->setInputSampleBuffer(0, samples[0], samples[1]); + mixer->process(sampleOutL + j * size, sampleOutR + j * size); + EXPECT_EQ(0, INSPECT(mixer, fullInspector)); + } + saveWaveFile(getResultFile(full_test_name + ".wav", true), sampleOutL, sampleOutR, nbRepeats * size, static_cast(SAMPLING_FREQUENCY), 16); + + delete mixer; + + delete[] samples[0]; + delete[] samples[1]; + delete[] samples; + delete[] sampleOutL; + delete[] sampleOutR; +} + +// TEST_P(FXScenarioTest, FXProcessingScenario) +// { +// const testing::TestInfo* test_info = testing::UnitTest::GetInstance()->current_test_info(); +// std::string full_test_name = test_info->test_case_name(); +// full_test_name += "."; +// full_test_name += test_info->name(); + +// const unsigned nbRepeats = 2; +// size_t size; +// float32_t** samples = readWaveFile(AUDIO_SOURCE_FILE, size); +// float32_t* sampleOutL = new float32_t[size * nbRepeats]; +// float32_t* sampleOutR = new float32_t[size * nbRepeats]; +// memset(sampleOutL, 0, size * nbRepeats * sizeof(float32_t)); +// memset(sampleOutR, 0, size * nbRepeats * sizeof(float32_t)); + +// Mixer* mixer = new Mixer(SAMPLING_FREQUENCY, size); + +// setupMixingConsoleFX(mixer); + +// int scenarioId = this->GetParam(); +// setupMixingConsoleFXForScenario(mixer, scenarioId); + +// for(unsigned j = 0; j < nbRepeats; ++j) +// { +// mixer->setInputSampleBuffer(0, samples[0], samples[1]); +// mixer->process(sampleOutL + j * size, sampleOutR + j * size); +// EXPECT_EQ(0, INSPECT(mixer, fullInspector)); +// } +// saveWaveFile(getResultFile(full_test_name + ".wav"), sampleOutL, sampleOutR, nbRepeats * size, static_cast(SAMPLING_FREQUENCY), 16); + +// delete mixer; + +// delete[] samples[0]; +// delete[] samples[1]; +// delete[] samples; +// delete[] sampleOutL; +// delete[] sampleOutR; +// } + +// INSTANTIATE_TEST_SUITE_P(MixingConsole, FXScenarioTest, testing::Range(0, 1 << (MixerOutput::kFXCount - 1))); diff --git a/src/test/test_fx.cpp b/src/test/test_fx_plate_reverb.cpp similarity index 72% rename from src/test/test_fx.cpp rename to src/test/test_fx_plate_reverb.cpp index f2d3bec..a6d2a86 100644 --- a/src/test/test_fx.cpp +++ b/src/test/test_fx_plate_reverb.cpp @@ -1,66 +1,70 @@ -#include - -#include "test_fx_helper.h" -#include "wave.h" - -#include "../effect_platervbstereo.h" - -TEST(FXElement, PlateReverbMigration) -{ - const unsigned nbRepeats = 4; - - AudioEffectPlateReverb* reverb = new AudioEffectPlateReverb(SAMPLING_FREQUENCY); - reverb->set_bypass(false); - reverb->size(0.7f); - reverb->hidamp(0.5f); - reverb->lodamp(0.5f); - reverb->lowpass(0.3f); - reverb->diffusion(0.65f); - reverb->level(1.0f); - - unsigned size; - float32_t** samples = readWaveFile(AUDIO_SOURCE_FILE, size); - float32_t* sampleOutL = new float32_t[size * nbRepeats]; - float32_t* sampleOutR = new float32_t[size * nbRepeats]; - memset(sampleOutL, 0, size * nbRepeats * sizeof(float32_t)); - memset(sampleOutR, 0, size * nbRepeats * sizeof(float32_t)); - - unsigned index = 0; - for(unsigned i = 0; i < nbRepeats; ++i) - { - for(unsigned j = 0; j < size; ++j) - { - reverb->processSample(samples[0][j], samples[1][j], sampleOutL[index], sampleOutR[index]); - ++index; - } - } - saveWaveFile(getResultFile("result-PlateReverb-new.wav"), sampleOutL, sampleOutR, nbRepeats * size, static_cast(SAMPLING_FREQUENCY), 16); - - unsigned indexOut = 0; - for (unsigned i = 0; i < nbRepeats; ++i) - { - unsigned len = size; - unsigned indexIn = 0; - - while(len > 0) - { - unsigned grainSize = (len < 1024 ? len : 1024); - - reverb->doReverb(samples[0] + indexIn, samples[1] + indexIn, sampleOutL + indexOut, sampleOutR + indexOut, grainSize); - - indexIn += grainSize; - indexOut += grainSize; - len -= grainSize; - } - - } - saveWaveFile(getResultFile("result-PlateReverb-legacy.wav"), sampleOutL, sampleOutR, nbRepeats * size, static_cast(SAMPLING_FREQUENCY), 16); - - delete[] sampleOutL; - delete[] sampleOutR; - delete[] samples[0]; - delete[] samples[1]; - delete[] samples; - - delete reverb; -} +#include + +#include "test_fx_helper.h" + +#include "../effect_platervbstereo.h" + +TEST(FXPlateReverb, Migration) +{ + const testing::TestInfo* test_info = testing::UnitTest::GetInstance()->current_test_info(); + std::string full_test_name = test_info->test_case_name(); + full_test_name += "."; + full_test_name += test_info->name(); + + const unsigned nbRepeats = 4; + + AudioEffectPlateReverb* reverb = new AudioEffectPlateReverb(SAMPLING_FREQUENCY); + reverb->set_bypass(false); + reverb->size(0.7f); + reverb->hidamp(0.5f); + reverb->lodamp(0.5f); + reverb->lowpass(0.3f); + reverb->diffusion(0.65f); + reverb->level(1.0f); + + size_t size; + float32_t** samples = readWaveFile(AUDIO_SOURCE_FILE, size); + float32_t* sampleOutL = new float32_t[size * nbRepeats]; + float32_t* sampleOutR = new float32_t[size * nbRepeats]; + memset(sampleOutL, 0, size * nbRepeats * sizeof(float32_t)); + memset(sampleOutR, 0, size * nbRepeats * sizeof(float32_t)); + + unsigned index = 0; + for(unsigned i = 0; i < nbRepeats; ++i) + { + for(unsigned j = 0; j < size; ++j) + { + reverb->processSample(samples[0][j], samples[1][j], sampleOutL[index], sampleOutR[index]); + ++index; + } + } + saveWaveFile(getResultFile(full_test_name + ".PlateReverb-new.wav", true), sampleOutL, sampleOutR, nbRepeats * size, static_cast(SAMPLING_FREQUENCY), 16); + + unsigned indexOut = 0; + for (unsigned i = 0; i < nbRepeats; ++i) + { + unsigned len = size; + unsigned indexIn = 0; + + while(len > 0) + { + unsigned grainSize = (len < 1024 ? len : 1024); + + reverb->doReverb(samples[0] + indexIn, samples[1] + indexIn, sampleOutL + indexOut, sampleOutR + indexOut, grainSize); + + indexIn += grainSize; + indexOut += grainSize; + len -= grainSize; + } + + } + saveWaveFile(getResultFile(full_test_name + ".PlateReverb-legacy.wav", true), sampleOutL, sampleOutR, nbRepeats * size, static_cast(SAMPLING_FREQUENCY), 16); + + delete[] sampleOutL; + delete[] sampleOutR; + delete[] samples[0]; + delete[] samples[1]; + delete[] samples; + + delete reverb; +} diff --git a/src/test/test_fx_rack.cpp b/src/test/test_fx_rack.cpp index 15a431a..acd3746 100644 --- a/src/test/test_fx_rack.cpp +++ b/src/test/test_fx_rack.cpp @@ -2,10 +2,8 @@ #include #include "test_fx_helper.h" -#include "wave.h" #include "../fx_rack.h" -#include "../effect_platervbstereo.h" using namespace std; @@ -73,8 +71,13 @@ TEST_P(FXScenarioTest, FXRackResetAllScenarios) TEST_P(FXScenarioTest, ScenarioProcessing) { + const testing::TestInfo* test_info = testing::UnitTest::GetInstance()->current_test_info(); + std::string full_test_name = test_info->test_case_name(); + full_test_name += "."; + full_test_name += test_info->name(); + const unsigned nbRepeats = 1; - unsigned size; + size_t size; float32_t** samples = readWaveFile(AUDIO_SOURCE_FILE, size); float32_t* sampleOutL = new float32_t[size * nbRepeats]; float32_t* sampleOutR = new float32_t[size * nbRepeats]; @@ -96,16 +99,17 @@ TEST_P(FXScenarioTest, ScenarioProcessing) } stringstream ss; - ss << "result-fx-rack" << name << ".wav"; - saveWaveFile(getResultFile(ss.str()), sampleOutL, sampleOutR, nbRepeats * size, static_cast(SAMPLING_FREQUENCY), 16); - - delete rack; + ss << full_test_name << "-fx-rack" << name << ".wav"; + saveWaveFile(getResultFile(ss.str(), true), sampleOutL, sampleOutR, nbRepeats * size, static_cast(SAMPLING_FREQUENCY), 16); delete[] samples[0]; delete[] samples[1]; delete[] samples; + delete[] sampleOutL; delete[] sampleOutR; + + delete rack; } INSTANTIATE_TEST_SUITE_P(FXRack, FXScenarioTest, testing::Range(0, 1 << (FXSwitch::FX__ShimmerReverb + 1))); diff --git a/src/test/test_fx_shimmer_reverb.cpp b/src/test/test_fx_shimmer_reverb.cpp new file mode 100644 index 0000000..814b297 --- /dev/null +++ b/src/test/test_fx_shimmer_reverb.cpp @@ -0,0 +1,182 @@ +#include + +#include "test_fx_helper.h" +#include "../fx_shimmer_reverb.h" + +TEST(FXShimmerReverb, TransientSilence) +{ + 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 = static_cast(SAMPLING_FREQUENCY); + float32_t* inSamples = new float32_t[size]; + memset(inSamples, 0, size * sizeof(float32_t)); + + 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)); + + ShimmerReverb* shimmer = new ShimmerReverb(SAMPLING_FREQUENCY); + + shimmer->setInputGain(0.55f); + shimmer->setTime(0.75f); + shimmer->setDiffusion(0.8f); + shimmer->setLP(0.7f); + + shimmer->reset(); + for(size_t i = 0; i < size; ++i) + { + shimmer->processSample( + inSamples[i], + inSamples[i], + outSamplesL[i], + outSamplesR[i] + ); + } + + saveWaveFile(getResultFile(full_test_name + ".wav", true), outSamplesL, outSamplesR, size, SAMPLING_FREQUENCY, 16); + + delete shimmer; + + delete[] inSamples; + + delete[] outSamplesL; + delete[] outSamplesR; +} + +TEST(FXShimmerReverb, TransientSilenceWithDirac) +{ + 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 = 4 * static_cast(SAMPLING_FREQUENCY); + 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)); + + ShimmerReverb* shimmer = new ShimmerReverb(SAMPLING_FREQUENCY); + + shimmer->setInputGain(0.55f); + shimmer->setTime(0.75f); + shimmer->setDiffusion(0.8f); + shimmer->setLP(0.7f); + + shimmer->reset(); + for(size_t i = 0; i < size; ++i) + { + shimmer->processSample( + inSamples[i], + inSamples[i], + outSamplesL[i], + outSamplesR[i] + ); + } + + saveWaveFile(getResultFile(full_test_name + ".wav", true), outSamplesL, outSamplesR, size, SAMPLING_FREQUENCY, 16); + + delete shimmer; + + delete[] inSamples; + + delete[] outSamplesL; + delete[] outSamplesR; +} + +TEST(FXShimmerReverb, TransientNoise) +{ + 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 = static_cast(SAMPLING_FREQUENCY); + float32_t* inSamples = new float32_t[size]; + for(size_t i = 0; i < size; ++i) inSamples[i] = getRandomValue(); + + 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)); + + ShimmerReverb* shimmer = new ShimmerReverb(SAMPLING_FREQUENCY); + + shimmer->setInputGain(0.55f); + shimmer->setTime(0.75f); + shimmer->setDiffusion(0.8f); + shimmer->setLP(0.7f); + + shimmer->reset(); + for(size_t i = 0; i < size; ++i) + { + shimmer->processSample( + inSamples[i], + inSamples[i], + outSamplesL[i], + outSamplesR[i] + ); + } + + saveWaveFile(getResultFile(full_test_name + ".wav", true), outSamplesL, outSamplesR, size, SAMPLING_FREQUENCY, 16); + + delete shimmer; + + delete[] inSamples; + + delete[] outSamplesL; + delete[] outSamplesR; +} + +TEST(FXShimmerReverb, TransientMusic) +{ + 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* 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)); + + ShimmerReverb* shimmer = new ShimmerReverb(SAMPLING_FREQUENCY); + + shimmer->setInputGain(0.55f); + shimmer->setTime(0.75f); + shimmer->setDiffusion(0.8f); + shimmer->setLP(0.7f); + + shimmer->reset(); + for(size_t i = 0; i < size; ++i) + { + shimmer->processSample( + inSamples[0][i], + inSamples[1][i], + outSamplesL[i], + outSamplesR[i] + ); + } + + saveWaveFile(getResultFile(full_test_name + ".wav", true), outSamplesL, outSamplesR, size, SAMPLING_FREQUENCY, 16); + + delete shimmer; + + delete[] inSamples[0]; + delete[] inSamples[1]; + delete[] inSamples; + + delete[] outSamplesL; + delete[] outSamplesR; +} diff --git a/src/test/wave.h b/src/test/wave.h index 22e486a..41d2df1 100644 --- a/src/test/wave.h +++ b/src/test/wave.h @@ -61,12 +61,12 @@ struct WaveHeaderDATA { uint32_t subchunk2Size; }; -float32_t** readWaveFile(const std::string& fileName, unsigned& size); +float32_t** readWaveFile(const std::string& fileName, size_t& size); void saveWaveFile(const std::string& fileName, float32_t* LChannel, float32_t* RChannel, - unsigned size, + size_t size, int sampleRate, int bitsPerSample); diff --git a/src/test/wavein.cpp b/src/test/wavein.cpp index d496f65..ae8e432 100644 --- a/src/test/wavein.cpp +++ b/src/test/wavein.cpp @@ -4,6 +4,12 @@ #include #include +#if defined(DEBUG) +#define ASSERT_NORMALIZED(x) assert(x <= 1.0f && x >= -1.0f) +#else +#define ASSERT_NORMALIZED(x) +#endif + template bool readChunk(std::ifstream& in, uint32_t id, T& chunk) { @@ -27,7 +33,7 @@ bool readChunk(std::ifstream& in, uint32_t id, T& chunk) return false; } -float32_t** readWaveFile(const std::string& fileName, unsigned& size) +float32_t** readWaveFile(const std::string& fileName, size_t& size) { std::ifstream file(fileName, std::ios::binary); if(!file) @@ -147,6 +153,9 @@ float32_t** readWaveFile(const std::string& fileName, unsigned& size) return nullptr; } + // ASSERT_NORMALIZED(LChannel[i]); + // ASSERT_NORMALIZED(RChannel[i]); + i += increment; } assert(i == size); diff --git a/src/test/waveout.cpp b/src/test/waveout.cpp index 1791b1f..c07dc6f 100644 --- a/src/test/waveout.cpp +++ b/src/test/waveout.cpp @@ -7,7 +7,7 @@ void saveWaveFile(const std::string& fileName, float32_t* LChannel, float32_t* RChannel, - unsigned size, + size_t size, int sampleRate, int bitsPerSample) {