/*** Oak - Non-Linear Video Editor Copyright (C) 2026 Oak Team This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ***/ #include "audiolevelmeter.h" #include #include #include "common/decibel.h" namespace olive { AudioLevelMeter::Stats AudioLevelMeter::AnalyzeSampleBuffer(const core::SampleBuffer &samples) { Stats stats; const int channel_count = samples.channel_count(); const size_t sample_count = samples.sample_count(); stats.channels.resize(channel_count); if (!channel_count || !sample_count) { return stats; } double total_square = 0.0; size_t total_samples = 0; for (int channel = 0; channel < channel_count; channel++) { const float *channel_data = samples.data(channel); double peak = 0.0; double square_sum = 0.0; for (size_t sample = 0; sample < sample_count; sample++) { const double value = channel_data[sample]; const double abs_value = std::abs(value); peak = std::max(peak, abs_value); square_sum += value * value; } const double mean_square = square_sum / static_cast(sample_count); const double rms = std::sqrt(mean_square); ChannelStats channel_stats; channel_stats.peak_linear = peak; channel_stats.peak_db = LinearToDb(peak); channel_stats.rms_linear = rms; channel_stats.rms_db = LinearToDb(rms); channel_stats.vu_db = channel_stats.rms_db; stats.channels[channel] = channel_stats; stats.max_peak_linear = std::max(stats.max_peak_linear, peak); total_square += square_sum; total_samples += sample_count; } stats.silence = qFuzzyIsNull(stats.max_peak_linear); stats.integrated_lufs = PowerToLufs( total_square / static_cast(total_samples)); return stats; } double AudioLevelMeter::LinearToDb(double linear) { if (linear <= 0.0) { return Decibel::MINIMUM; } return Decibel::fromLinear(linear); } double AudioLevelMeter::PowerToLufs(double mean_square) { if (mean_square <= 0.0) { return Decibel::MINIMUM; } // BS.1770 loudness uses K-weighted mean square. This first pass stores the // compatible unit and can be extended with K-weighting without changing UI. return -0.691 + 10.0 * std::log10(mean_square); } }