arduino-audio-tools
Fade.h
1 #pragma once
2 #include "AudioConfig.h"
3 #include "AudioStreams.h"
4 
5 namespace audio_tools {
6 
16 class Fade {
17 public:
18  void setFadeInActive(bool flag) {
19  is_fade_in = flag;
20  if (is_fade_in) {
21  volume = 0.0;
22  is_fade_out = false;
23  is_done = false;
24  }
25  }
26 
27  bool isFadeInActive() { return is_fade_in; }
28 
29  void setFadeOutActive(bool flag) {
30  is_fade_out = flag;
31  if (is_fade_out) {
32  volume = 1.0;
33  is_fade_in = false;
34  is_done = false;
35  }
36  }
37 
38  bool isFadeOutActive() { return is_fade_out; }
39 
46  void convert(uint8_t *data, int bytes, int channels, int bitsPerSample) {
47  this->channels = channels;
48  int bytes_per_sample = bitsPerSample / 8;
49  switch (bitsPerSample) {
50  case 16:
51  convertFrames<int16_t>((int16_t *)data,
52  bytes / bytes_per_sample / channels, channels);
53  break;
54  case 24:
55  convertFrames<int24_t>((int24_t *)data,
56  bytes / bytes_per_sample / channels, channels);
57  break;
58  case 32:
59  convertFrames<int32_t>((int32_t *)data,
60  bytes / bytes_per_sample / channels, channels);
61  break;
62  default:
63  LOGE("%s", "Unsupported bitsPerSample");
64  break;
65  }
66  }
67 
69  bool isFadeComplete() { return is_done; }
70 
71 protected:
72  bool is_fade_in = false;
73  bool is_fade_out = false;
74  int channels = 2;
75  float volume = 1.0;
76  bool is_done = false;
77 
78  template <typename T> void convertFrames(T *data, int frames, int channels) {
79  float delta = 1.0 / frames;
80  // handle fade out
81  if (is_fade_in) {
82  fadeIn<T>(data, frames, channels, delta);
83  is_fade_in = false;
84  } else if (is_fade_out) {
85  fadeOut<T>(data, frames, channels, delta);
86  }
87  if (frames > 0) {
88  is_done = true;
89  }
90  }
91 
92  template <typename T>
93  void fadeOut(T *data, int frames, int channels, float delta) {
94  for (int j = 0; j < frames; j++) {
95  for (int ch = 0; ch < channels; ch++) {
96  data[j * channels + ch] = data[j * channels + ch] * volume;
97  if (volume > 0) {
98  volume -= delta;
99  if (volume < 0) {
100  volume = 0;
101  }
102  }
103  }
104  }
105  is_fade_out = false;
106  LOGI("faded out %d frames to volume %f",frames, volume);
107  }
108 
109  template <typename T>
110  void fadeIn(T *data, int frames, int channels, float delta) {
111  LOGI("fade in %d frames from volume %f",frames, volume);
112  for (int j = 0; j < frames; j++) {
113  for (int ch = 0; ch < channels; ch++) {
114  data[j * channels + ch] = data[j * channels + ch] * volume;
115  volume += delta;
116  if (volume > 1.0f) {
117  volume = 1.0f;
118  }
119  }
120  }
121  volume = 1.0f;
122  is_fade_in = false;
123  }
124 };
125 
132 template <typename T>
134 public:
135  void setChannels(int ch) { channels = ch; last.resize(ch); }
136  size_t write(uint8_t *src, size_t size) {
137  if (channels == 0){
138  LOGE("channels=0");
139  return 0;
140  }
141  int frames = size / sizeof(T) / channels;
142  storeLastSamples(frames, src);
143  return size;
144  };
145 
148  void end(Print &print, int steps = 200) {
149  T out[channels];
150  for (int j = 0; j < steps; j++) {
151  for (int ch = 0; ch < channels; ch++) {
152  float factor =
153  static_cast<float>(steps - j) / static_cast<float>(steps);
154  out[ch] = last[ch] * factor;
155  }
156  print.write((uint8_t *)out, channels * sizeof(T));
157  }
158  }
159 
160 protected:
161  int channels = 0;
162  Vector<T> last{0};
163 
164  void storeLastSamples(int frames, uint8_t *src) {
165  T *data = (T *)src;
166  for (int ch = 0; ch < channels; ch++) {
167  last[ch] = data[frames - 2 * channels + ch];
168  }
169  }
170 };
171 
177 public:
178  void setChannels(int ch) {
179  f16.setChannels(ch);
180  f24.setChannels(ch);
181  f32.setChannels(ch);
182  }
183 
184  void setBitsPerSample(int bits){
185  bits_per_sample = bits;
186  }
187 
188  void setAudioInfo(AudioInfo info) {
189  setChannels(info.channels);
190  setBitsPerSample(info.bits_per_sample);
191  }
192 
193  size_t write(uint8_t *src, size_t size) {
194  switch(bits_per_sample){
195  case 16:
196  return f16.write(src, size);
197  case 24:
198  return f24.write(src, size);
199  case 32:
200  return f32.write(src, size);
201  default:
202  LOGE("bits_per_sample is 0");
203  }
204  return 0;
205  };
206 
209  void end(Print &print, int steps = 200) {
210  switch(bits_per_sample){
211  case 16:
212  f16.end(print, steps);
213  break;
214  case 24:
215  f24.end(print, steps);
216  break;
217  case 32:
218  f32.end(print, steps);
219  break;
220  }
221  }
222 
223 protected:
224  int bits_per_sample = 0;
228 };
229 
230 
240 class FadeStream : public ModifyingStream {
241 public:
242  FadeStream() = default;
243  FadeStream(Print &out) { setOutput(out); }
244  FadeStream(Stream &io) { setStream(io); }
245 
246  void setStream(Stream &io) override {
247  p_io = &io;
248  p_out = &io;
249  }
250 
251  void setOutput(Print &out) override { p_out = &out; }
252 
254  void setOutput(Stream &io) {
255  p_io = &io;
256  p_out = &io;
257  }
258 
260  void setStream(Print &out) { p_out = &out; }
261 
262  bool begin(AudioInfo info){
263  setAudioInfo(info);
264  return AudioStream::begin();
265  }
266 
267  void setAudioInfo(AudioInfo info) override {
269  fade_last.setAudioInfo(info);
270  active = true;
271  }
272 
273  size_t readBytes(uint8_t *buffer, size_t length) override {
274  if (!active) {
275  LOGE("%s", error_msg);
276  return 0;
277  }
278  fade.convert(buffer, length, info.channels, info.bits_per_sample);
279  fade_last.write(buffer, length);
280  return p_io->readBytes(buffer, length);
281  }
282 
283  int available() override { return p_io == nullptr ? 0 : p_io->available(); }
284 
285  size_t write(const uint8_t *buffer, size_t size) override {
286  if (p_out==nullptr) return 0;
287  if (!active) {
288  LOGE("%s", error_msg);
289  return 0;
290  }
291  if (fade.isFadeInActive() || fade.isFadeOutActive()){
292  fade.convert((uint8_t *)buffer, size, info.channels, info.bits_per_sample);
293  }
294  // update last information
295  fade_last.write((uint8_t *)buffer, size);
296  // write faded data
297  return p_out->write(buffer, size);
298  }
299 
300  int availableForWrite() override {
301  return p_out == nullptr ? 0 : p_out->availableForWrite();
302  }
303 
304  void setFadeInActive(bool flag) { fade.setFadeInActive(flag); }
305 
306  bool isFadeInActive() { return fade.isFadeInActive(); }
307 
308  void setFadeOutActive(bool flag) { fade.setFadeOutActive(flag); }
309 
310  bool isFadeOutActive() { return fade.isFadeOutActive(); }
311 
312  bool isFadeComplete() { return fade.isFadeComplete(); }
313 
314  // If can not provide any more samples we bring the last sample slowy back to 0
315  void writeEnd(Print &print, int steps = 200) {
316  fade_last.end(print, steps);
317  }
318 
319 protected:
320  bool active = false;
321  Fade fade;
322  LastSampleFader fade_last;
323  Print *p_out = nullptr;
324  Stream *p_io = nullptr;
325  const char *error_msg = "setAudioInfo not called";
326 };
327 
333 template <typename T> class FadeConverter : public BaseConverter{
334 public:
335  FadeConverter(int channels) { setChannels(channels); }
336 
337  void setChannels(int ch) { channels = ch; }
338 
339  void setFadeInActive(bool flag) { fade.setFadeInActive(flag); }
340 
341  bool isFadeInActive() { return fade.isFadeInActive(); }
342 
343  void setFadeOutActive(bool flag) { fade.setFadeOutActive(flag); }
344 
345  bool isFadeOutActive() { return fade.isFadeOutActive(); }
346 
347  bool isFadeComplete() { return fade.isFadeComplete(); }
348 
349  virtual size_t convert(uint8_t *src, size_t size) {
350  int frames = size / sizeof(T) / channels;
351  fade.convertFrames<T>(src, frames, channels);
352  return size;
353  };
354 
355 protected:
356  int channels = 0;
357  Fade fade;
358 };
359 
360 } // namespace audio_tools
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition: AudioStreams.h:32
Abstract Base class for Converters A converter is processing the data in the indicated array.
Definition: BaseConverter.h:24
converter which does a fade out or fade in.
Definition: Fade.h:333
Fade In and Fade out in order to prevent popping sound when the audio is started or stopped....
Definition: Fade.h:16
void convert(uint8_t *data, int bytes, int channels, int bitsPerSample)
Updates the amplitude of the data when a fade in or fade out has been requested.
Definition: Fade.h:46
bool isFadeComplete()
Returns true if the conversion has been executed with any data.
Definition: Fade.h:69
Stream which can be used to manage fade in and fade out. Before you read or write data you need to ca...
Definition: Fade.h:240
void setOutput(Print &out) override
Defines/Changes the output target.
Definition: Fade.h:251
void setStream(Print &out)
same as setOutput
Definition: Fade.h:260
void setAudioInfo(AudioInfo info) override
Defines the input AudioInfo.
Definition: Fade.h:267
void setStream(Stream &io) override
Defines/Changes the input & output.
Definition: Fade.h:246
void setOutput(Stream &io)
same as setStream
Definition: Fade.h:254
If we end audio and the last sample is not close to 0 we can hear a popping noise....
Definition: Fade.h:176
void end(Print &print, int steps=200)
When we do not have any data any more to fade out we try to bring the last sample slowly to 0.
Definition: Fade.h:209
If we end audio and the last sample is not close to 0 we can hear a popping noise....
Definition: Fade.h:133
void end(Print &print, int steps=200)
When we do not have any data any more to fade out we try to bring the last sample slowly to 0.
Definition: Fade.h:148
Abstract class: Objects can be put into a pipleline.
Definition: AudioStreams.h:136
Definition: NoArduino.h:58
Definition: NoArduino.h:125
Vector implementation which provides the most important methods as defined by std::vector....
Definition: Vector.h:21
24bit integer which is used for I2S sound processing. The values are represented as int32_t,...
Definition: Int24_4bytes_t.h:16
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
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