arduino-audio-tools
Loading...
Searching...
No Matches
QualityAnalysisStream.h
Go to the documentation of this file.
1#pragma once
2
3#include "AudioStreams.h"
4
5namespace audio_tools {
6
11enum class QualityIssue : uint8_t {
12 Click,
13 Dropout,
15};
16
23
41
64 public:
68
71 return begin();
72 }
73
74 bool begin() override {
76 resetState();
79 }
80
86
87 void setOutput(Print& out) override { p_out = &out; }
88
89 void setStream(Stream& io) override {
90 p_out = &io;
91 p_stream = &io;
92 }
93
96 setOutput((Print&)out);
97 }
98
101 setStream((Stream&)io);
102 }
103
104 size_t write(const uint8_t* data, size_t len) override {
105 analyze(data, len);
106 if (p_out != nullptr) return p_out->write(data, len);
107 return len;
108 }
109
110 size_t readBytes(uint8_t* data, size_t len) override {
111 if (p_stream == nullptr) return 0;
112 size_t result = p_stream->readBytes(data, len);
113 analyze(data, result);
114 return result;
115 }
116
117 int available() override {
118 return p_stream != nullptr ? p_stream->available() : 0;
119 }
120
121 int availableForWrite() override {
122 return p_out != nullptr ? p_out->availableForWrite() : DEFAULT_BUFFER_SIZE;
123 }
124
126 void setClickThreshold(float ratio) { click_threshold = ratio; }
127
129 void setDropoutMinSamples(int samples) { dropout_min_samples = samples; }
130
132 void setSilenceThreshold(float ratio) { silence_threshold = ratio; }
133
135 void setClippingMinSamples(int samples) { clipping_min_samples = samples; }
136
138 void setClippingMargin(float ratio) { clipping_margin = ratio; }
139
143 void setReporting(int period_ms, Print& output) {
145 p_report = &output;
146 }
147
150
152 const QualityStats& stats() const { return stats_data; }
153
155 void clearStats() {
157 resetState();
158 }
159
160 protected:
161 Print* p_out = nullptr;
162 Stream* p_stream = nullptr;
163
166
167 Print* p_report = nullptr;
170
171 float click_threshold = 0.5f;
173 float silence_threshold = 0.01f;
175 float clipping_margin = 0.01f;
176
177 float max_value = 32767.0f;
178 // per-channel previous sample for click detection
180 bool has_prev_sample = false;
181 // dropout detection
183 bool in_dropout = false;
184 // clipping detection
186 bool in_clipping = false;
187
188 void resetState() {
189 int ch = info.channels > 0 ? info.channels : 1;
191 for (int i = 0; i < ch; i++) prev_sample[i] = 0;
192 has_prev_sample = false;
194 in_dropout = false;
196 in_clipping = false;
197 }
198
199 void reportIfDue() {
200 if (p_report == nullptr || report_period_ms <= 0) return;
201 uint32_t now = millis();
204 printReport();
205 }
206 }
207
208 void printReport() {
209 char msg[120];
210 snprintf(msg, sizeof(msg),
211 "Quality: clicks=%lu, dropouts=%lu, clipping=%lu, samples=%lu",
212 (unsigned long)stats_data.click_count,
213 (unsigned long)stats_data.dropout_count,
214 (unsigned long)stats_data.clipping_count,
215 (unsigned long)stats_data.total_samples);
216 p_report->println(msg);
217 }
218
219 void analyze(const uint8_t* data, size_t len) {
220 if (data == nullptr || len == 0) return;
221 switch (info.bits_per_sample) {
222 case 8:
223 analyzeT<int8_t>(data, len);
224 break;
225 case 16:
226 analyzeT<int16_t>(data, len);
227 break;
228 case 24:
229 analyzeT<int24_t>(data, len);
230 break;
231 case 32:
232 analyzeT<int32_t>(data, len);
233 break;
234 default:
235 LOGE("QualityAnalysisStream: unsupported bits_per_sample %d",
237 break;
238 }
239 reportIfDue();
240 }
241
242 template <typename T>
243 void analyzeT(const uint8_t* buffer, size_t size) {
244 T* samples = (T*)buffer;
245 int count = size / sizeof(T);
246 int channels = info.channels > 0 ? info.channels : 1;
249 float abs_clip = max_value * (1.0f - clipping_margin);
250
251 for (int i = 0; i < count; i++) {
252 float val = static_cast<float>(static_cast<int>(samples[i]));
253 float abs_val = val < 0 ? -val : val;
254 int ch = i % channels;
255
257
258 // Click / pop detection
259 if (has_prev_sample) {
260 float delta = val - prev_sample[ch];
261 if (delta < 0) delta = -delta;
262 if (delta > abs_click) {
265 }
266 }
267 prev_sample[ch] = val;
268
269 // Dropout detection
270 if (abs_val <= abs_silence) {
273 in_dropout = true;
275 if (callback)
277 }
278 } else {
280 in_dropout = false;
281 }
282
283 // Clipping detection
284 if (abs_val >= abs_clip) {
287 in_clipping = true;
289 if (callback)
291 }
292 } else {
294 in_clipping = false;
295 }
296 }
297
298 // Mark that we have valid previous samples after the first buffer
299 if (count >= channels) has_prev_sample = true;
300 }
301};
302
303} // namespace audio_tools
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define DEFAULT_BUFFER_SIZE
Definition avr.h:20
Definition Arduino.h:56
virtual int availableForWrite()
Definition Arduino.h:128
virtual size_t write(const uint8_t *data, size_t len)
Definition Arduino.h:120
Definition Arduino.h:136
virtual size_t readBytes(uint8_t *data, size_t len)
Definition Arduino.h:140
virtual int available()
Definition Arduino.h:139
virtual void addNotifyAudioChange(AudioInfoSupport &bi)
Adds target to be notified about audio changes.
Definition AudioTypes.h:149
virtual void setAudioInfo(AudioInfo info)=0
Defines the input AudioInfo.
Abstract Audio Ouptut class.
Definition AudioOutput.h:25
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:120
AudioInfo info
Definition BaseStream.h:171
virtual bool begin()
Definition BaseStream.h:40
Abstract class: Objects can be put into a pipleline.
Definition AudioStreams.h:68
static int64_t maxValue(int value_bits_per_sample)
provides the biggest number for the indicated number of bits
Definition AudioTypes.h:297
Analyzes audio stream quality by detecting clicks/pops, gaps/dropouts, and clipping/corruption.
Definition QualityAnalysisStream.h:63
QualityStats stats_data
Definition QualityAnalysisStream.h:164
int report_period_ms
Definition QualityAnalysisStream.h:168
int consecutive_clipped
Definition QualityAnalysisStream.h:185
uint32_t last_report_time
Definition QualityAnalysisStream.h:169
void setOutput(Print &out) override
Defines/Changes the output target.
Definition QualityAnalysisStream.h:87
void setStream(AudioStream &io)
Defines/Changes the input & output and registers for audio change notifications.
Definition QualityAnalysisStream.h:99
int clipping_min_samples
Definition QualityAnalysisStream.h:174
QualityCallback callback
Definition QualityAnalysisStream.h:165
void setCallback(QualityCallback cb)
Register a callback for quality issue notifications.
Definition QualityAnalysisStream.h:149
const QualityStats & stats() const
Access the accumulated quality statistics.
Definition QualityAnalysisStream.h:152
void analyzeT(const uint8_t *buffer, size_t size)
Definition QualityAnalysisStream.h:243
void reportIfDue()
Definition QualityAnalysisStream.h:199
int consecutive_silent
Definition QualityAnalysisStream.h:182
float clipping_margin
Definition QualityAnalysisStream.h:175
void setSilenceThreshold(float ratio)
Samples below this ratio of max value are considered silent.
Definition QualityAnalysisStream.h:132
void setOutput(AudioOutput &out)
Defines/Changes the output target and registers for audio change notifications.
Definition QualityAnalysisStream.h:94
int dropout_min_samples
Definition QualityAnalysisStream.h:172
size_t readBytes(uint8_t *data, size_t len) override
Definition QualityAnalysisStream.h:110
bool in_dropout
Definition QualityAnalysisStream.h:183
bool in_clipping
Definition QualityAnalysisStream.h:186
float silence_threshold
Definition QualityAnalysisStream.h:173
int available() override
Definition QualityAnalysisStream.h:117
Print * p_report
Definition QualityAnalysisStream.h:167
void resetState()
Definition QualityAnalysisStream.h:188
size_t write(const uint8_t *data, size_t len) override
Definition QualityAnalysisStream.h:104
Stream * p_stream
Definition QualityAnalysisStream.h:162
QualityAnalysisStream(Stream &stream)
Definition QualityAnalysisStream.h:67
Vector< float > prev_sample
Definition QualityAnalysisStream.h:179
void setClippingMargin(float ratio)
Clipping is detected when sample >= max_value * (1 - margin)
Definition QualityAnalysisStream.h:138
int availableForWrite() override
Definition QualityAnalysisStream.h:121
void analyze(const uint8_t *data, size_t len)
Definition QualityAnalysisStream.h:219
QualityAnalysisStream(Print &print)
Definition QualityAnalysisStream.h:66
void setDropoutMinSamples(int samples)
Minimum consecutive near-silent samples to count as a dropout.
Definition QualityAnalysisStream.h:129
bool has_prev_sample
Definition QualityAnalysisStream.h:180
Print * p_out
Definition QualityAnalysisStream.h:161
float max_value
Definition QualityAnalysisStream.h:177
void clearStats()
Reset all statistics and detection state.
Definition QualityAnalysisStream.h:155
void printReport()
Definition QualityAnalysisStream.h:208
bool begin() override
Definition QualityAnalysisStream.h:74
void setAudioInfo(AudioInfo info) override
Defines the input AudioInfo.
Definition QualityAnalysisStream.h:81
void setReporting(int period_ms, Print &output)
Definition QualityAnalysisStream.h:143
void setStream(Stream &io) override
Defines/Changes the input & output.
Definition QualityAnalysisStream.h:89
void setClickThreshold(float ratio)
Sample-to-sample jump threshold as ratio of max value (0.0 to 1.0)
Definition QualityAnalysisStream.h:126
float click_threshold
Definition QualityAnalysisStream.h:171
bool begin(AudioInfo info)
Definition QualityAnalysisStream.h:69
void setClippingMinSamples(int samples)
Minimum consecutive samples at max to count as clipping.
Definition QualityAnalysisStream.h:135
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
bool resize(size_t newSize, T value)
Definition Vector.h:266
QualityIssue
Quality issues detected by QualityAnalysisStream.
Definition QualityAnalysisStream.h:11
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
void(*)(QualityIssue issue, uint32_t count) QualityCallback
Callback for quality issue notifications.
Definition QualityAnalysisStream.h:22
uint32_t millis()
Returns the milliseconds since the start.
Definition Arduino.h:256
size_t writeData(Print *p_out, T *data, int samples, int maxSamples=512)
Definition AudioTypes.h:508
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:51
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
Statistics collected by QualityAnalysisStream.
Definition QualityAnalysisStream.h:28
uint32_t total_samples
Definition QualityAnalysisStream.h:32
uint32_t dropout_count
Definition QualityAnalysisStream.h:30
void clear()
Definition QualityAnalysisStream.h:34
uint32_t click_count
Definition QualityAnalysisStream.h:29
uint32_t clipping_count
Definition QualityAnalysisStream.h:31