arduino-audio-tools
AudioEffects.h
1 #pragma once
2 #include "AudioBasic/Collections.h"
3 #include "AudioEffects/SoundGenerator.h"
4 #include "AudioEffects/AudioEffect.h"
5 #include "AudioTools/AudioStreams.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  if (sizeof(T)==cfg.bits_per_sample/8){
231  active = true;
232  } else {
233  LOGE("bits_per_sample not consistent: %d",cfg.bits_per_sample);
234  active = false;
235  }
236  return active;
237  }
238 
239  void end() override {
240  active = false;
241  }
242 
243  void setStream(Stream &io) override {
244  p_io = &io;
245  p_print = &io;
246  }
247 
248 
249  void setOutput(Print &print) override {
250  p_print = &print;
251  }
252 
257  size_t readBytes(uint8_t *buffer, size_t length) override {
258  if (!active || p_io==nullptr)return 0;
259  int frames = length / sizeof(T) / info.channels;
260  size_t result_size = 0;
261 
262  if (p_io->available()<(sizeof(T)*info.channels)){
263  return 0;
264  }
265 
266  for (int count=0;count<frames;count++){
267  // determine sample by combining all channels in frame
268  T result_sample = 0;
269  for (int ch=0;ch<info.channels;ch++){
270  T sample;
271  p_io->readBytes((uint8_t*)&sample, sizeof(T));
272  result_sample += sample / info.channels;
273  }
274 
275  // apply effects
276  for (int j=0; j<size(); j++){
277  result_sample = effects[j]->process(result_sample);
278  }
279 
280  // write result multiplying channels
281  T* p_buffer = ((T*)buffer)+(count*info.channels);
282  for (int ch=0;ch<info.channels;ch++){
283  p_buffer[ch] = result_sample;
284  result_size += sizeof(T);
285  }
286  }
287  return result_size;
288  }
289 
294  size_t write(const uint8_t *buffer, size_t length) override {
295  if (!active)return 0;
296  // length must be multple of channels
297  assert(length % (sizeof(T)*info.channels)==0);
298  int frames = length / sizeof(T) / info.channels;
299  size_t result_size = 0;
300 
301  // process all samples
302  for (int j=0;j<frames;j++){
303  // calculate sample for frame
304  T* p_buffer = ((T*)buffer) + (j*info.channels);
305  T sample=0;
306  for (int ch=0;ch<info.channels;ch++){
307  sample += p_buffer[ch] / info.channels;
308  result_size += sizeof(T);
309  }
310 
311  // apply effects
312  for (int j=0; j<size(); j++){
313  sample = effects[j]->process(sample);
314  }
315 
316  // wite result channel times to output defined in constructor
317  for (int ch=0;ch<info.channels;ch++){
318  if (p_io!=nullptr){
319  p_io->write((uint8_t*)&sample, sizeof(T));
320 
321  } else if (p_print!=nullptr){
322  p_print->write((uint8_t*)&sample, sizeof(T));
323  }
324  }
325  }
326  return result_size;
327  }
328 
329  int available() override {
330  if (p_io==nullptr) return 0;
331  return p_io->available();
332  }
333 
334  int availableForWrite() override {
335  if (p_print!=nullptr) return p_print->availableForWrite();
336  if (p_io!=nullptr) return p_io->availableForWrite();
337  return 0;
338  }
339 
341  void addEffect(AudioEffect &effect){
342  TRACED();
343  effects.addEffect(&effect);
344  }
345 
347  void addEffect(AudioEffect *effect){
348  TRACED();
349  effects.addEffect(effect);
350  LOGI("addEffect -> Number of effects: %d", (int) size());
351  }
352 
354  void clear() {
355  TRACED();
356  effects.clear();
357  }
358 
360  size_t size() {
361  return effects.size();
362  }
363 
366  return effects[idx];
367  }
368 
371  return effects.findEffect(id);
372  }
373 
374  protected:
375  AudioEffectCommon effects;
376  bool active = false;
377  Stream *p_io=nullptr;
378  Print *p_print=nullptr;
379 };
380 
381 #if defined(USE_VARIANTS) && __cplusplus >= 201703L || defined(DOXYGEN)
393  AudioEffectStream() = default;
394 
396  setOutput(io);
397  setInput(io);
398  }
399 
400  AudioEffectStream(Print &out){
401  setOutput(out);
402  }
403 
404  AudioInfo defaultConfig() {
405  AudioInfo cfg;
406  cfg.sample_rate = 44100;
407  cfg.bits_per_sample = 16;
408  cfg.channels = 2;
409  return cfg;
410  }
411 
412  bool begin(AudioInfo cfg){
413  info = cfg;
414  switch(cfg.bits_per_sample){
415  case 16:
416  variant.emplace<0>();
417  break;
418  case 24:
419  variant.emplace<1>();
420  break;
421  case 32:
422  variant.emplace<2>();
423  break;
424  default:
425  LOGE("Unspported bits_per_sample: %d", cfg.bits_per_sample);
426  return false;
427  }
428  std::visit( [this](auto&& e) {return e.setOutput(*p_print);}, variant );
429  std::visit( [this](auto&& e) {return e.setInput(*p_io);}, variant );
430  return std::visit( [cfg](auto&& e) {return e.begin(cfg);}, variant );
431  }
432 
433  void end() override {
434  std::visit( [](auto&& e) {e.end();}, variant );
435  }
436 
437  void setInput(Stream &io){
438  setStream(io);
439  }
440 
441  void setStream(Stream &io){
442  p_io = &io;
443  }
444 
445  void setOutput(Stream &io){
446  p_io = &io;
447  }
448 
449  void setOutput(Print &print){
450  p_print = &print;
451  }
452 
457  size_t readBytes(uint8_t *buffer, size_t length) override {
458  return std::visit( [buffer, length](auto&& e) {return e.readBytes(buffer, length);}, variant );
459  }
460 
465  size_t write(const uint8_t *buffer, size_t length) override {
466  return std::visit( [buffer, length](auto&& e) {return e.write(buffer, length);}, variant );
467  }
468 
469  int available() override {
470  return std::visit( [](auto&& e) {return e.available();}, variant );
471  }
472 
473  int availableForWrite() override {
474  return std::visit( [](auto&& e) {return e.availableForWrite();}, variant );
475  }
476 
478  void addEffect(AudioEffect &effect){
479  addEffect(&effect);
480  }
481 
483  void addEffect(AudioEffect *effect){
484  std::visit( [effect](auto&& e) {e.addEffect(effect);}, variant );
485  }
486 
488  void clear() {
489  std::visit( [](auto&& e) {e.clear();}, variant );
490  }
491 
493  size_t size() {
494  return std::visit( [](auto&& e) {return e.size();}, variant );
495  }
496 
498  AudioEffect* operator [](int idx){
499  return std::visit( [idx](auto&& e) {return e[idx];}, variant );
500  }
501 
503  AudioEffect* findEffect(int id){
504  return std::visit( [id](auto&& e) {return e.findEffect(id);}, variant );
505  }
506 
507  protected:
508  std::variant<AudioEffectStreamT<int16_t>, AudioEffectStreamT<int24_t>,AudioEffectStreamT<int32_t>> variant;
509  Stream *p_io=nullptr;
510  Print *p_print=nullptr;
511 
512 };
513 
514 #else
515 // Use int16_t as only supported data type
517 #endif
518 
519 } // 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:20
EffectsStream supporting variable bits_per_sample. This class is only available when __cplusplus >= 2...
Definition: AudioEffects.h:392
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:360
void setOutput(Print &print) override
Defines/Changes the output target.
Definition: AudioEffects.h:249
size_t readBytes(uint8_t *buffer, size_t length) override
Definition: AudioEffects.h:257
AudioEffect * operator[](int idx)
gets an effect by index
Definition: AudioEffects.h:365
void addEffect(AudioEffect *effect)
Adds an effect using a pointer.
Definition: AudioEffects.h:347
void addEffect(AudioEffect &effect)
Adds an effect object (by reference)
Definition: AudioEffects.h:341
AudioEffect * findEffect(int id)
Finds an effect by id.
Definition: AudioEffects.h:370
void clear()
deletes all defined effects
Definition: AudioEffects.h:354
void setStream(Stream &io) override
Defines/Changes the input & output.
Definition: AudioEffects.h:243
size_t write(const uint8_t *buffer, size_t length) override
Definition: AudioEffects.h:294
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:136
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: AnalogAudio.h:10
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:50
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