WE Core
Loading...
Searching...
No Matches
PerlinSource.hpp
Go to the documentation of this file.
1/*
2 * File: PerlinSource.hpp
3 *
4 * Created: 30/12/2024
5 *
6 * This file is part of WECore.
7 *
8 * WECore is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * WECore is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with WECore. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#pragma once
23
24#include <algorithm>
25#include <random>
26#include <vector>
27#include "ModulationSource.h"
29
30namespace WECore::Perlin {
31 inline float fade(float t) {
32 return t * t * t * (t * (t * 6 - 15) + 10);
33 }
34
35 inline float lerp(float a, float b, float t) {
36 return a + t * (b - a);
37 }
38
39 inline float grad(int hash, float x) {
40 // Keep only the last 4 bits
41 const int h = hash & 15;
42
43 // Randomly return a negtive if the top bit is 1
44 if (h & 8) {
45 return -x;
46 } else {
47 return x;
48 }
49 }
50
51 inline float perlin1D(float x, const std::vector<int>& permutation) {
52 // Get the indexes that our x is between
53 const int x0 = static_cast<int>(std::floor(x)) & 255;
54 const int x1 = (x0 + 1) & 255;
55
56 // Look up the indexes
57 const int g0 = permutation[x0];
58 const int g1 = permutation[x1];
59
60 // Get the distance of x from the lower index
61 const float xf = x - floor(x);
62
63 // Get the gradients at our position x for each index
64 const float dot0 = grad(g0, xf);
65 const float dot1 = grad(g1, xf - 1.0f);
66
67 // Interpolate between gradient contributions
68 const float u = fade(xf);
69 return lerp(dot0, dot1, u);
70 }
71
72 namespace Parameters {
74 DEPTH(0, 1, 0.5);
75
83
85 }
86
87 class PerlinSource : public ModulationSource<double> {
88 public:
89 PerlinSource() : _outputMode(Parameters::OUTPUTMODE.defaultValue),
90 _rawFreq(Parameters::FREQ.defaultValue),
92 _rawDepth(Parameters::DEPTH.defaultValue),
94 _sampleRate(44100),
95 _wavePosition(0) {
96 // Initialize the permutation vector with the default permutation
97 _permutation = {
98 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225,
99 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148,
100 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32,
101 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175,
102 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122,
103 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54,
104 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169,
105 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64,
106 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212,
107 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213,
108 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9,
109 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104,
110 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241,
111 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157,
112 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93,
113 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180
114 };
115 }
116
117 virtual ~PerlinSource() override = default;
118
119 void setFreq(double freq) { _rawFreq = Parameters::FREQ.BoundsCheck(freq); }
120 void setDepth(double depth) { _rawDepth = Parameters::DEPTH.BoundsCheck(depth); }
122 void setSampleRate(double val) { _sampleRate = val; }
123
124 double getFreq() const { return _rawFreq; }
126 double getDepth() const { return _rawDepth; }
128 int getOutputMode() { return _outputMode; }
129
130 inline bool addFreqModulationSource(std::shared_ptr<ModulationSource> source);
131 inline bool removeFreqModulationSource(std::shared_ptr<ModulationSource> source);
132 inline bool setFreqModulationAmount(size_t index, double amount);
134 std::vector<ModulationSourceWrapper<double>> getFreqModulationSources() const { return _freqModulationSources; }
135
136 inline bool addDepthModulationSource(std::shared_ptr<ModulationSource> source);
137 inline bool removeDepthModulationSource(std::shared_ptr<ModulationSource> source);
138 inline bool setDepthModulationAmount(size_t index, double amount);
140 std::vector<ModulationSourceWrapper<double>> getDepthModulationSources() const { return _depthModulationSources; }
141
147 return new PerlinSource(*this);
148 }
149
150 protected:
152
153 double _rawFreq,
159
160 std::vector<ModulationSourceWrapper<double>> _freqModulationSources,
162
163 std::vector<int> _permutation;
164
165 inline double _getNextOutputImpl(double inSample) override;
166
167 void _resetImpl() override { _wavePosition = 0; }
168
169 private:
170 // Used when cloning
184 };
185
186 bool PerlinSource::addFreqModulationSource(std::shared_ptr<ModulationSource> source) {
187 // Check if the source is already in the list
188 for (const ModulationSourceWrapper<double>& existingSource : _freqModulationSources) {
189 if (existingSource.source == source) {
190 return false;
191 }
192 }
193
194 _freqModulationSources.push_back({source, 0});
195 return true;
196 }
197
198 bool PerlinSource::removeFreqModulationSource(std::shared_ptr<ModulationSource> source) {
199 for (auto it = _freqModulationSources.begin(); it != _freqModulationSources.end(); it++) {
200 if ((*it).source == source) {
201 _freqModulationSources.erase(it);
202 return true;
203 }
204 }
205
206 return false;
207 }
208
209 bool PerlinSource::setFreqModulationAmount(size_t index, double amount) {
210 if (index >= _freqModulationSources.size()) {
211 return false;
212 }
213
214 _freqModulationSources[index].amount = amount;
215 return true;
216 }
217
218 bool PerlinSource::addDepthModulationSource(std::shared_ptr<ModulationSource> source) {
219 // Check if the source is already in the list
220 for (const ModulationSourceWrapper<double>& existingSource : _depthModulationSources) {
221 if (existingSource.source == source) {
222 return false;
223 }
224 }
225
226 _depthModulationSources.push_back({source, 0});
227 return true;
228 }
229
230 bool PerlinSource::removeDepthModulationSource(std::shared_ptr<ModulationSource> source) {
231 for (auto it = _depthModulationSources.begin(); it != _depthModulationSources.end(); it++) {
232 if ((*it).source == source) {
233 _depthModulationSources.erase(it);
234 return true;
235 }
236 }
237
238 return false;
239 }
240
241 bool PerlinSource::setDepthModulationAmount(size_t index, double amount) {
242 if (index >= _depthModulationSources.size()) {
243 return false;
244 }
245
246 _depthModulationSources[index].amount = amount;
247 return true;
248 }
249
250 double PerlinSource::_getNextOutputImpl(double /*inSample*/) {
251 // Get the mod amount to use, divide by 2 to reduce range to -0.5:0.5
252 const double freqModValue {calcModValue(_freqModulationSources) / 2};
253 const double depthModValue {calcModValue(_depthModulationSources) / 2};
254
255 // Calculate the frequency value after modulation
256 const double freq {Parameters::FREQ.BoundsCheck(
257 _rawFreq + (Parameters::FREQ.maxValue * freqModValue)
258 )};
259 _modulatedFreqValue = freq;
260
261 // Calculate the depth value after modulation
262 const double depth {Parameters::DEPTH.BoundsCheck(
263 _rawDepth + (Parameters::DEPTH.maxValue * depthModValue)
264 )};
265 _modulatedDepthValue = depth;
266
267 // Calculate the Perlin noise value
268 double noiseValue {perlin1D(_wavePosition, _permutation)};
270
271 noiseValue = _outputMode == Parameters::OUTPUTMODE.BIPOLAR ? noiseValue : (noiseValue + 0.5);
272
273 return noiseValue * _modulatedDepthValue;
274 }
275}
std::vector< ModulationSourceWrapper< double > > getDepthModulationSources() const
bool setDepthModulationAmount(size_t index, double amount)
std::vector< ModulationSourceWrapper< double > > _depthModulationSources
void setFreqModulationSources(std::vector< WECore::ModulationSourceWrapper< double > > sources)
double _getNextOutputImpl(double inSample) override
virtual ~PerlinSource() override=default
bool removeDepthModulationSource(std::shared_ptr< ModulationSource > source)
bool setFreqModulationAmount(size_t index, double amount)
std::vector< ModulationSourceWrapper< double > > _freqModulationSources
void setDepthModulationSources(std::vector< WECore::ModulationSourceWrapper< double > > sources)
std::vector< int > _permutation
double getModulatedDepthValue() const
bool addFreqModulationSource(std::shared_ptr< ModulationSource > source)
bool removeFreqModulationSource(std::shared_ptr< ModulationSource > source)
PerlinSource * clone() const
PerlinSource(const PerlinSource &other)
std::vector< ModulationSourceWrapper< double > > getFreqModulationSources() const
bool addDepthModulationSource(std::shared_ptr< ModulationSource > source)
const ParameterDefinition::RangedParameter< double > FREQ(0, 20, 1)
const OutputModeParameter OUTPUTMODE
const ParameterDefinition::RangedParameter< double > DEPTH(0, 1, 0.5)
float perlin1D(float x, const std::vector< int > &permutation)
float grad(int hash, float x)
float lerp(float a, float b, float t)
float fade(float t)
SampleType calcModValue(const std::vector< ModulationSourceWrapper< SampleType > > &sources)