HART  0.2.0
High level Audio Regression and Testing
Loading...
Searching...
No Matches
hart_additive_noise.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint> // uint_fast32_t
4#include <random>
5
7#include "hart_dsp.hpp"
10#include "hart_utils.hpp" // decibelsToRatio()
11
12namespace hart
13{
14
15/// @brief Mixes additive white noise to the signal
16/// @details Can operate either in symmetricall channel configurations, i.e.
17/// same number of inputs and outputs, or mono input to many outputs. Either
18/// way, each output channel with get its own noise realization.
19/// As anything in HART, the noise is deterministic, and can be controlled
20/// using a custom seed, either by specifying one as CLI argument, or by
21/// supplying one to the ctor directly.
22/// Repeated renders with the same seed produce bit-identical noise.
23/// @ingroup DSP
24template <typename SampleType>
26 public hart::DSP<SampleType, AdditiveNoise<SampleType>>
27{
28public:
29 enum Params
30 {
31 noiseLevelDb ///< Noise sample peak level in dB
32 };
33
34 /// @brief Creates a DSP that mixes white noise to the signal
35 /// @param initialNoiseLevelDb Noise sample peak level in dB (prior to mixing to the signal).
36 /// Can be overridden at a later point by calling `setValue()` with a `Param::noiseLevelDb` argument.
37 /// @param randomSeed Seed for noise generation.
38 AdditiveNoise (double initialNoiseLevelDb = 0.0, uint_fast32_t randomSeed = CLIConfig::getInstance().getRandomSeed()) :
39 m_initialNoiseLevelDb (initialNoiseLevelDb),
40 m_noiseLevelLinear (static_cast<SampleType> (decibelsToRatio (initialNoiseLevelDb))),
41 m_randomSeed (randomSeed),
42 m_randomNumberGenerator (randomSeed)
43 {
44 }
45
46 void prepare (double /* sampleRateHz */, size_t /* numInputChannels */, size_t /* numOutputChannels */, size_t /* maxBlockSizeFrames */) override {}
47
48 void process (const AudioBuffer<SampleType>& input, AudioBuffer<SampleType>& output, const EnvelopeBuffers& /* envelopeBuffers */, ChannelFlags channelsToProcess) override
49 {
50 const bool symmetricalChannelLayout = input.getNumChannels() == output.getNumChannels();
51 const bool monoToMultiChannelLayout = input.getNumChannels() == 1 && output.getNumChannels() > 1;
52
53 if (! symmetricalChannelLayout && ! monoToMultiChannelLayout)
54 {
55 hassertfalse; // Unexpected channel layout
56 return;
57 }
58
59 for (size_t outputChannel = 0; outputChannel < output.getNumChannels(); ++outputChannel)
60 {
61 const size_t inputChannel = symmetricalChannelLayout ? outputChannel : 0;
62 const SampleType* inputChannelData = input[inputChannel];
63 SampleType* outputChannelData = output[outputChannel];
64
65 if (channelsToProcess[outputChannel] == true)
66 {
67 for (size_t frame = 0; frame < input.getNumFrames(); ++frame)
68 outputChannelData[frame] = inputChannelData[frame] + m_noiseLevelLinear * m_uniformRealDistribution (m_randomNumberGenerator);
69 }
70 else
71 {
72 for (size_t frame = 0; frame < input.getNumFrames(); ++frame)
73 outputChannelData[frame] = inputChannelData[frame];
74 }
75 }
76 }
77
78 /// @brief Sets additive noise level
79 /// @param id Only `Param::noiseLevelDb` is accepted
80 /// @param value Noise sample peak level in dB (prior to mixing to the signal).
81 void setValue (int paramId, double value) override
82 {
83 if (paramId != Params::noiseLevelDb)
84 HART_THROW_OR_RETURN_VOID (hart::ValueError, "Unsupported value ID");
85
86 m_noiseLevelLinear = static_cast<SampleType> (decibelsToRatio (value));
87 }
88
89 void reset() override
90 {
91 m_randomNumberGenerator = std::mt19937 (m_randomSeed);
92 m_uniformRealDistribution.reset();
93 }
94
95 /// @brief Checks support for a specific channel layout
96 /// @details Can operate either in symmetrical channel configurations, i.e.
97 /// same number of inputs and outputs, or mono input to many outputs.
98 bool supportsChannelLayout (size_t numInputChannels, size_t numOutputChannels) const override
99 {
100 return numInputChannels == numOutputChannels
101 || (numInputChannels == 1 && numOutputChannels > 1);
102 }
103
104 virtual void represent (std::ostream& stream) const override
105 {
106 // Updated level values set by setValue() won't be displayed here,
107 // just whatever it was constructed with.
108
109 stream
110 << "AdditiveNoise ("
111 << dbPrecision << m_initialNoiseLevelDb << "_dB, "
112 << m_randomSeed << ')';
113 }
114
115 /// @brief No envelope support yet.
116 /// @note Envelope support can be implemented easily enough, but only
117 /// when there's a good reason to have it. Keeping things simple for now.
118 bool supportsEnvelopeFor (int /* id */) const override
119 {
120 return false;
121 }
122
124
125private:
126 double m_initialNoiseLevelDb;
127 SampleType m_noiseLevelLinear;
128 uint_fast32_t m_randomSeed;
129
130 std::mt19937 m_randomNumberGenerator;
131 std::uniform_real_distribution<SampleType> m_uniformRealDistribution {(SampleType) -1, (SampleType) 1};
132};
133
135
136} // namespace hart
Mixes additive white noise to the signal.
AdditiveNoise(double initialNoiseLevelDb=0.0, uint_fast32_t randomSeed=CLIConfig::getInstance().getRandomSeed())
Creates a DSP that mixes white noise to the signal.
void process(const AudioBuffer< SampleType > &input, AudioBuffer< SampleType > &output, const EnvelopeBuffers &, ChannelFlags channelsToProcess) override
Processes the audio.
void prepare(double, size_t, size_t, size_t) override
Prepare for processing.
void setValue(int paramId, double value) override
Sets additive noise level.
@ noiseLevelDb
Noise sample peak level in dB.
bool supportsEnvelopeFor(int) const override
No envelope support yet.
virtual void represent(std::ostream &stream) const override
Makes a text representation of this DSP effect for test failure outputs.
void reset() override
Resets to initial state.
bool supportsChannelLayout(size_t numInputChannels, size_t numOutputChannels) const override
Checks support for a specific channel layout.
Container for audio data.
A set of boolean flags mapped to each audio channel.
std::bitset< m_maxChannels >::reference operator[](size_t channel)
Access the flag value for a specific channel.
Base for DSP effects.
Definition hart_dsp.hpp:345
Thrown when an inappropriate value is encountered.
#define HART_DSP_COPYABLE(ClassName)
Implements a generic hart::DSP::copy() method.
Definition hart_dsp.hpp:602
#define HART_THROW_OR_RETURN_VOID(ExceptionType, message)
Throws an exception if HART_DO_NOT_THROW_EXCEPTIONS is set, prints a message and returns otherwise.
#define hassertfalse
Triggers a HartAssertException
std::ostream & dbPrecision(std::ostream &stream)
Sets number of decimal places for values in decibels.
static SampleType decibelsToRatio(SampleType valueDb)
Converts dB to linear value (ratio)
#define HART_DSP_DECLARE_ALIASES_FOR(ClassName)
Definition hart_dsp.hpp:619
Holds values set by the user via CLI interface.
uint_fast32_t getRandomSeed()
Gets random seed set by a "`--seed`/`-s`" argument.
static CLIConfig & getInstance()
Get the singleton instance.