Skip to content

Commit bb5f97d

Browse files
committed
Sandbox: DynamicResamplingQueueStream
1 parent 710fe3f commit bb5f97d

File tree

4 files changed

+115
-20
lines changed

4 files changed

+115
-20
lines changed

src/AudioTools/AudioLibs/PIDController.h

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,27 @@ namespace audio_tools {
1313
*/
1414

1515
class PIDController {
16-
public:
16+
public:
1717
// dt - loop interval time
1818
// max - maximum value of manipulated variable
1919
// min - minimum value of manipulated variable
2020
// kp - proportional gain
2121
// ki - Integral gain
2222
// kd - derivative gain
23-
void begin(float dt, float max, float min, float kp, float kd,
24-
float ki) {
23+
bool begin(float dt, float max, float min, float kp, float ki, float kd) {
2524
this->dt = dt;
2625
this->max = max;
2726
this->min = min;
2827
this->kp = kp;
2928
this->kd = kd;
3029
this->ki = ki;
30+
return true;
3131
}
3232

33-
34-
// setpoint = desired process value
35-
// pv = current process value: return new process value
33+
// target = desired process value
34+
// measured = current process value:
35+
// returns new process value
3636
float calculate(float target, float measured) {
37-
3837
// Calculate errori
3938
float error = target - measured;
4039

@@ -46,8 +45,8 @@ class PIDController {
4645
float Iout = ki * integral;
4746

4847
// Derivative term
49-
assert(dt!=0.0);
50-
48+
assert(dt != 0.0);
49+
5150
float derivative = (error - preerror) / dt;
5251
float dout = kd * derivative;
5352

@@ -66,7 +65,7 @@ class PIDController {
6665
return output;
6766
}
6867

69-
protected:
68+
protected:
7069
float dt = 1.0f;
7170
float max = 0.0f;
7271
float min = 0.0f;
@@ -76,6 +75,6 @@ class PIDController {
7675
float preerror = 0.0f;
7776
float integral = 0.0f;
7877

79-
}; // namespace audiotools
78+
}; // namespace audiotools
8079

81-
} // namespace audiotools
80+
} // namespace audio_tools

src/AudioTools/CoreAudio/AudioBasic/MovingAverage.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,11 @@ namespace audio_tools {
1313
template <class N>
1414
class MovingAverage {
1515
public:
16-
MovingAverage(int size) {
17-
this->size = size;
18-
this->values = List<float>();
19-
this->values.reserve(size);
16+
MovingAverage(size_t size) {
17+
setSize(size);
2018
}
2119

22-
void add(float value) {
20+
void add(N value) {
2321
if (this->values.size() == this->size) {
2422
this->values.pop_front();
2523
}
@@ -34,9 +32,14 @@ class MovingAverage {
3432
return sum / this->values.size();
3533
}
3634

35+
/// Defines the number of values
36+
void setSize(size_t size) {
37+
this->size = size;
38+
}
39+
3740
protected:
3841
List<N> values;
39-
int size;
42+
size_t size = 0;;
4043
};
4144

4245
} // namespace audio_tools

src/AudioTools/CoreAudio/BaseStream.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,8 @@ class NullStream : public BaseStream {
307307
template <class T>
308308
class QueueStream : public BaseStream {
309309
public:
310+
/// Empty Constructor: call setBuffer() to set the buffer
311+
QueueStream() = default;
310312
/// Default constructor
311313
QueueStream(int bufferSize, int bufferCount,
312314
bool autoRemoveOldestDataIfFull = false) {
@@ -316,8 +318,7 @@ class QueueStream : public BaseStream {
316318
}
317319
/// Create stream from any BaseBuffer subclass
318320
QueueStream(BaseBuffer<T> &buffer) {
319-
owns_buffer = false;
320-
callback_buffer_ptr = &buffer;
321+
setBuffer(buffer);
321322
}
322323

323324
virtual ~QueueStream() {
@@ -326,6 +327,11 @@ class QueueStream : public BaseStream {
326327
}
327328
}
328329

330+
void setBuffer(BaseBuffer<T> &buffer){
331+
owns_buffer = false;
332+
callback_buffer_ptr = &buffer;
333+
}
334+
329335
/// Activates the output
330336
virtual bool begin() override {
331337
TRACED();
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#pragma once
2+
3+
#include "AudioTools/AudioLibs/PIDController.h"
4+
#include "AudioTools/CoreAudio/AudioBasic/MovingAverage.h"
5+
#include "AudioTools/CoreAudio/AudioStreams.h"
6+
#include "AudioTools/CoreAudio/ResampleStream.h"
7+
8+
namespace audio_tools {
9+
/**
10+
* @brief An Audio Stream backed by a buffer (queue) which tries to correct
11+
* jitter and automatically adjusts for the slightly different clock rates
12+
* between an audio source and audio target. Use separate task to write and read
13+
* the data. Also make sure that you protect the access with a mutex or provide
14+
* a thread save buffer!
15+
* @ingroup buffers
16+
* @author Phil Schatzmann
17+
*/
18+
class DynamicResamplingQueueStream : public AudioStream {
19+
public:
20+
DynamicResamplingQueueStream(BaseBuffer<uint8_t>& buffer,
21+
float stepRangePercent = 0.05) {
22+
p_buffer = &buffer;
23+
setStepRangePercent(stepRangePercent);
24+
addNotifyAudioChange(resample_stream);
25+
}
26+
27+
bool begin() {
28+
if (p_buffer == nullptr) return false;
29+
queue_stream.setBuffer(*p_buffer);
30+
queue_stream.begin();
31+
resample_stream.setAudioInfo(audioInfo());
32+
resample_stream.setStream(queue_stream);
33+
resample_stream.begin(audioInfo());
34+
float from_step = 1.0 - resample_range;
35+
float to_step = 1.0 + resample_range;
36+
return pid.begin(1.0, from_step, to_step, p, i, d);
37+
}
38+
39+
/// Fill the buffer
40+
size_t write(const uint8_t* data, size_t len) override {
41+
if (p_buffer == 0) return 0;
42+
return p_buffer->writeArray(data, len);
43+
}
44+
45+
void end() {
46+
queue_stream.end();
47+
resample_stream.end();
48+
}
49+
50+
/// Read resampled data from the buffer
51+
size_t readBytes(uint8_t* data, size_t len) override {
52+
if (p_buffer->available() == 0) return 0;
53+
54+
// calculate new resampling step size
55+
moving_average_level_percent.add(p_buffer->levelPercent());
56+
step_size = pid.calculate(50.0, moving_average_level_percent.average());
57+
58+
// return resampled result
59+
resample_stream.setStepSize(step_size);
60+
return resample_stream.readBytes(data, len);
61+
}
62+
63+
void setMovingAvgSize(int size) {
64+
moving_average_level_percent.setSize(size);
65+
}
66+
67+
/// e.g. a value of 0.0005 means that we allow to resample for 44100 by +- 22.05 from 44077.95 to 44122.05
68+
void setStepRangePercent(float rangePercent){
69+
resample_range = rangePercent / 100.0;
70+
}
71+
72+
protected:
73+
PIDController pid; // p=0.005, i=0.00005, d=0.0001
74+
QueueStream<uint8_t> queue_stream;
75+
BaseBuffer<uint8_t>* p_buffer = nullptr;
76+
MovingAverage<float> moving_average_level_percent{50};
77+
ResampleStream resample_stream;
78+
float step_size = 1.0;
79+
float resample_range = 0;
80+
int copy_size = 80;
81+
int buffer_size = 0;
82+
float p = 0.005;
83+
float i = 0.00005;
84+
float d = 0.0001;
85+
};
86+
87+
} // namespace audio_tools

0 commit comments

Comments
 (0)