Files
cantata/replaygain/trackscanner.cpp
Craig Drummond b6bd94c236 Update (c) year
2022-01-08 21:24:07 +00:00

218 lines
5.3 KiB
C++

/*
* Cantata
*
* Copyright (c) 2011-2022 Craig Drummond <craig.p.drummond@gmail.com>
*
* ----
*
* 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 2 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; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "trackscanner.h"
#include "config.h"
#ifdef MPG123_FOUND
#include "mpg123input.h"
#endif
#ifdef FFMPEG_FOUND
#include "ffmpeginput.h"
#endif
#define RG_REFERENCE_LEVEL -18.0
double TrackScanner::clamp(double v)
{
return v < -51.0 ? -51.0
: v > 51.0
? 51.0
: v;
}
double TrackScanner::reference(double v)
{
return clamp(RG_REFERENCE_LEVEL-v);
}
TrackScanner::Data TrackScanner::global(const QList<TrackScanner *> &scanners)
{
Data d;
if (scanners.count()<1) {
return d;
} else if(scanners.count()==1) {
return scanners.first()->results();
} else {
ebur128_state **states = new ebur128_state * [scanners.count()];
for (int i=0; i<scanners.count(); ++i) {
TrackScanner *s=scanners.at(i);
states[i]=s->state;
if (s->results().peak>d.peak) {
d.peak=s->results().peak;
}
if (s->results().truePeak>d.truePeak) {
d.truePeak=s->results().truePeak;
}
}
double l=0.0;
int rv=ebur128_loudness_global_multiple(states, scanners.count(), &l);
delete [] states;
d.loudness=0==rv ? l : 0.0;
return d;
}
}
void TrackScanner::init()
{
static bool doneInit=false;
if (doneInit) {
return;
}
doneInit=true;
#ifdef MPG123_FOUND
Mpg123Input::init();
#endif
#ifdef FFMPEG_FOUND
FfmpegInput::init();
#endif
}
TrackScanner::TrackScanner(int i)
: idx(i)
, state(0)
, input(0)
{
}
TrackScanner::~TrackScanner()
{
delete input;
if (state) {
ebur128_destroy(&state);
state=0;
}
}
void TrackScanner::setFile(const QString &fileName)
{
file=fileName;
}
void TrackScanner::run()
{
bool ffmpegIsFloat=false;
#ifdef FFMPEG_FOUND
FfmpegInput *ffmpeg=new FfmpegInput(file);
if (*ffmpeg) {
input=ffmpeg;
ffmpegIsFloat=ffmpeg->isFloatCodec();
} else {
delete ffmpeg;
ffmpeg=0;
}
#endif
#if MPG123_FOUND
if (file.endsWith(".mp3", Qt::CaseInsensitive) && (!input || !ffmpegIsFloat)) {
Mpg123Input *mpg123=new Mpg123Input(file);
if (*mpg123) {
input=mpg123;
#ifdef FFMPEG_FOUND
if (ffmpeg) {
delete ffmpeg;
}
#endif
} else {
delete mpg123;
}
}
#endif
if (!input) {
setFinishedStatus(false);
return;
}
state=ebur128_init(input->channels(), input->sampleRate(), EBUR128_MODE_M|EBUR128_MODE_I|EBUR128_MODE_SAMPLE_PEAK);
int *channelMap=new int [state->channels];
if (input->setChannelMap(channelMap)) {
for (unsigned int i = 0; i < state->channels; ++i) {
ebur128_set_channel(state, i, channelMap[i]);
}
}
delete [] channelMap;
//if (1==state->channels && opts->force_dual_mono) {
// ebur128_set_channel(state, 0, EBUR128_DUAL_MONO);
//}
size_t numFramesRead=0;
size_t totalRead=0;
input->allocateBuffer();
while ((numFramesRead = input->readFrames())) {
if (abortRequested) {
setFinishedStatus(false);
return;
}
totalRead+=numFramesRead;
emit progress((int)((totalRead*100.0/input->totalFrames())+0.5));
if (ebur128_add_frames_float(state, input->buffer(), numFramesRead)) {
setFinishedStatus(false);
return;
}
}
if (abortRequested) {
setFinishedStatus(false);
return;
}
ebur128_loudness_global(state, &data.loudness);
// if (opts->lra) {
// result = ebur128_loudness_range(ebur, &lra);
// if (result) abort();
// }
if (EBUR128_MODE_SAMPLE_PEAK==(state->mode & EBUR128_MODE_SAMPLE_PEAK)) {
for (unsigned i = 0; i < state->channels; ++i) {
double sp;
ebur128_sample_peak(state, i, &sp);
if (sp > data.peak) {
data.peak = sp;
}
}
}
if (EBUR128_MODE_TRUE_PEAK==(state->mode & EBUR128_MODE_TRUE_PEAK)) {
for (unsigned i = 0; i < state->channels; ++i) {
double tp;
ebur128_true_peak(state, i, &tp);
if (tp > data.truePeak) {
data.truePeak = tp;
}
}
}
setFinishedStatus(true);
}
void TrackScanner::setFinishedStatus(bool f)
{
delete input;
input=0;
setFinished(f);
}
#include "moc_trackscanner.cpp"