diff --git a/extern/guitar_fx_lib/include/guitar_fx_lib/fx/clean.hpp b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/clean.hpp index 02bab17..1b1af12 100644 --- a/extern/guitar_fx_lib/include/guitar_fx_lib/fx/clean.hpp +++ b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/clean.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include class Clean : public Effect { diff --git a/extern/guitar_fx_lib/include/guitar_fx_lib/fx/delay.hpp b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/delay.hpp index e779a3d..1de335e 100644 --- a/extern/guitar_fx_lib/include/guitar_fx_lib/fx/delay.hpp +++ b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/delay.hpp @@ -2,7 +2,7 @@ #include -#include +#include class Delay : public Effect { diff --git a/extern/guitar_fx_lib/include/guitar_fx_lib/fx/distortion.hpp b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/distortion.hpp index 00f0fd1..2d664fd 100644 --- a/extern/guitar_fx_lib/include/guitar_fx_lib/fx/distortion.hpp +++ b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/distortion.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include class Distortion : public Effect { diff --git a/extern/guitar_fx_lib/include/guitar_fx_lib/fx/echo.hpp b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/echo.hpp index d1d88fc..b02ed27 100644 --- a/extern/guitar_fx_lib/include/guitar_fx_lib/fx/echo.hpp +++ b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/echo.hpp @@ -2,7 +2,7 @@ #include -#include +#include class Echo : public Effect { diff --git a/extern/guitar_fx_lib/include/guitar_fx_lib/interfaces/effect.hpp b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/effect.hpp similarity index 100% rename from extern/guitar_fx_lib/include/guitar_fx_lib/interfaces/effect.hpp rename to extern/guitar_fx_lib/include/guitar_fx_lib/fx/effect.hpp diff --git a/extern/guitar_fx_lib/include/guitar_fx_lib/fx/effects.hpp b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/effects.hpp new file mode 100644 index 0000000..3aed312 --- /dev/null +++ b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/effects.hpp @@ -0,0 +1,13 @@ +#pragma once + +// List of all supported effects. +// To save memory, use this enum to identify the effects and dynamically allocate +// only the effect that is used +enum class Effects +{ + CLEAN, + DISTORTION, + ECHO, + DELAY, + REVERB +}; diff --git a/extern/guitar_fx_lib/include/guitar_fx_lib/fx_factory.hpp b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/fx_factory.hpp similarity index 74% rename from extern/guitar_fx_lib/include/guitar_fx_lib/fx_factory.hpp rename to extern/guitar_fx_lib/include/guitar_fx_lib/fx/fx_factory.hpp index dd7eb0e..164cafb 100644 --- a/extern/guitar_fx_lib/include/guitar_fx_lib/fx_factory.hpp +++ b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/fx_factory.hpp @@ -6,17 +6,9 @@ #include #include #include +#include +#include #include -#include - -enum class Effects -{ - CLEAN, - DISTORTION, - ECHO, - DELAY, - REVERB -}; class FxFactory { @@ -24,28 +16,22 @@ class FxFactory FxFactory() = default; ~FxFactory() = default; - std::unique_ptr make(const Effects &fx) + EffectPtr make(const Effects &fx) { switch (fx) { case Effects::CLEAN: return std::make_unique(); - break; case Effects::DISTORTION: return std::make_unique(); - break; case Effects::ECHO: return std::make_unique(); - break; case Effects::DELAY: return std::make_unique(); - break; case Effects::REVERB: return std::make_unique(); - default: return nullptr; - break; } return nullptr; } diff --git a/extern/guitar_fx_lib/include/guitar_fx_lib/fx/reverb.hpp b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/reverb.hpp index ede51c1..a66e3bc 100644 --- a/extern/guitar_fx_lib/include/guitar_fx_lib/fx/reverb.hpp +++ b/extern/guitar_fx_lib/include/guitar_fx_lib/fx/reverb.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include class Reverb : public Effect { diff --git a/extern/guitar_fx_lib/include/guitar_fx_lib/fx_manager.hpp b/extern/guitar_fx_lib/include/guitar_fx_lib/fx_manager.hpp index dd0bbec..c34e444 100644 --- a/extern/guitar_fx_lib/include/guitar_fx_lib/fx_manager.hpp +++ b/extern/guitar_fx_lib/include/guitar_fx_lib/fx_manager.hpp @@ -6,21 +6,29 @@ #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include class FxManager { public: FxManager(const uint32_t &min, const uint32_t &max) - : signal_min(min), signal_max(max), signal_middle((max - min) / 2), factory() + : FxManager(min, max, + {Effects::CLEAN, Effects::DISTORTION, Effects::ECHO, Effects::DELAY, + Effects::REVERB}) { - effects = {Effects::CLEAN, Effects::DISTORTION, Effects::ECHO, Effects::DELAY, - Effects::REVERB}; + } + + FxManager(const uint32_t &min, const uint32_t &max, + const std::vector &effects_list) + : signal_min(min), signal_max(max), factory(), effects(effects_list) + { + if (effects.empty()) + { + // Ideally we would throw, but some platform don't support exceptions + effects.push_back(Effects::CLEAN); + } effects_it = effects.begin(); active_fx = factory.make(*effects_it); } @@ -74,11 +82,11 @@ class FxManager float normalised_output(0.0f); output = 0; - normalised_input = normalise_input(input); + normalised_input = normalise(input); if (active_fx->process(normalised_input, normalised_output)) { - output = convert_output(normalised_output); + output = denormalise(normalised_output); return true; } @@ -91,24 +99,38 @@ class FxManager } private: - float normalise_input(const uint32_t &input) + float normalise(const uint32_t &input) { - return (static_cast(input) - signal_middle) / (signal_middle + 1.0f); + // Constraint the input before the conversion + uint32_t safe_input = + std::min(std::max(input, signal_min), signal_max); + + return map(static_cast(safe_input), static_cast(signal_min), + static_cast(signal_max), norm_signal_min, norm_signal_max); } - uint32_t convert_output(const float &normalised_output) + uint32_t denormalise(const float &normalised_output) { - float output(0.0f); - // Constraint the output before the conversion - output = std::min(std::max(normalised_output, -1.0f), 1.0f); + float safe_output = std::min( + std::max(normalised_output, norm_signal_min), norm_signal_max); - return output * ((signal_middle + 1) + signal_middle); + return static_cast(map(safe_output, norm_signal_min, norm_signal_max, + static_cast(signal_min), + static_cast(signal_max)) + + 0.5f); // add .5f to avoid rounding errors + } + + float map(const float &x, const float &in_min, const float &in_max, + const float &out_min, const float &out_max) + { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } - uint32_t signal_max; - uint32_t signal_min; - uint32_t signal_middle; + const uint32_t signal_max; + const uint32_t signal_min; + const float norm_signal_max = 1.0f; + const float norm_signal_min = -1.0f; FxFactory factory; std::vector effects; diff --git a/extern/guitar_fx_lib/scripts/install.sh b/extern/guitar_fx_lib/scripts/install.sh index a850a07..a7ffb7d 100755 --- a/extern/guitar_fx_lib/scripts/install.sh +++ b/extern/guitar_fx_lib/scripts/install.sh @@ -2,8 +2,12 @@ set -euo pipefail +if [[ -d build ]]; then + rm -rf build +fi + # Build the automated test suite mkdir -p build cd build cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr/local -DBUILD_TESTS=OFF .. -cmake --build . --config Release --target install -- -j $(nproc) +cmake --build . -j $(nproc) --config Release --target install -- diff --git a/extern/guitar_fx_lib/scripts/test.sh b/extern/guitar_fx_lib/scripts/test.sh index 45497cc..9e65f8d 100755 --- a/extern/guitar_fx_lib/scripts/test.sh +++ b/extern/guitar_fx_lib/scripts/test.sh @@ -2,15 +2,19 @@ set -euo pipefail +if [[ -d build ]]; then + rm -rf build +fi + # Build the automated test suite mkdir -p build cd build cmake -DCMAKE_INSTALL_PREFIX:PATH=/tmp/guitar_fx_lib -DBUILD_TESTS=ON .. -cmake --build . --config Release -- -j $(nproc) +cmake --build . -j $(nproc) --config Release -- # Run the test export GTEST_COLOR=1 -cmake --build . --config Release --target run_tests -- -j $(nproc) +cmake --build . --config Release -j $(nproc) --target run_tests -- # Test install target -cmake --build . --config Release --target install -- -j $(nproc) +cmake --build . --config Release -j $(nproc) --target install -- diff --git a/extern/guitar_fx_lib/tests/test_fx_factory.cpp b/extern/guitar_fx_lib/tests/test_fx_factory.cpp index 5827c98..3f9a5b7 100644 --- a/extern/guitar_fx_lib/tests/test_fx_factory.cpp +++ b/extern/guitar_fx_lib/tests/test_fx_factory.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include class TestFxFactory : public ::testing::TestWithParam>> diff --git a/extern/guitar_fx_lib/tests/test_fx_manager.cpp b/extern/guitar_fx_lib/tests/test_fx_manager.cpp index 56cf95b..6336f0a 100644 --- a/extern/guitar_fx_lib/tests/test_fx_manager.cpp +++ b/extern/guitar_fx_lib/tests/test_fx_manager.cpp @@ -1,5 +1,6 @@ #include +#include #include class TestFxManager : public ::testing::Test @@ -88,3 +89,17 @@ TEST_F(TestFxManager, testProcessSignal) } } } + +TEST_F(TestFxManager, testSignalInternalConversion) +{ + // Use only the CLEAN effect with all the possible inputs to verify that + // any internal signal manipulation does not alter the output + for (uint32_t input = 0; input < 4096; ++input) + { + FxManager fx(0, 4095, {Effects::CLEAN}); + + uint32_t output = 0; + ASSERT_TRUE(fx.process(input, output)) << "Failed with input " << input; + ASSERT_EQ(input, output) << "Failed with input " << input; + } +} diff --git a/scripts/build.sh b/scripts/build.sh index d7f7c3f..de7187c 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,6 +1,12 @@ #!/usr/bin/env bash +set -euo pipefail + +if [[ -d build ]]; then + rm -rf build +fi + mkdir -p build cd build cmake .. -cmake --build . --config Release -- -j $(nproc) +cmake --build . -j $(nproc) --config Release --