diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ebb6fe7..bcdeef1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,5 +26,6 @@ jobs: - name: Run tests working-directory: ${{github.workspace}} run: | + ./build/tools/run_tests ./build/tools/benchmodel ./example_models/wavenet.nam ./build/tools/benchmodel ./example_models/lstm.nam diff --git a/NAM/dsp.h b/NAM/dsp.h index 4b7f8f0..8739883 100644 --- a/NAM/dsp.h +++ b/NAM/dsp.h @@ -58,11 +58,21 @@ class DSP // Expected sample rate, in Hz. // TODO throw if it doesn't know. double GetExpectedSampleRate() const { return mExpectedSampleRate; }; + // Input Level, in dBu, corresponding to 0 dBFS for a sine wave + // You should call HasInputLevel() first to be safe. + double GetInputLevel() {return mInputLevel.level;}; // Get how loud this model is, in dB. // Throws a std::runtime_error if the model doesn't know how loud it is. double GetLoudness() const; + // Output Level, in dBu, corresponding to 0 dBFS for a sine wave + // You should call HasOutputLevel() first to be safe. + double GetOutputLevel() {return mOutputLevel.level;}; + // Does this model know its output level? + bool HasInputLevel() {return mInputLevel.haveLevel;}; // Get whether the model knows how loud it is. bool HasLoudness() const { return mHasLoudness; }; + // Does this model know its output level? + bool HasOutputLevel() {return mOutputLevel.haveLevel;}; // General function for resetting the DSP unit. // This doesn't call prewarm(). If you want to do that, then you might want to use ResetAndPrewarm(). // See https://github.com/sdatkinson/NeuralAmpModelerCore/issues/96 for the reasoning. @@ -73,10 +83,12 @@ class DSP Reset(sampleRate, maxBufferSize); prewarm(); } + void SetInputLevel(const double inputLevel) {mInputLevel.haveLevel = true; mInputLevel.level = inputLevel;}; // Set the loudness, in dB. // This is usually defined to be the loudness to a standardized input. The trainer has its own, but you can always // use this to define it a different way if you like yours better. void SetLoudness(const double loudness); + void SetOutputLevel(const double outputLevel) {mOutputLevel.haveLevel = true; mOutputLevel.level = outputLevel;}; protected: bool mHasLoudness = false; @@ -92,6 +104,14 @@ class DSP // How many samples should be processed for me to be considered "warmed up"? virtual int PrewarmSamples() { return 0; }; + +private: + struct Level { + bool haveLevel=false; + float level = 0.0; + }; + Level mInputLevel; + Level mOutputLevel; }; // Class where an input buffer is kept so that long-time effects can be diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 1622cde..2508c38 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -11,6 +11,7 @@ include_directories(tools ${NAM_DEPS_PATH}/nlohmann) add_executable(loadmodel loadmodel.cpp ${NAM_SOURCES}) add_executable(benchmodel benchmodel.cpp ${NAM_SOURCES}) +add_executable(run_tests run_tests.cpp ${NAM_SOURCES}) source_group(NAM ${CMAKE_CURRENT_SOURCE_DIR} FILES ${NAM_SOURCES}) diff --git a/tools/run_tests.cpp b/tools/run_tests.cpp new file mode 100644 index 0000000..a5ee3d1 --- /dev/null +++ b/tools/run_tests.cpp @@ -0,0 +1,19 @@ +// Entry point for tests + +#include +#include "test/test_dsp.cpp" + +int main() { + std::cout << "Running tests..." << std::endl; + // TODO Automatically loop, catch exceptions, log results + test_dsp::test_construct(); + test_dsp::test_get_input_level(); + test_dsp::test_get_output_level(); + test_dsp::test_has_input_level(); + test_dsp::test_has_output_level(); + test_dsp::test_set_input_level(); + test_dsp::test_set_output_level(); + + std::cout << "Success!" << std::endl; + return 0; +} \ No newline at end of file diff --git a/tools/test/test_dsp.cpp b/tools/test/test_dsp.cpp new file mode 100644 index 0000000..179bc7c --- /dev/null +++ b/tools/test/test_dsp.cpp @@ -0,0 +1,59 @@ +// Tests for dsp + +#include "NAM/dsp.h" + +namespace test_dsp { + // Simplest test: can I construct something! + void test_construct() { + nam::DSP myDsp(48000.0); + } + + void test_get_input_level() { + nam::DSP myDsp(48000.0); + const double expected = 19.3; + myDsp.SetInputLevel(expected); + assert(myDsp.HasInputLevel()); + const double actual = myDsp.GetInputLevel(); + + assert(actual == expected); + } + + void test_get_output_level() { + nam::DSP myDsp(48000.0); + const double expected = 12.3; + myDsp.SetOutputLevel(expected); + assert(myDsp.HasOutputLevel()); + const double actual = myDsp.GetOutputLevel(); + + assert(actual == expected); + } + + // Test correct function of DSP::HasInputLevel() + void test_has_input_level() { + nam::DSP myDsp(48000.0); + assert(!myDsp.HasInputLevel()); + + myDsp.SetInputLevel(19.3); + assert(myDsp.HasInputLevel()); + } + + void test_has_output_level() { + nam::DSP myDsp(48000.0); + assert(!myDsp.HasOutputLevel()); + + myDsp.SetOutputLevel(12.3); + assert(myDsp.HasOutputLevel()); + } + + // Test correct function of DSP::HasInputLevel() + void test_set_input_level() { + nam::DSP myDsp(48000.0); + myDsp.SetInputLevel(19.3); + } + + void test_set_output_level() { + nam::DSP myDsp(48000.0); + myDsp.SetOutputLevel(19.3); + } +}; +