arduino-audio-tools
AudioEffects.h
1 #pragma once
2 #include "AudioTools/CoreAudio/AudioBasic/Collections.h"
3 #include "AudioTools/CoreAudio/AudioStreams.h"
4 #include "SoundGenerator.h"
5 #include "AudioEffect.h"
6 #if defined(USE_VARIANTS) && __cplusplus >= 201703L
7 # include <variant>
8 #endif
9 
16 namespace audio_tools {
17 
25  public:
27  void addEffect(AudioEffect &effect){
28  TRACED();
29  effects.push_back(&effect);
30  }
31 
33  void addEffect(AudioEffect *effect){
34  TRACED();
35  effects.push_back(effect);
36  LOGI("addEffect -> Number of effects: %d", (int)size());
37  }
39  void clear() {
40  TRACED();
41  effects.clear();
42  }
43 
45  size_t size() {
46  return effects.size();
47  }
48 
51  // find AudioEffect
52  AudioEffect* result = nullptr;
53  for (int j=0;j<size();j++){
54  // we assume that ADSRGain is the first effect!
55  if (effects[j]->id()==id){
56  result = effects[j];
57  }
58  LOGI("--> findEffect -> %d", effects[j]->id());
59  }
60  return result;
61  }
64  return effects[idx];
65  }
66 
67  protected:
68  Vector<AudioEffect*> effects;
69 
70 };
71 
86 template <class GeneratorT>
87 class AudioEffects : public SoundGenerator<effect_t> {
88  public:
90  AudioEffects() = default;
91 
94  TRACEI();
95  // create a copy of the source and all effects
96  p_generator = copy.p_generator;
97  for (int j=0;j<copy.size();j++){
98  effects.addEffect(copy[j]->clone());
99  }
100  LOGI("Number of effects %d -> %d", copy.size(), this->size());
101  }
102 
104  AudioEffects(GeneratorT &generator) {
106  }
107 
110  AudioEffects(Stream &input, int channels=2, float volume=1.0) {
111  setInput(* (new GeneratorT(input, channels, volume)));
112  owns_generator = true;
113  }
114 
116  virtual ~AudioEffects(){
117  TRACED();
118  if (owns_generator && p_generator!=nullptr){
119  delete p_generator;
120  }
121  for (int j=0;j<effects.size();j++){
122  delete effects[j];
123  }
124  }
125 
127  void setInput(GeneratorT &in){
128  TRACED();
129  p_generator = &in;
130  // automatically activate this object
131  AudioInfo info;
132  info.channels = 1;
133  info.bits_per_sample = sizeof(effect_t)*8;
134  begin(info);
135  }
136 
138  void addEffect(AudioEffect &effect){
139  TRACED();
140  effects.addEffect(&effect);
141  }
142 
144  void addEffect(AudioEffect *effect){
145  TRACED();
146  effects.addEffect(effect);
147  LOGI("addEffect -> Number of effects: %d", size());
148  }
149 
151  effect_t readSample() override {
152  effect_t sample;
153  if (p_generator!=nullptr){
154  sample = p_generator->readSample();
155  int size = effects.size();
156  for (int j=0; j<size; j++){
157  sample = effects[j]->process(sample);
158  }
159  }
160  return sample;
161  }
162 
164  void clear() {
165  TRACED();
166  effects.clear();
167  }
168 
170  size_t size() {
171  return effects.size();
172  }
173 
175  GeneratorT &generator(){
176  return *p_generator;
177  }
178 
181  return effects[idx];
182  }
183 
186  return effects.findEffect(id);
187  }
188 
189  protected:
190  AudioEffectCommon effects;
191  GeneratorT *p_generator=nullptr;
192  bool owns_generator = false;
193 };
194 
195 
207 template <class T>
209  public:
210  AudioEffectStreamT() = default;
211 
213  setStream(io);
214  }
215 
217  setOutput(out);
218  }
219 
220  AudioInfo defaultConfig() {
221  AudioInfo cfg;
222  cfg.sample_rate = 44100;
223  cfg.bits_per_sample = 16;
224  cfg.channels = 2;
225  return cfg;
226  }
227 
228  bool begin(AudioInfo cfg){
229  info = cfg;
230  return begin();
231  }
232 
233  bool begin(){
234  TRACEI();
235  if (sizeof(T)==info.bits_per_sample/8){
236  active = true;
237  } else {
238  LOGE("bits_per_sample not consistent: %d",info.bits_per_sample);
239  active = false;
240  }
241  return active;
242  }
243 
244  void end() override {
245  active = false;
246  }
247 
248  void setStream(Stream &io) override {
249  p_io = &io;
250  p_print = &io;
251  }
252 
253 
254  void setOutput(Print &print) override {
255  p_print = &print;
256  }
257 
262  size_t readBytes(uint8_t *data, size_t len) override {
263  if (!active || p_io==nullptr)return 0;
264  size_t result_size = 0;
265 
266  // read data from source
267  size_t result = p_io->readBytes((uint8_t*)data, len);
268  int frames = result / sizeof(T) / info.channels;
269  T* samples = (T*) data;
270 
271  for (int count=0;count<frames;count++){
272  // determine sample by combining all channels in frame
273  T result_sample = 0;
274  for (int ch=0;ch<info.channels;ch++){
275  T sample = *samples++;
276  //p_io->readBytes((uint8_t*)&sample, sizeof(T));
277  result_sample += sample / info.channels;
278  }
279 
280  // apply effects
281  for (int j=0; j<size(); j++){
282  result_sample = effects[j]->process(result_sample);
283  }
284 
285  // write result multiplying channels
286  T* p_buffer = ((T*)data)+(count*info.channels);
287  for (int ch=0;ch<info.channels;ch++){
288  p_buffer[ch] = result_sample;
289  result_size += sizeof(T);
290  }
291  }
292  return result_size;
293  }
294 
299  size_t write(const uint8_t *data, size_t len) override {
300  if (!active)return 0;
301  // length must be multple of channels
302  assert(len % (sizeof(T)*info.channels)==0);
303  int frames = len / sizeof(T) / info.channels;
304  size_t result_size = 0;
305 
306  // process all samples
307  for (int j=0;j<frames;j++){
308  // calculate sample for frame
309  T* p_buffer = ((T*)data) + (j*info.channels);
310  T sample=0;
311  for (int ch=0;ch<info.channels;ch++){
312  sample += p_buffer[ch] / info.channels;
313  result_size += sizeof(T);
314  }
315 
316  // apply effects
317  for (int j=0; j<size(); j++){
318  sample = effects[j]->process(sample);
319  }
320 
321  // wite result channel times to output defined in constructor
322  for (int ch=0;ch<info.channels;ch++){
323  if (p_io!=nullptr){
324  p_io->write((uint8_t*)&sample, sizeof(T));
325 
326  } else if (p_print!=nullptr){
327  p_print->write((uint8_t*)&sample, sizeof(T));
328  }
329  }
330  }
331  return result_size;
332  }
333 
334  int available() override {
335  if (p_io==nullptr) return 0;
336  return p_io->available();
337  }
338 
339  int availableForWrite() override {
340  if (p_print!=nullptr) return p_print->availableForWrite();
341  if (p_io!=nullptr) return p_io->availableForWrite();
342  return 0;
343  }
344 
346  void addEffect(AudioEffect &effect){
347  TRACED();
348  effects.addEffect(&effect);
349  }
350 
352  void addEffect(AudioEffect *effect){
353  TRACED();
354  effects.addEffect(effect);
355  LOGI("addEffect -> Number of effects: %d", (int) size());
356  }
357 
359  void clear() {
360  TRACED();
361  effects.clear();
362  }
363 
365  size_t size() {
366  return effects.size();
367  }
368 
371  return effects[idx];
372  }
373 
376  return effects.findEffect(id);
377  }
378 
379  protected:
380  AudioEffectCommon effects;
381  bool active = false;
382  Stream *p_io=nullptr;
383  Print *p_print=nullptr;
384 };
385 
386 #if defined(USE_VARIANTS) && __cplusplus >= 201703L || defined(DOXYGEN)
398  AudioEffectStream() = default;
399 
401  setOutput(io);
402  setInput(io);
403  }
404 
405  AudioEffectStream(Print &out){
406  setOutput(out);
407  }
408 
409  AudioInfo defaultConfig() {
410  AudioInfo cfg;
411  cfg.sample_rate = 44100;
412  cfg.bits_per_sample = 16;
413  cfg.channels = 2;
414  return cfg;
415  }
416 
417  bool begin(AudioInfo cfg){
418  info = cfg;
419  return begin();
420  }
421 
422  bool begin(){
423  TRACEI();
424  switch(info.bits_per_sample){
425  case 16:
426  variant.emplace<0>();
427  break;
428  case 24:
429  variant.emplace<1>();
430  break;
431  case 32:
432  variant.emplace<2>();
433  break;
434  default:
435  LOGE("Unspported bits_per_sample: %d", cfg.bits_per_sample);
436  return false;
437  }
438  std::visit( [this](auto&& e) {return e.setOutput(*p_print);}, variant );
439  std::visit( [this](auto&& e) {return e.setInput(*p_io);}, variant );
440  return std::visit( [cfg](auto&& e) {return e.begin(info);}, variant );
441  }
442 
443  void end() override {
444  std::visit( [](auto&& e) {e.end();}, variant );
445  }
446 
447  void setInput(Stream &io){
448  setStream(io);
449  }
450 
451  void setStream(Stream &io){
452  p_io = &io;
453  }
454 
455  void setOutput(Stream &io){
456  p_io = &io;
457  }
458 
459  void setOutput(Print &print){
460  p_print = &print;
461  }
462 
467  size_t readBytes(uint8_t *data, size_t len) override {
468  return std::visit( [data, len](auto&& e) {return e.readBytes(data, len);}, variant );
469  }
470 
475  size_t write(const uint8_t *data, size_t len) override {
476  return std::visit( [data, len](auto&& e) {return e.write(data, len);}, variant );
477  }
478 
479  int available() override {
480  return std::visit( [](auto&& e) {return e.available();}, variant );
481  }
482 
483  int availableForWrite() override {
484  return std::visit( [](auto&& e) {return e.availableForWrite();}, variant );
485  }
486 
488  void addEffect(AudioEffect &effect){
489  addEffect(&effect);
490  }
491 
493  void addEffect(AudioEffect *effect){
494  std::visit( [effect](auto&& e) {e.addEffect(effect);}, variant );
495  }
496 
498  void clear() {
499  std::visit( [](auto&& e) {e.clear();}, variant );
500  }
501 
503  size_t size() {
504  return std::visit( [](auto&& e) {return e.size();}, variant );
505  }
506 
508  AudioEffect* operator [](int idx){
509  return std::visit( [idx](auto&& e) {return e[idx];}, variant );
510  }
511 
513  AudioEffect* findEffect(int id){
514  return std::visit( [id](auto&& e) {return e.findEffect(id);}, variant );
515  }
516 
517  protected:
518  std::variant<AudioEffectStreamT<int16_t>, AudioEffectStreamT<int24_t>,AudioEffectStreamT<int32_t>> variant;
519  Stream *p_io=nullptr;
520  Print *p_print=nullptr;
521 
522 };
523 
524 #else
525 // Use int16_t as only supported data type
527 #endif
528 
529 } // namespace
Definition: AudioEffects.h:24
size_t size()
Provides the actual number of defined effects.
Definition: AudioEffects.h:45
AudioEffect * operator[](int idx)
gets an effect by index
Definition: AudioEffects.h:63
void addEffect(AudioEffect *effect)
Adds an effect using a pointer.
Definition: AudioEffects.h:33
void addEffect(AudioEffect &effect)
Adds an effect object (by reference)
Definition: AudioEffects.h:27
AudioEffect * findEffect(int id)
Finds an effect by id.
Definition: AudioEffects.h:50
void clear()
deletes all defined effects
Definition: AudioEffects.h:39
Abstract Base class for Sound Effects.
Definition: AudioEffect.h:21
EffectsStream supporting variable bits_per_sample. This class is only available when __cplusplus >= 2...
Definition: AudioEffects.h:397
EffectsStreamT: the template class describes an input or output stream to which one or multiple effec...
Definition: AudioEffects.h:208
size_t size()
Provides the actual number of defined effects.
Definition: AudioEffects.h:365
void setOutput(Print &print) override
Defines/Changes the output target.
Definition: AudioEffects.h:254
size_t readBytes(uint8_t *data, size_t len) override
Definition: AudioEffects.h:262
AudioEffect * operator[](int idx)
gets an effect by index
Definition: AudioEffects.h:370
size_t write(const uint8_t *data, size_t len) override
Definition: AudioEffects.h:299
void addEffect(AudioEffect *effect)
Adds an effect using a pointer.
Definition: AudioEffects.h:352
void addEffect(AudioEffect &effect)
Adds an effect object (by reference)
Definition: AudioEffects.h:346
AudioEffect * findEffect(int id)
Finds an effect by id.
Definition: AudioEffects.h:375
void clear()
deletes all defined effects
Definition: AudioEffects.h:359
void setStream(Stream &io) override
Defines/Changes the input & output.
Definition: AudioEffects.h:248
OBSOLETE AudioEffects: the template class describes the input audio to which the effects are applied:...
Definition: AudioEffects.h:87
effect_t readSample() override
provides the resulting sample
Definition: AudioEffects.h:151
size_t size()
Provides the actual number of defined effects.
Definition: AudioEffects.h:170
GeneratorT & generator()
Provides access to the sound generator.
Definition: AudioEffects.h:175
virtual ~AudioEffects()
Destructor.
Definition: AudioEffects.h:116
AudioEffects(AudioEffects &copy)
Copy constructor.
Definition: AudioEffects.h:93
AudioEffects(GeneratorT &generator)
Constructor which is assigning a generator.
Definition: AudioEffects.h:104
AudioEffect * operator[](int idx)
gets an effect by index
Definition: AudioEffects.h:180
void addEffect(AudioEffect *effect)
Adds an effect using a pointer.
Definition: AudioEffects.h:144
void addEffect(AudioEffect &effect)
Adds an effect object (by reference)
Definition: AudioEffects.h:138
void setInput(GeneratorT &in)
Defines the input source for the raw guitar input.
Definition: AudioEffects.h:127
AudioEffect * findEffect(int id)
Finds an effect by id.
Definition: AudioEffects.h:185
void clear()
deletes all defined effects
Definition: AudioEffects.h:164
AudioEffects(Stream &input, int channels=2, float volume=1.0)
Definition: AudioEffects.h:110
AudioEffects()=default
Default constructor.
Abstract class: Objects can be put into a pipleline.
Definition: AudioStreams.h:69
Definition: NoArduino.h:58
Base class to define the abstract interface for the sound generating classes.
Definition: SoundGenerator.h:25
Definition: NoArduino.h:125
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: AudioConfig.h:868
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:52
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition: AudioTypes.h:55
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition: AudioTypes.h:59