diff --git a/.gitignore b/.gitignore index b7539ce9..3c66e5f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ build build-arm build-subl -.vscode \ No newline at end of file +.vscode +perf.data +perf.data.old \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 4ee0bf4e..b52b5486 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,9 @@ [submodule "external/readerwriterqueue"] path = external/readerwriterqueue url = https://github.com/cameron314/readerwriterqueue.git +[submodule "external/gsl-lite"] + path = external/gsl-lite + url = https://github.com/martinmoene/gsl-lite.git +[submodule "external/cnpy"] + path = external/cnpy + url = https://github.com/rogersce/cnpy.git diff --git a/CMakeLists.txt b/CMakeLists.txt index f8edc1f2..eeb23cba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,6 @@ if (UNIX) add_compile_options(-Wextra) # add_compile_options(-fno-exceptions) add_compile_options(-ffast-math) - add_compile_options(-fno-rtti) # add_compile_options(-fno-omit-frame-pointer) endif() @@ -47,7 +46,9 @@ add_subdirectory(external/abseil-cpp) add_subdirectory(external/spdlog) add_subdirectory(external/Catch2) add_subdirectory(external/cxxopts) +add_subdirectory(external/gsl-lite) add_subdirectory(external/benchmark) +add_subdirectory(external/cnpy) # Download libsndfile if (WIN32) @@ -106,6 +107,7 @@ set(TEST_SOURCES tests/BufferT.cpp tests/StereoBufferT.cpp tests/FilesT.cpp + tests/OnePoleFilterT.cpp tests/MainT.cpp ) @@ -121,8 +123,12 @@ target_link_libraries(sfzprint absl::strings cxxopts) ############################### # Basic command line program add_executable(sfizz sources/Main.cpp ${COMMON_SOURCES}) +if (HAVE_INTRIN_H OR HAVE_X86INTRIN_H) + target_sources(sfizz PRIVATE ${SSE_SOURCES}) +endif() # Per OS properties if(UNIX) + target_compile_options(sfizz PRIVATE -fno-rtti) target_link_libraries(sfizz stdc++fs) endif(UNIX) target_link_libraries(sfizz absl::strings cxxopts sndfile absl::flat_hash_map readerwriterqueue) @@ -131,33 +137,37 @@ target_link_libraries(sfizz absl::strings cxxopts sndfile absl::flat_hash_map re # Test application add_executable(sfizz_tests ${TEST_SOURCES} ${COMMON_SOURCES}) # Per OS properties +if (HAVE_INTRIN_H OR HAVE_X86INTRIN_H) + target_sources(sfizz_tests PRIVATE ${SSE_SOURCES}) +endif() if(UNIX) -target_link_libraries(sfizz_tests stdc++fs) + target_link_libraries(sfizz_tests stdc++fs) endif(UNIX) -target_link_libraries(sfizz_tests Catch2::Catch2 absl::strings absl::flat_hash_map sndfile readerwriterqueue) +target_link_libraries(sfizz_tests Catch2::Catch2 absl::strings absl::flat_hash_map sndfile readerwriterqueue cnpy-static gsl::gsl-lite) target_include_directories(sfizz_tests SYSTEM PRIVATE sources) file(COPY "tests" DESTINATION ${CMAKE_BINARY_DIR}) ############################### -add_executable(bench_fill benchmarks/Stereo_Fill.cpp ${COMMON_SOURCES}) +add_executable(bench_fill benchmarks/Stereo_Fill.cpp sources/StereoBufferSSE.cpp) # Per OS properties -if(UNIX) - target_link_libraries(bench_fill stdc++fs) -endif(UNIX) -target_link_libraries(bench_fill absl::strings benchmark) +target_link_libraries(bench_fill benchmark) ############################### add_executable(bench_read benchmarks/Stereo_Read_Interleaved.cpp sources/StereoBufferSSE.cpp) # Per OS properties -if(UNIX) - target_link_libraries(bench_read stdc++fs) -endif(UNIX) -target_link_libraries(bench_read absl::strings benchmark) +target_link_libraries(bench_read benchmark) ############################### add_executable(bench_write benchmarks/Stereo_Write_Interleaved.cpp sources/StereoBufferSSE.cpp) # Per OS properties -if(UNIX) - target_link_libraries(bench_write stdc++fs) -endif(UNIX) -target_link_libraries(bench_write absl::strings benchmark) +target_link_libraries(bench_write benchmark) + +############################### +add_executable(bench_span benchmarks/Spans.cpp) +# Per OS properties +target_link_libraries(bench_span benchmark gsl::gsl-lite absl::span) + +############################### +add_executable(bench_opf_high_vs_low benchmarks/OPF_high_vs_low.cpp) +# Per OS properties +target_link_libraries(bench_opf_high_vs_low benchmark gsl::gsl-lite) diff --git a/benchmarks/OPF_high_vs_low.cpp b/benchmarks/OPF_high_vs_low.cpp new file mode 100644 index 00000000..f8e0fa27 --- /dev/null +++ b/benchmarks/OPF_high_vs_low.cpp @@ -0,0 +1,168 @@ +#include +#include "gsl/gsl-lite.hpp" +#include +#include +#include "../sources/Intrinsics.h" + +constexpr float filterGain { 0.25f }; + +void lowpass(gsl::span input, gsl::span lowpass, float gain) +{ + float state = 0.0f; + float intermediate; + const auto G = gain / (1 - gain); + for (auto [in, out] = std::make_pair(input.begin(), lowpass.begin()); + in < input.end() && out < lowpass.end(); + in++, out++) + { + intermediate = G * (*in - state); + *out = intermediate + state; + state = *out + intermediate; + } +} + +void highpass(gsl::span input, gsl::span highpass, float gain) +{ + float state = 0.0f; + float intermediate; + const auto G = gain / (1 - gain); + for (auto [in, out] = std::make_pair(input.begin(), highpass.begin()); + in < input.end() && out < highpass.end(); + in++, out++) + { + intermediate = G * (*in - state); + *out = *in - intermediate - state; + state += 2*intermediate; + } +} + +void highpass_foreach(gsl::span input, gsl::span highpass, float gain) +{ + lowpass(input, highpass, gain); + for (auto [in, out] = std::make_pair(input.begin(), highpass.begin()); + in < input.end() && out < highpass.end(); + in++, out++) + *out = *in - *out; +} + +void highpass_raw(gsl::span input, gsl::span highpass, float gain) +{ + lowpass(input, highpass, gain); + auto in = input.data(); + auto out = highpass.data(); + while (in < input.end() && out < highpass.end()) + { + *out = *in - *out; + out++; + in++; + } +} + +void highpass_sse(gsl::span input, gsl::span highpass, float gain) +{ + lowpass(input, highpass, gain); + auto in = input.data(); + auto out = highpass.data(); + constexpr int FloatAlignment { 4 }; + const auto inputAlignedEnd = input.data() + (input.size() - (input.size() & (FloatAlignment - 1))); + const auto outputAlignedEnd = highpass.data() + (highpass.size() - (highpass.size() & (FloatAlignment - 1))); + while (in < inputAlignedEnd && out < outputAlignedEnd) + { + const auto inputRegister = _mm_loadu_ps(in); + auto outputRegister = _mm_loadu_ps(out); + outputRegister = _mm_sub_ps(inputRegister, outputRegister); + _mm_storeu_ps(out, outputRegister); + in += 4; + out += 4; + } + while (in < input.end() && out < highpass.end()) + { + *out = *in - *out; + out++; + in++; + } +} + + +static void Low(benchmark::State& state) { + std::vector input(state.range(0)); + std::vector output(state.range(0)); + std::random_device rd { }; + std::mt19937 gen { rd() }; + + std::normal_distribution dist { }; + std::generate(input.begin(), input.end(), [&]() { + return dist(gen); + }); + + for (auto _ : state) + lowpass(input, output, filterGain); +} + +static void High(benchmark::State& state) { + std::vector input(state.range(0)); + std::vector output(state.range(0)); + std::random_device rd { }; + std::mt19937 gen { rd() }; + + std::normal_distribution dist { }; + std::generate(input.begin(), input.end(), [&]() { + return dist(gen); + }); + + for (auto _ : state) + highpass(input, output, filterGain); +} + +static void High_ForEach(benchmark::State& state) { + std::vector input(state.range(0)); + std::vector output(state.range(0)); + std::random_device rd { }; + std::mt19937 gen { rd() }; + + std::normal_distribution dist { }; + std::generate(input.begin(), input.end(), [&]() { + return dist(gen); + }); + + for (auto _ : state) + highpass_foreach(input, output, filterGain); +} + +static void High_Raw(benchmark::State& state) { + std::vector input(state.range(0)); + std::vector output(state.range(0)); + std::random_device rd { }; + std::mt19937 gen { rd() }; + + std::normal_distribution dist { }; + std::generate(input.begin(), input.end(), [&]() { + return dist(gen); + }); + + for (auto _ : state) + highpass_raw(input, output, filterGain); +} + +static void High_SSE(benchmark::State& state) { + std::vector input(state.range(0)); + std::vector output(state.range(0)); + std::random_device rd { }; + std::mt19937 gen { rd() }; + + std::normal_distribution dist { }; + std::generate(input.begin(), input.end(), [&]() { + return dist(gen); + }); + + for (auto _ : state) + highpass_sse(input, output, filterGain); +} + + +BENCHMARK(Low)->RangeMultiplier(2)->Range((2<<5), (2<<10)); +BENCHMARK(High)->RangeMultiplier(2)->Range((2<<5), (2<<10)); +BENCHMARK(High_ForEach)->RangeMultiplier(2)->Range((2<<5), (2<<10)); +BENCHMARK(High_Raw)->RangeMultiplier(2)->Range((2<<5), (2<<10)); +BENCHMARK(High_SSE)->RangeMultiplier(2)->Range((2<<5), (2<<10)); +BENCHMARK_MAIN(); \ No newline at end of file diff --git a/benchmarks/Spans.cpp b/benchmarks/Spans.cpp new file mode 100644 index 00000000..f537462c --- /dev/null +++ b/benchmarks/Spans.cpp @@ -0,0 +1,111 @@ +#include +#include "gsl/gsl-lite.hpp" +#include "absl/types/span.h" +#include +#include + +constexpr float filterGain { 0.25f }; + +void processRaw(float* input, float* lowpass, float gain, int numSamples) +{ + const auto end = input + numSamples; + float state = 0.0f; + float intermediate; + const auto G = gain / (1 - gain); + while (input < end) + { + intermediate = G * (*input++ - state); + *lowpass = intermediate + state; + state = *lowpass++ + intermediate; + } +} + +void processGSLSpan(gsl::span input, gsl::span lowpass, float gain) +{ + + float state = 0.0f; + float intermediate; + const auto G = gain / (1 - gain); + for (auto [in, out] = std::make_pair(input.begin(), lowpass.begin()); + in < input.end() && out < lowpass.end(); + in++, out++) + { + intermediate = G * (*in - state); + *out = intermediate + state; + state = *out + intermediate; + } +} + +void processABSLSpan(absl::Span input, absl::Span lowpass, float gain) +{ + + float state = 0.0f; + float intermediate; + const auto G = gain / (1 - gain); + for (auto [in, out] = std::make_pair(input.begin(), lowpass.begin()); + in < input.end() && out < lowpass.end(); + in++, out++) + { + intermediate = G * (*in - state); + *out = intermediate + state; + state = *out + intermediate; + } +} + +static void Raw(benchmark::State& state) { + std::vector input(state.range(0)); + std::vector output(state.range(0)); + std::random_device rd { }; + std::mt19937 gen { rd() }; + + std::normal_distribution dist { }; + std::generate(input.begin(), input.end(), [&]() { + return dist(gen); + }); + + for (auto _ : state) + { + processRaw(input.data(), output.data(), filterGain, state.range(0)); + } +} + +static void GSLSpan(benchmark::State& state) { + std::vector input(state.range(0)); + std::vector output(state.range(0)); + std::random_device rd { }; + std::mt19937 gen { rd() }; + + std::normal_distribution dist { }; + std::generate(input.begin(), input.end(), [&]() { + return dist(gen); + }); + + for (auto _ : state) + { + processGSLSpan(input, output, filterGain); + } +} + +static void ABSLSpan(benchmark::State& state) { + std::vector input(state.range(0)); + std::vector output(state.range(0)); + std::random_device rd { }; + std::mt19937 gen { rd() }; + + std::normal_distribution dist { }; + std::generate(input.begin(), input.end(), [&]() { + return dist(gen); + }); + + for (auto _ : state) + { + processABSLSpan(input, absl::MakeSpan(output), filterGain); + } +} + +// Register the function as a benchmark + +BENCHMARK(Raw)->RangeMultiplier(2)->Range((2<<6), (2<<12)); +BENCHMARK(GSLSpan)->RangeMultiplier(2)->Range((2<<6), (2<<12)); +BENCHMARK(ABSLSpan)->RangeMultiplier(2)->Range((2<<6), (2<<12)); +BENCHMARK_MAIN(); \ No newline at end of file diff --git a/external/cnpy b/external/cnpy new file mode 160000 index 00000000..4e8810b1 --- /dev/null +++ b/external/cnpy @@ -0,0 +1 @@ +Subproject commit 4e8810b1a8637695171ed346ce68f6984e585ef4 diff --git a/external/gsl-lite b/external/gsl-lite new file mode 160000 index 00000000..df36f637 --- /dev/null +++ b/external/gsl-lite @@ -0,0 +1 @@ +Subproject commit df36f6378336280043d7e06d8013e6fa4af6abd7 diff --git a/old/StateVariableFilter.cpp b/old/StateVariableFilter.cpp new file mode 100644 index 00000000..11e1311f --- /dev/null +++ b/old/StateVariableFilter.cpp @@ -0,0 +1,35 @@ +#include "StateVariableFilter.h" +#include + +// template<> +// template<> +// auto StateVariableFilter::process(const float& input [[maybe_unused]]) +// { +// return 0.0; +// } + +// template<> +// template<> +// auto StateVariableFilter::process(const float& input [[maybe_unused]]) +// { +// return std::make_pair(0.0, 0.0); +// } + +// template<> +// template<> +// auto StateVariableFilter::process(const float& input [[maybe_unused]]) +// { +// return std::make_tuple(0.0, 0.0, 0.0); +// } + +template<> +auto StateVariableFilter::process(const float& input [[maybe_unused]], float& bandpass [[maybe_unused]]) +{ + +} + +template<> +auto StateVariableFilter::process(const float& input [[maybe_unused]], float& bandpass [[maybe_unused]], float& lowpass [[maybe_unused]]) +{ + +} \ No newline at end of file diff --git a/old/StateVariableFilter.h b/old/StateVariableFilter.h new file mode 100644 index 00000000..ceb3620b --- /dev/null +++ b/old/StateVariableFilter.h @@ -0,0 +1,27 @@ +#pragma once +#include "Globals.h" +#include +#include + +// enum class SVFReturn { BP_LP_HP, BP_LP, BP}; + +// template +class StateVariableFilter +{ +public: + StateVariableFilter() = default; + StateVariableFilter(float R, float gain) + : R(R), gain(gain) + { + + } + + // Only use specializations + template + auto process(const InputType& input, OutputTypes... outputs) = delete; + +private: + std::array state; + float R { 0.0 }; + float gain { 1.0 }; +}; \ No newline at end of file diff --git a/old/StateVariableFilterSSE.cpp b/old/StateVariableFilterSSE.cpp new file mode 100644 index 00000000..b8a51306 --- /dev/null +++ b/old/StateVariableFilterSSE.cpp @@ -0,0 +1,36 @@ +#include "StateVariableFilter.h" +#include +#include "Intrinsics.h" + +// template<> +// template<> +// auto StateVariableFilter::process<__m128>(const __m128& input [[maybe_unused]]) +// { +// return 0.0; +// } + +// template<> +// template<> +// auto StateVariableFilter::process<__m128>(const __m128& input [[maybe_unused]]) +// { +// return std::make_pair(0.0, 0.0); +// } + +// template<> +// template<> +// auto StateVariableFilter::process<__m128>(const __m128& input [[maybe_unused]]) +// { +// return std::make_tuple(0.0, 0.0, 0.0); +// } + +template<> +auto StateVariableFilter::process(const __m128& input [[maybe_unused]], __m128& bandpass [[maybe_unused]]) +{ + +} + +template<> +auto StateVariableFilter::process(const __m128& input [[maybe_unused]], __m128& bandpass [[maybe_unused]], __m128& lowpass [[maybe_unused]]) +{ + +} \ No newline at end of file diff --git a/sources/FilePool.h b/sources/FilePool.h index 424d2b4a..2fd826db 100644 --- a/sources/FilePool.h +++ b/sources/FilePool.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include "readerwriterqueue.h" #include namespace sfz diff --git a/sources/OnePoleFilter.h b/sources/OnePoleFilter.h new file mode 100644 index 00000000..d8a64383 --- /dev/null +++ b/sources/OnePoleFilter.h @@ -0,0 +1,94 @@ +#include "Globals.h" +#include +#include "gsl/gsl-lite.hpp" + +template +class OnePoleFilter +{ +public: + OnePoleFilter() = default; + // Normalized cutoff with respect to the sampling rate + template + static Type normalizedGain(Type cutoff, C sampleRate) + { + return std::tan( cutoff / static_cast(sampleRate) * M_PIf32 ); + } + + OnePoleFilter(Type gain) + { + setGain(gain); + } + + void setGain(Type gain) + { + this->gain = gain; + G = gain / ( 1 + gain); + } + + Type getGain() const { return gain; } + + int processLowpass(gsl::span input, gsl::span lowpass) + { + for (auto [in, out] = std::pair(input.begin(), lowpass.begin()); + in < input.end() && out < lowpass.end(); in++, out++) + { + oneLowpass(in, out); + } + return std::min(input.size(), lowpass.size()); + } + + int processHighpass(gsl::span input, gsl::span highpass) + { + for (auto [in, out] = std::pair(input.begin(), highpass.begin()); + in < input.end() && out < highpass.end(); in++, out++) + { + oneHighpass(in, out); + } + return std::min(input.size(), highpass.size()); + } + + int processLowpassVariableGain(gsl::span input, gsl::span lowpass, gsl::span gain) + { + for (auto [in, out, g] = std::tuple(input.begin(), lowpass.begin(), gain.begin()); + in < input.end() && out < lowpass.end() && g < gain.end(); in++, out++, g++) + { + setGain(*g); + oneLowpass(in, out); + } + + return std::min({ input.size(), lowpass.size(), gain.size() }); + } + + int processHighpassVariableGain(gsl::span input, gsl::span highpass, gsl::span gain) + { + for (auto [in, out, g] = std::tuple(input.begin(), highpass.begin(), gain.begin()); + in < input.end() && out < highpass.end() && g < gain.end(); in++, out++, g++) + { + setGain(*g); + oneHighpass(in, out); + } + + return std::min({ input.size(), highpass.size(), gain.size() }); + } + + void reset() { state = 0.0; } +private: + Type state { 0.0 }; + Type gain { 0.25 }; + Type intermediate { 0.0 }; + Type G { gain / (1 + gain) }; + + inline void oneLowpass(const Type* in, Type* out) + { + intermediate = G * (*in - state); + *out = intermediate + state; + state = *out + intermediate; + } + + inline void oneHighpass(const Type* in, Type* out) + { + intermediate = G * (*in - state); + *out = *in - intermediate - state; + state += 2*intermediate; + } +}; \ No newline at end of file diff --git a/tests/OnePoleFilterT.cpp b/tests/OnePoleFilterT.cpp new file mode 100644 index 00000000..1d29efdb --- /dev/null +++ b/tests/OnePoleFilterT.cpp @@ -0,0 +1,102 @@ +#include "../sources/OnePoleFilter.h" +#include "catch2/catch.hpp" +#include "cnpy.h" +#include "gsl/gsl-lite.hpp" +#include +#include +using namespace Catch::literals; + +template +void testInputOutput(const std::filesystem::path& inputNumpyFile, const std::filesystem::path& outputNumpyFile, Type gain) +{ + const auto input = cnpy::npy_load(inputNumpyFile.string()); + REQUIRE( input.word_size == 8 ); + const auto inputSpan = gsl::make_span(input.data(), input.shape[0]); + + const auto output = cnpy::npy_load(outputNumpyFile.string()); + REQUIRE( output.word_size == 8 ); + const auto outputSpan = gsl::make_span(output.data(), output.shape[0]); + auto size = std::min(outputSpan.size(), inputSpan.size()); + REQUIRE( size > 0 ); + + std::vector inputData; + std::vector expectedData; + inputData.reserve(size); + expectedData.reserve(size); + for (auto& data: inputSpan) + inputData.push_back(static_cast(data)); + for (auto& data: outputSpan) + expectedData.push_back(static_cast(data)); + + OnePoleFilter filter { gain }; + std::vector outputData (size); + filter.processLowpass(inputData, outputData); + for (size_t i = 0; i < size; ++i) + REQUIRE( outputData[i] == Approx(expectedData[i]) ); + + filter.reset(); + std::fill(outputData.begin(), outputData.end(), 0.0); + std::vector gains(size); + std::fill(gains.begin(), gains.end(), gain); + filter.processLowpassVariableGain(inputData, outputData, gains); + for (size_t i = 0; i < size; ++i) + REQUIRE( outputData[i] == Approx(expectedData[i]) ); +} + +TEST_CASE("[OnePoleFilter] Float") +{ + testInputOutput( + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_input_gain_0.1.npy", + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_output_gain_0.1.npy", + 0.1f + ); + testInputOutput( + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_input_gain_0.3.npy", + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_output_gain_0.3.npy", + 0.3f + ); + testInputOutput( + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_input_gain_0.5.npy", + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_output_gain_0.5.npy", + 0.5f + ); + testInputOutput( + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_input_gain_0.7.npy", + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_output_gain_0.7.npy", + 0.7f + ); + testInputOutput( + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_input_gain_0.9.npy", + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_output_gain_0.9.npy", + 0.9f + ); +} + +TEST_CASE("[OnePoleFilter] Double") +{ + testInputOutput( + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_input_gain_0.1.npy", + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_output_gain_0.1.npy", + 0.1f + ); + testInputOutput( + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_input_gain_0.3.npy", + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_output_gain_0.3.npy", + 0.3f + ); + testInputOutput( + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_input_gain_0.5.npy", + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_output_gain_0.5.npy", + 0.5f + ); + testInputOutput( + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_input_gain_0.7.npy", + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_output_gain_0.7.npy", + 0.7f + ); + testInputOutput( + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_input_gain_0.9.npy", + std::filesystem::current_path() / "tests/TestFiles/OnePoleFilter/OPF_output_gain_0.9.npy", + 0.9f + ); +} diff --git a/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.1.npy b/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.1.npy new file mode 100644 index 00000000..7c87bb65 Binary files /dev/null and b/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.1.npy differ diff --git a/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.3.npy b/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.3.npy new file mode 100644 index 00000000..c5bee388 Binary files /dev/null and b/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.3.npy differ diff --git a/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.5.npy b/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.5.npy new file mode 100644 index 00000000..a7a3e773 Binary files /dev/null and b/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.5.npy differ diff --git a/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.7.npy b/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.7.npy new file mode 100644 index 00000000..eb17324d Binary files /dev/null and b/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.7.npy differ diff --git a/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.9.npy b/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.9.npy new file mode 100644 index 00000000..5b88b321 Binary files /dev/null and b/tests/TestFiles/OnePoleFilter/OPF_input_gain_0.9.npy differ diff --git a/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.1.npy b/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.1.npy new file mode 100644 index 00000000..2a0b42dd Binary files /dev/null and b/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.1.npy differ diff --git a/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.3.npy b/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.3.npy new file mode 100644 index 00000000..b17e6d95 Binary files /dev/null and b/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.3.npy differ diff --git a/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.5.npy b/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.5.npy new file mode 100644 index 00000000..6001b75b Binary files /dev/null and b/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.5.npy differ diff --git a/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.7.npy b/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.7.npy new file mode 100644 index 00000000..dcbda93b Binary files /dev/null and b/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.7.npy differ diff --git a/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.9.npy b/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.9.npy new file mode 100644 index 00000000..acec0e5f Binary files /dev/null and b/tests/TestFiles/OnePoleFilter/OPF_output_gain_0.9.npy differ