1 /** 2 * Various noise sources. 3 * 4 * Copyright: Copyright Auburn Sounds 2015 and later. 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 6 * Authors: Guillaume Piolat 7 */ 8 module dplug.dsp.noise; 9 10 import std.random, 11 std.math; 12 13 import dplug.core.nogc; 14 import dplug.core.random; 15 16 /// Generates white gaussian noise. 17 struct WhiteNoise(T) if (is(T == float) || is(T == double)) 18 { 19 public: 20 void initialize() nothrow @nogc 21 { 22 _rng.seed(nogc_unpredictableSeed()); 23 } 24 25 T nextSample() nothrow @nogc 26 { 27 return randNormal!Xorshift32(_rng, cast(T)0, cast(T)1); 28 } 29 30 void nextBuffer(T* output, int frames) nothrow @nogc 31 { 32 for (int i = 0; i < frames; ++i) 33 output[i] = nextSample(); 34 } 35 36 private: 37 Xorshift32 _rng; 38 } 39 40 unittest 41 { 42 WhiteNoise!float a; 43 WhiteNoise!double b; 44 } 45 46 47 /// Makes a periodic noise for plugins demos. 48 /// Simply multiply you signal to footprint by the next() sample. 49 struct DemoNoise(T) if (is(T == float) || is(T == double)) 50 { 51 public: 52 enum int PERIOD = 30; 53 enum int NOISE_DURATION = 2; 54 55 void initialize(float sampleRate) nothrow @nogc 56 { 57 _noise.initialize(); 58 _increment = 1.0 / sampleRate; 59 _counter = 0; 60 } 61 62 T nextSample() nothrow @nogc 63 { 64 _counter += _increment; 65 while (_counter >= PERIOD) 66 _counter = _counter - PERIOD; 67 68 if (_counter > PERIOD - NOISE_DURATION) 69 return 1 + _noise.nextSample() * 0.3 * sin(PI * (_counter - PERIOD + NOISE_DURATION) / NOISE_DURATION); 70 else 71 return 1; 72 } 73 74 void nextBuffer(T* output, int frames) nothrow @nogc 75 { 76 for (int i = 0; i < frames; ++i) 77 output[i] = nextSample(); 78 } 79 80 private: 81 float _counter; 82 float _increment; 83 WhiteNoise!T _noise; 84 } 85 86 unittest 87 { 88 DemoNoise!float a; 89 DemoNoise!double b; 90 } 91 92 /// 1D perlin noise octave. 93 /// Is useful to slightly move parameters over time. 94 struct Perlin1D(T) if (is(T == float) || is(T == double)) 95 { 96 public: 97 void initialize(double frequency, double samplerate) nothrow @nogc 98 { 99 _rng.seed(nogc_unpredictableSeed()); 100 _current = 0.0f; 101 newGoal(); 102 _phase = 0.0f; 103 _phaseInc = cast(float)(frequency / samplerate); 104 } 105 106 T nextSample() nothrow @nogc 107 { 108 _phase += _phaseInc; 109 if (_phase > 1) 110 { 111 _current = _goal; 112 newGoal(); 113 _phase -= 1; 114 } 115 float f = smootherstep!float(_phase); 116 return f * _goal + (1 - f) * _current; 117 } 118 119 void nextBuffer(T* output, int frames) nothrow @nogc 120 { 121 for (int i = 0; i < frames; ++i) 122 output[i] = nextSample(); 123 } 124 125 private: 126 static T smootherstep(T)(T x) nothrow @nogc 127 { 128 return x * x * x * (x * (x * 6 - 15) + 10); 129 } 130 131 void newGoal() nothrow @nogc 132 { 133 _goal = 2 * (nogc_uniform_float(0.0f, 1.0f, _rng) - 0.5f); 134 } 135 136 float _current; 137 float _phase; 138 float _phaseInc; 139 float _goal; 140 void _newGoal(); 141 142 Xorshift32 _rng; 143 } 144 145 unittest 146 { 147 Perlin1D!float a; 148 Perlin1D!double b; 149 } 150 151 /// Pink noise class using the autocorrelated generator method. 152 /// Method proposed and described by Larry Trammell "the RidgeRat" -- 153 /// see http://home.earthlink.net/~ltrammell/tech/newpink.htm 154 /// There are no restrictions. 155 /// See_also: http://musicdsp.org/showArchiveComment.php?ArchiveID=244 156 struct PinkNoise(T) if (is(T == float) || is(T == double)) 157 { 158 public: 159 void initialize() nothrow @nogc 160 { 161 _rng.seed(nogc_unpredictableSeed()); 162 _contrib[] = 0; 163 _accum = 0; 164 } 165 166 float nextSample() nothrow @nogc 167 { 168 int randu = nogc_uniform_int(0, 32768, _rng); 169 int randv = nogc_uniform_int(-32768, 32768, _rng); // [-32768,32767] 170 171 // Structured block, at most one update is performed 172 for (int n = 0; n < 5; ++n) 173 { 174 if (randu < pPSUM[n]) 175 { 176 _accum -= _contrib[n]; 177 _contrib[n] = randv * pA[n]; 178 _accum += _contrib[n]; 179 break; 180 } 181 } 182 return _accum / 32768.0f; 183 } 184 185 void nextBuffer(T* output, int frames) nothrow @nogc 186 { 187 for (int i = 0; i < frames; ++i) 188 output[i] = nextSample(); 189 } 190 191 private: 192 193 int[5] _contrib; // stage contributions 194 int _accum; // combined generators 195 Xorshift32 _rng; 196 197 static immutable int[5] pA = [ 14055, 12759, 10733, 12273, 15716 ]; 198 static immutable int[5] pPSUM = [ 22347, 27917, 29523, 29942, 30007 ]; 199 } 200 201 unittest 202 { 203 PinkNoise!float a; 204 PinkNoise!double b; 205 } 206 207 private 208 { 209 /// Returns: Normal (Gaussian) random sample. 210 /// See_also: Box-Muller algorithm. 211 float randNormal(RNG)(ref RNG rng, float mean = 0.0, float standardDeviation = 1.0) nothrow @nogc 212 { 213 assert(standardDeviation > 0); 214 double u1; 215 216 do 217 { 218 u1 = nogc_uniform_float(0.0f, 1.0f, rng); 219 } while (u1 == 0); // u1 must not be zero 220 float u2 = nogc_uniform_float(0.0f, 1.0f, rng); 221 float r = sqrt(-2.0 * log(u1)); 222 float theta = 2.0 * PI * u2; 223 return mean + standardDeviation * r * sin(theta); 224 } 225 }