LCOV - code coverage report
Current view: top level - Dynamic - GainFilter.h (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 52 54 96.3 %
Date: 2021-02-18 20:07:22 Functions: 66 83 79.5 %

          Line data    Source code
       1             : /**
       2             :  * \file GainFilter.h
       3             :  */
       4             : 
       5             : #ifndef ATK_DYNAMIC_GAINFILTER_H
       6             : #define ATK_DYNAMIC_GAINFILTER_H
       7             : 
       8             : #include <ATK/Core/TypedBaseFilter.h>
       9             : #include <ATK/Dynamic/config.h>
      10             : 
      11             : #include <cassert>
      12             : #include <atomic>
      13             : #include <future>
      14             : #include <vector>
      15             : 
      16             : namespace ATK
      17             : {
      18             :   /// Gain generic filter. Based on a LUT table, compute the gain.
      19             :   /*!
      20             :    * Be aware that the threshold is taken as a power measure contrary to the gain (there is a factor 2 in the dB computation)
      21             :    */
      22             :   template<typename DataType_>
      23             :   class ATK_DYNAMIC_EXPORT ParentGainFilter : public TypedBaseFilter<DataType_>
      24             :   {
      25             :   protected:
      26             :     /// Simplify parent calls
      27             :     using Parent = TypedBaseFilter<DataType_>;
      28             :     using typename Parent::DataType;
      29             : 
      30             :   public:
      31             :     /*!
      32             :     * @brief Constructor
      33             :     * @param nb_channels is the number of input and output channels
      34             :     * @param LUTsize is the total LUT size used by the filter
      35             :     * @param LUTprecision is the number of elements used to compute values < 1
      36             :     */
      37             :     ParentGainFilter(gsl::index nb_channels = 1, size_t LUTsize = 128*1024, size_t LUTprecision = 64);
      38             :     /// Destructor
      39          90 :     ~ParentGainFilter() override = default;
      40             :     
      41             :     /// Sets the threshold (superior to 0)
      42             :     void set_threshold(DataType_ threshold);
      43             :     /// Sets the threshold in dB
      44             :     void set_threshold_db(DataType_ threshold_db);
      45             :     /// Returns the threshold
      46             :     DataType_ get_threshold() const;
      47             :     /// 1:ratio is defined as the reduction factor. 1:1 is a reduction of 0, 1:2 is a reduction by a factor of 2...
      48             :     void set_ratio(DataType_ ratio);
      49             :     /// Returns ratio
      50             :     DataType_ get_ratio() const;
      51             : 
      52             :   protected:
      53             :     /// Threshold
      54             :     DataType_ threshold{1};
      55             :     /// Ratio
      56             :     DataType_ ratio{1};
      57             : 
      58             :     virtual void start_recomputeLUT() = 0;
      59             : 
      60             :     gsl::index LUTsize{0};
      61             :     gsl::index LUTprecision{0};
      62             :     std::vector<DataType_> gainLUT;
      63             :   };
      64             : 
      65             :   template<class ParentFilter>
      66             :   class GainFilter final : public ParentFilter
      67             :   {
      68             :   public:
      69             :     using Parent = ParentFilter;
      70             :     using typename Parent::DataType;
      71             :     using Parent::converted_inputs;
      72             :     using Parent::outputs;
      73             :     using Parent::threshold;
      74             :     using Parent::nb_input_ports;
      75             :     using Parent::nb_output_ports;
      76             :     using Parent::computeGain;
      77             :     using Parent::LUTsize;
      78             :     using Parent::LUTprecision;
      79             :     using Parent::gainLUT;
      80             : 
      81          90 :     GainFilter(gsl::index nb_channels = 1, gsl::index LUTsize = 128 * 1024, gsl::index LUTprecision = 64)
      82          90 :     :ParentFilter(nb_channels, LUTsize, LUTprecision)
      83             :     {
      84          90 :       start_recomputeLUT();
      85          90 :     }
      86             : 
      87          90 :     ~GainFilter() override
      88             :     {
      89             :       //Future has to be deleted in child destructor as it uses computeGain
      90          90 :       wait_for_LUT_completion();
      91          90 :     }
      92             : 
      93          95 :     void wait_for_LUT_completion()
      94             :     {
      95          95 :       if (recomputeFuture.valid())
      96             :       {
      97          95 :         recomputeFuture.wait();
      98             :       }
      99          95 :     }
     100             : 
     101             :   protected:
     102             :     /// Future used to track the thread recomputing the LUT
     103             :     std::future<void> recomputeFuture;
     104             :     /// Is the thread recomputing the LUT running (which way of computing the gain shall we use?)
     105             :     std::atomic<bool> isRunning{false};
     106             :     /// Indicates to start recomputing the LUT from the start, used when asked to change LUT parameters when the LUT is recomputed
     107             :     std::atomic<bool> resetRequest{false};
     108             : 
     109          51 :     void process_impl(gsl::index size) const final
     110             :     {
     111          51 :       assert(nb_input_ports == nb_output_ports);
     112             : 
     113          51 :       if (isRunning)
     114             :       {
     115          45 :         process_impl_direct(size);
     116             :       }
     117             :       else
     118             :       {
     119           6 :         process_impl_LUT(size);
     120             :       }
     121          51 :     }
     122             : 
     123             :     /// Computes the gain based on the LUT
     124           6 :     void process_impl_LUT(gsl::index size) const
     125             :     {
     126          12 :       for (gsl::index channel = 0; channel < nb_output_ports; ++channel)
     127             :       {
     128           6 :         const auto* ATK_RESTRICT input = converted_inputs[channel];
     129           6 :         auto* ATK_RESTRICT output = outputs[channel];
     130         390 :         for (gsl::index i = 0; i < size; ++i)
     131             :         {
     132         384 :           auto value = input[i] * threshold * LUTprecision;
     133         384 :           auto step = std::lround(std::ceil(value));
     134         384 :           if (step >= LUTsize - 1)
     135             :           {
     136           0 :             step = static_cast<int>(LUTsize) - 1;
     137           0 :             output[i] = gainLUT[step];
     138             :           }
     139             :           else
     140             :           {
     141         384 :             output[i] = (1 - (value - step)) * gainLUT[step] + (value - step) * gainLUT[step + 1];
     142             :           }
     143             :         }
     144             :       }
     145           6 :     }
     146             : 
     147             :     /// Computes the gain directly
     148          45 :     void process_impl_direct(gsl::index size) const
     149             :     {
     150          90 :       for (gsl::index channel = 0; channel < nb_output_ports; ++channel)
     151             :       {
     152          45 :         const auto* ATK_RESTRICT input = converted_inputs[channel];
     153          45 :         auto* ATK_RESTRICT output = outputs[channel];
     154        2925 :         for (gsl::index i = 0; i < size; ++i)
     155             :         {
     156        2880 :           output[i] = computeGain(*(input++) * threshold);
     157             :         }
     158             :       }
     159          45 :     }
     160             : 
     161             :     /// Asks to recompute the LUT
     162          90 :     void recomputeLUT()
     163             :     {
     164          90 :       auto gainLUT_ptr = gainLUT.data();
     165             : 
     166      737400 :       for (gsl::index i = 0; i < LUTsize; i += 16)
     167             :       {
     168      737310 :         if (resetRequest)
     169             :         {
     170          54 :           i = 0;
     171          54 :           resetRequest = false;
     172          54 :           gainLUT_ptr = gainLUT.data();
     173             :         }
     174    12534268 :         for (gsl::index j = 0; j < 16; ++j)
     175             :         {
     176    11796974 :           *(gainLUT_ptr++) = computeGain(static_cast<DataType>(i + j) / LUTprecision);
     177             :         }
     178             :       }
     179          90 :       isRunning = false;
     180          90 :     }
     181             : 
     182             :     /// Actually recomputes the LUT
     183         182 :     void start_recomputeLUT() final
     184             :     {
     185         182 :       if (isRunning)
     186             :       {
     187          92 :         resetRequest = true; // Tell the thread to start over
     188             :       }
     189             :       else
     190             :       {
     191          90 :         isRunning = true; // starting a new thread
     192          90 :         recomputeFuture = std::async(&GainFilter<ParentFilter>::recomputeLUT, this);
     193             :       }
     194         182 :     }
     195             : 
     196             :   };
     197             : }
     198             : 
     199             : #endif

Generated by: LCOV version TK-3.3.0-4-gdba42eea