5#include "AudioLogger.h"
6#include "AudioParameters.h"
7#include "AudioTools/CoreAudio/AudioOutput.h"
8#include "AudioTools/CoreAudio/AudioTypes.h"
14typedef int16_t effect_t;
29 virtual effect_t
process(effect_t in) = 0;
32 virtual void setActive(
bool value) { active_flag = value; }
35 virtual bool active() {
return active_flag; }
40 int id() {
return id_value; }
43 void setId(
int id) { this->id_value =
id; }
46 bool active_flag =
true;
50 id_value = copy->id_value;
51 active_flag = copy->active_flag;
55 int16_t
clip(int32_t in, int16_t clipLimit = 32767,
56 int16_t resultLimit = 32767) {
58 if (result > clipLimit) {
61 if (result < -clipLimit) {
62 result = -resultLimit;
55 int16_t
clip(int32_t in, int16_t clipLimit = 32767, {
…}
85 if (!
active())
return input;
86 int32_t result =
volume() * input;
104 Distortion(int16_t clipThreashold = 4990, int16_t maxInput = 6500) {
105 p_clip_threashold = clipThreashold;
106 max_input = maxInput;
104 Distortion(int16_t clipThreashold = 4990, int16_t maxInput = 6500) {
…}
111 void setClipThreashold(int16_t th) { p_clip_threashold = th; }
113 int16_t clipThreashold() {
return p_clip_threashold; }
115 void setMaxInput(int16_t maxInput) { max_input = maxInput; }
117 int16_t maxInput() {
return max_input; }
120 if (!
active())
return input;
123 return clip(input, p_clip_threashold, max_input);
129 int16_t p_clip_threashold;
143 Fuzz(
float fuzzEffectValue = 6.5, uint16_t maxOut = 300) {
144 p_effect_value = fuzzEffectValue;
143 Fuzz(
float fuzzEffectValue = 6.5, uint16_t maxOut = 300) {
…}
150 void setFuzzEffectValue(
float v) { p_effect_value = v; }
152 float fuzzEffectValue() {
return p_effect_value; }
154 void setMaxOut(uint16_t v) { max_out = v; }
156 uint16_t maxOut() {
return max_out; }
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);
165 Fuzz* clone() {
return new Fuzz(*
this); }
168 float p_effect_value;
183 Tremolo(int16_t duration_ms = 2000, uint8_t depthPercent = 50,
184 uint32_t sampleRate = 44100) {
185 this->duration_ms = duration_ms;
186 this->sampleRate = sampleRate;
187 this->p_percent = depthPercent;
188 int32_t rate_count = sampleRate * duration_ms / 1000;
189 rate_count_half = rate_count / 2;
183 Tremolo(int16_t duration_ms = 2000, uint8_t depthPercent = 50, {
…}
194 void setDuration(int16_t ms) {
195 this->duration_ms = ms;
196 int32_t rate_count = sampleRate * ms / 1000;
197 rate_count_half = rate_count / 2;
200 int16_t duration() {
return duration_ms; }
202 void setDepth(uint8_t percent) { p_percent = percent; }
204 uint8_t depth() {
return p_percent; }
207 if (!
active())
return input;
210 float tremolo_depth = p_percent > 100 ? 1.0 : 0.01 * p_percent;
211 float signal_depth = (100.0 - p_percent) / 100.0;
213 float tremolo_factor = tremolo_depth / rate_count_half;
214 int32_t out = (signal_depth * input) + (tremolo_factor * count * input);
218 if (count >= rate_count_half) {
220 }
else if (count <= 0) {
234 int32_t rate_count_half;
249 Delay(uint16_t duration_ms = 1000,
float depth = 0.5,
250 float feedbackAmount = 1.0, uint32_t sampleRate = 44100) {
251 setSampleRate(sampleRate);
252 setFeedback(feedbackAmount);
254 setDuration(duration_ms);
249 Delay(uint16_t duration_ms = 1000,
float depth = 0.5, {
…}
258 setSampleRate(copy.sampleRate);
259 setFeedback(copy.feedback);
260 setDepth(copy.depth);
261 setDuration(copy.duration);
264 void setDuration(int16_t dur) {
269 int16_t getDuration() {
return duration; }
271 void setDepth(
float value) {
273 if (depth > 1.0f) depth = 1.0f;
274 if (depth < 0.0f) depth = 0.0f;
277 float getDepth() {
return depth; }
279 void setFeedback(
float feed) {
281 if (feedback > 1.0f) feedback = 1.0f;
282 if (feedback < 0.0f) feedback = 0.0f;
285 float getFeedback() {
return feedback; }
287 void setSampleRate(int32_t sample) {
292 float getSampleRate() {
return sampleRate; }
295 if (!
active())
return input;
298 int32_t delayed_value = buffer[delay_line_index];
301 int32_t out = ((1.0f - depth) * input) + (depth * delayed_value);
305 float write_val = (float)input + feedback * (
float)delayed_value;
307 int32_t write_int = (int32_t)roundf(write_val);
309 buffer[delay_line_index] =
clip(write_int);
312 if (delay_line_index++ >= delay_len_samples) {
313 delay_line_index = 0;
321 Vector<effect_t> buffer{0};
322 float feedback = 0.0f, duration = 0.0f, sampleRate = 0.0f, depth = 0.0f;
323 size_t delay_len_samples = 0;
324 size_t delay_line_index = 0;
326 void updateBufferSize() {
327 if (sampleRate > 0 && duration > 0) {
328 size_t newSampleCount = sampleRate * duration / 1000;
329 if (newSampleCount != delay_len_samples) {
330 delay_len_samples = newSampleCount;
331 buffer.resize(delay_len_samples);
332 memset(buffer.data(), 0, delay_len_samples *
sizeof(effect_t));
333 LOGD(
"sample_count: %u", (
unsigned)delay_len_samples);
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);
363 adsr =
new ADSR(*(ref.adsr));
370 void setAttackRate(
float a) { adsr->setAttackRate(a); }
372 float attackRate() {
return adsr->attackRate(); }
374 void setDecayRate(
float d) { adsr->setDecayRate(d); }
376 float decayRate() {
return adsr->decayRate(); }
378 void setSustainLevel(
float s) { adsr->setSustainLevel(s); }
380 float sustainLevel() {
return adsr->sustainLevel(); }
382 void setReleaseRate(
float r) { adsr->setReleaseRate(r); }
384 float releaseRate() {
return adsr->releaseRate(); }
386 void keyOn(
float tgt = 0) { adsr->keyOn(tgt); }
388 void keyOff() { adsr->keyOff(); }
391 if (!
active())
return input;
392 effect_t result = factor * adsr->tick() * input;
396 bool isActive() {
return adsr->isActive(); }
398 ADSRGain* clone() {
return new ADSRGain(*
this); }
415 PitchShift(
float shift_value = 1.0,
int buffer_size = 1000) {
416 effect_value = shift_value;
418 buffer.
resize(buffer_size);
424 effect_value = ref.effect_value;
429 float value() {
return effect_value; }
431 void setValue(
float value) {
432 effect_value = value;
437 if (!
active())
return input;
447 VariableSpeedRingBuffer<int16_t> buffer;
466 Compressor(uint32_t sampleRate = 44100, uint16_t attackMs = 30,
467 uint16_t releaseMs = 20, uint16_t holdMs = 10,
468 uint8_t thresholdPercent = 10,
float compressionRatio = 0.5) {
473 sample_rate = sampleRate;
474 attack_count = sample_rate * attackMs / 1000;
475 release_count = sample_rate * releaseMs / 1000;
476 hold_count = sample_rate * holdMs / 1000;
480 0.01f * thresholdPercent * NumberConverter::maxValueT<effect_t>();
482 gainreduce = compressionRatio;
466 Compressor(uint32_t sampleRate = 44100, uint16_t attackMs = 30, {
…}
490 attack_count = sample_rate * attackMs / 1000;
496 release_count = sample_rate * releaseMs / 1000;
502 hold_count = sample_rate * holdMs / 1000;
509 0.01f * thresholdPercent * NumberConverter::maxValueT<effect_t>();
514 if (compressionRatio < 1.0f) {
515 gainreduce = compressionRatio;
522 if (!
active())
return input;
523 return compress(input);
529 enum CompStates { S_NoOperation, S_Attack, S_GainReduction, S_Release };
530 enum CompStates state = S_NoOperation;
532 int32_t attack_count, release_count, hold_count, timeout;
533 float gainreduce, gain_step_attack, gain_step_release, gain, threshold;
534 uint32_t sample_rate;
537 gain_step_attack = (1.0f - gainreduce) / attack_count;
538 gain_step_release = (1.0f - gainreduce) / release_count;
541 float compress(
float inSampleF) {
542 if (fabs(inSampleF) > threshold) {
543 if (gain >= gainreduce) {
544 if (state == S_NoOperation) {
546 timeout = attack_count;
547 }
else if (state == S_Release) {
549 timeout = attack_count;
552 if (state == S_GainReduction) timeout = hold_count;
555 if (fabs(inSampleF) < threshold && gain <= 1.0f) {
556 if (timeout == 0 && state == S_GainReduction) {
558 timeout = release_count;
564 if (timeout > 0 && gain > gainreduce) {
565 gain -= gain_step_attack;
568 state = S_GainReduction;
569 timeout = hold_count;
573 case S_GainReduction:
578 timeout = release_count;
583 if (timeout > 0 && gain < 1.0f) {
585 gain += gain_step_release;
587 state = S_NoOperation;
592 if (gain < 1.0f) gain = 1.0f;
599 float outSampleF = gain * inSampleF;
Real-time pitch shifting audio effect implementation.