HART  0.1.0
High level Audio Regression and Testing
Loading...
Searching...
No Matches
hart_gaindb.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm> // fill()
4#include <iomanip>
5#include <vector>
6
7#include "hart_dsp.hpp"
9#include "hart_utils.hpp"
10
11namespace hart
12{
13
14/// @brief Applies gain in decibels to the signal
15/// @note For automation, consider using @ref GainLinear instead, because the two classes produce different curve shapes.
16/// @ingroup DSP
17template <typename SampleType>
18class GainDb:
19 public hart::DSP<SampleType>
20{
21public:
22 enum Params
23 {
24 gainDb ///< Gain in decibels
25 };
26
27 /// @brief Constructor
28 /// @param gainDb Initial gain in decibels
29 GainDb (double gainDb = 0.0):
30 m_initialGainDb (gainDb),
31 m_gainLinear (decibelsToRatio (gainDb))
32 {
33 }
34
35 void prepare (double /* sampleRateHz */, size_t /* numInputChannels */, size_t /* numOutputChannels */, size_t maxBlockSizeFrames) override
36 {
37 m_gainEnvelopeValuesLinear.resize (this->hasEnvelopeFor (Params::gainDb) ? maxBlockSizeFrames : 0);
38 }
39
40 void process (const AudioBuffer<SampleType>& input, AudioBuffer<SampleType>& output, const EnvelopeBuffers& envelopeBuffers) override
41 {
42 const size_t numInputChannels = input.getNumChannels();
43 const size_t numOutputChannels = output.getNumChannels();
44 hassert (output.getNumFrames() == input.getNumFrames());
45
46 if (! supportsChannelLayout (numInputChannels, numOutputChannels))
47 HART_THROW_OR_RETURN_VOID (hart::ChannelLayoutError, "Unsupported channel configuration");
48
49 const bool hasGainEnvelope = ! envelopeBuffers.empty() && contains (envelopeBuffers, (int) Params::gainDb);
50 const bool multiplexerMode = numInputChannels != numOutputChannels;
51
52 if (hasGainEnvelope)
53 {
54 auto& gainEnvelopeValuesDb = envelopeBuffers. at(Params::gainDb);
55 hassert (gainEnvelopeValuesDb.size() == m_gainEnvelopeValuesLinear.size());
56
57 for (size_t i = 0; i < m_gainEnvelopeValuesLinear.size(); ++i)
58 m_gainEnvelopeValuesLinear[i] = decibelsToRatio (gainEnvelopeValuesDb[i]);
59
60 if (multiplexerMode)
61 processEnvelopedGainAsMultiplexer (input, output);
62 else
63 processEnvelopedGainAsMultiChannel (input, output);
64
65 return;
66 }
67
68 // No gain envelope
69 if (multiplexerMode)
70 processConstantGainAsMultiplexer (input, output);
71 else
72 processConstantGainAsMultiChannel (input, output);
73 }
74
75 void reset() override {}
76
77 /// @param id Only @ref GainDb::gainDb is accepted
78 /// @param value Gain in decibels
79 void setValue (int id, double value) override
80 {
81 if (id == Params::gainDb)
82 m_gainLinear = decibelsToRatio (value);
83 }
84
85 /// @param id Only @ref GainDb::gainDb is accepted
86 /// @retval (value) Gain in decibels
87 double getValue (int id) const override
88 {
89 if (id == Params::gainDb)
90 return ratioToDecibels (m_gainLinear);
91
92 return 0.0;
93 }
94
95 /// @brief Checks if the DSP supports given i/o configuration
96 /// @details Supports either 1-to-n or n-to-n configurations
97 virtual bool supportsChannelLayout (size_t numInputChannels, size_t numOutputChannels) const override
98 {
99 if (numInputChannels == numOutputChannels)
100 return true;
101
102 if (numInputChannels == 1)
103 return true;
104
105 return false;
106 }
107
108 virtual void represent (std::ostream& stream) const override
109 {
110 stream << dbPrecision << "GainDb (" << m_initialGainDb << "_dB)";
111 }
112
113 /// @param id Only @ref GainDb::gainDb is accepted
114 /// retval (bool) true for GainDb::gainDb, else otherwise
115 bool supportsEnvelopeFor (int id) const override
116 {
117 return id == Params::gainDb;
118 }
119
121
122private:
123 double m_initialGainDb;
124 double m_gainLinear;
125 std::vector<double> m_gainEnvelopeValuesLinear;
126
127 void processConstantGainAsMultiChannel (const AudioBuffer<SampleType>& input, AudioBuffer<SampleType>& output)
128 {
129 for (size_t channel = 0; channel < input.getNumChannels(); ++channel)
130 for (size_t frame = 0; frame < input.getNumFrames(); ++frame)
131 output[channel][frame] = input[channel][frame] * (SampleType) m_gainLinear;
132 }
133
134 void processConstantGainAsMultiplexer (const AudioBuffer<SampleType>& input, AudioBuffer<SampleType>& output)
135 {
136 for (size_t channel = 0; channel < output.getNumChannels(); ++channel)
137 for (size_t frame = 0; frame < input.getNumFrames(); ++frame)
138 output[channel][frame] = input[0][frame] * (SampleType) m_gainLinear;
139 }
140
141 void processEnvelopedGainAsMultiChannel (const AudioBuffer<SampleType>& input, AudioBuffer<SampleType>& output)
142 {
143 for (size_t channel = 0; channel < input.getNumChannels(); ++channel)
144 for (size_t frame = 0; frame < input.getNumFrames(); ++frame)
145 output[channel][frame] = input[channel][frame] * (SampleType) m_gainEnvelopeValuesLinear[frame];
146 }
147
148 void processEnvelopedGainAsMultiplexer (const AudioBuffer<SampleType>& input, AudioBuffer<SampleType>& output)
149 {
150 for (size_t channel = 0; channel < output.getNumChannels(); ++channel)
151 for (size_t frame = 0; frame < input.getNumFrames(); ++frame)
152 output[channel][frame] = input[0][frame] * (SampleType) m_gainEnvelopeValuesLinear[frame];
153 }
154};
155
157
158} // namespace hart
Base for DSP effects.
Definition hart_dsp.hpp:34
Applies gain in decibels to the signal.
virtual bool supportsChannelLayout(size_t numInputChannels, size_t numOutputChannels) const override
Checks if the DSP supports given i/o configuration.
void prepare(double, size_t, size_t, size_t maxBlockSizeFrames) override
Prepare for processing.
GainDb(double gainDb=0.0)
Constructor.
double getValue(int id) const override
void process(const AudioBuffer< SampleType > &input, AudioBuffer< SampleType > &output, const EnvelopeBuffers &envelopeBuffers) override
Processes the audio.
@ gainDb
Gain in decibels.
virtual void represent(std::ostream &stream) const override
Makes a text representation of this DSP effect for test failure outputs.
void setValue(int id, double value) override
bool supportsEnvelopeFor(int id) const override
void reset() override
Resets to initial state.
#define HART_DSP_DEFINE_COPY_AND_MOVE(ClassName)
Defines hart::DSP::copy() and hart::DSP::move() methods.
Definition hart_dsp.hpp:334
std::ostream & dbPrecision(std::ostream &stream)
Sets number of decimal places for values in decibels.
static bool contains(const std::unordered_map< KeyType, ValueType > &map, const KeyType &key)
std::unordered_map::contains() replacement for C++11
static SampleType ratioToDecibels(SampleType valueLinear)
Converts linear value (ratio) to dB.
static SampleType decibelsToRatio(SampleType valueDb)
Converts dB to linear value (ratio)
#define HART_DSP_DECLARE_ALIASES_FOR(ClassName)
Definition hart_dsp.hpp:370
#define HART_THROW_OR_RETURN_VOID(ExceptionType, message)
#define hassert(condition)