LCOV - code coverage report
Current view: top level - Special - ConvolutionFilter.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 85 86 98.8 %
Date: 2021-02-18 20:07:22 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /**
       2             :  * \file ConvolutionFilter.cpp
       3             :  */
       4             : 
       5             : #include "ConvolutionFilter.h"
       6             : 
       7             : #include <cassert>
       8             : #include <algorithm>
       9             : 
      10             : namespace ATK
      11             : {
      12             :   template <typename DataType>
      13           1 :   ConvolutionFilter<DataType>::ConvolutionFilter()
      14           1 :     :Parent(1, 1)
      15             :   {
      16           1 :   }
      17             : 
      18             :   template<typename DataType_>
      19           1 :   void ConvolutionFilter<DataType_>::set_impulse(AlignedScalarVector impulse)
      20             :   {
      21           1 :     this->impulse = std::move(impulse);
      22           1 :     setup();
      23           1 :   }
      24             :   
      25             :   template<typename DataType_>
      26           1 :   void ConvolutionFilter<DataType_>::set_split_size(unsigned int split_size)
      27             :   {
      28           1 :     this->split_size = split_size;
      29           1 :     setup();
      30           1 :   }
      31             :   
      32             :   template<typename DataType_>
      33           3 :   void ConvolutionFilter<DataType_>::setup()
      34             :   {
      35           3 :     if(impulse.size() == 0 || split_size == 0)
      36             :     {
      37           2 :       return;
      38             :     }
      39             : 
      40           1 :     auto nb_splits = (impulse.size() + split_size - 1) / split_size;
      41           1 :     partial_frequency_input.assign(nb_splits - 1, AlignedComplexVector(split_size * 2, 0));
      42             :     // Pad with zeros so the convolution is easier created.
      43           1 :     impulse.resize((partial_frequency_input.size() + 1) * split_size, 0);
      44             : 
      45           1 :     temp_out_buffer.assign(split_size * 2, 0);
      46           1 :     processor.set_size(split_size * 2);
      47             :     
      48             :     // The size is twice as big than the impulse, less
      49           1 :     partial_frequency_impulse.assign(split_size * 2 * (nb_splits - 1), 0);
      50          79 :     for(gsl::index i = 1; i < nb_splits; ++i)
      51             :     {
      52          78 :       processor.process_forward(impulse.data() + i * split_size, partial_frequency_impulse.data() + (i - 1) * split_size * 2, split_size);
      53             :     }
      54             : 
      55           1 :     input_delay = split_size - 1;
      56             :     
      57           1 :     Parent::setup();
      58             :   }
      59             : 
      60             :   template<typename DataType_>
      61       16376 :   void ConvolutionFilter<DataType_>::compute_convolutions() const
      62             :   {
      63     2112500 :     for(gsl::index i = 0; i < split_size; ++i)
      64             :     {
      65     2096130 :       temp_out_buffer[i] = temp_out_buffer[i + split_size];
      66     2096130 :       temp_out_buffer[i + split_size] = 0;
      67             :     }
      68             :     
      69       16376 :     result.assign(2 * split_size, 0);
      70       16376 :     DataType* ATK_RESTRICT result_ptr_orig = reinterpret_cast<DataType*>(result.data());
      71       16376 :     const DataType* ATK_RESTRICT partial_frequency_impulse_ptr_orig = reinterpret_cast<const DataType*>(partial_frequency_impulse.data());
      72             : 
      73             :     // offset in the impulse frequencies
      74       16376 :     int64_t offset = 0;
      75     1293700 :     for(const auto& buffer: partial_frequency_input)
      76             :     {
      77     1277330 :       DataType* ATK_RESTRICT result_ptr = result_ptr_orig;
      78     1277330 :       const DataType* ATK_RESTRICT buffer_ptr = reinterpret_cast<const DataType*>(buffer.data());
      79     1277330 :       const DataType* ATK_RESTRICT partial_frequency_impulse_ptr = partial_frequency_impulse_ptr_orig + offset;
      80             :       // Add the frequency result of this partial FFT
      81   164775000 :       for(gsl::index i = 0; i < split_size; ++i)
      82             :       {
      83   163498000 :         DataType br1 = *(buffer_ptr++);
      84   163498000 :         DataType bi1 = *(buffer_ptr++);
      85   163498000 :         DataType pr1 = *(partial_frequency_impulse_ptr++);
      86   163498000 :         DataType pi1 = *(partial_frequency_impulse_ptr++);
      87   163498000 :         DataType br2 = *(buffer_ptr++);
      88   163498000 :         DataType bi2 = *(buffer_ptr++);
      89   163498000 :         DataType pr2 = *(partial_frequency_impulse_ptr++);
      90   163498000 :         DataType pi2 = *(partial_frequency_impulse_ptr++);
      91   163498000 :         *(result_ptr++) += br1*pr1-bi1*pi1;
      92   163498000 :         *(result_ptr++) += br1*pi1+pr1*bi1;
      93   163498000 :         *(result_ptr++) += br2*pr2-bi2*pi2;
      94   163498000 :         *(result_ptr++) += br2*pi2+pr2*bi2;
      95             :       }
      96     1277330 :       offset += 4 * split_size;
      97             :     }
      98             : 
      99       32752 :     std::vector<DataType> ifft_result(2*split_size, 0);
     100       16376 :     processor.process_backward(result.data(), ifft_result.data(), 2*split_size);
     101     4208630 :     for(gsl::index i = 0; i < 2*split_size; ++i)
     102             :     {
     103     4192260 :       temp_out_buffer[i] += ifft_result[i] * split_size * 2;
     104             :     }
     105       16376 :   }
     106             : 
     107             :   template<typename DataType_>
     108       16376 :   void ConvolutionFilter<DataType_>::process_new_chunk(int64_t position) const
     109             :   {
     110       16376 :     if(partial_frequency_input.empty())
     111             :     {
     112           0 :       return;
     113             :     }
     114       16376 :     partial_frequency_input.pop_back();
     115       32752 :     AlignedComplexVector chunk(2 * split_size);
     116       16376 :     processor.process_forward(converted_inputs[0] + position - split_size, chunk.data(), split_size);
     117             :     
     118       16376 :     partial_frequency_input.push_front(std::move(chunk));
     119       16376 :     compute_convolutions();
     120             :   }
     121             : 
     122             :   template<typename DataType_>
     123       18408 :   void ConvolutionFilter<DataType_>::process_impulse_beginning(int64_t processed_size, unsigned int size_to_process) const
     124             :   {
     125       18408 :     const DataType* ATK_RESTRICT input = converted_inputs[0] + processed_size;
     126       18408 :     const DataType* ATK_RESTRICT impulse_ptr = impulse.data();
     127       18408 :     DataType* ATK_RESTRICT output = outputs[0] + processed_size;
     128             : 
     129     2114540 :     for(gsl::index i = 0; i < size_to_process; ++i)
     130             :     {
     131     2096130 :       output[i] = temp_out_buffer[split_position + i];
     132             :     }
     133             : 
     134     2374630 :     for(gsl::index j = 0; j < input_delay + 1; ++j)
     135             :     {
     136   270661000 :       for(gsl::index i = 0; i < size_to_process; ++i)
     137             :       {
     138   268304000 :         output[i] += impulse_ptr[j] * input[static_cast<int>(i) - static_cast<int>(j)];
     139             :       }
     140             :     }
     141       18408 :   }
     142             : 
     143             :   template<typename DataType_>
     144        2047 :   void ConvolutionFilter<DataType_>::process_impl(gsl::index size) const
     145             :   {
     146        2047 :     assert(input_sampling_rate == output_sampling_rate);
     147             :     
     148        2047 :     unsigned int processed_size = 0;
     149       16361 :     do
     150             :     {
     151             :       // We can only process split_size elements at a time, but if we already have some elements in the buffer,
     152             :       // we need to take them into account.
     153       18408 :       unsigned int size_to_process = std::min(split_size - split_position, static_cast<unsigned int>(size) - processed_size);
     154             : 
     155       18408 :       process_impulse_beginning(processed_size, size_to_process);
     156             : 
     157       18408 :       split_position += size_to_process;
     158       18408 :       processed_size += size_to_process;
     159       18408 :       if(split_position == split_size)
     160             :       {
     161       16376 :         process_new_chunk(processed_size);
     162       16376 :         split_position = 0;
     163             :       }
     164       18408 :     }while(processed_size != size);
     165        2047 :   }
     166             : 
     167             :   template class ConvolutionFilter<double>;
     168             : }

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