1 #include "analyzer/analyzerebur128.h"
2
3 #include <QtDebug>
4
5 #include "track/track.h"
6 #include "util/math.h"
7 #include "util/sample.h"
8 #include "util/timer.h"
9
10 namespace {
11 const double kReplayGain2ReferenceLUFS = -18;
12 } // anonymous namespace
13
AnalyzerEbur128(UserSettingsPointer pConfig)14 AnalyzerEbur128::AnalyzerEbur128(UserSettingsPointer pConfig)
15 : m_rgSettings(pConfig),
16 m_pState(nullptr) {
17 }
18
~AnalyzerEbur128()19 AnalyzerEbur128::~AnalyzerEbur128() {
20 cleanup(); // ...to prevent memory leaks
21 }
22
initialize(TrackPointer tio,int sampleRate,int totalSamples)23 bool AnalyzerEbur128::initialize(TrackPointer tio,
24 int sampleRate,
25 int totalSamples) {
26 if (m_rgSettings.isAnalyzerDisabled(2, tio) || totalSamples == 0) {
27 qDebug() << "Skipping AnalyzerEbur128";
28 return false;
29 }
30 DEBUG_ASSERT(m_pState == nullptr);
31 m_pState = ebur128_init(2u,
32 static_cast<unsigned long>(sampleRate),
33 EBUR128_MODE_I);
34 return m_pState != nullptr;
35 }
36
cleanup()37 void AnalyzerEbur128::cleanup() {
38 if (m_pState) {
39 ebur128_destroy(&m_pState);
40 // ebur128_destroy clears the pointer but let's not rely on that.
41 m_pState = nullptr;
42 }
43 }
44
processSamples(const CSAMPLE * pIn,const int iLen)45 bool AnalyzerEbur128::processSamples(const CSAMPLE *pIn, const int iLen) {
46 VERIFY_OR_DEBUG_ASSERT(m_pState) {
47 return false;
48 }
49 ScopedTimer t("AnalyzerEbur128::processSamples()");
50 size_t frames = iLen / 2;
51 int e = ebur128_add_frames_float(m_pState, pIn, frames);
52 VERIFY_OR_DEBUG_ASSERT(e == EBUR128_SUCCESS) {
53 qWarning() << "AnalyzerEbur128::processSamples() failed with" << e;
54 return false;
55 }
56 return true;
57 }
58
storeResults(TrackPointer tio)59 void AnalyzerEbur128::storeResults(TrackPointer tio) {
60 VERIFY_OR_DEBUG_ASSERT(m_pState) {
61 return;
62 }
63 double averageLufs;
64 int e = ebur128_loudness_global(m_pState, &averageLufs);
65 VERIFY_OR_DEBUG_ASSERT(e == EBUR128_SUCCESS) {
66 qWarning() << "AnalyzerEbur128::storeResults() failed with" << e;
67 return;
68 }
69 if (averageLufs == -HUGE_VAL || averageLufs == 0.0) {
70 qWarning() << "AnalyzerEbur128::storeResults() averageLufs invalid:"
71 << averageLufs;
72 return;
73 }
74
75 const double fReplayGain2 = kReplayGain2ReferenceLUFS - averageLufs;
76 mixxx::ReplayGain replayGain(tio->getReplayGain());
77 replayGain.setRatio(db2ratio(fReplayGain2));
78 tio->setReplayGain(replayGain);
79 qDebug() << "ReplayGain 2.0 (libebur128) result is" << fReplayGain2 << "dB for" << tio->getFileInfo();
80 }
81