arduino-audio-tools
Loading...
Searching...
No Matches
AudioEffects.h
Go to the documentation of this file.
1#pragma once
2#include "AudioToolsConfig.h"
5#include "SoundGenerator.h"
6#include "AudioEffect.h"
7// USE_VARIANTS defaults to on whenever the compiler is capable of it (needed
8// for AudioEffectStream's runtime bits_per_sample switching); define
9// `#define USE_VARIANTS 0` before including AudioTools.h to force the plain
10// AudioEffectStreamT<effect_t> typedef instead, e.g. on a size-constrained target.
11#ifndef USE_VARIANTS
12# define USE_VARIANTS (__cplusplus >= 201703L)
13#endif
14#if USE_VARIANTS
15# include <variant>
16#endif
17
24namespace audio_tools {
25
33 public:
35 void addEffect(AudioEffect &effect){
36 TRACED();
37 effects.push_back(&effect);
38 }
39
41 void addEffect(AudioEffect *effect){
42 TRACED();
43 effects.push_back(effect);
44 LOGI("addEffect -> Number of effects: %d", (int)size());
45 }
47 void clear() {
48 TRACED();
49 effects.clear();
50 }
51
53 size_t size() {
54 return effects.size();
55 }
56
59 // find AudioEffect
60 AudioEffect* result = nullptr;
61 for (int j=0;j<size();j++){
62 // we assume that ADSRGain is the first effect!
63 if (effects[j]->id()==id){
64 result = effects[j];
65 }
66 LOGI("--> findEffect -> %d", effects[j]->id());
67 }
68 return result;
69 }
72 return effects[idx];
73 }
74
75 protected:
77
78};
79
94template <class GeneratorT>
95class AudioEffects : public SoundGenerator<effect_t> {
96 public:
98 AudioEffects() = default;
99
102 TRACEI();
103 // create a copy of the source and all effects
105 for (int j=0;j<copy.size();j++){
106 effects.addEffect(copy[j]->clone());
107 }
108 LOGI("Number of effects %d -> %d", copy.size(), this->size());
109 }
110
112 AudioEffects(GeneratorT &generator) {
114 }
115
118 AudioEffects(Stream &input, int channels=2, float volume=1.0) {
119 setInput(* (new GeneratorT(input, channels, volume)));
120 owns_generator = true;
121 }
122
124 virtual ~AudioEffects(){
125 TRACED();
126 if (owns_generator && p_generator!=nullptr){
127 delete p_generator;
128 }
129 for (int j=0;j<effects.size();j++){
130 delete effects[j];
131 }
132 }
133
135 void setInput(GeneratorT &in){
136 TRACED();
137 p_generator = &in;
138 // automatically activate this object
140 info.channels = 1;
141 info.bits_per_sample = sizeof(effect_t)*8;
142 begin(info);
143 }
144
146 void addEffect(AudioEffect &effect){
147 TRACED();
148 effects.addEffect(&effect);
149 }
150
152 void addEffect(AudioEffect *effect){
153 TRACED();
154 effects.addEffect(effect);
155 LOGI("addEffect -> Number of effects: %d", size());
156 }
157
159 effect_t readSample() override {
160 effect_t sample;
161 if (p_generator!=nullptr){
162 sample = p_generator->readSample();
163 int size = effects.size();
164 for (int j=0; j<size; j++){
165 sample = effects[j]->process(sample);
166 }
167 }
168 return sample;
169 }
170
172 void clear() {
173 TRACED();
174 effects.clear();
175 }
176
178 size_t size() {
179 return effects.size();
180 }
181
183 GeneratorT &generator(){
184 return *p_generator;
185 }
186
189 return effects[idx];
190 }
191
194 return effects.findEffect(id);
195 }
196
197 protected:
199 GeneratorT *p_generator=nullptr;
200 bool owns_generator = false;
201};
202
203
222template <class T>
224 public:
226
228 setStream(io);
229 }
230
232 setOutput(out);
233 }
234
235 // copying would shallow-copy channel_effects/owned_clones and double-free on destruction
238
240 clear();
241 }
242
244 AudioInfo cfg;
245 cfg.sample_rate = 44100;
246 cfg.bits_per_sample = 16;
247 cfg.channels = 2;
248 return cfg;
249 }
250
251 bool begin(AudioInfo cfg){
252 info = cfg;
253 return begin();
254 }
255
256 bool begin(){
257 TRACEI();
258 // 24-bit samples are commonly stored padded to 4 bytes (int24_4bytes_t,
259 // the default int24_t) for alignment/performance, so sizeof(T) won't
260 // equal bits_per_sample/8==3 in that case; accept sizeof(int24_t) too.
261 bool bits_ok = sizeof(T)==info.bits_per_sample/8
262 || (info.bits_per_sample==24 && sizeof(T)==sizeof(int24_t));
263 if (bits_ok){
264 active = true;
266 } else {
267 LOGE("bits_per_sample not consistent: %d",info.bits_per_sample);
268 active = false;
269 }
270 return active;
271 }
272
273 void end() override {
274 active = false;
275 }
276
277 void setStream(Stream &io) override {
278 p_io = &io;
279 p_out = &io;
280 }
281
282
283 void setOutput(Print &print) override {
284 p_out = &print;
285 }
286
291 size_t readBytes(uint8_t *data, size_t len) override {
292 if (!active || p_io==nullptr)return 0;
293
294 // read data from source
295 size_t result = p_io->readBytes((uint8_t*)data, len);
296 int frames = result / sizeof(T) / info.channels;
297 T* samples = (T*) data;
298
299 for (int f=0;f<frames;f++){
300 for (int ch=0;ch<info.channels;ch++){
301 T &sample = samples[f*info.channels+ch];
303 for (int j=0; j<chain.size(); j++){
304 sample = chain[j]->process(sample);
305 }
306 }
307 }
308 return result;
309 }
310
318 size_t write(const uint8_t *data, size_t len) override {
319 if (!active)return 0;
320 // length must be multple of channels
321 assert(len % (sizeof(T)*info.channels)==0);
322 int frames = len / sizeof(T) / info.channels;
323 int total_samples = frames * info.channels;
324
325 buffer_out.resize(total_samples);
326 T* out = buffer_out.data();
327
328 // process all samples
329 for (int f=0;f<frames;f++){
330 const T* p_buffer = ((const T*)data) + (f*info.channels);
331 T* p_frame_out = out + (f*info.channels);
332 for (int ch=0;ch<info.channels;ch++){
333 T sample = p_buffer[ch];
335 for (int j=0; j<chain.size(); j++){
336 sample = chain[j]->process(sample);
337 }
338 p_frame_out[ch] = sample;
339 }
340 }
341
342 size_t written_samples = 0;
343 if (p_io!=nullptr){
344 written_samples = writeDataT<T, Stream>(p_io, out, total_samples);
345 } else if (p_out!=nullptr){
346 written_samples = writeDataT<T, Print>(p_out, out, total_samples);
347 }
348 return written_samples * sizeof(T);
349 }
350
351 int available() override {
352 if (p_io==nullptr) return 0;
353 return p_io->available();
354 }
355
356 int availableForWrite() override {
357 if (p_out!=nullptr) return p_out->availableForWrite();
358 if (p_io!=nullptr) return p_io->availableForWrite();
359 return 0;
360 }
361
362 void flush() override {
363 if (p_out!=nullptr) p_out->flush();
364 else if (p_io!=nullptr) p_io->flush();
365 }
366
368 void addEffect(AudioEffect &effect){
369 addEffect(&effect);
370 }
371
373 void addEffect(AudioEffect *effect){
374 TRACED();
375 effects.addEffect(effect);
376 LOGI("addEffect -> Number of effects: %d", (int) size());
377 // if channels are already set up, extend them immediately instead of
378 // waiting for the next begin()
379 if (active){
380 for (int ch=0; ch<channel_effects.size(); ch++){
381 cloneInto(ch, effect);
382 }
383 }
384 }
385
388 void addEffect(int channel, AudioEffect &effect){
389 addEffect(channel, &effect);
390 }
391
394 void addEffect(int channel, AudioEffect *effect){
395 TRACED();
396 if (!active || channel<0 || channel>=channel_effects.size()){
397 LOGE("Invalid channel %d or begin() not yet called", channel);
398 return;
399 }
400 channel_effects[channel].addEffect(effect);
401 }
402
404 void clear() {
405 TRACED();
406 for (int i=0; i<owned_clones.size(); i++){
407 delete owned_clones[i];
408 }
409 owned_clones.clear();
410 channel_effects.clear();
411 effects.clear();
412 }
413
415 size_t size() {
416 return effects.size();
417 }
418
421 return effects[idx];
422 }
423
426 return effects.findEffect(id);
427 }
428
431 return channel_effects[channel];
432 }
433
436 return channel_effects.size();
437 }
438
439 protected:
440 AudioEffectCommon effects; // template chain populated via addEffect()
441 Vector<AudioEffectCommon> channel_effects; // one independent chain per channel, cloned from `effects`
442 Vector<AudioEffect*> owned_clones; // clones created internally; ours to delete
443 Vector<T> buffer_out; // reused scratch buffer for write(): avoids per-sample writes
444 bool active = false;
445 Stream *p_io=nullptr;
446 Print *p_out=nullptr;
447
449 void cloneInto(int ch, AudioEffect *effect){
450 AudioEffect *clone = effect->clone();
451 channel_effects[ch].addEffect(clone);
452 owned_clones.push_back(clone);
453 }
454
457 for (int i=0; i<owned_clones.size(); i++){
458 delete owned_clones[i];
459 }
460 owned_clones.clear();
461 channel_effects.clear();
463 for (int ch=0; ch<info.channels; ch++){
464 for (int j=0; j<effects.size(); j++){
465 cloneInto(ch, effects[j]);
466 }
467 }
468 }
469};
470
471#if USE_VARIANTS || defined(DOXYGEN)
483 public:
484 AudioEffectStream() = default;
485
487 setOutput(io);
488 setInput(io);
489 }
490
492 setOutput(out);
493 }
494
496 AudioInfo cfg;
497 cfg.sample_rate = 44100;
498 cfg.bits_per_sample = 16;
499 cfg.channels = 2;
500 return cfg;
501 }
502
503 bool begin(AudioInfo cfg){
504 info = cfg;
505 return begin();
506 }
507
508 bool begin(){
509 TRACEI();
510 switch(info.bits_per_sample){
511 case 16:
512 variant.emplace<0>();
513 break;
514 case 24:
515 variant.emplace<1>();
516 break;
517 case 32:
518 variant.emplace<2>();
519 break;
520 default:
521 LOGE("Unspported bits_per_sample: %d", info.bits_per_sample);
522 return false;
523 }
524 if (p_out != nullptr) {
525 std::visit( [this](auto&& e) {return e.setOutput(*p_out);}, variant );
526 }
527 if (p_io != nullptr) {
528 std::visit( [this](auto&& e) {return e.setStream(*p_io);}, variant );
529 }
530 return std::visit( [this](auto&& e) {return e.begin(info);}, variant );
531 }
532
533 void end() override {
534 std::visit( [](auto&& e) {e.end();}, variant );
535 }
536
537 void setInput(Stream &io){
538 setStream(io);
539 }
540
541 void setStream(Stream &io){
542 p_io = &io;
543 }
544
545 void setOutput(Stream &io){
546 p_out = &io;
547 }
548
549 void setOutput(Print &print){
550 p_out = &print;
551 }
552
557 size_t readBytes(uint8_t *data, size_t len) override {
558 return std::visit( [data, len](auto&& e) {return e.readBytes(data, len);}, variant );
559 }
560
565 size_t write(const uint8_t *data, size_t len) override {
566 return std::visit( [data, len](auto&& e) {return e.write(data, len);}, variant );
567 }
568
569 int available() override {
570 return std::visit( [](auto&& e) {return e.available();}, variant );
571 }
572
573 int availableForWrite() override {
574 return std::visit( [](auto&& e) {return e.availableForWrite();}, variant );
575 }
576
577 void flush() override {
578 std::visit( [](auto&& e) {e.flush();}, variant );
579 }
580
582 void addEffect(AudioEffect &effect){
583 addEffect(&effect);
584 }
585
587 void addEffect(AudioEffect *effect){
588 std::visit( [effect](auto&& e) {e.addEffect(effect);}, variant );
589 }
590
592 void addEffect(int channel, AudioEffect &effect){
593 addEffect(channel, &effect);
594 }
595
597 void addEffect(int channel, AudioEffect *effect){
598 std::visit( [channel, effect](auto&& e) {e.addEffect(channel, effect);}, variant );
599 }
600
602 void clear() {
603 std::visit( [](auto&& e) {e.clear();}, variant );
604 }
605
607 size_t size() {
608 return std::visit( [](auto&& e) {return e.size();}, variant );
609 }
610
613 return std::visit( [idx](auto&& e) {return e[idx];}, variant );
614 }
615
618 return std::visit( [id](auto&& e) {return e.findEffect(id);}, variant );
619 }
620
623 return std::visit( [channel](auto&& e) -> AudioEffectCommon& {return e.channelEffects(channel);}, variant );
624 }
625
628 return std::visit( [](auto&& e) {return e.channelCount();}, variant );
629 }
630
631 protected:
632 std::variant<AudioEffectStreamT<int16_t>, AudioEffectStreamT<int24_t>,AudioEffectStreamT<int32_t>> variant;
633 Stream *p_io=nullptr;
634 Print *p_out=nullptr;
635
636};
637
638#else
639// Use int16_t as only supported data type
641#endif
642
643} // namespace
#define TRACEI()
Definition AudioLoggerIDF.h:32
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define assert(T)
Definition avr.h:10
Definition Arduino.h:56
virtual int availableForWrite()
Definition Arduino.h:128
virtual void flush()
Definition Arduino.h:130
Definition Arduino.h:136
virtual size_t readBytes(uint8_t *data, size_t len)
Definition Arduino.h:140
virtual int available()
Definition Arduino.h:139
Definition AudioEffects.h:32
size_t size()
Provides the actual number of defined effects.
Definition AudioEffects.h:53
AudioEffect * findEffect(int id)
Finds an effect by id.
Definition AudioEffects.h:58
Vector< AudioEffect * > effects
Definition AudioEffects.h:76
void addEffect(AudioEffect *effect)
Adds an effect using a pointer.
Definition AudioEffects.h:41
void addEffect(AudioEffect &effect)
Adds an effect object (by reference)
Definition AudioEffects.h:35
AudioEffect * operator[](int idx)
gets an effect by index
Definition AudioEffects.h:71
void clear()
deletes all defined effects
Definition AudioEffects.h:47
Abstract Base class for Sound Effects.
Definition AudioEffect.h:24
virtual AudioEffect * clone()=0
EffectsStream supporting variable bits_per_sample. This class is only available when __cplusplus >= 2...
Definition AudioEffects.h:482
void flush() override
Definition AudioEffects.h:577
size_t size()
Provides the actual number of defined effects.
Definition AudioEffects.h:607
AudioEffect * findEffect(int id)
Finds an effect by id.
Definition AudioEffects.h:617
void addEffect(int channel, AudioEffect &effect)
Adds an effect object (by reference) directly to a single channel's own chain.
Definition AudioEffects.h:592
size_t readBytes(uint8_t *data, size_t len) override
Definition AudioEffects.h:557
AudioEffectCommon & channelEffects(int channel)
Provides access to a single channel's own effect chain (valid after begin())
Definition AudioEffects.h:622
bool begin()
Definition AudioEffects.h:508
void end() override
Definition AudioEffects.h:533
int available() override
Definition AudioEffects.h:569
size_t write(const uint8_t *data, size_t len) override
Definition AudioEffects.h:565
void addEffect(AudioEffect *effect)
Adds an effect using a pointer.
Definition AudioEffects.h:587
AudioEffectStream(Stream &io)
Definition AudioEffects.h:486
AudioEffectStream(Print &out)
Definition AudioEffects.h:491
std::variant< AudioEffectStreamT< int16_t >, AudioEffectStreamT< int24_t >, AudioEffectStreamT< int32_t > > variant
Definition AudioEffects.h:632
AudioInfo defaultConfig()
Definition AudioEffects.h:495
int availableForWrite() override
Definition AudioEffects.h:573
void addEffect(AudioEffect &effect)
Adds an effect object (by reference)
Definition AudioEffects.h:582
Print * p_out
Definition AudioEffects.h:634
AudioEffect * operator[](int idx)
gets an effect by index
Definition AudioEffects.h:612
void addEffect(int channel, AudioEffect *effect)
Adds an effect using a pointer directly to a single channel's own chain.
Definition AudioEffects.h:597
int channelCount()
Provides the number of channels that have their own effect chain (valid after begin())
Definition AudioEffects.h:627
void clear()
deletes all defined effects
Definition AudioEffects.h:602
void setStream(Stream &io)
Defines/Changes the input & output.
Definition AudioEffects.h:541
void setOutput(Stream &io)
Definition AudioEffects.h:545
bool begin(AudioInfo cfg)
Definition AudioEffects.h:503
Stream * p_io
Definition AudioEffects.h:633
void setInput(Stream &io)
Definition AudioEffects.h:537
void setOutput(Print &print)
Defines/Changes the output target.
Definition AudioEffects.h:549
EffectsStreamT: the template class describes an input or output stream to which one or multiple effec...
Definition AudioEffects.h:223
bool active
Definition AudioEffects.h:444
void flush() override
Definition AudioEffects.h:362
size_t size()
Provides the actual number of defined effects in the template chain.
Definition AudioEffects.h:415
AudioEffect * findEffect(int id)
Finds an effect by id in the template chain.
Definition AudioEffects.h:425
void setOutput(Print &print) override
Defines/Changes the output target.
Definition AudioEffects.h:283
void addEffect(int channel, AudioEffect &effect)
Definition AudioEffects.h:388
size_t readBytes(uint8_t *data, size_t len) override
Definition AudioEffects.h:291
void setupChannels()
(re)builds channel_effects from the template effects chain
Definition AudioEffects.h:456
AudioEffectStreamT(Print &out)
Definition AudioEffects.h:231
AudioEffectCommon & channelEffects(int channel)
Provides access to a single channel's own effect chain (valid after begin())
Definition AudioEffects.h:430
Vector< T > buffer_out
Definition AudioEffects.h:443
bool begin()
Definition AudioEffects.h:256
void end() override
Definition AudioEffects.h:273
Vector< AudioEffectCommon > channel_effects
Definition AudioEffects.h:441
Vector< AudioEffect * > owned_clones
Definition AudioEffects.h:442
int available() override
Definition AudioEffects.h:351
size_t write(const uint8_t *data, size_t len) override
Definition AudioEffects.h:318
void addEffect(AudioEffect *effect)
Adds an effect using a pointer to the template chain: cloned into every channel.
Definition AudioEffects.h:373
AudioInfo defaultConfig()
Definition AudioEffects.h:243
AudioEffectStreamT(const AudioEffectStreamT &)=delete
int availableForWrite() override
Definition AudioEffects.h:356
void addEffect(AudioEffect &effect)
Adds an effect object (by reference) to the template chain: cloned into every channel.
Definition AudioEffects.h:368
Print * p_out
Definition AudioEffects.h:446
AudioEffect * operator[](int idx)
gets an effect by index from the template chain
Definition AudioEffects.h:420
AudioEffectCommon effects
Definition AudioEffects.h:440
void addEffect(int channel, AudioEffect *effect)
Definition AudioEffects.h:394
~AudioEffectStreamT()
Definition AudioEffects.h:239
AudioEffectStreamT & operator=(const AudioEffectStreamT &)=delete
int channelCount()
Provides the number of channels that have their own effect chain (valid after begin())
Definition AudioEffects.h:435
void clear()
deletes all defined effects
Definition AudioEffects.h:404
AudioEffectStreamT(Stream &io)
Definition AudioEffects.h:227
void setStream(Stream &io) override
Defines/Changes the input & output.
Definition AudioEffects.h:277
void cloneInto(int ch, AudioEffect *effect)
clones a single effect into a single channel's chain, tracking ownership
Definition AudioEffects.h:449
bool begin(AudioInfo cfg)
Definition AudioEffects.h:251
Stream * p_io
Definition AudioEffects.h:445
OBSOLETE AudioEffects: the template class describes the input audio to which the effects are applied:...
Definition AudioEffects.h:95
effect_t readSample() override
provides the resulting sample
Definition AudioEffects.h:159
size_t size()
Provides the actual number of defined effects.
Definition AudioEffects.h:178
AudioEffect * findEffect(int id)
Finds an effect by id.
Definition AudioEffects.h:193
GeneratorT & generator()
Provides access to the sound generator.
Definition AudioEffects.h:183
GeneratorT * p_generator
Definition AudioEffects.h:199
virtual ~AudioEffects()
Destructor.
Definition AudioEffects.h:124
AudioEffects(AudioEffects &copy)
Copy constructor.
Definition AudioEffects.h:101
AudioEffects(GeneratorT &generator)
Constructor which is assigning a generator.
Definition AudioEffects.h:112
void addEffect(AudioEffect *effect)
Adds an effect using a pointer.
Definition AudioEffects.h:152
void addEffect(AudioEffect &effect)
Adds an effect object (by reference)
Definition AudioEffects.h:146
AudioEffect * operator[](int idx)
gets an effect by index
Definition AudioEffects.h:188
AudioEffectCommon effects
Definition AudioEffects.h:198
void setInput(GeneratorT &in)
Defines the input source for the raw guitar input.
Definition AudioEffects.h:135
void clear()
deletes all defined effects
Definition AudioEffects.h:172
AudioEffects(Stream &input, int channels=2, float volume=1.0)
Definition AudioEffects.h:118
AudioEffects()=default
Default constructor.
bool owns_generator
Definition AudioEffects.h:200
AudioInfo info
Definition BaseStream.h:171
Abstract class: Objects can be put into a pipleline.
Definition AudioStreams.h:68
Base class to define the abstract interface for the sound generating classes.
Definition SoundGenerator.h:30
AudioInfo info
Definition SoundGenerator.h:176
virtual bool begin()
Starts the processing.
Definition SoundGenerator.h:43
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
int16_t effect_t
Definition AudioEffect.h:15
int24_4bytes_t int24_t
Definition int24_t.h:12
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:51
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:53
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:55
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:57