arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
Fade.h
1#pragma once
2#include "AudioConfig.h"
3#include "AudioStreams.h"
4
5namespace audio_tools {
6
16class Fade {
17public:
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:
52 bytes / bytes_per_sample / channels, channels);
53 break;
54 case 24:
56 bytes / bytes_per_sample / channels, channels);
57 break;
58 case 32:
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
71protected:
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
132template <typename T>
134public:
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
160protected:
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
177public:
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
223protected:
224 int bits_per_sample = 0;
228};
229
230
241public:
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 *data, size_t len) override {
274 if (!active) {
275 LOGE("%s", error_msg);
276 return 0;
277 }
278 fade.convert(data, len, info.channels, info.bits_per_sample);
279 fade_last.write(data, len);
280 return p_io->readBytes(data, len);
281 }
282
283 int available() override { return p_io == nullptr ? 0 : p_io->available(); }
284
285 size_t write(const uint8_t *data, size_t len) 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 *)data, len, info.channels, info.bits_per_sample);
293 }
294 // update last information
295 fade_last.write((uint8_t *)data, len);
296 // write faded data
297 return p_out->write(data, len);
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
319protected:
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
333template <typename T> class FadeConverter : public BaseConverter{
334public:
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
355protected:
356 int channels = 0;
357 Fade fade;
358};
359
360} // namespace audio_tools
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition BaseStream.h:123
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:69
Definition NoArduino.h:62
Definition NoArduino.h:142
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 AudioConfig.h:885
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:52
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