/* leqm-nrt is a non-real-time implementation of Leq(M) measurement according to ISO 21727:2004(E) "Cinematography -- Method of measurement of perceived loudness of motion-picture audio material" Copyright (C) 2011-2013, 2017-2018 Luca Trisciani 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 . */ #pragma once #include #include #include #include #include #include #include namespace leqm_nrt { class Sum { public: Sum() : _csum(0.0) , _sum(0.0) , _nsamples(0) {} void sum_samples(std::vector const& input_samples, std::vector const& c_input_samples, int nsamples) { _mutex.lock(); _nsamples += nsamples; for (auto i = 0; i < nsamples; i++) { _sum += input_samples[i]; _csum += c_input_samples[i]; } _mutex.unlock(); } int nsamples() const { return _nsamples; } /* How the final offset is calculated without reference to a test tone: P0 is the SPL reference 20 uPa Reference SPL is RMS ! So 85 SPL over 20 uPa is 10^4.25 x 0.000020 = 0.355655882 Pa (RMS), but Peak value is 0.355655882 x sqr(2) = 0.502973372 that is 20 x log ( 0.502973372 / 0.000020) = 88.010299957 To that one has to add the 20 dB offset of the reference -20dBFS: 88.010299957 + 20.00 = 108.010299957 But ISO 21727:2004(E) ask for a reference level "measured using an average responding meter". So reference level is not 0.707, but 0.637 = 2/pi */ double rms() const { return 20 * log10(mean()) + 108.010299957; } double leqm() const { return 20 * log10(cmean()) + 108.010299957; } private: double mean() const { return pow(_sum / _nsamples, 0.500); } double cmean() const { return pow(_csum / _nsamples, 0.500); } double _csum; // convolved sum double _sum; // flat sum int _nsamples; std::mutex _mutex; }; struct Result { Result(int status_) : status(status_) {} Result(double leq_m_, double leq_nw_) : status(0) , leq_m(leq_m_) , leq_nw(leq_nw_) {} /** 0 on success, or * * -100: Either channel_corrections contained a different number of * calibrations than; number of channels in the file or it was empty and the * program cannot infer one from the number of channels. Please specify a * values in channel_corrections. * * -101: Failed to open the sound file. * * -102: buffer_size_ms is not an integer number of samples at the sound file's rate. */ int status; double leq_m; double leq_nw; }; #ifdef LEQM_NRT_WITH_LIBSNDFILE Result calculate_file( std::string sound_filename, std::vector channel_corrections, int buffer_size_ms, int number_of_filter_interpolation_points, int num_cpu ); #endif double convert_log_to_linear_single(double in); class BadBufferSizeError : public std::runtime_error { public: BadBufferSizeError() : std::runtime_error("Buffer size does not correspond to an integer number of samples") {} }; class BadChannelCorrectionsError : public std::runtime_error { public: BadChannelCorrectionsError() : std::runtime_error("Incorrect number of channel corrections given, and no defaults are available") {} }; class Worker; class Calculator { public: Calculator( int channels, int sample_rate, int bits_per_sample, std::vector channel_corrections, int buffer_size_ms, int number_of_filter_interpolation_points, int num_cpu ); Calculator(Calculator&) = delete; Calculator(Calculator&&) = delete; bool operator=(Calculator&) = delete; bool operator=(Calculator&&) = delete; void add(std::vector samples); double leq_m(); double leq_nw(); private: void process_buffer(); int _channels; std::vector _channel_corrections; int _number_of_filter_interpolation_points; int _num_cpu; std::vector> _workers; Sum _sum; std::vector _ir; std::vector _buffer; size_t _buffer_free_offset; }; }