tracktion-engine 3.0-10-g034fdde4aa5
Tracktion Engine — High level data model for audio applications

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_FourOscPlugin.h
Go to the documentation of this file.
1 /*
2 ,--. ,--. ,--. ,--.
3 ,-' '-.,--.--.,--,--.,---.| |,-.,-' '-.`--' ,---. ,--,--, Copyright 2018
4 '-. .-'| .--' ,-. | .--'| /'-. .-',--.| .-. || \ Tracktion Software
5 | | | | \ '-' \ `--.| \ \ | | | |' '-' '| || | Corporation
6 `---' `--' `--`--'`---'`--'`--' `---' `--' `---' `--''--' www.tracktion.com
7*/
8
9
10namespace tracktion { inline namespace engine
11{
12
13class FODelay;
14class FOChorus;
15
16//==============================================================================
18template <class T>
20{
21public:
22 void reset (double sr, double time) { delta = 1.0f / T (sr * time); }
23 T getCurrentValue() { return currentValue; }
24 void setValue (T v) { targetValue = v; }
25 void snapToValue() { currentValue = targetValue; }
26
27 void process (int n)
28 {
29 if (targetValue != currentValue)
30 for (int i = 0; i < n; i++)
31 getNextValue();
32 }
33
34 T getNextValue()
35 {
36 if (currentValue < targetValue)
37 currentValue = juce::jmin (targetValue, currentValue + delta);
38 else if (currentValue > targetValue)
39 currentValue = juce::jmax (targetValue, currentValue - delta);
40 return currentValue;
41 }
42
43 void setValueUnsmoothed (T v)
44 {
45 targetValue = v;
46 currentValue = v;
47 }
48
49private:
50 T delta = 0, targetValue = 0, currentValue = 0;
51};
52
53//==============================================================================
55{
56public:
57 //==============================================================================
58 enum WaveShape : int
59 {
60 none,
61 sine,
62 triangle,
63 sawUp,
64 sawDown,
65 square,
66 random
67 };
68
69 //==============================================================================
71 {
72 Parameters() = default;
73 Parameters (float frequencyIn, float phaseOffsetIn, float offsetIn, float depthIn,
74 WaveShape waveShapeIn, float pulseWidthIn) :
75 waveShape (waveShapeIn), frequency (frequencyIn), phaseOffset (phaseOffsetIn),
76 offset (offsetIn), depth (depthIn), pulseWidth (pulseWidthIn) {}
77
78 WaveShape waveShape = sine;
79 float frequency = 0, phaseOffset = 0, offset = 0, depth = 0, pulseWidth = 0;
80 };
81
82 //==============================================================================
83 void setSampleRate (double newSampleRate) { sampleRate = newSampleRate; }
84 void setParameters (Parameters newParameters) { parameters = newParameters; }
85 void reset() { phase = 0; }
86
87 void process (int numSamples)
88 {
89 double step = 0.0;
90 if (parameters.frequency > 0.001f)
91 step = parameters.frequency / sampleRate;
92
93 for (int i = 0; i < numSamples; i++)
94 {
95 phase += step;
96 if (phase >= 1.0)
97 phase -= 1.0;
98
99 float localPhase = 0.0f;
100
101 if (parameters.phaseOffset != 0)
102 localPhase = wrapValue ((float) std::fmod (phase + parameters.phaseOffset, 1.0f), 1.0f);
103 else
104 localPhase = wrapValue ((float) phase, 1.0f);
105
106 jassert (localPhase >= 0.0f && localPhase <= 1.0f);
107
108 if (parameters.waveShape == random)
109 {
110 if (localPhase < lastLocalPhase)
111 lastRandomVal = randomSource.nextFloat() * 2.0f - 1.0f;
112
113 lastLocalPhase = localPhase;
114 }
115 }
116 }
117
118 float getCurrentValue()
119 {
120 float val = 0.0f, localPhase = 0.0f;
121
122 if (parameters.phaseOffset != 0)
123 localPhase = wrapValue ((float) std::fmod (phase + parameters.phaseOffset, 1.0f), 1.0f);
124 else
125 localPhase = wrapValue ((float) phase, 1.0f);
126
127 jassert (localPhase >= 0.0f && localPhase <= 1.0f);
128
129 switch (parameters.waveShape)
130 {
131 case none: val = 0; break;
132 case sine: val = std::sin (localPhase * juce::MathConstants<float>::pi * 2); break;
133 case triangle: val = (localPhase < 0.5f) ? (4.0f * localPhase - 1.0f) : (-4.0f * localPhase + 3.0f); break;
134 case sawUp: val = localPhase * 2.0f - 1.0f; break;
135 case sawDown: val = (1.0f - localPhase) * 2.0f - 1.0f; break;
136 case square: val = (localPhase < parameters.pulseWidth) ? 1.0f : -1.0f; break;
137 case random: val = lastRandomVal; break;
138 }
139
140 return (val * parameters.depth + parameters.offset);
141 }
142
143private:
144 Parameters parameters;
145
146 double phase = 0, lastLocalPhase = 1, sampleRate = 0;
147 float lastRandomVal = 0;
148
149 juce::Random randomSource {1};
150
151 inline float wrapValue (float v, float range)
152 {
153 while (v >= range) v -= range;
154 while (v < 0) v += range;
155 return v;
156 }
157};
158
159//==============================================================================
160class FourOscPlugin : public Plugin,
161 private juce::MPESynthesiser,
162 private juce::AsyncUpdater,
164{
165public:
167 ~FourOscPlugin() override;
168
169 bool isMono() const { return voiceModeValue.get() == 0; }
170 bool isLegato() const { return voiceModeValue.get() == 1; }
171 bool isPoly() const { return voiceModeValue.get() == 2; }
172
173 //==============================================================================
174 static const char* getPluginName() { return NEEDS_TRANS("4OSC"); }
175 static const char* xmlTypeName;
176
177 juce::String getName() const override { return TRANS("4OSC"); }
178 juce::String getPluginType() override { return xmlTypeName; }
179 juce::String getShortName (int) override { return "4OSC"; }
180 juce::String getSelectableDescription() override { return TRANS("4OSC Plugin"); }
181 bool needsConstantBufferSize() override { return false; }
182
183 int getNumOutputChannelsGivenInputs (int numInputChannels) override { return juce::jmin (numInputChannels, 2); }
184
185 void initialise (const PluginInitialisationInfo&) override;
186 void deinitialise() override;
187
188 void reset() override;
189
190 void applyToBuffer (const PluginRenderContext&) override;
191
192 //==============================================================================
193 bool takesMidiInput() override { return true; }
194 bool takesAudioInput() override { return false; }
195 bool isSynth() override { return true; }
196 bool producesAudioWhenNoAudioInput() override { return true; }
197 double getTailLength() const override { return ampRelease->getCurrentValue(); }
198
199 void restorePluginStateFromValueTree (const juce::ValueTree&) override;
200
201 float getCurrentTempo() { return currentTempo; }
202
203private:
205
206public:
207 //==============================================================================
209 {
210 OscParams (FourOscPlugin& plugin, int oscNum);
211 void attach();
212 void detach();
213
214 juce::CachedValue<int> waveShapeValue, voicesValue;
215 juce::CachedValue<float> tuneValue, fineTuneValue, levelValue, pulseWidthValue,
216 detuneValue, spreadValue, panValue;
217
218 AutomatableParameter::Ptr tune, fineTune, level, pulseWidth, detune, spread, pan;
219
220 void restorePluginStateFromValueTree (const juce::ValueTree& v)
221 {
222 copyPropertiesToCachedValues (v, tuneValue, fineTuneValue, levelValue, pulseWidthValue,
223 detuneValue, spreadValue, panValue, waveShapeValue, voicesValue);
224 }
225 };
226
228
229 //==============================================================================
231 {
232 LFOParams (FourOscPlugin& plugin, int lfoNum);
233 void attach();
234 void detach();
235
236 juce::CachedValue<bool> syncValue;
237 juce::CachedValue<int> waveShapeValue;
238 juce::CachedValue<float> rateValue, beatValue, depthValue;
239
240 AutomatableParameter::Ptr rate, depth;
241
242 void restorePluginStateFromValueTree (const juce::ValueTree& v)
243 {
244 copyPropertiesToCachedValues (v, rateValue, beatValue, depthValue, waveShapeValue, syncValue);
245 }
246 };
247
249
250 //==============================================================================
252 {
253 MODEnvParams (FourOscPlugin& plugin, int envNum);
254 void attach();
255 void detach();
256
257 juce::CachedValue<float> modAttackValue, modDecayValue, modSustainValue, modReleaseValue;
258 AutomatableParameter::Ptr modAttack, modDecay, modSustain, modRelease;
259
260 void restorePluginStateFromValueTree (const juce::ValueTree& v)
261 {
262 copyPropertiesToCachedValues (v, modAttackValue, modDecayValue, modSustainValue, modReleaseValue);
263 }
264 };
265
267
268 //==============================================================================
269 juce::CachedValue<float> ampAttackValue, ampDecayValue, ampSustainValue, ampReleaseValue, ampVelocityValue;
270 juce::CachedValue<float> filterAttackValue, filterDecayValue, filterSustainValue, filterReleaseValue, filterFreqValue,
271 filterResonanceValue, filterAmountValue, filterKeyValue, filterVelocityValue;
272 juce::CachedValue<int> filterTypeValue, filterSlopeValue;
273 juce::CachedValue<bool> ampAnalogValue;
274
275 AutomatableParameter::Ptr ampAttack, ampDecay, ampSustain, ampRelease, ampVelocity;
276 AutomatableParameter::Ptr filterAttack, filterDecay, filterSustain, filterRelease, filterFreq, filterResonance, filterAmount, filterKey, filterVelocity;
277
278 juce::CachedValue<bool> distortionOnValue, reverbOnValue, delayOnValue, chorusOnValue;
279
280 juce::CachedValue<float> distortionValue;
281 AutomatableParameter::Ptr distortion;
282
283 juce::CachedValue<float> reverbSizeValue, reverbDampingValue, reverbWidthValue, reverbMixValue;
284 AutomatableParameter::Ptr reverbSize, reverbDamping, reverbWidth, reverbMix;
285
286 juce::CachedValue<float> delayValue, delayFeedbackValue, delayCrossfeedValue, delayMixValue;
287 AutomatableParameter::Ptr delayFeedback, delayCrossfeed, delayMix;
288
289 juce::CachedValue<float> chorusSpeedValue, chorusDepthValue, chorusWidthValue, chorusMixValue;
290 AutomatableParameter::Ptr chorusSpeed, chorusDepth, chorusWidth, chorusMix;
291
292 juce::CachedValue<int> voiceModeValue, voicesValue;
293 juce::CachedValue<float> legatoValue, masterLevelValue;
294 AutomatableParameter::Ptr legato, masterLevel;
295
296 //==============================================================================
297
298 enum ModSource : int
299 {
300 none = -1,
301 lfo1 = 0,
302 lfo2,
303 env1,
304 env2,
305 mpePressure,
306 mpeTimbre,
307 midiNoteNum,
308 midiVelocity,
309 ccBankSelect,
310 ccPolyMode = ccBankSelect + 127,
311 numModSources
312 };
313
314 juce::String modulationSourceToName (ModSource src);
315 juce::String modulationSourceToID (ModSource src);
316 ModSource idToModulationSource (juce::String idStr);
317 bool isModulated (AutomatableParameter::Ptr param);
318 juce::Array<float> getLiveModulationPositions (AutomatableParameter::Ptr param);
319 juce::Array<ModSource> getModulationSources (AutomatableParameter::Ptr param);
320 float getModulationDepth (ModSource src, AutomatableParameter::Ptr param);
321 void setModulationDepth (ModSource src, AutomatableParameter::Ptr param, float depth);
322 void clearModulation (ModSource src, AutomatableParameter::Ptr param);
323
325 {
326 public:
327 ModAssign()
328 {
329 for (auto& d : depths)
330 d = -1000.0f;
331 }
332
333 inline void updateCachedInfo()
334 {
335 int f = -1, l = -1;
336 for (int i = 0; i < juce::numElementsInArray (depths); i++)
337 {
338 if (depths[i] >= -1.0f && f == -1) f = i;
339 if (depths[i] >= -1.0) l = i;
340 }
341
342 firstModIndex = f;
343 lastModIndex = l;
344 }
345
346 inline bool isModulated()
347 {
348 return firstModIndex != -1 && lastModIndex != -1;
349 }
350
351 int firstModIndex = -1, lastModIndex = -1;
352 float depths[numModSources] = {};
353 };
354
356 float controllerValues[128] = {0};
357
358 float getLevel (int channel);
359
360private:
361 //==============================================================================
362 void valueTreeChanged() override;
363 void valueTreePropertyChanged (juce::ValueTree&, const juce::Identifier&) override;
364 void valueTreeChildAdded (juce::ValueTree&, juce::ValueTree&) override;
365 void valueTreeChildRemoved (juce::ValueTree&, juce::ValueTree&, int) override;
366 void handleAsyncUpdate() override;
367 void handleController (int midiChannel, int controllerNumber, int controllerValue) override;
368
369 void flushPluginStateToValueTree() override;
370
371 void loadModMatrix();
372 void setupTextFunctions();
373 AutomatableParameter* addParam (const juce::String& paramID, const juce::String& name, juce::NormalisableRange<float> valueRange, juce::String label = {});
374
376 void updateParams (juce::AudioBuffer<float>& buffer);
377 void applyEffects (juce::AudioBuffer<float>& buffer);
378 float paramValue (AutomatableParameter::Ptr param);
379
381 juce::Reverb reverb;
385
386 bool flushingState = false;
387 float currentTempo = 0.0f;
388 LevelMeasurer levelMeasurer;
389 DbTimePair levels[2];
390
392};
393
394}} // namespace tracktion { inline namespace engine
Type get() const noexcept
float nextFloat() noexcept
TempoSequence tempoSequence
The global TempoSequence of this Edit.
juce::String getSelectableDescription() override
Subclasses must return a description of what they are.
juce::String getName() const override
The name of the type, e.g.
int getNumOutputChannelsGivenInputs(int numInputChannels) override
This must return the number of output channels that the plugin will produce, given a number of input ...
void applyToBuffer(const PluginRenderContext &) override
Process the next block of data.
void deinitialise() override
Called after play stops to release resources.
void reset() override
Should reset synth voices, tails, clear delay buffers, etc.
Smooths a value between 0 and 1 at a constant rate.
T fmod(T... args)
#define TRANS(stringLiteral)
#define NEEDS_TRANS(stringLiteral)
#define jassert(expression)
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
constexpr Type jmin(Type a, Type b)
constexpr Type jmax(Type a, Type b)
constexpr int numElementsInArray(Type(&)[N]) noexcept
tempo::Sequence::Position createPosition(const TempoSequence &s)
Creates a Position to iterate over the given TempoSequence.
Passed into Plugins when they are being initialised, to give them useful contextual information that ...
T sin(T... args)
A Sequence::Position is an iterator through a Sequence.
The context passed to plugin render methods to provide it with buffers to fill.
time