67 sample_rate_ = sample_rate > 0.0 ? sample_rate : sample_rate_;
68 update_coefficients();
70 for (std::size_t index = 0; index < normalisations_.size(); ++index) {
72 measure_normalisation();
73 normalisations_[index] = norm_;
76 norm_ = normalisations_[
static_cast<std::size_t
>(color_)];
84 const auto index = std::min(
static_cast<std::size_t
>(
c), normalisations_.size() - 1);
86 norm_ = normalisations_[index];
112 return static_cast<SampleType
>(norm_ * colorise(white_next()));
116 for (
int i = 0;
i < num_samples; ++
i)
124 return static_cast<SampleType
>(white_next());
143 static constexpr std::size_t kPinkPoles = 5;
144 static constexpr double kPinkBaseHz = 8.0;
145 static constexpr double kPinkSpacing = 8.0;
149 static constexpr double kBrownHz = 12.0;
152 static constexpr double kTargetRms = 0.57735026918962576;
154 double white_next() {
155 state_ ^= state_ << 13;
156 state_ ^= state_ >> 17;
157 state_ ^= state_ << 5;
159 return static_cast<double>(state_) * (1.0 / 2147483648.0) - 1.0;
162 double colorise(
double w) {
171 return differentiate(pink(w));
173 return differentiate(w);
178 double pink(
double w) {
180 for (std::size_t k = 0;
k < kPinkPoles; ++
k) {
181 pink_state_[
k] =
snap_to_zero(pink_state_[k] + pink_a_[k] * (w - pink_state_[k]));
182 sum += pink_w_[
k] * pink_state_[
k];
187 double brown(
double w) {
188 brown_state_ =
snap_to_zero(brown_state_ + brown_a_ * (w - brown_state_));
192 double differentiate(
double x) {
193 const double y =
x - diff_state_;
198 void reset_filters() {
199 pink_state_.fill(0.0);
204 void update_coefficients() {
205 double weight_sum = 0.0;
206 for (std::size_t k = 0;
k < kPinkPoles; ++
k) {
207 const double fc = kPinkBaseHz * std::pow(kPinkSpacing,
static_cast<double>(k));
210 const double clamped = std::min(fc, 0.45 * sample_rate_);
211 pink_a_[
k] = 1.0 - std::exp(-2.0 * 3.14159265358979323846 * clamped / sample_rate_);
212 pink_w_[
k] = 1.0 / std::sqrt(clamped);
213 weight_sum += pink_w_[
k];
217 for (std::size_t k = 0;
k < kPinkPoles; ++
k)
218 pink_w_[k] /= weight_sum;
220 brown_a_ = 1.0 - std::exp(-2.0 * 3.14159265358979323846 * kBrownHz / sample_rate_);
227 void measure_normalisation() {
235 constexpr int kBurst = 16384;
238 constexpr int kWarmup = 4096;
240 const std::uint32_t saved_state = state_;
241 const auto saved_pink = pink_state_;
242 const double saved_brown = brown_state_;
243 const double saved_diff = diff_state_;
247 for (
int i = 0;
i < kWarmup; ++
i)
248 colorise(white_next());
251 for (
int i = 0;
i < kBurst; ++
i) {
252 const double y = colorise(white_next());
255 const double rms = std::sqrt(sum_sq / kBurst);
256 norm_ =
rms > 1
e-12 ? kTargetRms /
rms : 1.0;
258 state_ = saved_state;
259 pink_state_ = saved_pink;
260 brown_state_ = saved_brown;
261 diff_state_ = saved_diff;
264 double sample_rate_ = 44100.0;
269 std::array<double, 5> normalisations_{1.0, 1.0, 1.0, 1.0, 1.0};
271 std::array<double, kPinkPoles> pink_a_{};
272 std::array<double, kPinkPoles> pink_w_{};
273 std::array<double, kPinkPoles> pink_state_{};
274 double brown_a_ = 0.0;
275 double brown_state_ = 0.0;
276 double diff_state_ = 0.0;
A deterministic, colourable noise generator.
Definition noise_source.hpp:51
std::uint32_t seed() const
Definition noise_source.hpp:100
void set_color(NoiseColor c)
Selects the spectral tilt.
Definition noise_source.hpp:83
void process(SampleType *buffer, int num_samples)
Definition noise_source.hpp:115
SampleType process()
Next sample, normalised so every colour has approximately the same RMS.
Definition noise_source.hpp:111
void reset()
Rewinds the generator to its seed and clears the colour filter state.
Definition noise_source.hpp:105
void prepare(double sample_rate)
Fixes the sample rate and re-measures the per-colour normalisation.
Definition noise_source.hpp:66
NoiseSourceT()
A default-constructed source is immediately usable at 44.1 kHz, so a voice that forgets to call prepa...
Definition noise_source.hpp:60
void set_seed(std::uint32_t seed)
Sets the seed used by reset().
Definition noise_source.hpp:96
SampleType white()
Raw uniform white sample in [-1, 1), bypassing the colour filter and the normalisation.
Definition noise_source.hpp:123
static constexpr std::uint32_t default_seed
Definition noise_source.hpp:55
NoiseColor color() const
Definition noise_source.hpp:90
Definition additive_bank.hpp:218
@ buffer
A borrowed static buffer with a traversable playhead.
Definition granular.hpp:110
@ rms
Running mean-square. Reads program loudness.
Definition feedforward_compressor.hpp:120
NoiseSourceT< double > NoiseSource64
Definition noise_source.hpp:280
@ c
Definition spectrum_trace.hpp:35
T snap_to_zero(T x)
Returns 0 if |x| < snap_threshold, else x.
Definition denormal.hpp:45
@ i
Definition formant_filter_bank.hpp:20
@ e
Definition formant_filter_bank.hpp:20
NoiseColor
Spectral tilt of a NoiseSourceT, named by the usual colour convention.
Definition noise_source.hpp:17
@ blue
+3 dB/octave — the mirror of pink.
Definition noise_source.hpp:21
@ pink
-3 dB/octave — equal power per octave.
Definition noise_source.hpp:19
@ brown
-6 dB/octave — integrated white ("red" noise).
Definition noise_source.hpp:20
@ violet
+6 dB/octave — differentiated white ("purple" noise).
Definition noise_source.hpp:22
@ white
0 dB/octave — the raw generator output.
Definition noise_source.hpp:18
NoiseSourceT< float > NoiseSource
Definition noise_source.hpp:279
float sum(const float *data, std::size_t count) noexcept
@ y
Definition input_events.hpp:42
@ k
Definition input_events.hpp:40
@ x
Definition input_events.hpp:41