181 if (
config.reset_on_audio_change) {
196 if (data ==
nullptr ||
p_in ==
nullptr) {
200 size_t result =
p_in->readBytes(data, len);
210 size_t write(
const uint8_t* data,
size_t len)
override {
211 if (data ==
nullptr ||
p_out ==
nullptr) {
219 return p_out->write(data, len);
224 return p_out ==
nullptr ? 0 :
p_out->availableForWrite();
246 static float dbToLinear(
float db) {
return powf(10.0f, db / 20.0f); }
249 if (value <= 0.0000001f) {
253 return 20.0f * log10f(value);
264 if (seconds <= 0.0f) {
272 float block_seconds =
static_cast<float>(samples) /
275 return 1.0f - expf(-block_seconds / seconds);
287 template <
typename T>
288 void analyze(
const T* data,
size_t samples,
float& rms,
float& peak) {
294 int32_t peak_raw = 0;
296 for (
size_t i = 0; i < samples; ++i) {
300 int32_t value =
static_cast<int32_t
>(sample) >> shift;
301 int32_t abs_value = value < 0 ? -value : value;
303 if (abs_value > peak_raw) {
304 peak_raw = abs_value;
307 sum_sq +=
static_cast<int64_t
>(value) * value;
310 float scaled_max = max_sample /
static_cast<float>(1 << shift);
312 rms = samples == 0 ? 0.0f
313 : sqrtf(
static_cast<float>(sum_sq) /
314 static_cast<float>(samples)) /
316 peak =
static_cast<float>(peak_raw) / scaled_max;
323 for (
size_t i = 0; i < samples; ++i) {
327 float value =
static_cast<float>(sample) / max_sample;
329 float abs_value = fabsf(value);
331 sum += value * value;
333 if (abs_value > peak) {
338 rms = samples == 0 ? 0.0f : sqrtf(sum /
static_cast<float>(samples));
345 bool analyze(
const uint8_t* buffer,
size_t bytes,
float& rms,
float& peak) {
352 analyze(
reinterpret_cast<const int16_t*
>(buffer),
353 bytes /
sizeof(int16_t), rms, peak);
358 bytes /
sizeof(
int24_t), rms, peak);
362 analyze(
reinterpret_cast<const int32_t*
>(buffer),
363 bytes /
sizeof(int32_t), rms, peak);
382 if (rms_db <=
config.silence_db) {
396 float desired =
config.target_db - rms_db;
401 if (desired >
config.max_gain_db) {
402 desired =
config.max_gain_db;
405 if (desired <
config.min_gain_db) {
406 desired =
config.min_gain_db;
415 float peak_after_gain = peak_db + desired;
417 if (peak_after_gain >
config.peak_headroom_db) {
418 float peak_limited_gain =
config.peak_headroom_db - peak_db;
420 if (peak_limited_gain < desired) {
421 desired = peak_limited_gain;
429 if (desired <
config.min_gain_db) {
430 desired =
config.min_gain_db;
483 template <
typename T>
484 void apply(T* data,
size_t samples,
float gain) {
488 for (
size_t i = 0; i < samples; ++i) {
489 data[i] = fixed_gain.
scale(data[i]);
496 const float dgain =
static_cast<float>(gain);
498 for (
size_t i = 0; i < samples; ++i) {
499 float value =
static_cast<float>(data[i]) * dgain;
501 if (value > max_value) {
505 if (value < min_value) {
509 data[i] =
static_cast<T
>(value);
517 void apply(uint8_t* buffer,
size_t bytes,
float gain) {
520 apply(
reinterpret_cast<int16_t*
>(buffer), bytes /
sizeof(int16_t),
530 apply(
reinterpret_cast<int32_t*
>(buffer), bytes /
sizeof(int32_t),
539 void process(
const uint8_t* input,
size_t bytes) {
540 if (input ==
nullptr || bytes == 0 ||
channels == 0) {
549 uint8_t* buffer =
const_cast<uint8_t*
>(input);
560 if (!
analyze(buffer, bytes, rms, peak)) {
567 float rms_db =
linearToDb(
static_cast<float>(rms));
569 float peak_db =
linearToDb(
static_cast<float>(peak));
576 if (sample_size == 0) {
580 size_t samples = bytes / sample_size;
601 apply(buffer, bytes, gain);