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