Anklang 0.3.0-460-gc4ef46ba
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
colorednoise.cc
Go to the documentation of this file.
1 // This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
2#include "ase/processor.hh"
3#include "ase/randomhash.hh"
4#include "ase/internal.hh"
5
6namespace {
7using namespace Ase;
8
10struct WhiteRand {
11 uint64_t rmix_, next_;
12 WhiteRand (uint64_t seed1 = random_int64(), uint64_t seed2 = random_int64()) :
13 rmix_ (seed1 | 1), next_ (seed2 ? seed2 : 0x14057b7ef767814fU)
14 {
15 rand64(); // avoid seed2 handout
16 rand64(); // avoid seed1 * M handout
17 rand64(); // helps with bad seeds (e.g. 31-bit seeds from rand())
18 }
19 inline uint64_t
20 rand64()
21 {
22 constexpr uint64_t M = 0xd3833e804f4c574bU;
23 const uint64_t last = next_;
24 next_ = rmix_ * M;
25 rmix_ = rotr (rmix_ - last, 37);
26 return last;
27 }
29 randf2()
30 {
31 const uint64_t r = rand64();
32 const uint32_t h = r >> 32, l = r;
33 constexpr float i2f = 4.65661287416159475086293992373695129617e-10; // 1.0 / 2147483647.5;
34 return { int32_t (h) * i2f, int32_t (l) * i2f };
35 }
36};
37
41template<size_t N, class D, class F> extern inline F
42iir_eval_tdf2 (const D *b, const D *a, D *w, F x)
43{ // https://en.wikipedia.org/wiki/Digital_biquad_filter#Transposed_Direct_form_2
44 static_assert (N >= 1); // assumes a[0] == 1.0
45 const D y = x * b[0] + w[0];
46 D v = x * b[N] - y * a[N];
47 size_t n = N;
48 while (--n)
49 {
50 const D t = w[n];
51 w[n] = v;
52 v = x * b[n] + t - y * a[n];
53 }
54 w[0] = v;
55 return y;
56}
57
59template<class Float>
60struct PinkFilter {
61 // https://ccrma.stanford.edu/~jos/sasp/Example_Synthesis_1_F_Noise.html
62 static constexpr size_t N = 3;
63 static constexpr Float B[N + 1] = { 0.049922035, -0.095993537, 0.050612699, -0.004408786 };
64 static constexpr Float A[N + 1] = { 1, -2.494956002, 2.017265875, -0.522189400 };
65 float delays_[N] = { 0, };
66 void reset () { floatfill (delays_, 0.0, N); }
67 Float eval (Float x) { return iir_eval_tdf2<N> (B, A, delays_, x); }
68};
69
70template<class F> static inline F
71db2amp (F dB)
72{
73 constexpr F db2log2 = 0.166096404744368117393515971474469508793; // log2 (10) / 20
74 return std::exp2 (dB * db2log2);
75}
76
78class ColoredNoise : public AudioProcessor {
79 using Pink = PinkFilter<float>;
80 OBusId stereout_;
81 WhiteRand white_rand_;
82 Pink pink0, pink1;
83 float gain_factor_ = 1.0;
84 bool mono_ = false;
85 bool pink_ = true;
86 enum Params { GAIN = 1, MONO, PINK };
87public:
88 ColoredNoise (const ProcessorSetup &psetup) :
89 AudioProcessor (psetup)
90 {}
91 static void
92 static_info (AudioProcessorInfo &info)
93 {
94 info.version = "1";
95 info.label = "Pink & White Noise";
96 info.category = "Generators";
97 info.creator_name = "Tim Janik";
98 info.website_url = "https://anklang.testbit.eu";
99 }
100 void
101 initialize (SpeakerArrangement busses) override
102 {
104 stereout_ = add_output_bus ("Stereo Out", SpeakerArrangement::STEREO);
105
106 ParameterMap pmap;
107
108 pmap.group = _("Noise Settings");
109 pmap[GAIN] = Param { "gain", _("Gain"), _("Gain"), 0, "dB", { -96, 24, }, };
110 pmap[MONO] = Param { "mono", _("Monophonic"), _("Mono"), false };
111 pmap[PINK] = Param { "pink", _("Pink Noise"), _("Pink"), true };
112
113 install_params (pmap);
114 }
115 void
116 adjust_param (uint32_t tag) override
117 {
118 switch (Params (tag))
119 {
120 case GAIN: gain_factor_ = db2amp (get_param (tag)); break;
121 case MONO: mono_ = get_param (tag); break;
122 case PINK: pink_ = get_param (tag); break;
123 }
124 }
125 void
126 reset (uint64 target_stamp) override
127 {
128 pink0.reset();
129 pink1.reset();
130 adjust_all_params();
131 }
132 void render (uint n_frames) override;
133 // optimize rendering variants via template argument
134 enum Cases { INSTEREO = 1, WITHPINK = 2, WITHGAIN = 4, MASK = 0x7 };
135 template<Cases> void render_cases (float *out0, float *out1, uint n_frames, const float gain);
136 using RenderF = void (ColoredNoise::*) (float*, float*, uint, float);
137};
138
139static auto noise_module = register_audio_processor<ColoredNoise> ("Ase::Devices::ColoredNoise");
140
141template<ColoredNoise::Cases CASES> void
142ColoredNoise::render_cases (float *out0, float *out1, uint n_frames, const float gain)
143{
144 static_assert (CASES <= MASK);
145 for (size_t i = 0; i < n_frames; i++)
146 {
147 auto [f0, f1] = white_rand_.randf2();
148 if_constexpr (bool (CASES & WITHPINK) && bool (CASES & INSTEREO))
149 {
150 f0 = pink0.eval (f0); // left filter
151 f1 = pink1.eval (f1); // right filter
152 }
153 if_constexpr (bool (CASES & WITHPINK) && !bool (CASES & INSTEREO))
154 {
155 f0 = pink0.eval (f0); // mono filter
156 f1 = pink0.eval (f1); // mono filter
157 }
158 if_constexpr (bool (CASES & WITHGAIN))
159 {
160 f0 *= gain;
161 f1 *= gain;
162 }
163 if_constexpr (bool (CASES & INSTEREO))
164 {
165 out0[i] = f0;
166 out1[i] = f1;
167 }
168 else
169 {
170 out0[i] = f0;
171 out1[i] = f0;
172 i++;
173 out0[i] = f1;
174 out1[i] = f1;
175 }
176 }
177}
178
179// construct table *outside* of time critical render() method
180static const auto render_table = make_case_table<ColoredNoise::MASK> ([] (auto CASE)
181 { // decltype (CASE) is std::integral_constant<unsigned long, N...>
182 return &ColoredNoise::render_cases<ColoredNoise::Cases (CASE.value)>;
183 });
184
185void
186ColoredNoise::render (uint n_frames)
187{
188 apply_input_events();
189 float *out0 = oblock (stereout_, 0);
190 float *out1 = oblock (stereout_, 1);
191 const float gain = gain_factor_;
192 const uint index = INSTEREO * !mono_ + WITHPINK * pink_ + WITHGAIN * (gain != 1.0);
193 (this->*render_table[index]) (out0, out1, n_frames, gain);
194}
195
196} // Anon
Audio signal AudioProcessor base class, implemented by all effects and instruments.
Definition processor.hh:76
void remove_all_buses()
Remove existing bus configurations, useful at the start of configure().
Definition processor.cc:646
double get_param(Id32 paramid)
Fetch value of parameter id.
Definition processor.hh:525
OBusId add_output_bus(CString uilabel, SpeakerArrangement speakerarrangement, const String &hints="", const String &blurb="")
Add an output bus with uilabel and channels configured via speakerarrangement.
Definition processor.cc:530
virtual void initialize(SpeakerArrangement busses)=0
Definition processor.cc:432
void install_params(const AudioParams::Map &params)
Reset list of parameters, enqueues parameter value initializaiton events.
Definition processor.cc:213
T exp2(T... args)
#define _(...)
Retrieve the translation of a C or C++ string.
Definition internal.hh:18
#define if_constexpr
Indentation helper for editors that cannot (yet) decipher if constexpr
Definition internal.hh:40
typedef float
The Anklang C++ API namespace.
Definition api.hh:9
CString website_url
Website of/about this AudioProcessor.
Definition processor.hh:35
uint64_t uint64
A 64-bit unsigned integer, use PRI*64 in format strings.
Definition cxxaux.hh:25
void floatfill(float *dst, float f, size_t n)
Fill n values of dst with f.
Definition datautils.hh:29
SpeakerArrangement
Definition transport.hh:11
@ MONO
Single Channel (M)
OBusId
ID type for AudioProcessor output buses, buses are numbered with increasing index.
Definition processor.hh:25
CString version
Version identifier.
Definition processor.hh:31
CString creator_name
Name of the creator.
Definition processor.hh:36
CString label
Preferred user interface name.
Definition processor.hh:30
uint32_t uint
Provide 'uint' as convenience type.
Definition cxxaux.hh:18
CString category
Category to allow grouping for processors of similar function.
Definition processor.hh:32
uint64_t random_int64()
Detailed information and common properties of AudioProcessor subclasses.
Definition processor.hh:29
T rotr(T... args)
typedef uint64_t
Structured initializer for Parameter.
Definition parameter.hh:31
Parameter list construction helper.
Definition parameter.hh:93
String group
Group to be applied to all newly inserted Parameter objects.
Definition parameter.hh:95