From f571ac37ef8e2c78809cc16a63f344d2017f8d90 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 26 Feb 2020 21:31:00 +0100 Subject: [PATCH] Add the HIIR downsampler --- src/external/hiir/Downsampler2xFpu.h | 115 +++++++++ src/external/hiir/Downsampler2xFpu.hpp | 303 ++++++++++++++++++++++ src/external/hiir/Downsampler2xNeon.h | 126 ++++++++++ src/external/hiir/Downsampler2xNeon.hpp | 299 ++++++++++++++++++++++ src/external/hiir/Downsampler2xSse.h | 126 ++++++++++ src/external/hiir/Downsampler2xSse.hpp | 322 ++++++++++++++++++++++++ 6 files changed, 1291 insertions(+) create mode 100644 src/external/hiir/Downsampler2xFpu.h create mode 100644 src/external/hiir/Downsampler2xFpu.hpp create mode 100644 src/external/hiir/Downsampler2xNeon.h create mode 100644 src/external/hiir/Downsampler2xNeon.hpp create mode 100644 src/external/hiir/Downsampler2xSse.h create mode 100644 src/external/hiir/Downsampler2xSse.hpp diff --git a/src/external/hiir/Downsampler2xFpu.h b/src/external/hiir/Downsampler2xFpu.h new file mode 100644 index 00000000..d69f1e44 --- /dev/null +++ b/src/external/hiir/Downsampler2xFpu.h @@ -0,0 +1,115 @@ +/***************************************************************************** + + Downsampler2xFpu.h + Author: Laurent de Soras, 2005 + +Downsamples by a factor 2 the input signal, using FPU. + +Template parameters: + - NC: number of coefficients, > 0 + +--- Legal stuff --- + +This program is free software. It comes without any warranty, to +the extent permitted by applicable law. You can redistribute it +and/or modify it under the terms of the Do What The Fuck You Want +To Public License, Version 2, as published by Sam Hocevar. See +http://sam.zoy.org/wtfpl/COPYING for more details. + +*Tab=3***********************************************************************/ + + + +#if ! defined (hiir_Downsampler2xFpu_HEADER_INCLUDED) +#define hiir_Downsampler2xFpu_HEADER_INCLUDED + +#if defined (_MSC_VER) + #pragma once + #pragma warning (4 : 4250) // "Inherits via dominance." +#endif + + + +/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +#include "hiir/def.h" + +#include + + + +namespace hiir +{ + + + +template +class Downsampler2xFpu +{ + + static_assert ((NC > 0), "Number of coefficient must be positive."); + +/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +public: + + enum { NBR_COEFS = NC }; + + Downsampler2xFpu (); + + void set_coefs (const double coef_arr []); + + hiir_FORCEINLINE float + process_sample (const float in_ptr [2]); + void process_block (float out_ptr [], const float in_ptr [], long nbr_spl); + + hiir_FORCEINLINE void + process_sample_split (float &low, float &high, const float in_ptr [2]); + void process_block_split (float out_l_ptr [], float out_h_ptr [], const float in_ptr [], long nbr_spl); + + void clear_buffers (); + + + +/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +protected: + + + +/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +private: + + typedef std::array HyperGluar; + + HyperGluar _coef; + HyperGluar _x; + HyperGluar _y; + + + +/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +private: + + bool operator == (const Downsampler2xFpu &other); + bool operator != (const Downsampler2xFpu &other); + +}; // class Downsampler2xFpu + + + +} // namespace hiir + + + +#include "hiir/Downsampler2xFpu.hpp" + + + +#endif // hiir_Downsampler2xFpu_HEADER_INCLUDED + + + +/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ diff --git a/src/external/hiir/Downsampler2xFpu.hpp b/src/external/hiir/Downsampler2xFpu.hpp new file mode 100644 index 00000000..4d30b5ef --- /dev/null +++ b/src/external/hiir/Downsampler2xFpu.hpp @@ -0,0 +1,303 @@ +/***************************************************************************** + + Downsampler2xFpu.hpp + Author: Laurent de Soras, 2005 + +--- Legal stuff --- + +This program is free software. It comes without any warranty, to +the extent permitted by applicable law. You can redistribute it +and/or modify it under the terms of the Do What The Fuck You Want +To Public License, Version 2, as published by Sam Hocevar. See +http://sam.zoy.org/wtfpl/COPYING for more details. + +*Tab=3***********************************************************************/ + + + +#if defined (hiir_Downsampler2xFpu_CURRENT_CODEHEADER) + #error Recursive inclusion of Downsampler2xFpu code header. +#endif +#define hiir_Downsampler2xFpu_CURRENT_CODEHEADER + +#if ! defined (hiir_Downsampler2xFpu_CODEHEADER_INCLUDED) +#define hiir_Downsampler2xFpu_CODEHEADER_INCLUDED + + + +/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +#include "hiir/StageProcFpu.h" + +#include + + + +namespace hiir +{ + + + +/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + + + +/* +============================================================================== +Name: ctor +Throws: Nothing +============================================================================== +*/ + +template +Downsampler2xFpu ::Downsampler2xFpu () +: _coef () +, _x () +, _y () +{ + for (int i = 0; i < NBR_COEFS; ++i) + { + _coef [i] = 0; + } + clear_buffers (); +} + + + +/* +============================================================================== +Name: set_coefs +Description: + Sets filter coefficients. Generate them with the PolyphaseIir2Designer + class. + Call this function before doing any processing. +Input parameters: + - coef_arr: Array of coefficients. There should be as many coefficients as + mentioned in the class template parameter. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xFpu ::set_coefs (const double coef_arr []) +{ + assert (coef_arr != 0); + + for (int i = 0; i < NBR_COEFS; ++i) + { + _coef [i] = float (coef_arr [i]); + } +} + + + +/* +============================================================================== +Name: process_sample +Description: + Downsamples (x2) one pair of samples, to generate one output sample. +Input parameters: + - in_ptr: pointer on the two samples to decimate +Returns: Samplerate-reduced sample. +Throws: Nothing +============================================================================== +*/ + +template +float Downsampler2xFpu ::process_sample (const float in_ptr [2]) +{ + assert (in_ptr != 0); + + float spl_0 (in_ptr [1]); + float spl_1 (in_ptr [0]); + + #if defined (_MSC_VER) + #pragma inline_depth (255) + #endif // _MSC_VER + + StageProcFpu ::process_sample_pos ( + NBR_COEFS, + spl_0, + spl_1, + &_coef [0], + &_x [0], + &_y [0] + ); + + return 0.5f * (spl_0 + spl_1); +} + + + +/* +============================================================================== +Name: process_block +Description: + Downsamples (x2) a block of samples. + Input and output blocks may overlap, see assert() for details. +Input parameters: + - in_ptr: Input array, containing nbr_spl * 2 samples. + - nbr_spl: Number of samples to output, > 0 +Output parameters: + - out_ptr: Array for the output samples, capacity: nbr_spl samples. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xFpu ::process_block (float out_ptr [], const float in_ptr [], long nbr_spl) +{ + assert (in_ptr != 0); + assert (out_ptr != 0); + assert (out_ptr <= in_ptr || out_ptr >= in_ptr + nbr_spl * 2); + assert (nbr_spl > 0); + + long pos = 0; + do + { + out_ptr [pos] = process_sample (&in_ptr [pos * 2]); + ++pos; + } + while (pos < nbr_spl); +} + + + +/* +============================================================================== +Name: process_sample_split +Description: + Split (spectrum-wise) in half a pair of samples. The lower part of the + spectrum is a classic downsampling, equivalent to the output of + process_sample(). + The higher part is the complementary signal: original filter response + is flipped from left to right, becoming a high-pass filter with the same + cutoff frequency. This signal is then critically sampled (decimation by 2), + flipping the spectrum: Fs/4...Fs/2 becomes Fs/4...0. +Input parameters: + - in_ptr: pointer on the pair of input samples +Output parameters: + - low: output sample, lower part of the spectrum (downsampling) + - high: output sample, higher part of the spectrum. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xFpu ::process_sample_split (float &low, float &high, const float in_ptr [2]) +{ + assert (in_ptr != 0); + + float spl_0 = in_ptr [1]; + float spl_1 = in_ptr [0]; + + #if defined (_MSC_VER) + #pragma inline_depth (255) + #endif // _MSC_VER + + StageProcFpu ::process_sample_pos ( + NBR_COEFS, + spl_0, + spl_1, + &_coef [0], + &_x [0], + &_y [0] + ); + + low = (spl_0 + spl_1) * 0.5f; + high = spl_0 - low; // (spl_0 - spl_1) * 0.5f; +} + + + +/* +============================================================================== +Name: process_block_split +Description: + Split (spectrum-wise) in half a block of samples. The lower part of the + spectrum is a classic downsampling, equivalent to the output of + process_block(). + The higher part is the complementary signal: original filter response + is flipped from left to right, becoming a high-pass filter with the same + cutoff frequency. This signal is then critically sampled (decimation by 2), + flipping the spectrum: Fs/4...Fs/2 becomes Fs/4...0. + Input and output blocks may overlap, see assert() for details. +Input parameters: + - in_ptr: Input array, containing nbr_spl * 2 samples. + - nbr_spl: Number of samples for each output, > 0 +Output parameters: + - out_l_ptr: Array for the output samples, lower part of the spectrum + (downsampling). Capacity: nbr_spl samples. + - out_h_ptr: Array for the output samples, higher part of the spectrum. + Capacity: nbr_spl samples. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xFpu ::process_block_split (float out_l_ptr [], float out_h_ptr [], const float in_ptr [], long nbr_spl) +{ + assert (in_ptr != 0); + assert (out_l_ptr != 0); + assert (out_l_ptr <= in_ptr || out_l_ptr >= in_ptr + nbr_spl * 2); + assert (out_h_ptr != 0); + assert (out_h_ptr <= in_ptr || out_h_ptr >= in_ptr + nbr_spl * 2); + assert (out_h_ptr != out_l_ptr); + assert (nbr_spl > 0); + + long pos = 0; + do + { + process_sample_split ( + out_l_ptr [pos], + out_h_ptr [pos], + &in_ptr [pos * 2] + ); + ++pos; + } + while (pos < nbr_spl); +} + + + +/* +============================================================================== +Name: clear_buffers +Description: + Clears filter memory, as if it processed silence since an infinite amount + of time. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xFpu ::clear_buffers () +{ + for (int i = 0; i < NBR_COEFS; ++i) + { + _x [i] = 0; + _y [i] = 0; + } +} + + + +/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + + + +/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + + + +} // namespace hiir + + + +#endif // hiir_Downsampler2xFpu_CODEHEADER_INCLUDED + +#undef hiir_Downsampler2xFpu_CURRENT_CODEHEADER + + + +/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ diff --git a/src/external/hiir/Downsampler2xNeon.h b/src/external/hiir/Downsampler2xNeon.h new file mode 100644 index 00000000..28188c8e --- /dev/null +++ b/src/external/hiir/Downsampler2xNeon.h @@ -0,0 +1,126 @@ +/***************************************************************************** + + Downsampler2xNeon.h + Author: Laurent de Soras, 2016 + +Downsamples by a factor 2 the input signal, using NEON instruction set. + +This object must be aligned on a 16-byte boundary! + +If the number of coefficients is 2 or 3 modulo 4, the output is delayed from +1 sample, compared to the theoretical formula (or FPU implementation). + +Template parameters: + - NC: number of coefficients, > 0 + +--- Legal stuff --- + +This program is free software. It comes without any warranty, to +the extent permitted by applicable law. You can redistribute it +and/or modify it under the terms of the Do What The Fuck You Want +To Public License, Version 2, as published by Sam Hocevar. See +http://sam.zoy.org/wtfpl/COPYING for more details. + +*Tab=3***********************************************************************/ + + + +#pragma once +#if ! defined (hiir_Downsampler2xNeon_HEADER_INCLUDED) +#define hiir_Downsampler2xNeon_HEADER_INCLUDED + +#if defined (_MSC_VER) + #pragma warning (4 : 4250) +#endif + + + +/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +#include "hiir/def.h" +#include "hiir/StageDataNeon.h" + +#include + + + +namespace hiir +{ + + + +template +class Downsampler2xNeon +{ + + static_assert ((NC > 0), "Number of coefficient must be positive."); + +/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +public: + + enum { NBR_COEFS = NC }; + + Downsampler2xNeon (); + Downsampler2xNeon (const Downsampler2xNeon &other) = default; + + Downsampler2xNeon & + operator = (const Downsampler2xNeon &other) = default; + + void set_coefs (const double coef_arr []); + + hiir_FORCEINLINE float + process_sample (const float in_ptr [2]); + void process_block (float out_ptr [], const float in_ptr [], long nbr_spl); + + hiir_FORCEINLINE void + process_sample_split (float &low, float &high, const float in_ptr [2]); + void process_block_split (float out_l_ptr [], float out_h_ptr [], const float in_ptr [], long nbr_spl); + + void clear_buffers (); + + + +/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +protected: + + + +/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +private: + + enum { STAGE_WIDTH = 4 }; + enum { NBR_STAGES = (NBR_COEFS + STAGE_WIDTH - 1) / STAGE_WIDTH }; + + typedef std::array Filter; // Stage 0 contains only input memory + + Filter _filter; // Should be the first member (thus easier to align) + + + +/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +private: + + bool operator == (const Downsampler2xNeon &other) const = delete; + bool operator != (const Downsampler2xNeon &other) const = delete; + +}; // class Downsampler2xNeon + + + +} // namespace hiir + + + +#include "hiir/Downsampler2xNeon.hpp" + + + +#endif // hiir_Downsampler2xNeon_HEADER_INCLUDED + + + +/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ diff --git a/src/external/hiir/Downsampler2xNeon.hpp b/src/external/hiir/Downsampler2xNeon.hpp new file mode 100644 index 00000000..9d0ddeaf --- /dev/null +++ b/src/external/hiir/Downsampler2xNeon.hpp @@ -0,0 +1,299 @@ +/***************************************************************************** + + Downsampler2xNeon.hpp + Author: Laurent de Soras, 2016 + +--- Legal stuff --- + +This program is free software. It comes without any warranty, to +the extent permitted by applicable law. You can redistribute it +and/or modify it under the terms of the Do What The Fuck You Want +To Public License, Version 2, as published by Sam Hocevar. See +http://sam.zoy.org/wtfpl/COPYING for more details. + +*Tab=3***********************************************************************/ + + + +#if ! defined (hiir_Downsampler2xNeon_CODEHEADER_INCLUDED) +#define hiir_Downsampler2xNeon_CODEHEADER_INCLUDED + + + +/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +#include "hiir/StageProcNeon.h" + +#include + +#include + + + +namespace hiir +{ + + + +/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + + + +/* +============================================================================== +Name: ctor +Throws: Nothing +============================================================================== +*/ + +template +Downsampler2xNeon ::Downsampler2xNeon () +: _filter () +{ + for (int i = 0; i < NBR_STAGES + 1; ++i) + { + _filter [i]._mem4 = vdupq_n_f32 (0); + } + if ((NBR_COEFS & 1) != 0) + { + const int pos = (NBR_COEFS ^ 1) & (STAGE_WIDTH - 1); + _filter [NBR_STAGES]._coef [pos] = 1; + } + + clear_buffers (); +} + + + +/* +============================================================================== +Name: set_coefs +Description: + Sets filter coefficients. Generate them with the PolyphaseIir2Designer + class. + Call this function before doing any processing. +Input parameters: + - coef_arr: Array of coefficients. There should be as many coefficients as + mentioned in the class template parameter. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xNeon ::set_coefs (const double coef_arr []) +{ + assert (coef_arr != 0); + + for (int i = 0; i < NBR_COEFS; ++i) + { + const int stage = (i / STAGE_WIDTH) + 1; + const int pos = (i ^ 1) & (STAGE_WIDTH - 1); + _filter [stage]._coef [pos] = float (coef_arr [i]); + } +} + + + +/* +============================================================================== +Name: process_sample +Description: + Downsamples (x2) one pair of samples, to generate one output sample. +Input parameters: + - in_ptr: pointer on the two samples to decimate +Returns: Samplerate-reduced sample. +Throws: Nothing +============================================================================== +*/ + +template +float Downsampler2xNeon ::process_sample (const float in_ptr [2]) +{ + assert (in_ptr != 0); + + // Combines two input samples and two mid-processing data + const float32x2_t spl_in = vreinterpret_f32_u8 ( + vld1_u8 (reinterpret_cast (in_ptr)) + ); + const float32x2_t spl_mid = vget_low_f32 (_filter [NBR_STAGES]._mem4); + float32x4_t y = vcombine_f32 (spl_in, spl_mid); + float32x4_t mem = _filter [0]._mem4; + + // Processes each stage + StageProcNeon ::process_sample_pos (&_filter [0], y, mem); + _filter [NBR_STAGES]._mem4 = y; + + // Averages both paths and outputs the result + const float out_0 = vgetq_lane_f32 (y, 3); + const float out_1 = vgetq_lane_f32 (y, 2); + const float out = (out_0 + out_1) * 0.5f; + + return out; +} + + + +/* +============================================================================== +Name: process_block +Description: + Downsamples (x2) a block of samples. + Input and output blocks may overlap, see assert() for details. +Input parameters: + - in_ptr: Input array, containing nbr_spl * 2 samples. + - nbr_spl: Number of samples to output, > 0 +Output parameters: + - out_ptr: Array for the output samples, capacity: nbr_spl samples. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xNeon ::process_block (float out_ptr [], const float in_ptr [], long nbr_spl) +{ + assert (in_ptr != 0); + assert (out_ptr != 0); + assert (out_ptr <= in_ptr || out_ptr >= in_ptr + nbr_spl * 2); + assert (nbr_spl > 0); + + long pos = 0; + do + { + out_ptr [pos] = process_sample (in_ptr + pos * 2); + ++ pos; + } + while (pos < nbr_spl); +} + + + +/* +============================================================================== +Name: process_sample_split +Description: + Split (spectrum-wise) in half a pair of samples. The lower part of the + spectrum is a classic downsampling, equivalent to the output of + process_sample(). + The higher part is the complementary signal: original filter response + is flipped from left to right, becoming a high-pass filter with the same + cutoff frequency. This signal is then critically sampled (decimation by 2), + flipping the spectrum: Fs/4...Fs/2 becomes Fs/4...0. +Input parameters: + - in_ptr: pointer on the pair of input samples +Output parameters: + - low: output sample, lower part of the spectrum (downsampling) + - high: output sample, higher part of the spectrum. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xNeon ::process_sample_split (float &low, float &high, const float in_ptr [2]) +{ + assert (in_ptr != 0); + + // Combines two input samples and two mid-processing data + const float32x2_t spl_in = vreinterpret_f32_u8 ( + vld1_u8 (reinterpret_cast (in_ptr)) + ); + const float32x2_t spl_mid = vget_low_f32 (_filter [NBR_STAGES]._mem4); + float32x4_t y = vcombine_f32 (spl_in, spl_mid); + float32x4_t mem = _filter [0]._mem4; + + // Processes each stage + StageProcNeon ::process_sample_pos (&_filter [0], y, mem); + _filter [NBR_STAGES]._mem4 = y; + + // Outputs the result + const float out_0 = vgetq_lane_f32 (y, 3); + const float out_1 = vgetq_lane_f32 (y, 2); + low = (out_0 + out_1) * 0.5f; + high = out_0 - low; +} + + + +/* +============================================================================== +Name: process_block_split +Description: + Split (spectrum-wise) in half a block of samples. The lower part of the + spectrum is a classic downsampling, equivalent to the output of + process_block(). + The higher part is the complementary signal: original filter response + is flipped from left to right, becoming a high-pass filter with the same + cutoff frequency. This signal is then critically sampled (decimation by 2), + flipping the spectrum: Fs/4...Fs/2 becomes Fs/4...0. + Input and output blocks may overlap, see assert() for details. +Input parameters: + - in_ptr: Input array, containing nbr_spl * 2 samples. + - nbr_spl: Number of samples for each output, > 0 +Output parameters: + - out_l_ptr: Array for the output samples, lower part of the spectrum + (downsampling). Capacity: nbr_spl samples. + - out_h_ptr: Array for the output samples, higher part of the spectrum. + Capacity: nbr_spl samples. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xNeon ::process_block_split (float out_l_ptr [], float out_h_ptr [], const float in_ptr [], long nbr_spl) +{ + assert (in_ptr != 0); + assert (out_l_ptr != 0); + assert (out_l_ptr <= in_ptr || out_l_ptr >= in_ptr + nbr_spl * 2); + assert (out_h_ptr != 0); + assert (out_h_ptr <= in_ptr || out_h_ptr >= in_ptr + nbr_spl * 2); + assert (out_h_ptr != out_l_ptr); + assert (nbr_spl > 0); + + long pos = 0; + do + { + process_sample_split (out_l_ptr [pos], out_h_ptr [pos], in_ptr + pos * 2); + ++ pos; + } + while (pos < nbr_spl); +} + + + +/* +============================================================================== +Name: clear_buffers +Description: + Clears filter memory, as if it processed silence since an infinite amount + of time. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xNeon ::clear_buffers () +{ + for (int i = 0; i < NBR_STAGES + 1; ++i) + { + _filter [i]._mem4 = vdupq_n_f32 (0); + } +} + + + +/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + + + +/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + + + +} // namespace hiir + + + +#endif // hiir_Downsampler2xNeon_CODEHEADER_INCLUDED + + + +/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ diff --git a/src/external/hiir/Downsampler2xSse.h b/src/external/hiir/Downsampler2xSse.h new file mode 100644 index 00000000..9aa6ff7c --- /dev/null +++ b/src/external/hiir/Downsampler2xSse.h @@ -0,0 +1,126 @@ +/***************************************************************************** + + Downsampler2xSse.h + Author: Laurent de Soras, 2005 + +Downsamples by a factor 2 the input signal, using SSE instruction set. + +This object must be aligned on a 16-byte boundary! + +If the number of coefficients is 2 or 3 modulo 4, the output is delayed from +1 sample, compared to the theoretical formula (or FPU implementation). + +Template parameters: + - NC: number of coefficients, > 0 + +--- Legal stuff --- + +This program is free software. It comes without any warranty, to +the extent permitted by applicable law. You can redistribute it +and/or modify it under the terms of the Do What The Fuck You Want +To Public License, Version 2, as published by Sam Hocevar. See +http://sam.zoy.org/wtfpl/COPYING for more details. + +*Tab=3***********************************************************************/ + + + +#if ! defined (hiir_Downsampler2xSse_HEADER_INCLUDED) +#define hiir_Downsampler2xSse_HEADER_INCLUDED + +#if defined (_MSC_VER) + #pragma once + #pragma warning (4 : 4250) // "Inherits via dominance." +#endif + + + +/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +#include "hiir/def.h" +#include "hiir/StageDataSse.h" + +#include + + + +namespace hiir +{ + + + +template +class Downsampler2xSse +{ + + static_assert ((NC > 0), "Number of coefficient must be positive."); + +/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +public: + + enum { NBR_COEFS = NC }; + + Downsampler2xSse (); + Downsampler2xSse (const Downsampler2xSse &other) = default; + + Downsampler2xSse & + operator = (const Downsampler2xSse &other) = default; + + void set_coefs (const double coef_arr []); + + hiir_FORCEINLINE float + process_sample (const float in_ptr [2]); + void process_block (float out_ptr [], const float in_ptr [], long nbr_spl); + + hiir_FORCEINLINE void + process_sample_split (float &low, float &high, const float in_ptr [2]); + void process_block_split (float out_l_ptr [], float out_h_ptr [], const float in_ptr [], long nbr_spl); + + void clear_buffers (); + + + +/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +protected: + + + +/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +private: + + enum { STAGE_WIDTH = 4 }; + enum { NBR_STAGES = (NBR_COEFS + STAGE_WIDTH - 1) / STAGE_WIDTH }; + + typedef std::array Filter; // Stage 0 contains only input memory + + Filter _filter; // Should be the first member (thus easier to align) + + + +/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +private: + + bool operator == (const Downsampler2xSse &other) = delete; + bool operator != (const Downsampler2xSse &other) = delete; + +}; // class Downsampler2xSse + + + +} // namespace hiir + + + +#include "hiir/Downsampler2xSse.hpp" + + + +#endif // hiir_Downsampler2xSse_HEADER_INCLUDED + + + +/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ diff --git a/src/external/hiir/Downsampler2xSse.hpp b/src/external/hiir/Downsampler2xSse.hpp new file mode 100644 index 00000000..b05b82c0 --- /dev/null +++ b/src/external/hiir/Downsampler2xSse.hpp @@ -0,0 +1,322 @@ +/***************************************************************************** + + Downsampler2xSse.hpp + Author: Laurent de Soras, 2005 + +--- Legal stuff --- + +This program is free software. It comes without any warranty, to +the extent permitted by applicable law. You can redistribute it +and/or modify it under the terms of the Do What The Fuck You Want +To Public License, Version 2, as published by Sam Hocevar. See +http://sam.zoy.org/wtfpl/COPYING for more details. + +*Tab=3***********************************************************************/ + + + +#if defined (hiir_Downsampler2xSse_CURRENT_CODEHEADER) + #error Recursive inclusion of Downsampler2xSse code header. +#endif +#define hiir_Downsampler2xSse_CURRENT_CODEHEADER + +#if ! defined (hiir_Downsampler2xSse_CODEHEADER_INCLUDED) +#define hiir_Downsampler2xSse_CODEHEADER_INCLUDED + + + +/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +#include "hiir/StageProcSse.h" + +#include + +#include + + + +namespace hiir +{ + + + +/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + + + +/* +============================================================================== +Name: ctor +Throws: Nothing +============================================================================== +*/ + +template +Downsampler2xSse ::Downsampler2xSse () +: _filter () +{ + for (int i = 0; i < NBR_STAGES + 1; ++i) + { + _filter [i]._coef [0] = 0; + _filter [i]._coef [1] = 0; + _filter [i]._coef [2] = 0; + _filter [i]._coef [3] = 0; + } + if ((NBR_COEFS & 1) != 0) + { + const int pos = (NBR_COEFS ^ 1) & (STAGE_WIDTH - 1); + _filter [NBR_STAGES]._coef [pos] = 1; + } + + clear_buffers (); +} + + + +/* +============================================================================== +Name: set_coefs +Description: + Sets filter coefficients. Generate them with the PolyphaseIir2Designer + class. + Call this function before doing any processing. +Input parameters: + - coef_arr: Array of coefficients. There should be as many coefficients as + mentioned in the class template parameter. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xSse ::set_coefs (const double coef_arr []) +{ + assert (coef_arr != 0); + + for (int i = 0; i < NBR_COEFS; ++i) + { + const int stage = (i / STAGE_WIDTH) + 1; + const int pos = (i ^ 1) & (STAGE_WIDTH - 1); + _filter [stage]._coef [pos] = float (coef_arr [i]); + } +} + + + +/* +============================================================================== +Name: process_sample +Description: + Downsamples (x2) one pair of samples, to generate one output sample. +Input parameters: + - in_ptr: pointer on the two samples to decimate +Returns: Samplerate-reduced sample. +Throws: Nothing +============================================================================== +*/ + +template +float Downsampler2xSse ::process_sample (const float in_ptr [2]) +{ + assert (in_ptr != 0); + + // Combines two input samples and two mid-processing data + const __m128 spl_in = _mm_loadu_ps (in_ptr); + const __m128 spl_mid = _mm_load_ps (_filter [NBR_STAGES]._mem); + __m128 y = _mm_shuffle_ps (spl_in, spl_mid, 0x44); + + __m128 mem = _mm_load_ps (_filter [0]._mem); + + // Processes each stage + StageProcSse ::process_sample_pos (&_filter [0], y, mem); + + _mm_store_ps (_filter [NBR_STAGES]._mem, y); + + // Averages both paths and outputs the result + const __m128 dup_y = y; + y = _mm_shuffle_ps (y, y, 0x80); + y = _mm_add_ps (y, dup_y); + y = _mm_shuffle_ps (y, y, 3); + y = _mm_mul_ss (y, _mm_set_ss (0.5f)); + float result; + _mm_store_ss (&result, y); + + return (result); +} + + + +/* +============================================================================== +Name: process_block +Description: + Downsamples (x2) a block of samples. + Input and output blocks may overlap, see assert() for details. +Input parameters: + - in_ptr: Input array, containing nbr_spl * 2 samples. + - nbr_spl: Number of samples to output, > 0 +Output parameters: + - out_ptr: Array for the output samples, capacity: nbr_spl samples. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xSse ::process_block (float out_ptr [], const float in_ptr [], long nbr_spl) +{ + assert (in_ptr != 0); + assert (out_ptr != 0); + assert (out_ptr <= in_ptr || out_ptr >= in_ptr + nbr_spl * 2); + assert (nbr_spl > 0); + + long pos = 0; + do + { + out_ptr [pos] = process_sample (in_ptr + pos * 2); + ++ pos; + } + while (pos < nbr_spl); +} + + + +/* +============================================================================== +Name: process_sample_split +Description: + Split (spectrum-wise) in half a pair of samples. The lower part of the + spectrum is a classic downsampling, equivalent to the output of + process_sample(). + The higher part is the complementary signal: original filter response + is flipped from left to right, becoming a high-pass filter with the same + cutoff frequency. This signal is then critically sampled (decimation by 2), + flipping the spectrum: Fs/4...Fs/2 becomes Fs/4...0. +Input parameters: + - in_ptr: pointer on the pair of input samples +Output parameters: + - low: output sample, lower part of the spectrum (downsampling) + - high: output sample, higher part of the spectrum. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xSse ::process_sample_split (float &low, float &high, const float in_ptr [2]) +{ + assert (in_ptr != 0); + + // Combines two input samples and two mid-processing data + const __m128 spl_in = _mm_loadu_ps (in_ptr); + const __m128 spl_mid = _mm_load_ps (_filter [NBR_STAGES]._mem); + __m128 y = _mm_shuffle_ps (spl_in, spl_mid, 0x44); + + __m128 mem = _mm_load_ps (_filter [0]._mem); + + // Processes each stage + StageProcSse ::process_sample_pos (&_filter [0], y, mem); + + _mm_store_ps (_filter [NBR_STAGES]._mem, y); + + //Outputs the result + __m128 dup_y = y; + y = _mm_shuffle_ps (y, y, 0x80); + y = _mm_add_ps (y, dup_y); + y = _mm_shuffle_ps (y, y, 3); + y = _mm_mul_ss (y, _mm_set_ss (0.5f)); + _mm_store_ss (&low, y); + + dup_y = _mm_shuffle_ps (dup_y, dup_y, 3); + dup_y = _mm_sub_ps (dup_y, y); + _mm_store_ss (&high, dup_y); +} + + + +/* +============================================================================== +Name: process_block_split +Description: + Split (spectrum-wise) in half a block of samples. The lower part of the + spectrum is a classic downsampling, equivalent to the output of + process_block(). + The higher part is the complementary signal: original filter response + is flipped from left to right, becoming a high-pass filter with the same + cutoff frequency. This signal is then critically sampled (decimation by 2), + flipping the spectrum: Fs/4...Fs/2 becomes Fs/4...0. + Input and output blocks may overlap, see assert() for details. +Input parameters: + - in_ptr: Input array, containing nbr_spl * 2 samples. + - nbr_spl: Number of samples for each output, > 0 +Output parameters: + - out_l_ptr: Array for the output samples, lower part of the spectrum + (downsampling). Capacity: nbr_spl samples. + - out_h_ptr: Array for the output samples, higher part of the spectrum. + Capacity: nbr_spl samples. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xSse ::process_block_split (float out_l_ptr [], float out_h_ptr [], const float in_ptr [], long nbr_spl) +{ + assert (in_ptr != 0); + assert (out_l_ptr != 0); + assert (out_l_ptr <= in_ptr || out_l_ptr >= in_ptr + nbr_spl * 2); + assert (out_h_ptr != 0); + assert (out_h_ptr <= in_ptr || out_h_ptr >= in_ptr + nbr_spl * 2); + assert (out_h_ptr != out_l_ptr); + assert (nbr_spl > 0); + + long pos = 0; + do + { + process_sample_split (out_l_ptr [pos], out_h_ptr [pos], in_ptr + pos * 2); + ++ pos; + } + while (pos < nbr_spl); +} + + + +/* +============================================================================== +Name: clear_buffers +Description: + Clears filter memory, as if it processed silence since an infinite amount + of time. +Throws: Nothing +============================================================================== +*/ + +template +void Downsampler2xSse ::clear_buffers () +{ + for (int i = 0; i < NBR_STAGES + 1; ++i) + { + _filter [i]._mem [0] = 0; + _filter [i]._mem [1] = 0; + _filter [i]._mem [2] = 0; + _filter [i]._mem [3] = 0; + } +} + + + +/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + + + +/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + + + +} // namespace hiir + + + +#endif // hiir_Downsampler2xSse_CODEHEADER_INCLUDED + +#undef hiir_Downsampler2xSse_CURRENT_CODEHEADER + + + +/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/