2 * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include "audiographer/general/loudness_reader.h"
20 #include "pbd/fastlog.h"
22 using namespace AudioGrapher;
24 LoudnessReader::LoudnessReader (float sample_rate, unsigned int channels, framecnt_t bufsize)
27 , _sample_rate (sample_rate)
28 , _channels (channels)
29 , _bufsize (bufsize / channels)
32 //printf ("NEW LoudnessReader %p r:%.1f c:%d f:%ld\n", this, sample_rate, channels, bufsize);
33 assert (bufsize % channels == 0);
35 assert (_bufsize > 0);
37 if (channels > 0 && channels <= 2) {
38 using namespace Vamp::HostExt;
39 PluginLoader* loader (PluginLoader::getInstance ());
40 _ebur_plugin = loader->loadPlugin ("libardourvampplugins:ebur128", sample_rate, PluginLoader::ADAPT_ALL_SAFE);
41 assert (_ebur_plugin);
42 _ebur_plugin->reset ();
43 if (!_ebur_plugin->initialise (channels, _bufsize, _bufsize)) {
49 _dbtp_plugin = (Vamp::Plugin**) malloc (sizeof(Vamp::Plugin*) * channels);
50 for (unsigned int c = 0; c < _channels; ++c) {
51 using namespace Vamp::HostExt;
52 PluginLoader* loader (PluginLoader::getInstance ());
53 _dbtp_plugin[c] = loader->loadPlugin ("libardourvampplugins:dBTP", sample_rate, PluginLoader::ADAPT_ALL_SAFE);
54 assert (_dbtp_plugin[c]);
55 _dbtp_plugin[c]->reset ();
56 if (!_dbtp_plugin[c]->initialise (1, _bufsize, _bufsize)) {
57 delete _dbtp_plugin[c];
62 _bufs[0] = (float*) malloc (sizeof (float) * _bufsize);
63 _bufs[1] = (float*) malloc (sizeof (float) * _bufsize);
66 LoudnessReader::~LoudnessReader ()
69 for (unsigned int c = 0; c < _channels; ++c) {
70 delete _dbtp_plugin[c];
78 LoudnessReader::reset ()
81 _ebur_plugin->reset ();
84 for (unsigned int c = 0; c < _channels; ++c) {
85 if (_dbtp_plugin[c]) {
86 _dbtp_plugin[c]->reset ();
92 LoudnessReader::process (ProcessContext<float> const & ctx)
94 const framecnt_t n_samples = ctx.frames () / ctx.channels ();
95 assert (ctx.channels () == _channels);
96 assert (ctx.frames () % ctx.channels () == 0);
97 assert (n_samples <= _bufsize);
98 //printf ("PROC %p @%ld F: %ld, S: %ld C:%d\n", this, _pos, ctx.frames (), n_samples, ctx.channels ());
100 unsigned processed_channels = 0;
102 assert (_channels <= 2);
103 processed_channels = _channels;
105 float const * d = ctx.data ();
106 for (s = 0; s < n_samples; ++s) {
107 for (unsigned int c = 0; c < _channels; ++c, ++d) {
111 for (; s < _bufsize; ++s) {
112 for (unsigned int c = 0; c < _channels; ++c) {
116 _ebur_plugin->process (_bufs, Vamp::RealTime::fromSeconds ((double) _pos / _sample_rate));
117 if (_dbtp_plugin[0]) {
118 _dbtp_plugin[0]->process (&_bufs[0], Vamp::RealTime::fromSeconds ((double) _pos / _sample_rate));
120 if (_channels == 2 && _dbtp_plugin[1]) {
121 _dbtp_plugin[0]->process (&_bufs[1], Vamp::RealTime::fromSeconds ((double) _pos / _sample_rate));
125 for (unsigned int c = processed_channels; c < _channels; ++c) {
126 if (!_dbtp_plugin[c]) {
130 float const * const d = ctx.data ();
131 for (s = 0; s < n_samples; ++s) {
132 _bufs[0][s] = d[s * _channels + c];
134 for (; s < _bufsize; ++s) {
137 _dbtp_plugin[c]->process (_bufs, Vamp::RealTime::fromSeconds ((double) _pos / _sample_rate));
141 ListedSource<float>::output (ctx);
145 LoudnessReader::get_normalize_gain (float target_lufs, float target_dbtp)
149 uint32_t have_lufs = 0;
150 uint32_t have_dbtp = 0;
153 Vamp::Plugin::FeatureSet features = _ebur_plugin->getRemainingFeatures ();
154 if (!features.empty () && features.size () == 3) {
155 const float lufs = features[0][0].values[0];
156 LUFS = std::max (LUFS, lufs);
161 for (unsigned int c = 0; c < _channels; ++c) {
162 if (_dbtp_plugin[c]) {
163 Vamp::Plugin::FeatureSet features = _dbtp_plugin[c]->getRemainingFeatures ();
164 if (!features.empty () && features.size () == 2) {
165 const float dbtp = features[0][0].values[0];
166 dBTP = std::max (dBTP, dbtp);
172 float g = 100000.0; // +100dB
174 if (have_lufs && LUFS > -180.0f && target_lufs <= 0.f) {
175 const float ge = pow (10.f, (target_lufs * 0.05f)) / pow (10.f, (LUFS * 0.05f));
176 //printf ("LU: %f LUFS, %f\n", LUFS, ge);
177 g = std::min (g, ge);
181 // TODO check that all channels were used.. ? (have_dbtp == _channels)
182 if (have_dbtp && dBTP > 0.f && target_dbtp <= 0.f) {
183 const float ge = pow (10.f, (target_dbtp * 0.05f)) / dBTP;
184 //printf ("TP:(%d chn) %fdBTP -> %f\n", have_dbtp, dBTP, ge);
185 g = std::min (g, ge);
192 //printf ("LF %f / %f\n", g, 1.f / g);