diff options
Diffstat (limited to 'src/lib/level_calculator.cc')
| -rw-r--r-- | src/lib/level_calculator.cc | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/src/lib/level_calculator.cc b/src/lib/level_calculator.cc new file mode 100644 index 000000000..0563d4ed8 --- /dev/null +++ b/src/lib/level_calculator.cc @@ -0,0 +1,127 @@ +/* + Copyright (C) 2025 Carl Hetherington <cth@carlh.net> + + This file is part of DCP-o-matic. + + DCP-o-matic 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 2 of the License, or + (at your option) any later version. + + DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>. + +*/ + + +#include "audio_buffers.h" +#include "level_calculator.h" + + +using std::make_pair; +using std::shared_ptr; +using boost::optional; + + +constexpr int frames_per_measurement = 48000 / 30; + + +LevelCalculator::LevelCalculator() + : _enabled(false) +{ + +} + + +void +LevelCalculator::put(shared_ptr<const AudioBuffers> audio, dcpomatic::DCPTime time, int frame_rate) +{ + if (!_enabled) { + std::cout << "no calcs for me.\n"; + return; + } + + boost::mutex::scoped_lock lm(_current_mutex); + + auto const channels = audio->channels(); + + if (static_cast<int>(_current_peaks.size()) != channels) { + _current_peaks.resize(channels); + } + + auto const data = audio->data(); + auto const frames = audio->frames(); + for (auto frame = 0; frame < frames; ++frame) { + for (auto channel = 0; channel < channels; ++channel) { + _current_peaks[channel] = std::max(std::abs(data[channel][frame]), _current_peaks[channel]); + } + + ++_current_frames; + if (_current_frames == frames_per_measurement) { + { + boost::mutex::scoped_lock lm(_store_mutex); + _peaks.emplace_back(time + dcpomatic::DCPTime::from_frames(frame, frame_rate), _current_peaks); + } + std::fill(_current_peaks.begin(), _current_peaks.end(), 0.0f); + _current_frames = 0; + } + } + +} + + +void +LevelCalculator::clear() +{ + boost::mutex::scoped_lock slm(_store_mutex); + _peaks.clear(); + + boost::mutex::scoped_lock clm(_current_mutex); + std::fill(_current_peaks.begin(), _current_peaks.end(), 0.0f); + _current_frames = 0; +} + + +std::vector<float> +LevelCalculator::get(dcpomatic::DCPTime time) +{ + boost::mutex::scoped_lock slm(_store_mutex); + + auto iter = _peaks.begin(); + optional<dcpomatic::DCPTime> last_delta; + std::list<Measurement>::iterator last_iter; + while (iter != _peaks.end()) { + auto const delta = dcpomatic::DCPTime(time - iter->time).abs(); + if (last_delta) { + if (delta > *last_delta) { + /* This is worse than the last - use the last one */ + return last_iter->value; + } else { + /* This is better - keep looking */ + _peaks.erase(last_iter); + } + } + last_delta = delta; + last_iter = iter; + ++iter; + } + + if (iter == _peaks.end()) { + return {}; + } + + return iter->value; +} + + +void +LevelCalculator::enable(bool e) +{ + _enabled = e; +} + |
