LMMS
Loading...
Searching...
No Matches
juce_SmoothedValue.h
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26//==============================================================================
35template <typename SmoothedValueType>
37{
38private:
39 //==============================================================================
40 template <typename T> struct FloatTypeHelper;
41
42 template <template <typename> class SmoothedValueClass, typename FloatType>
43 struct FloatTypeHelper <SmoothedValueClass <FloatType>>
44 {
45 using Type = FloatType;
46 };
47
48 template <template <typename, typename> class SmoothedValueClass, typename FloatType, typename SmoothingType>
49 struct FloatTypeHelper <SmoothedValueClass <FloatType, SmoothingType>>
50 {
51 using Type = FloatType;
52 };
53
54public:
56
57 //==============================================================================
59 SmoothedValueBase() = default;
60
61 //==============================================================================
63 bool isSmoothing() const noexcept { return countdown > 0; }
64
67
68 //==============================================================================
71
76 {
77 target = currentValue = newValue;
78 countdown = 0;
79 }
80
81 //==============================================================================
87 void applyGain (FloatType* samples, int numSamples) noexcept
88 {
89 jassert (numSamples >= 0);
90
91 if (isSmoothing())
92 {
93 for (int i = 0; i < numSamples; ++i)
94 samples[i] *= getNextSmoothedValue();
95 }
96 else
97 {
98 FloatVectorOperations::multiply (samples, target, numSamples);
99 }
100 }
101
108 void applyGain (FloatType* samplesOut, const FloatType* samplesIn, int numSamples) noexcept
109 {
110 jassert (numSamples >= 0);
111
112 if (isSmoothing())
113 {
114 for (int i = 0; i < numSamples; ++i)
115 samplesOut[i] = samplesIn[i] * getNextSmoothedValue();
116 }
117 else
118 {
119 FloatVectorOperations::multiply (samplesOut, samplesIn, target, numSamples);
120 }
121 }
122
124 void applyGain (AudioBuffer<FloatType>& buffer, int numSamples) noexcept
125 {
126 jassert (numSamples >= 0);
127
128 if (isSmoothing())
129 {
130 if (buffer.getNumChannels() == 1)
131 {
132 auto* samples = buffer.getWritePointer (0);
133
134 for (int i = 0; i < numSamples; ++i)
135 samples[i] *= getNextSmoothedValue();
136 }
137 else
138 {
139 for (auto i = 0; i < numSamples; ++i)
140 {
141 auto gain = getNextSmoothedValue();
142
143 for (int channel = 0; channel < buffer.getNumChannels(); channel++)
144 buffer.setSample (channel, i, buffer.getSample (channel, i) * gain);
145 }
146 }
147 }
148 else
149 {
150 buffer.applyGain (0, numSamples, target);
151 }
152 }
153
154private:
155 //==============================================================================
157 {
158 return static_cast <SmoothedValueType*> (this)->getNextValue();
159 }
160
161protected:
162 //==============================================================================
165 int countdown = 0;
166};
167
168//==============================================================================
179{
185 struct Linear {};
186
192 struct Multiplicative {};
193}
194
195//==============================================================================
225template <typename FloatType, typename SmoothingType = ValueSmoothingTypes::Linear>
226class SmoothedValue : public SmoothedValueBase <SmoothedValue <FloatType, SmoothingType>>
227{
228public:
229 //==============================================================================
232 : SmoothedValue ((FloatType) (std::is_same<SmoothingType, ValueSmoothingTypes::Linear>::value ? 0 : 1))
233 {
234 }
235
237 SmoothedValue (FloatType initialValue) noexcept
238 {
239 // Multiplicative smoothed values cannot ever reach 0!
240 jassert (! (std::is_same<SmoothingType, ValueSmoothingTypes::Multiplicative>::value && initialValue == 0));
241
242 // Visual Studio can't handle base class initialisation with CRTP
243 this->currentValue = initialValue;
244 this->target = this->currentValue;
245 }
246
247 //==============================================================================
252 void reset (double sampleRate, double rampLengthInSeconds) noexcept
253 {
254 jassert (sampleRate > 0 && rampLengthInSeconds >= 0);
255 reset ((int) std::floor (rampLengthInSeconds * sampleRate));
256 }
257
261 void reset (int numSteps) noexcept
262 {
263 stepsToTarget = numSteps;
264 this->setCurrentAndTargetValue (this->target);
265 }
266
267 //==============================================================================
271 void setTargetValue (FloatType newValue) noexcept
272 {
273 if (newValue == this->target)
274 return;
275
276 if (stepsToTarget <= 0)
277 {
278 this->setCurrentAndTargetValue (newValue);
279 return;
280 }
281
282 // Multiplicative smoothed values cannot ever reach 0!
283 jassert (! (std::is_same<SmoothingType, ValueSmoothingTypes::Multiplicative>::value && newValue == 0));
284
285 this->target = newValue;
286 this->countdown = stepsToTarget;
287
288 setStepSize();
289 }
290
291 //==============================================================================
296 {
297 if (! this->isSmoothing())
298 return this->target;
299
300 --(this->countdown);
301
302 if (this->isSmoothing())
303 setNextValue();
304 else
305 this->currentValue = this->target;
306
307 return this->currentValue;
308 }
309
310 //==============================================================================
316 FloatType skip (int numSamples) noexcept
317 {
318 if (numSamples >= this->countdown)
319 {
320 this->setCurrentAndTargetValue (this->target);
321 return this->target;
322 }
323
324 skipCurrentValue (numSamples);
325
326 this->countdown -= numSamples;
327 return this->currentValue;
328 }
329
330 //==============================================================================
331 #ifndef DOXYGEN
340 [[deprecated ("Use setTargetValue and setCurrentAndTargetValue instead.")]]
341 void setValue (FloatType newValue, bool force = false) noexcept
342 {
343 if (force)
344 {
345 this->setCurrentAndTargetValue (newValue);
346 return;
347 }
348
349 setTargetValue (newValue);
350 }
351 #endif
352
353private:
354 //==============================================================================
355 template <typename T>
356 using LinearVoid = typename std::enable_if <std::is_same <T, ValueSmoothingTypes::Linear>::value, void>::type;
357
358 template <typename T>
359 using MultiplicativeVoid = typename std::enable_if <std::is_same <T, ValueSmoothingTypes::Multiplicative>::value, void>::type;
360
361 //==============================================================================
362 template <typename T = SmoothingType>
364 {
365 step = (this->target - this->currentValue) / (FloatType) this->countdown;
366 }
367
368 template <typename T = SmoothingType>
370 {
371 step = std::exp ((std::log (std::abs (this->target)) - std::log (std::abs (this->currentValue))) / (FloatType) this->countdown);
372 }
373
374 //==============================================================================
375 template <typename T = SmoothingType>
380
381 template <typename T = SmoothingType>
386
387 //==============================================================================
388 template <typename T = SmoothingType>
389 LinearVoid<T> skipCurrentValue (int numSamples) noexcept
390 {
391 this->currentValue += step * (FloatType) numSamples;
392 }
393
394 template <typename T = SmoothingType>
396 {
397 this->currentValue *= (FloatType) std::pow (step, numSamples);
398 }
399
400 //==============================================================================
403};
404
405template <typename FloatType>
406using LinearSmoothedValue = SmoothedValue <FloatType, ValueSmoothingTypes::Linear>;
407
408
409//==============================================================================
410//==============================================================================
411#if JUCE_UNIT_TESTS
412
413template <class SmoothedValueType>
414class CommonSmoothedValueTests : public UnitTest
415{
416public:
417 CommonSmoothedValueTests()
418 : UnitTest ("CommonSmoothedValueTests", UnitTestCategories::smoothedValues)
419 {}
420
421 void runTest() override
422 {
423 beginTest ("Initial state");
424 {
425 SmoothedValueType sv;
426
427 auto value = sv.getCurrentValue();
428 expectEquals (sv.getTargetValue(), value);
429
430 sv.getNextValue();
431 expectEquals (sv.getCurrentValue(), value);
432 expect (! sv.isSmoothing());
433 }
434
435 beginTest ("Resetting");
436 {
437 auto initialValue = 15.0f;
438
439 SmoothedValueType sv (initialValue);
440 sv.reset (3);
441 expectEquals (sv.getCurrentValue(), initialValue);
442
443 auto targetValue = initialValue + 1.0f;
444 sv.setTargetValue (targetValue);
445 expectEquals (sv.getTargetValue(), targetValue);
446 expectEquals (sv.getCurrentValue(), initialValue);
447 expect (sv.isSmoothing());
448
449 auto currentValue = sv.getNextValue();
450 expect (currentValue > initialValue);
451 expectEquals (sv.getCurrentValue(), currentValue);
452 expectEquals (sv.getTargetValue(), targetValue);
453 expect (sv.isSmoothing());
454
455 sv.reset (5);
456
457 expectEquals (sv.getCurrentValue(), targetValue);
458 expectEquals (sv.getTargetValue(), targetValue);
459 expect (! sv.isSmoothing());
460
461 sv.getNextValue();
462 expectEquals (sv.getCurrentValue(), targetValue);
463
464 sv.setTargetValue (1.5f);
465 sv.getNextValue();
466
467 float newStart = 0.2f;
468 sv.setCurrentAndTargetValue (newStart);
469 expectEquals (sv.getNextValue(), newStart);
470 expectEquals (sv.getTargetValue(), newStart);
471 expectEquals (sv.getCurrentValue(), newStart);
472 expect (! sv.isSmoothing());
473 }
474
475 beginTest ("Sample rate");
476 {
477 SmoothedValueType svSamples { 3.0f };
478 auto svTime = svSamples;
479
480 auto numSamples = 12;
481
482 svSamples.reset (numSamples);
483 svTime.reset (numSamples * 2, 1.0);
484
485 for (int i = 0; i < numSamples; ++i)
486 {
487 svTime.skip (1);
488 expectWithinAbsoluteError (svSamples.getNextValue(),
489 svTime.getNextValue(),
490 1.0e-7f);
491 }
492 }
493
494 beginTest ("Block processing");
495 {
496 SmoothedValueType sv (1.0f);
497
498 sv.reset (12);
499 sv.setTargetValue (2.0f);
500
501 const auto numSamples = 15;
502
503 AudioBuffer<float> referenceData (1, numSamples);
504
505 for (int i = 0; i < numSamples; ++i)
506 referenceData.setSample (0, i, sv.getNextValue());
507
508 expect (referenceData.getSample (0, 0) > 0);
509 expect (referenceData.getSample (0, 10) < sv.getTargetValue());
510 expectWithinAbsoluteError (referenceData.getSample (0, 11),
511 sv.getTargetValue(),
512 2.0e-7f);
513
514 auto getUnitData = [] (int numSamplesToGenerate)
515 {
516 AudioBuffer<float> result (1, numSamplesToGenerate);
517
518 for (int i = 0; i < numSamplesToGenerate; ++i)
519 result.setSample (0, i, 1.0f);
520
521 return result;
522 };
523
524 auto compareData = [this] (const AudioBuffer<float>& test,
525 const AudioBuffer<float>& reference)
526 {
527 for (int i = 0; i < test.getNumSamples(); ++i)
528 expectWithinAbsoluteError (test.getSample (0, i),
529 reference.getSample (0, i),
530 2.0e-7f);
531 };
532
533 auto testData = getUnitData (numSamples);
534 sv.setCurrentAndTargetValue (1.0f);
535 sv.setTargetValue (2.0f);
536 sv.applyGain (testData.getWritePointer (0), numSamples);
537 compareData (testData, referenceData);
538
539 testData = getUnitData (numSamples);
540 AudioBuffer<float> destData (1, numSamples);
541 sv.setCurrentAndTargetValue (1.0f);
542 sv.setTargetValue (2.0f);
543 sv.applyGain (destData.getWritePointer (0),
544 testData.getReadPointer (0),
545 numSamples);
546 compareData (destData, referenceData);
547 compareData (testData, getUnitData (numSamples));
548
549 testData = getUnitData (numSamples);
550 sv.setCurrentAndTargetValue (1.0f);
551 sv.setTargetValue (2.0f);
552 sv.applyGain (testData, numSamples);
553 compareData (testData, referenceData);
554 }
555
556 beginTest ("Skip");
557 {
558 SmoothedValueType sv;
559
560 sv.reset (12);
561 sv.setCurrentAndTargetValue (1.0f);
562 sv.setTargetValue (2.0f);
563
564 Array<float> reference;
565
566 for (int i = 0; i < 15; ++i)
567 reference.add (sv.getNextValue());
568
569 sv.setCurrentAndTargetValue (1.0f);
570 sv.setTargetValue (2.0f);
571
572 expectWithinAbsoluteError (sv.skip (1), reference[0], 1.0e-6f);
573 expectWithinAbsoluteError (sv.skip (1), reference[1], 1.0e-6f);
574 expectWithinAbsoluteError (sv.skip (2), reference[3], 1.0e-6f);
575 sv.skip (3);
576 expectWithinAbsoluteError (sv.getCurrentValue(), reference[6], 1.0e-6f);
577 expectEquals (sv.skip (300), sv.getTargetValue());
578 expectEquals (sv.getCurrentValue(), sv.getTargetValue());
579 }
580
581 beginTest ("Negative");
582 {
583 SmoothedValueType sv;
584
585 auto numValues = 12;
586 sv.reset (numValues);
587
588 std::vector<std::pair<float, float>> ranges = { { -1.0f, -2.0f },
589 { -100.0f, -3.0f } };
590
591 for (auto range : ranges)
592 {
593 auto start = range.first, end = range.second;
594
595 sv.setCurrentAndTargetValue (start);
596 sv.setTargetValue (end);
597
598 auto val = sv.skip (numValues / 2);
599
600 if (end > start)
601 expect (val > start && val < end);
602 else
603 expect (val < start && val > end);
604
605 auto nextVal = sv.getNextValue();
606 expect (end > start ? (nextVal > val) : (nextVal < val));
607
608 auto endVal = sv.skip (500);
609 expectEquals (endVal, end);
610 expectEquals (sv.getNextValue(), end);
611 expectEquals (sv.getCurrentValue(), end);
612
613 sv.setCurrentAndTargetValue (start);
614 sv.setTargetValue (end);
615
616 SmoothedValueType positiveSv { -start };
617 positiveSv.reset (numValues);
618 positiveSv.setTargetValue (-end);
619
620 for (int i = 0; i < numValues + 2; ++i)
621 expectEquals (sv.getNextValue(), -positiveSv.getNextValue());
622 }
623 }
624 }
625};
626
627#endif
628
629} // namespace juce
#define noexcept
Definition DistrhoDefines.h:72
CAdPlugDatabase::CRecord::RecordType type
Definition adplugdb.cpp:93
Definition juce_Array.h:56
void add(const ElementType &newElement)
Definition juce_Array.h:418
Definition juce_AudioSampleBuffer.h:34
Type getSample(int channel, int sampleIndex) const noexcept
Definition juce_AudioSampleBuffer.h:636
Type * getWritePointer(int channelNumber) noexcept
Definition juce_AudioSampleBuffer.h:291
void setSample(int destChannel, int destSample, Type newValue) noexcept
Definition juce_AudioSampleBuffer.h:651
FloatType target
Definition juce_SmoothedValue.h:164
FloatType currentValue
Definition juce_SmoothedValue.h:163
bool isSmoothing() const noexcept
Definition juce_SmoothedValue.h:63
int countdown
Definition juce_SmoothedValue.h:165
void applyGain(FloatType *samples, int numSamples) noexcept
Definition juce_SmoothedValue.h:87
FloatType getNextSmoothedValue() noexcept
Definition juce_SmoothedValue.h:156
void applyGain(AudioBuffer< FloatType > &buffer, int numSamples) noexcept
Definition juce_SmoothedValue.h:124
void setCurrentAndTargetValue(FloatType newValue)
Definition juce_SmoothedValue.h:75
FloatType getTargetValue() const noexcept
Definition juce_SmoothedValue.h:70
FloatType getCurrentValue() const noexcept
Definition juce_SmoothedValue.h:66
typename FloatTypeHelper< SmoothedValueType >::Type FloatType
Definition juce_SmoothedValue.h:55
void applyGain(FloatType *samplesOut, const FloatType *samplesIn, int numSamples) noexcept
Definition juce_SmoothedValue.h:108
FloatType skip(int numSamples) noexcept
Definition juce_SmoothedValue.h:316
FloatType getNextValue() noexcept
Definition juce_SmoothedValue.h:295
void setValue(FloatType newValue, bool force=false) noexcept
Definition juce_SmoothedValue.h:341
int stepsToTarget
Definition juce_SmoothedValue.h:402
MultiplicativeVoid< T > setNextValue() noexcept
Definition juce_SmoothedValue.h:382
typename std::enable_if< std::is_same< T, ValueSmoothingTypes::Multiplicative >::value, void >::type MultiplicativeVoid
Definition juce_SmoothedValue.h:359
LinearVoid< T > skipCurrentValue(int numSamples) noexcept
Definition juce_SmoothedValue.h:389
LinearVoid< T > setStepSize() noexcept
Definition juce_SmoothedValue.h:363
SmoothedValue(FloatType initialValue) noexcept
Definition juce_SmoothedValue.h:237
void reset(double sampleRate, double rampLengthInSeconds) noexcept
Definition juce_SmoothedValue.h:252
FloatType step
Definition juce_SmoothedValue.h:401
MultiplicativeVoid< T > skipCurrentValue(int numSamples)
Definition juce_SmoothedValue.h:395
LinearVoid< T > setNextValue() noexcept
Definition juce_SmoothedValue.h:376
SmoothedValue() noexcept
Definition juce_SmoothedValue.h:231
void reset(int numSteps) noexcept
Definition juce_SmoothedValue.h:261
MultiplicativeVoid< T > setStepSize()
Definition juce_SmoothedValue.h:369
typename std::enable_if< std::is_same< T, ValueSmoothingTypes::Linear >::value, void >::type LinearVoid
Definition juce_SmoothedValue.h:356
void setTargetValue(FloatType newValue) noexcept
Definition juce_SmoothedValue.h:271
Definition juce_UnitTest.h:70
register unsigned i
Definition inflate.c:1575
static PuglViewHint int value
Definition pugl.h:1708
virtual ASIOError start()=0
int val
Definition jpeglib.h:956
#define jassert(expression)
static const String smoothedValues
Definition juce_UnitTestCategories.h:46
Definition juce_SmoothedValue.h:179
Definition carla_juce.cpp:31
RangedDirectoryIterator end(const RangedDirectoryIterator &)
Definition juce_RangedDirectoryIterator.h:184
SmoothedValue< FloatType, ValueSmoothingTypes::Linear > LinearSmoothedValue
Definition juce_SmoothedValue.h:406
Definition juce_Uuid.h:141
static int test(SerdEnv *env, bool top_level, bool pretty_numbers)
Definition sratom_test.c:79
Definition juce_SmoothedValue.h:40
Definition juce_SmoothedValue.h:185
Definition juce_SmoothedValue.h:192
int result
Definition process.c:1455
#define const
Definition zconf.h:137