arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Macros Modules Pages
ResampleStreamT.h
1#pragma once
2#include "AudioTools/CoreAudio/AudioBasic/Collections/Vector.h"
3#include "AudioTools/CoreAudio/Buffers.h"
4
5namespace audio_tools {
6
28 bool begin() {
29 // make sure the buffer has enough space for entries
30 int size = vectorSize();
31 values.resize(size);
32 return true;
33 }
34
39 void addValue(float value) {
40 // keep buffer at the minimum size
41 if (values.available() == vectorSize()) {
42 step -= 1.0f;
44 }
45 // add the new value
47 }
54 bool getValue(float& newValue) {
55 // limit the step between 0 and 1
56 if (step >= 1.0f) return false;
57 // make sure we have enough values in the buffer
58 if (values.available() < vectorSize()) return false;
59
60 // calculate the interpolated value
61 newValue = valueExt(values.address(), step);
62
63 // determine next step
64 step += step_size;
65
66 return true;
67 }
68
69 float valueExt(float* y, float xf) {
70 return value(y, xf);
71 }
72
74 operator bool() const {
75 int step_copy = step;
76 if (step_copy >= 1.0) return false;
77 return true;
78 }
79
85 void setStepSize(float step) {
86 if (step_size == step) return;
87 step_size = step;
88 // clear the buffer to start fresh
89 values.clear();
90 }
91
92 protected:
95 float step_size = 1.0f;
96 float step = 0;
97
98 virtual int vectorSize() = 0;
99
106 virtual float value(float* y, float xf) = 0;
107};
108
116 return 2;
117 }
124 float value(float* y, float xf) {
125 if (xf == 0.0f) return y[0];
126 if (xf == 1.0f) return y[1];
127
128 int x = xf;
129 float dx = xf - x;
130 return y[x] + dx * (y[x + 1] - y[x]);
131 }
132};
133
141 return 4;
142 }
149 float value(float* y, float xf) {
150 int x = xf;
151 float dx = xf - x;
152 // Shift all indices up by 1: y[x-1] -> y[x], y[x] -> y[x+1], etc.
153 float ym1py1 = y[x] + y[x + 2];
154 float c0 = 1.0f / 6.0f * ym1py1 + 2.0f / 3.0f * y[x + 1];
155 float c1 = 1.0f / 2.0f * (y[x + 2] - y[x]);
156 float c2 = 1.0f / 2.0f * ym1py1 - y[x + 1];
157 float c3 =
158 1.0f / 2.0f * (y[x + 1] - y[x + 2]) + 1.0f / 6.0f * (y[x + 3] - y[x]);
159 return ((c3 * dx + c2) * dx + c1) * dx + c0;
160 }
161};
162
170 return 4;
171 }
178 float value(float* y, float xf) {
179 int x = xf;
180 float dx = xf - x;
181 // Shift all indices up by 1
182 float c0 = y[x + 1];
183 float c1 = y[x + 2] - 1.0f / 3.0f * y[x] - 1.0f / 2.0f * y[x + 1] -
184 1.0f / 6.0f * y[x + 3];
185 float c2 = 1.0f / 2.0f * (y[x] + y[x + 2]) - y[x + 1];
186 float c3 =
187 1.0f / 6.0f * (y[x + 3] - y[x]) + 1.0f / 2.0f * (y[x + 1] - y[x + 2]);
188 return ((c3 * dx + c2) * dx + c1) * dx + c0;
189 }
190};
191
199 return 4;
200 }
207 float value(float* y, float xf) {
208 int x = xf;
209 float dx = xf - x;
210 // Shift all indices up by 1
211 float c0 = y[x + 1];
212 float c1 = 1.0f / 2.0f * (y[x + 2] - y[x]);
213 float c2 = y[x] - 5.0f / 2.0f * y[x + 1] + 2.0f * y[x + 2] -
214 1.0f / 2.0f * y[x + 3];
215 float c3 =
216 1.0f / 2.0f * (y[x + 3] - y[x]) + 3.0f / 2.0f * (y[x + 1] - y[x + 2]);
217 return ((c3 * dx + c2) * dx + c1) * dx + c0;
218 }
219};
220
228 return 4;
229 }
236 float value(float* y, float xf) {
237 int x = xf;
238 float dx = xf - x;
239 // Shift all indices up by 1
240 float y1mym1 = y[x + 2] - y[x];
241 float c0 = 1.0f / 2.0f * y[x + 1] + 1.0f / 4.0f * (y[x] + y[x + 2]);
242 float c1 = 1.0f / 2.0f * y1mym1;
243 float c2 = 1.0f / 4.0f * (y[x + 3] - y[x + 1] - y1mym1);
244 return (c2 * dx + c1) * dx + c0;
245 }
246};
247
254template <class TInterpolator>
256 public:
257 void setChannels(int channels) {
258 if (_channels == channels) return;
259
260 _resamplers.resize(channels);
261 // create new resamplers
262 _channels = channels;
263 for (int i = 0; i < _channels; ++i) {
264 _resamplers[i].begin();
265 }
266 }
267
272 void setStepSize(float step) {
273 for (int i = 0; i < _channels; ++i) {
274 _resamplers[i].setStepSize(step);
275 }
276 }
277
282 void addValues(const float* values) {
283 for (int i = 0; i < _channels; ++i) {
284 _resamplers[i].addValue(values[i]);
285 }
286 }
287
288 void addValue(float value, int channel) {
289 if (channel < 0 || channel >= _channels) {
290 LOGE("Invalid channel index: %d", channel);
291 return;
292 }
293 _resamplers[channel].addValue(value);
294 }
295
301 bool getValues(float* out) {
302 bool ok = true;
303 for (int i = 0; i < _channels; ++i) {
304 ok &= _resamplers[i].getValue(out[i]);
305 }
306 return ok;
307 }
308
309 operator bool() const {
310 if (_channels <= 0) return false;
311 return _resamplers[0] && static_cast<bool>(_resamplers[0]);
312 }
313
317 int channels() const { return _channels; }
318
319 protected:
320 int _channels = 0;
321 Vector<TInterpolator> _resamplers;
322};
323
329template <class TInterpolator>
331 public:
335 ResampleStreamT() = default;
341 ResampleStreamT(Print& out) { setOutput(out); }
348 setAudioInfo(out.audioInfo());
349 setOutput(out);
350 }
371 this->cfg = cfg;
372 setAudioInfo(cfg);
373 return begin();
374 ;
375 }
383 bool begin(AudioInfo info, float step) {
384 cfg.copyFrom(info);
385 cfg.step_size = step;
386 return begin();
387 }
388
389 bool begin() {
390 setupReader();
391 if (cfg.step_size) {
392 setStepSize(cfg.step_size);
393 } else if (cfg.to_sample_rate > 0) {
394 // calculate step size from sample rate
395 cfg.step_size = static_cast<float>(cfg.sample_rate) /
396 static_cast<float>(cfg.to_sample_rate);
397 setStepSize(cfg.step_size);
398 } else {
399 cfg.step_size = 1.0f;
400 setStepSize(1.0f);
401 }
402 return true;
403 }
404
410 void setStepSize(float step) {
411 cfg.step_size = step;
412 _resampler.setStepSize(step);
413 }
419 float getStepSize() const { return cfg.step_size; }
420
427 AudioInfo out = audioInfo();
428 if (cfg.to_sample_rate > 0) {
429 out.sample_rate = cfg.to_sample_rate;
430 } else if (cfg.step_size != 1.0f) {
431 out.sample_rate = out.sample_rate / cfg.step_size;
432 }
433 return out;
434 }
435
439 size_t write(const uint8_t* data, size_t len) override {
440 LOGD("ResampleStreamT::write: %d", (int)len);
441 // addNotifyOnFirstWrite();
442 size_t written = 0;
443 switch (info.bits_per_sample) {
444 case 16:
445 writeT<int16_t>(p_print, data, len, written);
446 break;
447 case 24:
448 writeT<int24_t>(p_print, data, len, written);
449 break;
450 case 32:
451 writeT<int32_t>(p_print, data, len, written);
452 break;
453 default:
454 TRACEE();
455 }
456 return len;
457 }
458
464 void setAudioInfo(AudioInfo newInfo) override {
466 _resampler.setChannels(newInfo.channels);
467 cfg.copyFrom(newInfo);
468 // if target sample rate is set, calculate step size
469 if (cfg.to_sample_rate > 0) {
470 // calculate step size from sample rate
471 cfg.step_size = static_cast<float>(cfg.sample_rate) /
472 static_cast<float>(cfg.to_sample_rate);
473 setStepSize(cfg.step_size);
474 }
475 }
476
477 float getByteFactor() override { return 1.0f / cfg.step_size; }
478
479 ResampleConfig defaultConfig() {
480 ResampleConfig result;
481 return result;
482 }
483
484 protected:
485 MultiChannelResampler<TInterpolator> _resampler;
486 ResampleConfig cfg;
487
489 template <typename T>
490 size_t writeT(Print* p_out, const uint8_t* buffer, size_t bytes,
491 size_t& written) {
492 if (p_out == nullptr) return 0;
493
494 // If no resampling is needed, write directly
495 if (cfg.step_size == 1.0f) {
496 return p_out->write(buffer, bytes);
497 }
498
499 // resample the data
500 int channels = audioInfo().channels;
501 T* data = (T*)buffer;
502 float frame[channels];
503 size_t frames = bytes / (sizeof(T) * channels);
504 size_t frames_written = 0;
505 for (size_t i = 0; i < frames; ++i) {
506 // fill frame (of floats) with values from data
507 for (int ch = 0; ch < channels; ++ch) {
508 frame[ch] = static_cast<float>(data[i * channels + ch]);
509 }
510
511 // Add values to resampler
512 _resampler.addValues(frame);
513
514 // Get resampled values
515 float result[channels];
516 while (_resampler.getValues(result)) {
517 // Convert float to correct output type
518 T resultT[channels];
519 for (int ch = 0; ch < channels; ++ch) {
520 resultT[ch] = NumberConverter::clipT<T>(result[ch]);
521 }
522
523 // Write the frame
524 size_t to_write = sizeof(T) * channels;
525 size_t written = p_out->write((const uint8_t*)resultT, to_write);
526 if (written != to_write) {
527 LOGE("write error %zu -> %zu", to_write, written);
528 }
529 frames_written++;
530 }
531 }
532
533 return frames_written * sizeof(T) * channels;
534 }
535};
536
537} // namespace audio_tools
Abstract Audio Ouptut class.
Definition AudioOutput.h:22
virtual AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition AudioOutput.h:59
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:122
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition BaseStream.h:130
virtual AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition BaseStream.h:153
void clear()
same as reset
Definition Buffers.h:95
Multi-channel resampler that applies a BaseInterpolator-derived algorithm to each channel.
Definition ResampleStreamT.h:255
bool getValues(float *out)
Gets the next interpolated value for each channel.
Definition ResampleStreamT.h:301
int channels() const
Returns the number of channels.
Definition ResampleStreamT.h:317
void addValues(const float *values)
Adds a new value for each channel.
Definition ResampleStreamT.h:282
void setStepSize(float step)
Sets the step size for all channels.
Definition ResampleStreamT.h:272
Definition NoArduino.h:62
Base class for chained converting streams.
Definition AudioIO.h:156
virtual void setStream(Stream &stream) override
Defines/Changes the input & output.
Definition AudioIO.h:158
A Stream implementation for resamping using a specified interpolation algorithm.
Definition ResampleStreamT.h:330
ResampleStreamT(Print &out)
Constructor for output to a Print interface.
Definition ResampleStreamT.h:341
bool begin(AudioInfo info, float step)
Initializes the resampler with audio info and a step size.
Definition ResampleStreamT.h:383
void setAudioInfo(AudioInfo newInfo) override
Sets the audio format information and updates the channel count.
Definition ResampleStreamT.h:464
ResampleStreamT(Stream &io)
Constructor for input/output via a Stream interface.
Definition ResampleStreamT.h:355
size_t writeT(Print *p_out, const uint8_t *buffer, size_t bytes, size_t &written)
Writes the buffer to defined output after resampling.
Definition ResampleStreamT.h:490
ResampleStreamT(AudioOutput &out)
Constructor for output to an AudioOutput interface.
Definition ResampleStreamT.h:347
size_t write(const uint8_t *data, size_t len) override
Write interleaved samples to the stream.
Definition ResampleStreamT.h:439
void setStepSize(float step)
Sets the resampling step size for all channels.
Definition ResampleStreamT.h:410
ResampleStreamT()=default
Default constructor.
bool begin(ResampleConfig cfg)
Initializes the resampler with the given configuration.
Definition ResampleStreamT.h:370
AudioInfo audioInfoOut() override
Returns the output audio information, adjusting the sample rate according to the step size.
Definition ResampleStreamT.h:426
float getStepSize() const
Gets the current resampling step size.
Definition ResampleStreamT.h:419
ResampleStreamT(AudioStream &io)
Constructor for input/output via an AudioStream interface.
Definition ResampleStreamT.h:360
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:172
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:202
int available() override
provides the number of entries that are available to read
Definition Buffers.h:229
T * address() override
Provides address to beginning of the buffer.
Definition Buffers.h:268
bool resize(int size)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:292
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition Buffers.h:239
Definition NoArduino.h:142
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 AudioCodecsBase.h:10
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:53
void copyFrom(AudioInfo info)
Same as set.
Definition AudioTypes.h:103
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
Cubic B-spline interpolation using y[0]..y[3].
Definition ResampleStreamT.h:139
int vectorSize()
Minimum number of values required for interpolation.
Definition ResampleStreamT.h:140
float value(float *y, float xf)
Computes the cubic B-spline interpolation.
Definition ResampleStreamT.h:149
Base class for resampling algorithms using a buffer of float values.
Definition ResampleStreamT.h:24
SingleBuffer< float > values
Buffer holding the last 4 values for interpolation.
Definition ResampleStreamT.h:94
float step_size
Step size for resampling, default is 1.0.
Definition ResampleStreamT.h:95
bool begin()
Constructor. Initializes the buffer with four zeros.
Definition ResampleStreamT.h:28
void setStepSize(float step)
Sets the step size for interpolation.
Definition ResampleStreamT.h:85
virtual float value(float *y, float xf)=0
Interpolation function to be implemented by derived classes.
bool getValue(float &newValue)
Gets the next interpolated value.
Definition ResampleStreamT.h:54
void addValue(float value)
Adds a new value to the buffer, discarding the oldest.
Definition ResampleStreamT.h:39
Cubic Hermite interpolation using y[0]..y[3].
Definition ResampleStreamT.h:197
int vectorSize()
Minimum number of values required for interpolation.
Definition ResampleStreamT.h:198
float value(float *y, float xf)
Computes the cubic Hermite interpolation.
Definition ResampleStreamT.h:207
Cubic Lagrange interpolation using y[0]..y[3].
Definition ResampleStreamT.h:168
int vectorSize()
Minimum number of values required for interpolation.
Definition ResampleStreamT.h:169
float value(float *y, float xf)
Computes the cubic Lagrange interpolation.
Definition ResampleStreamT.h:178
Linear interpolation between y[0] and y[1].
Definition ResampleStreamT.h:114
int vectorSize()
Minimum number of values required for interpolation.
Definition ResampleStreamT.h:115
float value(float *y, float xf)
Computes the linear interpolation.
Definition ResampleStreamT.h:124
Parabolic interpolation using y[0]..y[3].
Definition ResampleStreamT.h:226
int vectorSize()
Minimum number of values required for interpolation.
Definition ResampleStreamT.h:227
float value(float *y, float xf)
Computes the parabolic interpolation.
Definition ResampleStreamT.h:236
Optional Configuration object. The critical information is the channels and the step_size....
Definition ResampleStream.h:18
int to_sample_rate
Optional fixed target sample rate.
Definition ResampleStream.h:21