diff --git a/.appveyor.yml b/.appveyor.yml index 7c06374d..e61f39a7 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -version: '2.1.0.{build}' +version: '2.1.1.{build}' shallow_clone: true diff --git a/.travis.yml b/.travis.yml index dfa3d9d4..164973cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,7 @@ matrix: - ENABLE_PYTHON=ON - PYTHON_VERSION=2.7 - PYTHON=python2 - - Python_ADDITIONAL_VERSIONS=2.7.12 + - Python_ADDITIONAL_VERSIONS=2.7.13 - compiler: gcc os: linux dist: trusty @@ -43,9 +43,9 @@ matrix: - PLATFORM=gcc-5 - ADDITONAL_CMAKE_FLAGS= - ENABLE_PYTHON=ON - - PYTHON_VERSION=3.5 + - PYTHON_VERSION=3.6 - PYTHON=python3 - - Python_ADDITIONAL_VERSIONS=3.5.2 + - Python_ADDITIONAL_VERSIONS=3.6.0 - compiler: gcc os: linux dist: trusty @@ -66,7 +66,7 @@ matrix: - ENABLE_PYTHON=ON - PYTHON_VERSION=2.7 - PYTHON=python2 - - Python_ADDITIONAL_VERSIONS=2.7.12 + - Python_ADDITIONAL_VERSIONS=2.7.13 - compiler: gcc os: linux dist: trusty @@ -85,9 +85,9 @@ matrix: - PLATFORM=gcc-6 - ADDITONAL_CMAKE_FLAGS= - ENABLE_PYTHON=ON - - PYTHON_VERSION=3.5 + - PYTHON_VERSION=3.6 - PYTHON=python3 - - Python_ADDITIONAL_VERSIONS=3.5.2 + - Python_ADDITIONAL_VERSIONS=3.6.0 - compiler: clang-3.8 os: linux dist: trusty @@ -110,7 +110,7 @@ matrix: - ENABLE_PYTHON=ON - PYTHON_VERSION=2.7 - PYTHON=python2 - - Python_ADDITIONAL_VERSIONS=2.7.12 + - Python_ADDITIONAL_VERSIONS=2.7.13 - compiler: clang-3.8 os: linux dist: trusty @@ -131,9 +131,9 @@ matrix: - PLATFORM=clang-3.8 - ADDITONAL_CMAKE_FLAGS= - ENABLE_PYTHON=ON - - PYTHON_VERSION=3.5 + - PYTHON_VERSION=3.6 - PYTHON=python3 - - Python_ADDITIONAL_VERSIONS=3.5.2 + - Python_ADDITIONAL_VERSIONS=3.6.0 - compiler: clang-3.9 os: linux dist: trusty @@ -156,7 +156,7 @@ matrix: - ENABLE_PYTHON=ON - PYTHON_VERSION=2.7 - PYTHON=python2 - - Python_ADDITIONAL_VERSIONS=2.7.12 + - Python_ADDITIONAL_VERSIONS=2.7.13 - compiler: clang-3.9 os: linux dist: trusty @@ -177,9 +177,9 @@ matrix: - PLATFORM=clang-3.9 - ADDITONAL_CMAKE_FLAGS= - ENABLE_PYTHON=ON - - PYTHON_VERSION=3.5 + - PYTHON_VERSION=3.6 - PYTHON=python3 - - Python_ADDITIONAL_VERSIONS=3.5.2 + - Python_ADDITIONAL_VERSIONS=3.6.0 - os: osx osx_image: xcode7.3 env: @@ -224,6 +224,7 @@ matrix: before_install: - mkdir $HOME/usr - export PATH="$HOME/usr/bin:$PATH" + - if [[ "$TRAVIS_OS_NAME" != "osx" ]]; then dir /opt/python/ ; fi - if [[ "$TRAVIS_OS_NAME" != "osx" ]]; then wget https://cmake.org/files/v3.8/cmake-3.8.1-Linux-x86_64.sh ; fi - if [[ "$TRAVIS_OS_NAME" != "osx" ]]; then chmod +x cmake-3.8.1-Linux-x86_64.sh ; fi - if [[ "$TRAVIS_OS_NAME" != "osx" ]]; then ./cmake-3.8.1-Linux-x86_64.sh --prefix=$HOME/usr --exclude-subdir --skip-license ; fi diff --git a/ATK/Core/BaseFilter.cpp b/ATK/Core/BaseFilter.cpp index 7d48a7a9..fb24df1b 100644 --- a/ATK/Core/BaseFilter.cpp +++ b/ATK/Core/BaseFilter.cpp @@ -143,7 +143,13 @@ namespace ATK void BaseFilter::process(std::size_t size) { reset(); - process_conditionnally(size); + process_conditionnally(size); + } + + void BaseFilter::dryrun(std::size_t size) + { + reset(); + process_conditionnally(size); } #if ATK_USE_THREADPOOL == 1 @@ -154,6 +160,7 @@ namespace ATK } #endif + template void BaseFilter::process_conditionnally(std::size_t size) { if(size == 0) @@ -178,7 +185,7 @@ namespace ATK else { assert(output_sampling_rate); - connections[port].second->process_conditionnally(uint64_t(size) * input_sampling_rate / output_sampling_rate); + connections[port].second->template process_conditionnally(uint64_t(size) * input_sampling_rate / output_sampling_rate); } } #if ATK_PROFILING == 1 @@ -196,7 +203,10 @@ namespace ATK output_conversion_time += (timer2 - timer); timer = timer2; #endif - process_impl(size); + if(must_process) + { + process_impl(size); + } #if ATK_PROFILING == 1 timer2 = std::chrono::steady_clock::now(); process_time += (timer2 - timer); diff --git a/ATK/Core/BaseFilter.h b/ATK/Core/BaseFilter.h index 27917c42..4befca0a 100644 --- a/ATK/Core/BaseFilter.h +++ b/ATK/Core/BaseFilter.h @@ -51,7 +51,9 @@ namespace ATK /// Starts processing after calling reset ATK_CORE_EXPORT void process(std::size_t size); - + /// As process, but doesn't call process_impl + ATK_CORE_EXPORT void dryrun(std::size_t size); + #if ATK_USE_THREADPOOL == 1 /// Allows threaded processing ATK_CORE_EXPORT void process_parallel(std::size_t size); @@ -114,6 +116,7 @@ namespace ATK /// Returns the type that the filter processes virtual int get_type() const = 0; /// Starts processing without calling reset + template void process_conditionnally(std::size_t size); #if ATK_USE_THREADPOOL == 1 /// Starts parallel processing without calling reset diff --git a/ATK/Core/OutCircularPointerFilter.cpp b/ATK/Core/OutCircularPointerFilter.cpp index c6d50726..76d29f99 100644 --- a/ATK/Core/OutCircularPointerFilter.cpp +++ b/ATK/Core/OutCircularPointerFilter.cpp @@ -35,7 +35,7 @@ namespace ATK { auto update_size = std::min(size, array.size() - offset); memcpy(reinterpret_cast(&array[offset]), reinterpret_cast(converted_inputs[0]), static_cast(update_size) * sizeof(DataType)); - offset += size; + offset += update_size; if(offset == array.size()) { auto additional_update_size = size - update_size; diff --git a/ATK/Core/PipelineGlobalSinkFilter.cpp b/ATK/Core/PipelineGlobalSinkFilter.cpp index a32f4e8f..52524c0c 100644 --- a/ATK/Core/PipelineGlobalSinkFilter.cpp +++ b/ATK/Core/PipelineGlobalSinkFilter.cpp @@ -81,7 +81,7 @@ namespace ATK { for (auto it = filters.begin(); it != filters.end(); ++it) { - (*it)->process_conditionnally(size * (*it)->get_output_sampling_rate() / input_sampling_rate); + (*it)->process_conditionnally(size * (*it)->get_output_sampling_rate() / input_sampling_rate); } } } diff --git a/ATK/Delay/HadamardMixture.cpp b/ATK/Delay/HadamardMixture.cpp index e8f6d5b9..59318cdf 100644 --- a/ATK/Delay/HadamardMixture.cpp +++ b/ATK/Delay/HadamardMixture.cpp @@ -48,10 +48,10 @@ namespace ATK } template - static typename std::enable_if::Scalar, 1<>::type recursive_create() + static typename std::enable_if::Scalar, (1<>::type recursive_create() { - constexpr auto big_size = 1 << recursive_order; - constexpr auto small_size = 1 << (recursive_order - 1); + constexpr auto big_size = (1U << recursive_order); + constexpr auto small_size = (1U << (recursive_order - 1)); Eigen::Matrix::Scalar, big_size, big_size> cur_transition; auto M_1 = recursive_create(); diff --git a/ATK/Delay/HadamardMixture.h b/ATK/Delay/HadamardMixture.h index 8a1e128b..9a938b89 100644 --- a/ATK/Delay/HadamardMixture.h +++ b/ATK/Delay/HadamardMixture.h @@ -23,10 +23,9 @@ namespace ATK static const unsigned int nb_channels = 1 << order; typedef DataType_ DataType; /// Gain factor to take into account in the feedback loop due to the instability of the mixture - static constexpr double gain_factor = 1; + static constexpr float gain_factor = 1.f; class MixtureImpl; - }; } diff --git a/ATK/Delay/HouseholderMixture.h b/ATK/Delay/HouseholderMixture.h index 18f33225..7b424a1b 100644 --- a/ATK/Delay/HouseholderMixture.h +++ b/ATK/Delay/HouseholderMixture.h @@ -23,10 +23,9 @@ namespace ATK static const int nb_channels = nb_channels_; typedef DataType_ DataType; /// Gain factor to take into account in the feedback loop due to the instability of the mixture - static constexpr double gain_factor = 0.5; // should be std::pow(2, -order / 2.);, but pow is not constexpr :/ + static constexpr float gain_factor = 0.5f; // should be std::pow(2, -order / 2.);, but pow is not constexpr :/ class MixtureImpl; - }; } diff --git a/ATK/Dynamic/GainColoredCompressorFilter.cpp b/ATK/Dynamic/GainColoredCompressorFilter.cpp index 81762fb4..d51d7ff0 100644 --- a/ATK/Dynamic/GainColoredCompressorFilter.cpp +++ b/ATK/Dynamic/GainColoredCompressorFilter.cpp @@ -78,7 +78,7 @@ namespace ATK DataType diff = 10 * fmath::log10(value); DataType additional_color = color * fmath::exp(- diff * diff * quality); - return static_cast(std::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * (ratio - 1) / ratio)) + additional_color; + return static_cast(fmath::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * (ratio - 1) / ratio)) + additional_color; } template class GainColoredCompressorFilter; diff --git a/ATK/Dynamic/GainColoredExpanderFilter.cpp b/ATK/Dynamic/GainColoredExpanderFilter.cpp index c8af037f..1e8294a4 100644 --- a/ATK/Dynamic/GainColoredExpanderFilter.cpp +++ b/ATK/Dynamic/GainColoredExpanderFilter.cpp @@ -77,7 +77,7 @@ namespace ATK return 0; DataType diff = -10 * fmath::log10(value); DataType additional_color = color * fmath::exp(- diff * diff * quality); - return static_cast(std::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * (ratio - 1))) + additional_color; + return static_cast(fmath::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * (ratio - 1))) + additional_color; } template class GainColoredExpanderFilter; diff --git a/ATK/Dynamic/GainCompressorFilter.cpp b/ATK/Dynamic/GainCompressorFilter.cpp index 967bfe67..74e3346c 100644 --- a/ATK/Dynamic/GainCompressorFilter.cpp +++ b/ATK/Dynamic/GainCompressorFilter.cpp @@ -46,7 +46,7 @@ namespace ATK if(value == 0) return 1; DataType diff = 10 * fmath::log10(value); - return static_cast(std::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * (ratio - 1) / ratio)); + return static_cast(fmath::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * (ratio - 1) / ratio)); } template class GainCompressorFilter; diff --git a/ATK/Dynamic/GainExpanderFilter.cpp b/ATK/Dynamic/GainExpanderFilter.cpp index e479c0c0..2c4a3a6b 100644 --- a/ATK/Dynamic/GainExpanderFilter.cpp +++ b/ATK/Dynamic/GainExpanderFilter.cpp @@ -46,7 +46,7 @@ namespace ATK if(value == 0) return 0; DataType diff = -10 * fmath::log10(value); - return static_cast(std::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * (ratio - 1))); + return static_cast(fmath::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * (ratio - 1))); } template class GainExpanderFilter; diff --git a/ATK/Dynamic/GainLimiterFilter.cpp b/ATK/Dynamic/GainLimiterFilter.cpp index 719f2eae..a4316399 100644 --- a/ATK/Dynamic/GainLimiterFilter.cpp +++ b/ATK/Dynamic/GainLimiterFilter.cpp @@ -46,7 +46,7 @@ namespace ATK if(value == 0) return 1; DataType diff = 10 * fmath::log10(value); - return static_cast(std::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40)); + return static_cast(fmath::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40)); } template class GainLimiterFilter; diff --git a/ATK/Dynamic/GainMaxColoredExpanderFilter.cpp b/ATK/Dynamic/GainMaxColoredExpanderFilter.cpp index 544a9c07..a77f7512 100644 --- a/ATK/Dynamic/GainMaxColoredExpanderFilter.cpp +++ b/ATK/Dynamic/GainMaxColoredExpanderFilter.cpp @@ -99,12 +99,12 @@ namespace ATK DataType_ GainMaxColoredExpanderFilter::computeGain( DataType_ value ) const { if(value == 0) - return static_cast(std::pow(max_reduction, 1 / (ratio - 1))); + return static_cast(fmath::pow(max_reduction, 1 / (ratio - 1))); - DataType diff = static_cast(-5 * fmath::log10(value * value + std::pow(max_reduction, 2 / (ratio - 1)))); + DataType diff = static_cast(-5 * fmath::log10(value * value + fmath::pow(max_reduction, 2 / (ratio - 1)))); DataType additional_color = color * fmath::exp(- diff * diff * quality); - return static_cast(std::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * (ratio - 1))) + additional_color; + return static_cast(fmath::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * (ratio - 1))) + additional_color; } template class GainMaxColoredExpanderFilter; diff --git a/ATK/Dynamic/GainMaxCompressorFilter.cpp b/ATK/Dynamic/GainMaxCompressorFilter.cpp new file mode 100644 index 00000000..660126d5 --- /dev/null +++ b/ATK/Dynamic/GainMaxCompressorFilter.cpp @@ -0,0 +1,80 @@ +/** + * \file GainMaxCompressorFilter.cpp + */ + +#include "GainMaxCompressorFilter.h" + +#include +#include +#include + +#include + +namespace ATK +{ + template + GainMaxCompressorFilter::GainMaxCompressorFilter(std::size_t nb_channels, size_t LUTsize, size_t LUTprecision) + :Parent(nb_channels, LUTsize, LUTprecision), softness(static_cast(.0001)), max_reduction(static_cast(0.01)) + { + } + + template + GainMaxCompressorFilter::~GainMaxCompressorFilter() + { + } + + template + void GainMaxCompressorFilter::set_softness(DataType_ softness) + { + if (softness <= 0) + { + throw std::out_of_range("Softness factor must be strictly positive value"); + } + this->softness = softness; + start_recomputeLUT(); + } + + template + DataType_ GainMaxCompressorFilter::get_softness() const + { + return softness; + } + + template + void GainMaxCompressorFilter::set_max_reduction(DataType_ max_reduction) + { + if (max_reduction <= 0) + { + throw std::out_of_range("Maximum reduction factor must be strictly positive value"); + } + this->max_reduction = max_reduction; + start_recomputeLUT(); + } + + template + void GainMaxCompressorFilter::set_max_reduction_db(DataType_ max_reduction_db) + { + this->max_reduction = static_cast(std::pow(10, max_reduction_db / 10)); + start_recomputeLUT(); + } + + template + DataType_ GainMaxCompressorFilter::get_max_reduction() const + { + return max_reduction; + } + + template + DataType_ GainMaxCompressorFilter::computeGain( DataType_ value ) const + { + if(value == 0) + return 1; + DataType diff = static_cast(-5 * fmath::log10(1/(value * value) + fmath::pow(max_reduction, 2 * ratio / (ratio - 1)))); + return static_cast(fmath::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * (ratio - 1) / ratio)); + } + + template class GainMaxCompressorFilter; + template class GainMaxCompressorFilter; + template class GainFilter>; + template class GainFilter>; +} diff --git a/ATK/Dynamic/GainMaxCompressorFilter.h b/ATK/Dynamic/GainMaxCompressorFilter.h new file mode 100644 index 00000000..17140e40 --- /dev/null +++ b/ATK/Dynamic/GainMaxCompressorFilter.h @@ -0,0 +1,54 @@ +/** + * \file GainMaxCompressorFilter.h + */ + +#ifndef ATK_DYNAMIC_GAINMAXCOMPRESSORFILTER_H +#define ATK_DYNAMIC_GAINMAXCOMPRESSORFILTER_H + +#include + +#include +#include "config.h" + +namespace ATK +{ + /// Gain "compressor". Computes a new amplitude/volume gain based on threshold, slope and the power of the input signal + template + class ATK_DYNAMIC_EXPORT GainMaxCompressorFilter : public ParentGainFilter + { + public: + typedef ParentGainFilter Parent; + using Parent::ratio; + using Parent::start_recomputeLUT; + using typename Parent::DataType; + /*! + * @brief Constructor + * @param nb_channels is the number of input and output channels + * @param LUTsize is the total LUT size used by the filter + * @param LUTprecision is the number of elements used to compute values < 1 + */ + GainMaxCompressorFilter(std::size_t nb_channels = 1, size_t LUTsize = 128*1024, size_t LUTprecision = 64); + /// Destructor + ~GainMaxCompressorFilter(); + + /// Sets the softness of the knee of the filter (positive value) + void set_softness(DataType_ softness); + /// Retrieves the softness afctor + DataType_ get_softness() const; + + /// Sets the maximum reduction factor of the filter (limit reduction to this factor instead of infinite) + void set_max_reduction(DataType_ max_reduction); + /// Sets the maximum reduction in dB + void set_max_reduction_db(DataType_ max_reduction); + /// Gets the maximum reduction factor + DataType_ get_max_reduction() const; + + protected: + DataType_ computeGain(DataType_ value) const; + private: + DataType_ softness; + DataType_ max_reduction; + }; +} + +#endif diff --git a/ATK/Dynamic/GainMaxExpanderFilter.cpp b/ATK/Dynamic/GainMaxExpanderFilter.cpp index f5f28ec4..8ce67c0c 100644 --- a/ATK/Dynamic/GainMaxExpanderFilter.cpp +++ b/ATK/Dynamic/GainMaxExpanderFilter.cpp @@ -49,12 +49,14 @@ namespace ATK throw std::out_of_range("Maximum reduction factor must be strictly positive value"); } this->max_reduction = max_reduction; + start_recomputeLUT(); } template void GainMaxExpanderFilter::set_max_reduction_db(DataType_ max_reduction_db) { this->max_reduction = static_cast(std::pow(10, max_reduction_db / 10)); + start_recomputeLUT(); } template @@ -67,11 +69,11 @@ namespace ATK DataType_ GainMaxExpanderFilter::computeGain( DataType_ value ) const { if(value == 0) - return static_cast(std::pow(max_reduction, 1 / (ratio - 1))); + return static_cast(fmath::pow(max_reduction, 1 / (ratio - 1))); - DataType diff = static_cast(-10 * fmath::log10(std::sqrt(value * value + std::pow(max_reduction, 2 / (ratio - 1))))); + DataType diff = static_cast(-5 * fmath::log10(value * value + fmath::pow(max_reduction, 2 / (ratio - 1)))); - return static_cast(std::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * (ratio - 1))); + return static_cast(fmath::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * (ratio - 1))); } template class GainMaxExpanderFilter; diff --git a/ATK/Dynamic/GainSwellFilter.cpp b/ATK/Dynamic/GainSwellFilter.cpp index 2515e246..ebec2307 100644 --- a/ATK/Dynamic/GainSwellFilter.cpp +++ b/ATK/Dynamic/GainSwellFilter.cpp @@ -46,7 +46,7 @@ namespace ATK if(value == 0) return 1; DataType diff = 10 * fmath::log10(value); - return static_cast(std::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * ratio)); + return static_cast(fmath::pow(10, -(std::sqrt(diff*diff + softness) + diff) / 40 * ratio)); } template class GainSwellFilter; diff --git a/ATK/EQ/BesselFilter.cpp b/ATK/EQ/BesselFilter.cpp index f9483fe8..07e5f513 100644 --- a/ATK/EQ/BesselFilter.cpp +++ b/ATK/EQ/BesselFilter.cpp @@ -444,4 +444,12 @@ namespace ATK template class IIRFilter >; template class IIRFilter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; } diff --git a/ATK/EQ/ButterworthFilter.cpp b/ATK/EQ/ButterworthFilter.cpp index 14ed0160..e556e558 100644 --- a/ATK/EQ/ButterworthFilter.cpp +++ b/ATK/EQ/ButterworthFilter.cpp @@ -325,4 +325,12 @@ namespace ATK template class IIRFilter >; template class IIRFilter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; } diff --git a/ATK/EQ/Chebyshev1Filter.cpp b/ATK/EQ/Chebyshev1Filter.cpp index 64621678..a6af3d0b 100644 --- a/ATK/EQ/Chebyshev1Filter.cpp +++ b/ATK/EQ/Chebyshev1Filter.cpp @@ -402,4 +402,12 @@ namespace ATK template class IIRFilter >; template class IIRFilter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; } diff --git a/ATK/EQ/Chebyshev2Filter.cpp b/ATK/EQ/Chebyshev2Filter.cpp index e477e278..c128a7c7 100644 --- a/ATK/EQ/Chebyshev2Filter.cpp +++ b/ATK/EQ/Chebyshev2Filter.cpp @@ -401,4 +401,12 @@ namespace ATK template class IIRFilter >; template class IIRFilter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; } diff --git a/ATK/EQ/CustomIIRFilter.cpp b/ATK/EQ/CustomIIRFilter.cpp index c6f50b4c..ec77bd03 100644 --- a/ATK/EQ/CustomIIRFilter.cpp +++ b/ATK/EQ/CustomIIRFilter.cpp @@ -47,7 +47,11 @@ namespace ATK template class IIRFilter>; template class IIRFilter>; - template class IIRFilter>>; template class IIRFilter>>; + + template class IIRTDF2Filter>; + template class IIRTDF2Filter>; + template class IIRTDF2Filter>>; + template class IIRTDF2Filter>>; } diff --git a/ATK/EQ/IIRFilter.h b/ATK/EQ/IIRFilter.h index e985f48e..f8a6e61b 100644 --- a/ATK/EQ/IIRFilter.h +++ b/ATK/EQ/IIRFilter.h @@ -209,6 +209,82 @@ namespace ATK AlignedVector coefficients_out_4; }; + /// IIR filter template class. Transposed Direct Form II implementation + template + class ATK_EQ_EXPORT IIRTDF2Filter final : public Coefficients + { + public: + /// Simplify parent calls + typedef Coefficients Parent; + using typename Parent::DataType; + using Parent::converted_inputs; + using Parent::outputs; + using Parent::coefficients_in; + using Parent::coefficients_out; + using Parent::input_sampling_rate; + using Parent::output_sampling_rate; + using Parent::nb_input_ports; + using Parent::nb_output_ports; + + using Parent::in_order; + using Parent::out_order; + using Parent::input_delay; + using Parent::output_delay; + using Parent::setup; + protected: + mutable std::vector state; + public: + IIRTDF2Filter(std::size_t nb_channels = 1) + :Parent(nb_channels) + { + } + + /// Move constructor + IIRTDF2Filter(IIRTDF2Filter&& other) + :Parent(std::move(other)) + { + } + + void setup() override final + { + Parent::setup(); + input_delay = in_order; + output_delay = out_order; + state.resize(nb_input_ports * std::max(input_delay, output_delay), 0); + } + + virtual void process_impl(std::size_t size) const override final + { + assert(input_sampling_rate == output_sampling_rate); + + for(unsigned int channel = 0; channel < nb_input_ports; ++channel) + { + const DataType* ATK_RESTRICT input = converted_inputs[channel]; + DataType* ATK_RESTRICT output = outputs[channel]; + DataType* ATK_RESTRICT current_state = &state[channel * std::max(input_delay, output_delay)]; + + for(std::size_t i = 0; i < size; ++i) + { + output[i] = coefficients_in[in_order] * input[i] + current_state[0]; + for(size_t j = 0; j < state.size() - 1; ++j) + { + current_state[j] = state[j + 1]; + } + current_state[state.size() - 1] = 0; + + for(unsigned int j = 0; j < in_order; ++j) + { + current_state[j] += input[i] * coefficients_in[in_order - static_cast(j) - 1]; + } + for(unsigned int j = 0; j < out_order; ++j) + { + current_state[j] += output[i] * coefficients_out[out_order - static_cast(j) - 1]; + } + } + } + } + }; + } #endif diff --git a/ATK/EQ/LinkwitzRileyFilter.cpp b/ATK/EQ/LinkwitzRileyFilter.cpp index 0ce36ae4..df0a40b2 100644 --- a/ATK/EQ/LinkwitzRileyFilter.cpp +++ b/ATK/EQ/LinkwitzRileyFilter.cpp @@ -138,4 +138,9 @@ namespace ATK template class IIRFilter >; template class IIRFilter >; template class IIRFilter >; + + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; + template class IIRTDF2Filter >; } diff --git a/ATK/EQ/RIAAFilter.cpp b/ATK/EQ/RIAAFilter.cpp index c04e0ac0..9d8af412 100644 --- a/ATK/EQ/RIAAFilter.cpp +++ b/ATK/EQ/RIAAFilter.cpp @@ -69,32 +69,43 @@ namespace ATK coefficients_out.assign(out_order, 0); auto pi = boost::math::constants::pi(); - DataType t1 = pi / (input_sampling_rate * std::tan(pi / (75e-6 * input_sampling_rate))); - DataType t2 = pi / (input_sampling_rate * std::tan(pi / (318e-6 * input_sampling_rate))); - DataType t3 = pi / (input_sampling_rate * std::tan(pi / (3180e-6 * input_sampling_rate))); + DataType t1 = 1 / (input_sampling_rate * std::tan(pi / (75e-6 * input_sampling_rate))); + DataType t2 = 1 / (input_sampling_rate * std::tan(pi / (318e-6 * input_sampling_rate))); + DataType t3 = 1 / (input_sampling_rate * std::tan(pi / (3180e-6 * input_sampling_rate))); std::vector > z; std::vector > p; - DataType k = 75e-6/318e-6 / t2*(t1*t3); - p.push_back(-1/t2); - z.push_back(-1/t1); - z.push_back(-1/t3); + DataType k = 318e-6 / 75e-6 * t2 / (t1*t3); + z.push_back(-1 / t2); + p.push_back(-1 / t1); + p.push_back(-1 / t3); boost::math::tools::polynomial b({ 1 }); boost::math::tools::polynomial a({ 1 }); zpk_bilinear(input_sampling_rate, z, p, k); + z.back() = -.8; zpk2ba(input_sampling_rate, z, p, k, b, a); - auto in_size = std::min(std::size_t(in_order + 1), b.size()); + auto cut_frequency = 21000; + DataType c = std::tan(boost::math::constants::pi() * cut_frequency / input_sampling_rate); + DataType d = (1 + std::sqrt(static_cast(2.)) * c + c * c); + + boost::math::tools::polynomial b1 = { { c * c / d, 2 * c * c / d, c * c / d } }; + boost::math::tools::polynomial a1 = { { (1 - std::sqrt(static_cast(2.)) * c + c * c) / d , 2 * (c * c - 1) / d, 1 } }; + + b = b * a1; + a = a * b1; + + auto in_size = std::min(std::size_t(in_order + 1), a.size()); for (size_t i = 0; i < in_size; ++i) { - coefficients_in[i] = b[i]; + coefficients_in[i] = a[i] / b[b.size() - 1]; } - auto out_size = std::min(std::size_t(in_order), a.size() - 1); + auto out_size = std::min(std::size_t(in_order), b.size() - 1); for (size_t i = 0; i < out_size; ++i) { - coefficients_out[i] = -a[i]; + coefficients_out[i] = -b[i] / b[b.size() - 1]; } } diff --git a/ATK/EQ/RIAAFilter.h b/ATK/EQ/RIAAFilter.h index f16e8986..7c0726f4 100644 --- a/ATK/EQ/RIAAFilter.h +++ b/ATK/EQ/RIAAFilter.h @@ -24,8 +24,8 @@ namespace ATK using Parent::output_sampling_rate; using Parent::setup; protected: - const static unsigned int in_order=2; - const static unsigned int out_order=2; + const static unsigned int in_order = 2; + const static unsigned int out_order = 2; AlignedVector coefficients_in; AlignedVector coefficients_out; @@ -52,8 +52,8 @@ namespace ATK using Parent::output_sampling_rate; using Parent::setup; protected: - const static unsigned int in_order=2; - const static unsigned int out_order=2; + const static unsigned int in_order = 4; + const static unsigned int out_order = 4; AlignedVector coefficients_in; AlignedVector coefficients_out; diff --git a/ATK/EQ/RemezBasedFilter.cpp b/ATK/EQ/RemezBasedFilter.cpp index a34a609b..94f11b6f 100644 --- a/ATK/EQ/RemezBasedFilter.cpp +++ b/ATK/EQ/RemezBasedFilter.cpp @@ -22,17 +22,17 @@ namespace public: typedef typename ATK::TypedBaseFilter::AlignedVector AlignedVector; private: - const static unsigned int grid_size = 1024; // grid size, power of two better for FFT + const static std::size_t grid_size = 1024; // grid size, power of two better for FFT constexpr static DataType SN = 1e-8; - unsigned int M; + std::size_t M; std::vector grid; std::vector, std::pair> > target; /// Computed coefficients AlignedVector coeffs; /// Selected indices - std::vector indices; + std::vector indices; /// Weight function on the grid std::vector weights; /// Objective function on the grid @@ -43,11 +43,11 @@ namespace ATK::FFT fft_processor; public: - RemezBuilder(unsigned int order, const std::vector, std::pair> >& target) + RemezBuilder(std::size_t order, const std::vector, std::pair> >& target) :M(order / 2), target(target) { grid.resize(grid_size); - for(unsigned int i = 0; i < grid_size; ++i) + for(std::size_t i = 0; i < grid_size; ++i) { grid[i] = i * boost::math::constants::pi() / grid_size; } @@ -83,7 +83,7 @@ namespace } } int flag = -1; - for (unsigned int i = 0; i < M + 2; ++i) + for (std::size_t i = 0; i < M + 2; ++i) { s[i] = flag; flag = -flag; @@ -91,11 +91,11 @@ namespace indices = set_starting_conditions(); } - std::vector set_starting_conditions() const + std::vector set_starting_conditions() const { - std::vector indices; + std::vector indices; - std::vector valid_indices; + std::vector valid_indices; for (std::size_t i = 0; i < grid_size; ++i) { if (weights[i] != 0) @@ -104,9 +104,9 @@ namespace } } - for (unsigned int i = 0; i < M + 2; ++i) + for (std::size_t i = 0; i < M + 2; ++i) { - indices.push_back(valid_indices[std::round(valid_indices.size() / (M + 4.) * (i + 1))]); + indices.push_back(valid_indices[std::lround(valid_indices.size() / (M + 4.) * (i + 1))]); } return indices; @@ -123,26 +123,26 @@ namespace while(true) { Eigen::Matrix A(M + 2, M + 2); - for (unsigned int i = 0; i < M + 2; ++i) + for (std::size_t i = 0; i < M + 2; ++i) { - for (unsigned int j = 0; j < M + 1; ++j) + for (std::size_t j = 0; j < M + 1; ++j) { A(i, j) = std::cos(grid[indices[i]] * j); } } - for (unsigned int i = 0; i < M + 2; ++i) + for (std::size_t i = 0; i < M + 2; ++i) { A(i, M + 1) = s[i] / weights[indices[i]]; } Eigen::Matrix b(M + 2, 1); - for (unsigned int i = 0; i < M + 2; ++i) + for (std::size_t i = 0; i < M + 2; ++i) { b(i) = objective[indices[i]]; } Eigen::Matrix x = A.colPivHouseholderQr().solve(b); - for (unsigned int i = 0; i < M; ++i) + for (std::size_t i = 0; i < M; ++i) { coeffs[i] = coeffs[2 * M - i] = x[M - i] / 2; } @@ -197,9 +197,9 @@ namespace } // Finds min and max - std::vector locmax(const std::vector& data) const + std::vector locmax(const std::vector& data) const { - std::vector v; + std::vector v; std::vector temp1; std::vector temp2; @@ -242,9 +242,9 @@ namespace return v; } - void filter_SN(DataType delta, std::vector& indices, const std::vector& err) const + void filter_SN(DataType delta, std::vector& indices, const std::vector& err) const { - std::vector new_indices; + std::vector new_indices; for (auto indice : indices) { @@ -257,9 +257,9 @@ namespace indices = std::move(new_indices); } - std::vector etap(const std::vector& data) const + std::vector etap(const std::vector& data) const { - std::vector v; + std::vector v; auto xe = data[0]; std::size_t xv = 0; for (std::size_t i = 1; i < data.size(); ++i) @@ -283,7 +283,7 @@ namespace return v; } - void filter_monotony(std::vector& indices, const std::vector& err) const + void filter_monotony(std::vector& indices, const std::vector& err) const { std::vector filtered_err; for (auto indice : indices) @@ -292,8 +292,8 @@ namespace } auto selected_indices = etap(filtered_err); - std::vector new_indices; - for (unsigned int i = 0; i < M + 2; ++i) + std::vector new_indices; + for (std::size_t i = 0; i < M + 2; ++i) { new_indices.push_back(indices[selected_indices[i]]); } @@ -330,7 +330,7 @@ namespace ATK } template - void RemezBasedCoefficients::set_order(unsigned int order) + void RemezBasedCoefficients::set_order(std::size_t order) { if(order % 2 == 1) { diff --git a/ATK/EQ/RemezBasedFilter.h b/ATK/EQ/RemezBasedFilter.h index fc300f07..efc3bb3d 100644 --- a/ATK/EQ/RemezBasedFilter.h +++ b/ATK/EQ/RemezBasedFilter.h @@ -29,7 +29,7 @@ namespace ATK */ std::vector, std::pair > > target; /// Oarger of the polynomial we can use - unsigned int in_order; + std::size_t in_order; /// Launches the computation void setup(); /// Final coefficients @@ -48,7 +48,7 @@ namespace ATK const std::vector, std::pair > >& get_template() const; /// Order of the FIR filter - void set_order(unsigned int order); + void set_order(std::size_t order); }; } diff --git a/ATK/EQ/helpers.h b/ATK/EQ/helpers.h index 3fcfff96..f2127fe0 100644 --- a/ATK/EQ/helpers.h +++ b/ATK/EQ/helpers.h @@ -122,7 +122,7 @@ namespace /// Apply a bilinear transform on z, p, k template - void zpk_bilinear(int fs, std::vector >& z, std::vector >& p, DataType& k) + void zpk_bilinear(std::size_t fs, std::vector >& z, std::vector >& p, DataType& k) { auto z_size = z.size(); auto p_size = p.size(); @@ -154,7 +154,7 @@ namespace /// Transforms the z, p, k coefficients in b, a form template - void zpk2ba(int fs, const std::vector >& z, const std::vector >& p, DataType k, boost::math::tools::polynomial& b, boost::math::tools::polynomial& a) + void zpk2ba(std::size_t fs, const std::vector >& z, const std::vector >& p, DataType k, boost::math::tools::polynomial& b, boost::math::tools::polynomial& a) { auto z_size = z.size(); auto p_size = p.size(); diff --git a/ATK/IO/OutWavFilter.cpp b/ATK/IO/OutWavFilter.cpp index 5cb003d2..9c0bc8b8 100644 --- a/ATK/IO/OutWavFilter.cpp +++ b/ATK/IO/OutWavFilter.cpp @@ -79,11 +79,11 @@ namespace ATK std::strncpy(format.FormatBlocID, "fmt ", 4); std::strncpy(data.DataBlocID, "data", 4); format.AudioFormat = WavTraits::get_wav_type(); - format.Frequence = input_sampling_rate; + format.Frequence = static_cast(input_sampling_rate); format.BitsPerSample = sizeof(DataType)* 8; format.BytePerBloc = format.NbChannels * format.BitsPerSample / 8; - format.BytePerSec = format.BytePerBloc * input_sampling_rate; - format.NbChannels = nb_input_ports; + format.BytePerSec = static_cast(format.BytePerBloc * input_sampling_rate); + format.NbChannels = static_cast(nb_input_ports); std::size_t total_size = wavstream.tellp(); std::size_t bloc_size = sizeof(WavFormat); diff --git a/ATK/Preamplifier/KorenTriodeFunction.h b/ATK/Preamplifier/KorenTriodeFunction.h index 51ec267e..b3885cd8 100644 --- a/ATK/Preamplifier/KorenTriodeFunction.h +++ b/ATK/Preamplifier/KorenTriodeFunction.h @@ -52,7 +52,7 @@ namespace ATK { if (muVbeVce > 0) { - return K * mu * 1.5 * muVbeVce2; + return K * mu * 1.5f * muVbeVce2; } return 0; } @@ -62,7 +62,7 @@ namespace ATK { if (muVbeVce > 0) { - return K * 1.5 * muVbeVce2; + return K * 1.5f * muVbeVce2; } return 0; } diff --git a/ATK/Preamplifier/LeachTriodeFunction.h b/ATK/Preamplifier/LeachTriodeFunction.h index eadcc9a6..511d4134 100644 --- a/ATK/Preamplifier/LeachTriodeFunction.h +++ b/ATK/Preamplifier/LeachTriodeFunction.h @@ -37,7 +37,7 @@ namespace ATK { if (mu * Vbe + Vce > 0) { - return K * mu * 1.5 * std::sqrt(mu * Vbe + Vce); + return K * mu * 1.5f * std::sqrt(mu * Vbe + Vce); } return 0; } @@ -47,7 +47,7 @@ namespace ATK { if (mu * Vbe + Vce > 0) { - return K * 1.5 * std::sqrt(mu * Vbe + Vce); + return K * 1.5f * std::sqrt(mu * Vbe + Vce); } return 0; } diff --git a/ATK/Preamplifier/ModifiedMunroPiazzaTriodeFunction.h b/ATK/Preamplifier/ModifiedMunroPiazzaTriodeFunction.h index ae7c25c2..9a47c54f 100644 --- a/ATK/Preamplifier/ModifiedMunroPiazzaTriodeFunction.h +++ b/ATK/Preamplifier/ModifiedMunroPiazzaTriodeFunction.h @@ -75,7 +75,7 @@ namespace ATK { if (E1 > 0 && Vbe >= 0 && Vbe <= 5) { - return Kg * Vce / 5 * Kvb * sqrt_E1 * 1.5; + return Kg * Vce / 5 * Kvb * sqrt_E1 * 1.5f; } return 0; } @@ -85,7 +85,7 @@ namespace ATK { if (E1 > 0 && Vbe >= 0 && Vbe <= 5) { - return Kvb * sqrt_E1 * E1 / 5 + Vce / 5 * Kvb * sqrt_E1 * 1.5; + return Kvb * sqrt_E1 * E1 / 5 + Vce / 5 * Kvb * sqrt_E1 * 1.5f; } return 0; } diff --git a/ATK/Preamplifier/MunroPiazzaTriodeFunction.h b/ATK/Preamplifier/MunroPiazzaTriodeFunction.h index 79118353..cb4b116e 100644 --- a/ATK/Preamplifier/MunroPiazzaTriodeFunction.h +++ b/ATK/Preamplifier/MunroPiazzaTriodeFunction.h @@ -39,7 +39,7 @@ namespace ATK { if(mu + Vbe > 0) { - return K * 1.5 * std::sqrt(mu + Vbe); + return K * 1.5f * std::sqrt(mu + Vbe); } return 0; } @@ -67,7 +67,7 @@ namespace ATK auto E1 = Kp + Vce + Kg * Vbe; if (E1 > 0 && Vbe >= 0 && Vbe <= 5) { - return Kg * Vce / 5 * Kvb * std::sqrt(E1) * 1.5; + return Kg * Vce / 5 * Kvb * std::sqrt(E1) * 1.5f; } return 0; } @@ -78,7 +78,7 @@ namespace ATK auto E1 = Kp + Vce + Kg * Vbe; if (E1 > 0 && Vbe >= 0 && Vbe <= 5) { - return Kvb * std::sqrt(E1) * E1 / 5 + Vce / 5 * Kvb * std::sqrt(E1) * 1.5; + return Kvb * std::sqrt(E1) * E1 / 5 + Vce / 5 * Kvb * std::sqrt(E1) * 1.5f; } return 0; } diff --git a/ATK/Tools/VolumeFilter.cpp b/ATK/Tools/VolumeFilter.cpp index 261b54cc..195ddf72 100644 --- a/ATK/Tools/VolumeFilter.cpp +++ b/ATK/Tools/VolumeFilter.cpp @@ -28,7 +28,7 @@ namespace ATK template void VolumeFilter::set_volume_db(double volume_db) { - set_volume(std::pow(10., volume_db/20)); + set_volume(static_cast(std::pow(10., volume_db/20))); } template diff --git a/ATK/Utility/FFT.cpp b/ATK/Utility/FFT.cpp index adf5c4bf..d671e4cd 100644 --- a/ATK/Utility/FFT.cpp +++ b/ATK/Utility/FFT.cpp @@ -135,7 +135,7 @@ namespace ATK void process(const DataType_* input, std::size_t input_size, std::size_t size) const { - double factor = size; + double factor = static_cast(size); #if ATK_USE_FFTW == 1 for(std::size_t j = 0; j < std::min(input_size, size); ++j) { @@ -221,7 +221,7 @@ namespace ATK void process(const std::complex* input, std::size_t input_size, std::size_t size) const { - double factor = size; + double factor = static_cast(size); #if ATK_USE_FFTW == 1 for (std::size_t j = 0; j < std::min(input_size, size); ++j) { diff --git a/CMakeLists.txt b/CMakeLists.txt index b2b6aa34..1bb7460b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(AudioTK) SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake) set_property(GLOBAL PROPERTY USE_FOLDERS ON) -set(ATK_VERSION 2.1.0) +set(ATK_VERSION 2.1.1) option(ENABLE_TESTS "Enable tests generation" ON) option(ENABLE_PROFILE_INFO "Enable profile info" OFF) @@ -351,6 +351,7 @@ ENDMACRO(SOURCE_GROUP_BY_FOLDER) add_subdirectory(ATK) if(ENABLE_TESTS) find_package(Boost REQUIRED unit_test_framework system) + ADD_DEFINITIONS("-DBOOST_ALL_NO_LIB") add_subdirectory(tests) add_subdirectory(profiling) endif(ENABLE_TESTS) diff --git a/Doxyfile b/Doxyfile index 79a22898..d97ac9cb 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "Audio Toolkit" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 2.1.0 +PROJECT_NUMBER = 2.1.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/Python/Dynamic/Dynamic.cpp b/Python/Dynamic/Dynamic.cpp index 2727b260..16d5e732 100644 --- a/Python/Dynamic/Dynamic.cpp +++ b/Python/Dynamic/Dynamic.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -151,6 +152,8 @@ PYBIND11_PLUGIN(PythonDynamic) { populate_ColoredGainFilter>(m, "DoubleTempGainColoredExpanderFilter"); populate_MaxColoredGainFilter>(m, "FloatTempGainMaxColoredExpanderFilter"); populate_MaxColoredGainFilter>(m, "DoubleTempGainMaxColoredExpanderFilter"); + populate_MaxGainFilter>(m, "FloatTempGainMaxCompressorFilter"); + populate_MaxGainFilter>(m, "DoubleTempGainMaxCompressorFilter"); populate_MaxGainFilter>(m, "FloatTempGainMaxExpanderFilter"); populate_MaxGainFilter>(m, "DoubleTempGainMaxExpanderFilter"); @@ -160,6 +163,8 @@ PYBIND11_PLUGIN(PythonDynamic) { populate_GainFilter>(m, "DoubleGainColoredExpanderFilter"); populate_GainFilter>(m, "FloatGainMaxColoredExpanderFilter"); populate_GainFilter>(m, "DoubleGainMaxColoredExpanderFilter"); + populate_GainFilter>(m, "FloatGainMaxCompressorFilter"); + populate_GainFilter>(m, "DoubleGainMaxCompressorFilter"); populate_GainFilter>(m, "FloatGainMaxExpanderFilter"); populate_GainFilter>(m, "DoubleGainMaxExpanderFilter"); diff --git a/README.md b/README.md index 7cd9348a..1c5fbc4c 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,14 @@ and output sampling rates are also identical. Audio Toolkit is published under the BSD license. ## Changelog +### 2.1.1 +* Added a Gain Max Compressor filter with wrappers +* Added a dryrun call on BaseFilter to setup maximum sizes on a pipeline +* Added a IIR TDF2 (Transposed Direct Form 2) filter implementation (no Python wrappers for now) +* Fixed max gain reduction in the expanders to use 20 log10 instead of 10 log10 (as it is applied to the amplitude and not power) +* Fix a bug in OutCircularPointerFilter with offset handling +* Fix a bug in RIAA inverse filters + ### 2.1.0 * Added a config file for CMake * Rewrote the Python wrappers to use pybind11 instead of SWIG diff --git a/doc/documentation.md b/doc/documentation.md index 23dfa35d..05336d1d 100644 --- a/doc/documentation.md +++ b/doc/documentation.md @@ -138,10 +138,11 @@ The *Dynamic* module contains filters enabling compressor construction. * **GainCompressorFilter** is a filter that changes an input signal (a gain) like a compressor does * **GainExpanderFilter** is a filter that changes an input signal (a gain) like an expander/noise gate does * **GainLimiterFilter** is a filter that changes an input signal (a gain) like a limiter does - * **GainSwellFilter** is a filter that changes an input signal (a gain) like aan auto swell does + * **GainSwellFilter** is a filter that changes an input signal (a gain) like an auto swell does * **GainColoredCompressorFilter** is a filter that changes an input signal (a gain) like a compressor does with an additional color component - * **GainColoredExpanderFilter** is a filter that changes an input signal (a gain) like am expander/noise gate does with an additional color component - * **GainMaxExpanderFilter** is a filter that changes an input signal (a gain) like am expander/noise gate does with a maximum gain reduction + * **GainColoredExpanderFilter** is a filter that changes an input signal (a gain) like an expander/noise gate does with an additional color component + * **GainMaxCompressorFilter** is a filter that changes an input signal (a gain) like a compressor gate does with a maximum gain reduction + * **GainMaxExpanderFilter** is a filter that changes an input signal (a gain) like an expander/noise gate does with a maximum gain reduction * **PowerFilter** is a filter that outputs an AR(1)-filtered version of the squared input signal * **RelativePowerFilter** is a filter that outputs the squared input signal divided by an AR(1)-filtered version of the squared input signal diff --git a/tests/EQ/BesselFilter.cpp b/tests/EQ/BesselFilter.cpp index 2d07cf50..71d32ce1 100644 --- a/tests/EQ/BesselFilter.cpp +++ b/tests/EQ/BesselFilter.cpp @@ -21,7 +21,7 @@ BOOST_AUTO_TEST_CASE( IIRFilter_BesselLowPassCoefficients_1k_test ) generator.set_output_sampling_rate(1024*64); generator.set_amplitude(1); generator.set_frequency(1000); - + ATK::IIRFilter > filter; filter.set_input_sampling_rate(1024*64); filter.set_output_sampling_rate(1024*64); @@ -44,6 +44,35 @@ BOOST_AUTO_TEST_CASE( IIRFilter_BesselLowPassCoefficients_1k_test ) checker.process(PROCESSSIZE); } +BOOST_AUTO_TEST_CASE( IIRTDF2Filter_BesselLowPassCoefficients_1k_test ) +{ + ATK::SimpleSinusGeneratorFilter generator; + generator.set_output_sampling_rate(1024*64); + generator.set_amplitude(1); + generator.set_frequency(1000); + + ATK::IIRTDF2Filter > filter; + filter.set_input_sampling_rate(1024*64); + filter.set_output_sampling_rate(1024*64); + filter.set_cut_frequency(100); + filter.set_order(3); + + ATK::FFTCheckerFilter checker; + checker.set_input_sampling_rate(1024*64); + std::vector > frequency_checks; + frequency_checks.push_back(std::make_pair(100, 0)); + frequency_checks.push_back(std::make_pair(1000, 0.03150874916131525)); + frequency_checks.push_back(std::make_pair(10000, 0)); + checker.set_checks(frequency_checks); + + checker.set_input_port(0, &filter, 0); + filter.set_input_port(0, &generator, 0); + + filter.process(1024*64); + + checker.process(PROCESSSIZE); +} + BOOST_AUTO_TEST_CASE( IIRFilter_BesselLowPassCoefficients_100_test ) { ATK::SimpleSinusGeneratorFilter generator; diff --git a/tests/Python/Dynamic/PyATKDynamic_compressorgain_test.py b/tests/Python/Dynamic/PyATKDynamic_compressorgain_test.py index 0a6174bd..3886a9d2 100644 --- a/tests/Python/Dynamic/PyATKDynamic_compressorgain_test.py +++ b/tests/Python/Dynamic/PyATKDynamic_compressorgain_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python from ATK.Core import DoubleInPointerFilter, DoubleOutPointerFilter -from ATK.Dynamic import DoubleGainCompressorFilter +from ATK.Dynamic import DoubleGainCompressorFilter, DoubleGainMaxCompressorFilter from ATK.Tools import DoubleApplyGainFilter sample_rate = 96000 @@ -36,6 +36,37 @@ def filter(input, ratio=4, threshold=1, softness=1): return output +def max_filter(input, ratio=4, threshold=1, softness=1, max_reduction=0.1): + import numpy as np + output = np.zeros(input.shape, dtype=np.float64) + + input2 = input**2 + in2filter = DoubleInPointerFilter(input2, False) + in2filter.input_sampling_rate = sample_rate + + infilter = DoubleInPointerFilter(input, False) + infilter.input_sampling_rate = sample_rate + + gainfilter = DoubleGainMaxCompressorFilter(1) + gainfilter.input_sampling_rate = sample_rate + gainfilter.set_input_port(0, in2filter, 0) + gainfilter.threshold = threshold + gainfilter.ratio = ratio + gainfilter.softness = softness + gainfilter.max_reduction = max_reduction + + applygainfilter = DoubleApplyGainFilter(1) + applygainfilter.input_sampling_rate = sample_rate + applygainfilter.set_input_port(0, gainfilter, 0) + applygainfilter.set_input_port(1, infilter, 0) + + outfilter = DoubleOutPointerFilter(output, False) + outfilter.input_sampling_rate = sample_rate + outfilter.set_input_port(0, applygainfilter, 0) + outfilter.process(input.shape[1]) + + return output + def compressor_out_0_5_1_1_test(): import numpy as np from numpy.testing import assert_almost_equal @@ -120,6 +151,18 @@ def compressor_out_10_01_10_test(): out = filter(x, 10, .1, 10) assert_almost_equal(out, ref) +def max_compressor_out_4_01_1__001_test(): + import numpy as np + from numpy.testing import assert_almost_equal + + import os + dirname = os.path.dirname(__file__) + + x = np.fromfile(dirname + os.sep + "input_compgain.dat", dtype=np.float64).reshape(1, -1) + ref = np.fromfile(dirname + os.sep + "output_maxcompgain_4_01_1__01.dat", dtype=np.float64).reshape(1, -1) + out = max_filter(x, 4, .01, 1, .01) + assert_almost_equal(out, ref) + if __name__ == "__main__": import numpy as np import matplotlib.pyplot as plt @@ -142,14 +185,17 @@ def compressor_out_10_01_10_test(): out_10_01_1.tofile("output_compgain_10_01_1.dat") out_10_01_10 = filter(x, 10, .1, 10) out_10_01_10.tofile("output_compgain_10_01_10.dat") + max_out_4_01_1 = max_filter(x, 4, .01, 1, .01) + max_out_4_01_1.tofile("output_maxcompgain_4_01_1__01.dat") + plt.figure() - plt.loglog(x[0], out_0_5_1_1[0], label="ratio(.5), threshold(1), softness(1)") plt.loglog(x[0], out_2_1_1[0], label="ratio(2), threshold(1), softness(1)") plt.loglog(x[0], out_4_1_1[0], label="ratio(4), threshold(1), softness(1)") plt.loglog(x[0], out_8_1_1[0], label="ratio(8), threshold(1), softness(1)") plt.loglog(x[0], out_10_01_001[0], label="ratio(10), threshold(0.1), softness(1e-2)") plt.loglog(x[0], out_10_01_1[0], label="ratio(10), threshold(0.1), softness(1)") plt.loglog(x[0], out_10_01_10[0], label="ratio(10), threshold(0.1), softness(10)") + plt.loglog(x[0], max_out_4_01_1[0], label="ratio(4), threshold(0.1), softness(1), max reduction(0.01)") plt.title("Compressor gain") plt.legend(loc=4) plt.grid() diff --git a/tests/Python/Dynamic/PyATKDynamic_expandergain_test.py b/tests/Python/Dynamic/PyATKDynamic_expandergain_test.py index a629840d..86629508 100644 --- a/tests/Python/Dynamic/PyATKDynamic_expandergain_test.py +++ b/tests/Python/Dynamic/PyATKDynamic_expandergain_test.py @@ -12,25 +12,25 @@ def filter(input, ratio=4, threshold=1, softness=1): input2 = input**2 in2filter = DoubleInPointerFilter(input2, False) - in2filter.set_input_sampling_rate(sample_rate) + in2filter.input_sampling_rate = sample_rate infilter = DoubleInPointerFilter(input, False) - infilter.set_input_sampling_rate(sample_rate) + infilter.input_sampling_rate = sample_rate gainfilter = DoubleGainExpanderFilter(1) - gainfilter.set_input_sampling_rate(sample_rate) + gainfilter.input_sampling_rate = sample_rate gainfilter.set_input_port(0, in2filter, 0) - gainfilter.set_threshold(threshold) - gainfilter.set_ratio(ratio) - gainfilter.set_softness(softness) + gainfilter.threshold = threshold + gainfilter.ratio = ratio + gainfilter.softness = softness applygainfilter = DoubleApplyGainFilter(1) - applygainfilter.set_input_sampling_rate(sample_rate) + applygainfilter.input_sampling_rate = sample_rate applygainfilter.set_input_port(0, gainfilter, 0) applygainfilter.set_input_port(1, infilter, 0) outfilter = DoubleOutPointerFilter(output, False) - outfilter.set_input_sampling_rate(sample_rate) + outfilter.input_sampling_rate = sample_rate outfilter.set_input_port(0, applygainfilter, 0) outfilter.process(input.shape[1]) @@ -42,31 +42,115 @@ def max_filter(input, ratio=4, threshold=1, softness=1, max_reduction=0.1): input2 = input**2 in2filter = DoubleInPointerFilter(input2, False) - in2filter.set_input_sampling_rate(sample_rate) + in2filter.input_sampling_rate = sample_rate infilter = DoubleInPointerFilter(input, False) - infilter.set_input_sampling_rate(sample_rate) + infilter.input_sampling_rate = sample_rate gainfilter = DoubleGainMaxExpanderFilter(1) - gainfilter.set_input_sampling_rate(sample_rate) + gainfilter.input_sampling_rate = sample_rate gainfilter.set_input_port(0, in2filter, 0) - gainfilter.set_threshold(threshold) - gainfilter.set_ratio(ratio) - gainfilter.set_softness(softness) - gainfilter.set_max_reduction(max_reduction) + gainfilter.threshold = threshold + gainfilter.ratio = ratio + gainfilter.softness = softness + gainfilter.max_reduction = max_reduction applygainfilter = DoubleApplyGainFilter(1) - applygainfilter.set_input_sampling_rate(sample_rate) + applygainfilter.input_sampling_rate = sample_rate applygainfilter.set_input_port(0, gainfilter, 0) applygainfilter.set_input_port(1, infilter, 0) outfilter = DoubleOutPointerFilter(output, False) - outfilter.set_input_sampling_rate(sample_rate) + outfilter.input_sampling_rate = sample_rate outfilter.set_input_port(0, applygainfilter, 0) outfilter.process(input.shape[1]) return output +def expander_out_2_1_1_test(): + import numpy as np + from numpy.testing import assert_almost_equal + + import os + dirname = os.path.dirname(__file__) + + x = np.fromfile(dirname + os.sep + "input_expgain.dat", dtype=np.float64).reshape(1, -1) + ref = np.fromfile(dirname + os.sep + "output_expgain_2_1_1.dat", dtype=np.float64).reshape(1, -1) + out = filter(x, 2, 1, 1) + assert_almost_equal(out, ref) + +def expander_out_4_1_1_test(): + import numpy as np + from numpy.testing import assert_almost_equal + + import os + dirname = os.path.dirname(__file__) + + x = np.fromfile(dirname + os.sep + "input_expgain.dat", dtype=np.float64).reshape(1, -1) + ref = np.fromfile(dirname + os.sep + "output_expgain_4_1_1.dat", dtype=np.float64).reshape(1, -1) + out = filter(x, 4, 1, 1) + assert_almost_equal(out, ref) + +def expander_out_8_1_1_test(): + import numpy as np + from numpy.testing import assert_almost_equal + + import os + dirname = os.path.dirname(__file__) + + x = np.fromfile(dirname + os.sep + "input_expgain.dat", dtype=np.float64).reshape(1, -1) + ref = np.fromfile(dirname + os.sep + "output_expgain_8_1_1.dat", dtype=np.float64).reshape(1, -1) + out = filter(x, 8, 1, 1) + assert_almost_equal(out, ref) + +def expander_out_10_01_001_test(): + import numpy as np + from numpy.testing import assert_almost_equal + + import os + dirname = os.path.dirname(__file__) + + x = np.fromfile(dirname + os.sep + "input_expgain.dat", dtype=np.float64).reshape(1, -1) + ref = np.fromfile(dirname + os.sep + "output_expgain_10_01_001.dat", dtype=np.float64).reshape(1, -1) + out = filter(x, 10, .1, 0.01) + assert_almost_equal(out, ref) + +def expander_out_10_01_10_test(): + import numpy as np + from numpy.testing import assert_almost_equal + + import os + dirname = os.path.dirname(__file__) + + x = np.fromfile(dirname + os.sep + "input_expgain.dat", dtype=np.float64).reshape(1, -1) + ref = np.fromfile(dirname + os.sep + "output_expgain_10_01_10.dat", dtype=np.float64).reshape(1, -1) + out = filter(x, 10, .1, 10) + assert_almost_equal(out, ref) + +def expander_out_10_01_1_test(): + import numpy as np + from numpy.testing import assert_almost_equal + + import os + dirname = os.path.dirname(__file__) + + x = np.fromfile(dirname + os.sep + "input_expgain.dat", dtype=np.float64).reshape(1, -1) + ref = np.fromfile(dirname + os.sep + "output_expgain_10_01_1.dat", dtype=np.float64).reshape(1, -1) + out = filter(x, 10, .1, 1) + assert_almost_equal(out, ref) + +def maxexpander_out_4_1_1__001_test(): + import numpy as np + from numpy.testing import assert_almost_equal + + import os + dirname = os.path.dirname(__file__) + + x = np.fromfile(dirname + os.sep + "input_expgain.dat", dtype=np.float64).reshape(1, -1) + ref = np.fromfile(dirname + os.sep + "output_maxexpgain_4_1_1__001.dat", dtype=np.float64).reshape(1, -1) + out = max_filter(x, 4, 1, 1, .001) + assert_almost_equal(out, ref) + if __name__ == "__main__": import numpy as np import matplotlib.pyplot as plt @@ -74,16 +158,22 @@ def max_filter(input, ratio=4, threshold=1, softness=1, max_reduction=0.1): size = 1000 x = np.arange(size, dtype=np.float64).reshape(1, -1) / 100 - - np.savetxt("input.txt", x) + x.tofile("input_expgain.dat") out_2_1_1 = filter(x, 2, 1, 1) + out_2_1_1.tofile("output_expgain_2_1_1.dat") out_4_1_1 = filter(x, 4, 1, 1) + out_4_1_1.tofile("output_expgain_4_1_1.dat") out_8_1_1 = filter(x, 8, 1, 1) + out_8_1_1.tofile("output_expgain_8_1_1.dat") out_10_01_001 = filter(x, 10, .1, 0.01) + out_10_01_001.tofile("output_expgain_10_01_001.dat") out_10_01_1 = filter(x, 10, .1, 1) + out_10_01_1.tofile("output_expgain_10_01_1.dat") out_10_01_10 = filter(x, 10, .1, 10) + out_10_01_10.tofile("output_expgain_10_01_10.dat") max_out_4_1_1 = max_filter(x, 4, 1, 1, .001) + max_out_4_1_1.tofile("output_maxexpgain_4_1_1__001.dat") plt.figure() plt.loglog(x[0], out_2_1_1[0], label="ratio(2), threshold(1), softness(1)") diff --git a/tests/Python/Dynamic/input_expgain.dat b/tests/Python/Dynamic/input_expgain.dat new file mode 100644 index 00000000..936db2a4 Binary files /dev/null and b/tests/Python/Dynamic/input_expgain.dat differ diff --git a/tests/Python/Dynamic/output_compgain_0_5_1_1.dat b/tests/Python/Dynamic/output_compgain_0_5_1_1.dat index 30fbb37c..47261f30 100644 Binary files a/tests/Python/Dynamic/output_compgain_0_5_1_1.dat and b/tests/Python/Dynamic/output_compgain_0_5_1_1.dat differ diff --git a/tests/Python/Dynamic/output_compgain_10_01_001.dat b/tests/Python/Dynamic/output_compgain_10_01_001.dat index 11238a3d..da619db2 100644 Binary files a/tests/Python/Dynamic/output_compgain_10_01_001.dat and b/tests/Python/Dynamic/output_compgain_10_01_001.dat differ diff --git a/tests/Python/Dynamic/output_compgain_10_01_1.dat b/tests/Python/Dynamic/output_compgain_10_01_1.dat index d6c0b589..7c83bd05 100644 Binary files a/tests/Python/Dynamic/output_compgain_10_01_1.dat and b/tests/Python/Dynamic/output_compgain_10_01_1.dat differ diff --git a/tests/Python/Dynamic/output_compgain_10_01_10.dat b/tests/Python/Dynamic/output_compgain_10_01_10.dat index 5b4f0c98..cf8d79bc 100644 Binary files a/tests/Python/Dynamic/output_compgain_10_01_10.dat and b/tests/Python/Dynamic/output_compgain_10_01_10.dat differ diff --git a/tests/Python/Dynamic/output_compgain_2_1_1.dat b/tests/Python/Dynamic/output_compgain_2_1_1.dat index 83025508..fb8b3ad8 100644 Binary files a/tests/Python/Dynamic/output_compgain_2_1_1.dat and b/tests/Python/Dynamic/output_compgain_2_1_1.dat differ diff --git a/tests/Python/Dynamic/output_compgain_4_1_1.dat b/tests/Python/Dynamic/output_compgain_4_1_1.dat index 84ba6810..5ce82eff 100644 Binary files a/tests/Python/Dynamic/output_compgain_4_1_1.dat and b/tests/Python/Dynamic/output_compgain_4_1_1.dat differ diff --git a/tests/Python/Dynamic/output_compgain_8_1_1.dat b/tests/Python/Dynamic/output_compgain_8_1_1.dat index 32121df7..efcd51a6 100644 Binary files a/tests/Python/Dynamic/output_compgain_8_1_1.dat and b/tests/Python/Dynamic/output_compgain_8_1_1.dat differ diff --git a/tests/Python/Dynamic/output_expgain_10_01_001.dat b/tests/Python/Dynamic/output_expgain_10_01_001.dat new file mode 100644 index 00000000..f17d6c30 Binary files /dev/null and b/tests/Python/Dynamic/output_expgain_10_01_001.dat differ diff --git a/tests/Python/Dynamic/output_expgain_10_01_1.dat b/tests/Python/Dynamic/output_expgain_10_01_1.dat new file mode 100644 index 00000000..2b7f9efe Binary files /dev/null and b/tests/Python/Dynamic/output_expgain_10_01_1.dat differ diff --git a/tests/Python/Dynamic/output_expgain_10_01_10.dat b/tests/Python/Dynamic/output_expgain_10_01_10.dat new file mode 100644 index 00000000..196704f1 Binary files /dev/null and b/tests/Python/Dynamic/output_expgain_10_01_10.dat differ diff --git a/tests/Python/Dynamic/output_expgain_2_1_1.dat b/tests/Python/Dynamic/output_expgain_2_1_1.dat new file mode 100644 index 00000000..aaf06eb1 Binary files /dev/null and b/tests/Python/Dynamic/output_expgain_2_1_1.dat differ diff --git a/tests/Python/Dynamic/output_expgain_4_1_1.dat b/tests/Python/Dynamic/output_expgain_4_1_1.dat new file mode 100644 index 00000000..fdb232be Binary files /dev/null and b/tests/Python/Dynamic/output_expgain_4_1_1.dat differ diff --git a/tests/Python/Dynamic/output_expgain_8_1_1.dat b/tests/Python/Dynamic/output_expgain_8_1_1.dat new file mode 100644 index 00000000..50f69fff Binary files /dev/null and b/tests/Python/Dynamic/output_expgain_8_1_1.dat differ diff --git a/tests/Python/Dynamic/output_maxcompgain_4_01_1__01.dat b/tests/Python/Dynamic/output_maxcompgain_4_01_1__01.dat new file mode 100644 index 00000000..0394a15c Binary files /dev/null and b/tests/Python/Dynamic/output_maxcompgain_4_01_1__01.dat differ diff --git a/tests/Python/Dynamic/output_maxexpgain_4_1_1__001.dat b/tests/Python/Dynamic/output_maxexpgain_4_1_1__001.dat new file mode 100644 index 00000000..bf82e644 Binary files /dev/null and b/tests/Python/Dynamic/output_maxexpgain_4_1_1__001.dat differ diff --git a/update_version.py b/update_version.py index ed754e19..3eee125f 100755 --- a/update_version.py +++ b/update_version.py @@ -31,6 +31,7 @@ def update_changelog(new_version): sys.stdout.write("### %s\n\n" % new_version) if __name__ == "__main__": + update_cmakelist(sys.argv[1]) update_appveyor(sys.argv[1]) update_doxygen(sys.argv[1]) update_changelog(sys.argv[1])