From 9f0fe70f88ed4a9b20ced19d971c0df14cec4069 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Mon, 9 Nov 2015 00:08:02 +0100 Subject: [PATCH] Implement oversampled peak detection. --- mixer.cpp | 26 ++++++++++++++++++++++---- mixer.h | 3 ++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/mixer.cpp b/mixer.cpp index 6bf8119..bc349be 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -153,6 +153,10 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) r128.integr_start(); locut.init(FILTER_HPF, 2); + + // hlen=16 is pretty low quality, but we use quite a bit of CPU otherwise, + // and there's a limit to how important the peak meter is. + peak_resampler.setup(OUTPUT_FREQUENCY, OUTPUT_FREQUENCY * 4, /*num_channels=*/2, /*hlen=*/16); } Mixer::~Mixer() @@ -182,10 +186,10 @@ int unwrap_timecode(uint16_t current_wrapped, int last) } } -float find_peak(const vector &samples) +float find_peak(const float *samples, size_t num_samples) { float m = fabs(samples[0]); - for (size_t i = 1; i < samples.size(); ++i) { + for (size_t i = 1; i < num_samples; ++i) { m = std::max(m, fabs(samples[i])); } return m; @@ -600,8 +604,21 @@ void Mixer::process_audio_one_frame() // printf("limiter=%+5.1f compressor=%+5.1f\n", 20.0*log10(limiter_att), 20.0*log10(compressor_att)); - // Find peak and R128 levels. - peak = max(peak, find_peak(samples_out)); + // Upsample 4x to find interpolated peak. + peak_resampler.inp_data = samples_out.data(); + peak_resampler.inp_count = samples_out.size() / 2; + + vector interpolated_samples_out; + interpolated_samples_out.resize(samples_out.size()); + while (peak_resampler.inp_count > 0) { // About four iterations. + peak_resampler.out_data = &interpolated_samples_out[0]; + peak_resampler.out_count = interpolated_samples_out.size() / 2; + peak_resampler.process(); + size_t out_stereo_samples = interpolated_samples_out.size() / 2 - peak_resampler.out_count; + peak = max(peak, find_peak(interpolated_samples_out.data(), out_stereo_samples * 2)); + } + + // Find R128 levels. vector left, right; deinterleave_samples(samples_out, &left, &right); float *ptrs[] = { left.data(), right.data() }; @@ -698,6 +715,7 @@ void Mixer::channel_clicked(int preview_num) void Mixer::reset_meters() { + peak_resampler.reset(); peak = 0.0f; r128.reset(); r128.integr_start(); diff --git a/mixer.h b/mixer.h index 3a19d3a..0fd07ae 100644 --- a/mixer.h +++ b/mixer.h @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -213,7 +214,7 @@ private: audio_level_callback_t audio_level_callback = nullptr; Ebu_r128_proc r128; - // TODO: Implement oversampled peak detection. + Resampler peak_resampler; std::atomic peak{0.0f}; StereoFilter locut; // Default cutoff 150 Hz, 24 dB/oct. -- 2.39.2