arduino-audio-tools
Loading...
Searching...
No Matches
AudioEffect.h
Go to the documentation of this file.
1#pragma once
2#include <math.h>
3#include <stdint.h>
4
5#include "AudioLogger.h"
6#include "AudioParameters.h"
9#include "PitchShift.h"
10
11namespace audio_tools {
12
13// we use int16_t for our effects
15
24 public:
25 AudioEffect() = default;
26 virtual ~AudioEffect() = default;
27
29 virtual effect_t process(effect_t in) = 0;
30
32 virtual void setActive(bool value) { active_flag = value; }
33
35 virtual bool active() { return active_flag; }
36
37 virtual AudioEffect* clone() = 0;
38
40 int id() { return id_value; }
41
43 void setId(int id) { this->id_value = id; }
44
45 protected:
46 bool active_flag = true;
47 int id_value = -1;
48
49 void copyParent(AudioEffect* copy) {
50 id_value = copy->id_value;
52 }
53
56 int16_t resultLimit = 32767) {
57 int32_t result = in;
58 if (result > clipLimit) {
59 result = resultLimit;
60 }
61 if (result < -clipLimit) {
62 result = -resultLimit;
63 }
64 return result;
65 }
66};
67
76class Boost : public AudioEffect, public VolumeSupport {
77 public:
80 Boost(float volume = 1.0) { setVolume(volume); }
81
82 Boost(const Boost& copy) = default;
83
85 if (!active()) return input;
86 int32_t result = volume() * input;
87 // clip to int16_t
88 return clip(result);
89 }
90
91 Boost* clone() { return new Boost(*this); }
92};
93
101class Distortion : public AudioEffect {
102 public:
108
109 Distortion(const Distortion& copy) = default;
110
112
114
116
118
120 if (!active()) return input;
121 // the input signal is 16bits (values from -32768 to +32768
122 // the value of input is clipped to the distortion_threshold value
123 return clip(input, p_clip_threashold, max_input);
124 }
125
126 Distortion* clone() { return new Distortion(*this); }
127
128 protected:
131};
132
140class Fuzz : public AudioEffect {
141 public:
147
148 Fuzz(const Fuzz& copy) = default;
149
151
152 float fuzzEffectValue() { return p_effect_value; }
153
155
156 uint16_t maxOut() { return max_out; }
157
159 if (!active()) return input;
160 float v = p_effect_value;
161 int32_t result = clip(v * input);
162 return map(result * v, -32768, +32767, -max_out, max_out);
163 }
164
165 Fuzz* clone() { return new Fuzz(*this); }
166
167 protected:
170};
171
179class Tremolo : public AudioEffect {
180 public:
184 uint32_t sampleRate = 44100) {
185 this->duration_ms = duration_ms;
186 this->sampleRate = sampleRate;
187 this->p_percent = depthPercent;
189 rate_count_half = rate_count / 2;
190 }
191
192 Tremolo(const Tremolo& copy) = default;
193
195 this->duration_ms = ms;
196 int32_t rate_count = sampleRate * ms / 1000;
198 }
199
201
203
204 uint8_t depth() { return p_percent; }
205
207 if (!active()) return input;
208
209 // limit value to max 100% and calculate factors
210 float tremolo_depth = p_percent > 100 ? 1.0 : 0.01 * p_percent;
211 float signal_depth = (100.0 - p_percent) / 100.0;
212
214 int32_t out = (signal_depth * input) + (tremolo_factor * count * input);
215
216 // saw tooth shaped counter
217 count += inc;
218 if (count >= rate_count_half) {
219 inc = -1;
220 } else if (count <= 0) {
221 inc = +1;
222 }
223
224 return clip(out);
225 }
226
227 Tremolo* clone() { return new Tremolo(*this); }
228
229 protected:
234 int32_t rate_count_half; // number of samples for on raise and fall
236};
237
246class Delay : public AudioEffect {
247 public:
249 Delay(uint16_t duration_ms = 1000, float depth = 0.5,
250 float feedbackAmount = 1.0, uint32_t sampleRate = 44100) {
254 setDuration(duration_ms);
255 }
256
257 Delay(const Delay& copy) {
259 setFeedback(copy.feedback);
260 setDepth(copy.depth);
261 setDuration(copy.duration);
262 };
263
265 duration = dur;
267 }
268
270
271 void setDepth(float value) {
272 depth = value;
273 if (depth > 1.0f) depth = 1.0f;
274 if (depth < 0.0f) depth = 0.0f;
275 }
276
277 float getDepth() { return depth; }
278
279 void setFeedback(float feed) {
280 feedback = feed;
281 if (feedback > 1.0f) feedback = 1.0f;
282 if (feedback < 0.0f) feedback = 0.0f;
283 }
284
285 float getFeedback() { return feedback; }
286
287 void setSampleRate(int32_t sample) {
288 sampleRate = sample;
290 }
291
292 float getSampleRate() { return sampleRate; }
293
295 if (!active()) return input;
296
297 // Read last audio sample in each delay line
299
300 // Mix the above with current audio and write the results back to output
301 int32_t out = ((1.0f - depth) * input) + (depth * delayed_value);
302
303 // Update each delay line
304 // write = input + feedback * delayed_value (typical delay feedback)
305 float write_val = (float)input + feedback * (float)delayed_value;
306 // round to nearest integer to avoid truncation bias
308 // clip to allowed range and store
310
311 // Finally, update the delay line index
314 }
315 return clip(out);
316 }
317
318 Delay* clone() { return new Delay(*this); }
319
320 protected:
322 float feedback = 0.0f, duration = 0.0f, sampleRate = 0.0f, depth = 0.0f;
325
327 if (sampleRate > 0 && duration > 0) {
328 size_t newSampleCount = sampleRate * duration / 1000;
333 LOGD("sample_count: %u", (unsigned)delay_len_samples);
334 }
335 }
336 }
337};
338
354class ADSRGain : public AudioEffect {
355 public:
356 ADSRGain(float attack = 0.001, float decay = 0.001, float sustainLevel = 0.5,
357 float release = 0.005, float boostFactor = 1.0) {
358 this->factor = boostFactor;
359 adsr = new ADSR(attack, decay, sustainLevel, release);
360 }
361
362 ADSRGain(const ADSRGain& ref) {
363 adsr = new ADSR(*(ref.adsr));
364 factor = ref.factor;
365 copyParent((AudioEffect*)&ref);
366 };
367
368 virtual ~ADSRGain() { delete adsr; }
369
370 void setAttackRate(float a) { adsr->setAttackRate(a); }
371
372 float attackRate() { return adsr->attackRate(); }
373
374 void setDecayRate(float d) { adsr->setDecayRate(d); }
375
376 float decayRate() { return adsr->decayRate(); }
377
379
380 float sustainLevel() { return adsr->sustainLevel(); }
381
383
384 float releaseRate() { return adsr->releaseRate(); }
385
386 void keyOn(float tgt = 0) { adsr->keyOn(tgt); }
387
388 void keyOff() { adsr->keyOff(); }
389
391 if (!active()) return input;
392 effect_t result = factor * adsr->tick() * input;
393 return result;
394 }
395
396 bool isActive() { return adsr->isActive(); }
397
398 ADSRGain* clone() { return new ADSRGain(*this); }
399
400 protected:
402 float factor;
403};
404
411class PitchShift : public AudioEffect {
412 public:
415 PitchShift(float shift_value = 1.0, int buffer_size = 1000) {
417 size = buffer_size;
418 buffer.resize(buffer_size);
420 }
421
422 PitchShift(const PitchShift& ref) {
423 size = ref.size;
427 };
428
429 float value() { return effect_value; }
430
431 void setValue(float value) {
434 }
435
437 if (!active()) return input;
438 buffer.write(input);
439 effect_t result;
440 buffer.read(result);
441 return result;
442 }
443
444 PitchShift* clone() { return new PitchShift(*this); }
445
446 protected:
449 int size;
450};
451
460class Compressor : public AudioEffect {
461 public:
463 Compressor(const Compressor& copy) = default;
464
466 Compressor(uint32_t sampleRate = 44100, uint16_t attackMs = 30,
468 uint8_t thresholdPercent = 10, float compressionRatio = 0.5) {
469 // assuming 1 sample = 1/96kHz = ~10us
470 // Attack -> 30 ms -> 3000
471 // Release -> 20 ms -> 2000
472 // Hold -> 10ms -> 1000
473 sample_rate = sampleRate;
476 hold_count = sample_rate * holdMs / 1000;
477
478 // threshold -20dB below limit -> 0.1 * 2^31
479 threshold =
480 0.01f * thresholdPercent * NumberConverter::maxValueT<effect_t>();
481 // compression ratio: 6:1 -> -6dB = 0.5
483 // initial gain = 1.0 -> no compression
484 gain = 1.0f;
485 recalculate();
486 }
487
493
499
502 hold_count = sample_rate * holdMs / 1000;
503 recalculate();
504 }
505
508 threshold =
509 0.01f * thresholdPercent * NumberConverter::maxValueT<effect_t>();
510 }
511
514 if (compressionRatio < 1.0f) {
516 }
517 recalculate();
518 }
519
522 if (!active()) return input;
523 return compress(input);
524 }
525
526 Compressor* clone() { return new Compressor(*this); }
527
528 protected:
531
535
540
541 float compress(float inSampleF) {
542 if (fabs(inSampleF) > threshold) {
543 if (gain >= gainreduce) {
544 if (state == S_NoOperation) {
545 state = S_Attack;
547 } else if (state == S_Release) {
548 state = S_Attack;
550 }
551 }
553 }
554
555 if (fabs(inSampleF) < threshold && gain <= 1.0f) {
556 if (timeout == 0 && state == S_GainReduction) {
559 }
560 }
561
562 switch (state) {
563 case S_Attack:
564 if (timeout > 0 && gain > gainreduce) {
566 timeout--;
567 } else {
570 }
571 break;
572
573 case S_GainReduction:
574 if (timeout > 0)
575 timeout--;
576 else {
579 }
580 break;
581
582 case S_Release:
583 if (timeout > 0 && gain < 1.0f) {
584 timeout--;
586 } else {
588 }
589 break;
590
591 case S_NoOperation:
592 if (gain < 1.0f) gain = 1.0f;
593 break;
594
595 default:
596 break;
597 }
598
599 float outSampleF = gain * inSampleF;
600 return outSampleF;
601 }
602};
603
604} // namespace audio_tools
#define LOGD(...)
Definition AudioLoggerIDF.h:27
Real-time pitch shifting audio effect implementation.
ADSR Envelope: Attack, Decay, Sustain and Release. Attack is the time taken for initial run-up oeffec...
Definition AudioEffect.h:354
void setDecayRate(float d)
Definition AudioEffect.h:374
float decayRate()
Definition AudioEffect.h:376
void keyOn(float tgt=0)
Definition AudioEffect.h:386
float factor
Definition AudioEffect.h:402
ADSRGain(float attack=0.001, float decay=0.001, float sustainLevel=0.5, float release=0.005, float boostFactor=1.0)
Definition AudioEffect.h:356
effect_t process(effect_t input)
calculates the effect output from the input
Definition AudioEffect.h:390
void setSustainLevel(float s)
Definition AudioEffect.h:378
float attackRate()
Definition AudioEffect.h:372
virtual ~ADSRGain()
Definition AudioEffect.h:368
ADSRGain(const ADSRGain &ref)
Definition AudioEffect.h:362
bool isActive()
Definition AudioEffect.h:396
void setReleaseRate(float r)
Definition AudioEffect.h:382
void setAttackRate(float a)
Definition AudioEffect.h:370
float releaseRate()
Definition AudioEffect.h:384
ADSRGain * clone()
Definition AudioEffect.h:398
float sustainLevel()
Definition AudioEffect.h:380
void keyOff()
Definition AudioEffect.h:388
ADSR * adsr
Definition AudioEffect.h:401
Generates ADSR values between 0.0 and 1.0.
Definition AudioParameters.h:51
void setDecayRate(float d)
Definition AudioParameters.h:71
float decayRate()
Definition AudioParameters.h:75
void keyOn(float tgt=0)
Definition AudioParameters.h:95
void setSustainLevel(float s)
Definition AudioParameters.h:79
float attackRate()
Definition AudioParameters.h:67
bool isActive()
Definition AudioParameters.h:110
void setReleaseRate(float r)
Definition AudioParameters.h:87
void setAttackRate(float a)
Definition AudioParameters.h:63
float releaseRate()
Definition AudioParameters.h:91
float sustainLevel()
Definition AudioParameters.h:83
void keyOff()
Definition AudioParameters.h:102
virtual float tick()
Definition AudioParameters.h:18
Abstract Base class for Sound Effects.
Definition AudioEffect.h:23
virtual AudioEffect * clone()=0
virtual bool active()
determines if the effect is active
Definition AudioEffect.h:35
virtual void setActive(bool value)
sets the effect active/inactive
Definition AudioEffect.h:32
void setId(int id)
Allows to identify an effect.
Definition AudioEffect.h:43
int id()
Allows to identify an effect.
Definition AudioEffect.h:40
virtual effect_t process(effect_t in)=0
calculates the effect output from the input
int id_value
Definition AudioEffect.h:47
bool active_flag
Definition AudioEffect.h:46
void copyParent(AudioEffect *copy)
Definition AudioEffect.h:49
virtual ~AudioEffect()=default
int16_t clip(int32_t in, int16_t clipLimit=32767, int16_t resultLimit=32767)
generic clipping method
Definition AudioEffect.h:55
Boost AudioEffect.
Definition AudioEffect.h:76
effect_t process(effect_t input)
calculates the effect output from the input
Definition AudioEffect.h:84
Boost * clone()
Definition AudioEffect.h:91
Boost(const Boost &copy)=default
Boost(float volume=1.0)
Definition AudioEffect.h:80
Compressor inspired by https://github.com/YetAnotherElectronicsChannel/STM32_DSP_COMPRESSOR/blob/mast...
Definition AudioEffect.h:460
int32_t hold_count
Definition AudioEffect.h:532
int32_t timeout
Definition AudioEffect.h:532
void setAttack(uint16_t attackMs)
Defines the attack duration in ms.
Definition AudioEffect.h:489
float gainreduce
Definition AudioEffect.h:533
uint32_t sample_rate
Definition AudioEffect.h:534
effect_t process(effect_t input)
Processes the sample.
Definition AudioEffect.h:521
float threshold
Definition AudioEffect.h:533
Compressor * clone()
Definition AudioEffect.h:526
enum CompStates state
Definition AudioEffect.h:530
CompStates
Definition AudioEffect.h:529
@ S_Attack
Definition AudioEffect.h:529
@ S_Release
Definition AudioEffect.h:529
@ S_NoOperation
Definition AudioEffect.h:529
@ S_GainReduction
Definition AudioEffect.h:529
void recalculate()
Definition AudioEffect.h:536
float gain_step_attack
Definition AudioEffect.h:533
void setRelease(uint16_t releaseMs)
Defines the release duration in ms.
Definition AudioEffect.h:495
float gain_step_release
Definition AudioEffect.h:533
float compress(float inSampleF)
Definition AudioEffect.h:541
Compressor(uint32_t sampleRate=44100, uint16_t attackMs=30, uint16_t releaseMs=20, uint16_t holdMs=10, uint8_t thresholdPercent=10, float compressionRatio=0.5)
Default Constructor.
Definition AudioEffect.h:466
void setHold(uint16_t holdMs)
Defines the hold duration in ms.
Definition AudioEffect.h:501
int32_t attack_count
Definition AudioEffect.h:532
Compressor(const Compressor &copy)=default
Copy Constructor.
void setCompressionRatio(float compressionRatio)
Defines the compression ratio from 0 to 1.
Definition AudioEffect.h:513
float gain
Definition AudioEffect.h:533
void setThresholdPercent(uint8_t thresholdPercent)
Defines the threshod in %.
Definition AudioEffect.h:507
int32_t release_count
Definition AudioEffect.h:532
Delay/Echo AudioEffect. See https://wiki.analog.com/resources/tools-software/sharc-audio-module/barem...
Definition AudioEffect.h:246
Vector< effect_t > buffer
Definition AudioEffect.h:321
effect_t process(effect_t input)
calculates the effect output from the input
Definition AudioEffect.h:294
Delay(uint16_t duration_ms=1000, float depth=0.5, float feedbackAmount=1.0, uint32_t sampleRate=44100)
e.g. depth=0.5, ms=1000, sampleRate=44100
Definition AudioEffect.h:249
Delay * clone()
Definition AudioEffect.h:318
void setFeedback(float feed)
Definition AudioEffect.h:279
void setDuration(int16_t dur)
Definition AudioEffect.h:264
void updateBufferSize()
Definition AudioEffect.h:326
float duration
Definition AudioEffect.h:322
float getFeedback()
Definition AudioEffect.h:285
float getDepth()
Definition AudioEffect.h:277
float depth
Definition AudioEffect.h:322
size_t delay_line_index
Definition AudioEffect.h:324
void setSampleRate(int32_t sample)
Definition AudioEffect.h:287
Delay(const Delay &copy)
Definition AudioEffect.h:257
int16_t getDuration()
Definition AudioEffect.h:269
void setDepth(float value)
Definition AudioEffect.h:271
float feedback
Definition AudioEffect.h:322
float sampleRate
Definition AudioEffect.h:322
float getSampleRate()
Definition AudioEffect.h:292
size_t delay_len_samples
Definition AudioEffect.h:323
Distortion AudioEffect.
Definition AudioEffect.h:101
Distortion(const Distortion &copy)=default
void setClipThreashold(int16_t th)
Definition AudioEffect.h:111
void setMaxInput(int16_t maxInput)
Definition AudioEffect.h:115
int16_t p_clip_threashold
Definition AudioEffect.h:129
Distortion(int16_t clipThreashold=4990, int16_t maxInput=6500)
Distortion Constructor: e.g. use clipThreashold 4990 and maxInput=6500.
Definition AudioEffect.h:104
effect_t process(effect_t input)
calculates the effect output from the input
Definition AudioEffect.h:119
int16_t maxInput()
Definition AudioEffect.h:117
int16_t max_input
Definition AudioEffect.h:130
int16_t clipThreashold()
Definition AudioEffect.h:113
Distortion * clone()
Definition AudioEffect.h:126
Fuzz AudioEffect.
Definition AudioEffect.h:140
void setFuzzEffectValue(float v)
Definition AudioEffect.h:150
float p_effect_value
Definition AudioEffect.h:168
effect_t process(effect_t input)
calculates the effect output from the input
Definition AudioEffect.h:158
Fuzz(float fuzzEffectValue=6.5, uint16_t maxOut=300)
Fuzz Constructor: use e.g. effectValue=6.5; maxOut = 300.
Definition AudioEffect.h:143
Fuzz * clone()
Definition AudioEffect.h:165
void setMaxOut(uint16_t v)
Definition AudioEffect.h:154
uint16_t max_out
Definition AudioEffect.h:169
uint16_t maxOut()
Definition AudioEffect.h:156
Fuzz(const Fuzz &copy)=default
float fuzzEffectValue()
Definition AudioEffect.h:152
Shifts the pitch by the indicated step size: e.g. 2 doubles the pitch.
Definition AudioEffect.h:411
PitchShift * clone()
Definition AudioEffect.h:444
effect_t process(effect_t input)
calculates the effect output from the input
Definition AudioEffect.h:436
int size
Definition AudioEffect.h:449
PitchShift(float shift_value=1.0, int buffer_size=1000)
Definition AudioEffect.h:415
PitchShift(const PitchShift &ref)
Definition AudioEffect.h:422
void setValue(float value)
Definition AudioEffect.h:431
VariableSpeedRingBuffer< int16_t > buffer
Definition AudioEffect.h:447
float value()
Definition AudioEffect.h:429
float effect_value
Definition AudioEffect.h:448
Tremolo AudioEffect.
Definition AudioEffect.h:179
void setDepth(uint8_t percent)
Definition AudioEffect.h:202
int16_t duration_ms
Definition AudioEffect.h:230
effect_t process(effect_t input)
calculates the effect output from the input
Definition AudioEffect.h:206
int32_t count
Definition AudioEffect.h:232
uint8_t p_percent
Definition AudioEffect.h:235
void setDuration(int16_t ms)
Definition AudioEffect.h:194
Tremolo(int16_t duration_ms=2000, uint8_t depthPercent=50, uint32_t sampleRate=44100)
Definition AudioEffect.h:183
uint32_t sampleRate
Definition AudioEffect.h:231
int32_t rate_count_half
Definition AudioEffect.h:234
uint8_t depth()
Definition AudioEffect.h:204
Tremolo * clone()
Definition AudioEffect.h:227
Tremolo(const Tremolo &copy)=default
int16_t inc
Definition AudioEffect.h:233
int16_t duration()
Definition AudioEffect.h:200
Optimized buffer implementation for pitch shifting with interpolation.
Definition PitchShift.h:375
void setIncrement(float increment)
Set the reading speed increment for pitch shifting.
Definition PitchShift.h:391
bool resize(int size)
Resize buffer and set initial read position to prevent immediate overrun.
Definition PitchShift.h:398
bool write(T sample)
write add an entry to the buffer
Definition PitchShift.h:425
bool read(T &result)
reads a single value
Definition PitchShift.h:405
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
bool resize(int newSize, T value)
Definition Vector.h:266
T * data()
Definition Vector.h:316
Supports the setting and getting of the volume.
Definition AudioTypes.h:191
virtual float volume()
provides the actual volume in the range of 0.0f to 1.0f
Definition AudioTypes.h:194
virtual bool setVolume(float volume)
define the actual volume in the range of 0.0f to 1.0f
Definition AudioTypes.h:196
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
int16_t effect_t
Definition AudioEffect.h:14
long map(long x, long in_min, long in_max, long out_min, long out_max)
Maps input to output values.
Definition NoArduino.h:189
size_t writeData(Print *p_out, T *data, int samples, int maxSamples=512)
Definition AudioTypes.h:512