Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow playing tracks longer than 6 h #11511

Merged
merged 11 commits into from
Aug 11, 2023
17 changes: 10 additions & 7 deletions src/analyzer/analyzer.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "audio/signalinfo.h"
#include "util/assert.h"
#include "util/types.h"

Expand All @@ -21,7 +22,9 @@ class Analyzer {
// 1. Check if the track needs to be analyzed, otherwise return false.
// 2. Perform the initialization and return true on success.
// 3. If the initialization failed log the internal error and return false.
virtual bool initialize(TrackPointer tio, int sampleRate, int totalSamples) = 0;
virtual bool initialize(TrackPointer pTrack,
mixxx::audio::SampleRate sampleRate,
SINT frameLength) = 0;

/////////////////////////////////////////////////////////////////////////
// All following methods will only be invoked after initialize()
Expand All @@ -32,12 +35,12 @@ class Analyzer {
// If processing fails the analysis can be aborted early by returning
// false. After aborting the analysis only cleanup() will be invoked,
// but not finalize()!
virtual bool processSamples(const CSAMPLE* pIn, const int iLen) = 0;
virtual bool processSamples(const CSAMPLE* pIn, SINT count) = 0;

// Update the track object with the analysis results after
// processing finished successfully, i.e. all available audio
// samples have been processed.
virtual void storeResults(TrackPointer tio) = 0;
virtual void storeResults(TrackPointer pTrack) = 0;

// Discard any temporary results or free allocated memory.
// This function will be invoked after the results have been
Expand Down Expand Up @@ -66,9 +69,9 @@ class AnalyzerWithState final {
return m_active;
}

bool initialize(TrackPointer tio, int sampleRate, int totalSamples) {
bool initialize(TrackPointer pTrack, mixxx::audio::SampleRate sampleRate, SINT frameLength) {
DEBUG_ASSERT(!m_active);
return m_active = m_analyzer->initialize(tio, sampleRate, totalSamples);
return m_active = m_analyzer->initialize(pTrack, sampleRate, frameLength);
}

void processSamples(const CSAMPLE* pIn, const int iLen) {
Expand All @@ -82,9 +85,9 @@ class AnalyzerWithState final {
}
}

void finish(TrackPointer tio) {
void finish(TrackPointer pTrack) {
if (m_active) {
m_analyzer->storeResults(tio);
m_analyzer->storeResults(pTrack);
m_analyzer->cleanup();
m_active = false;
}
Expand Down
30 changes: 15 additions & 15 deletions src/analyzer/analyzerbeats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ AnalyzerBeats::AnalyzerBeats(UserSettingsPointer pConfig, bool enforceBpmDetecti
m_bPreferencesReanalyzeImported(false),
m_bPreferencesFixedTempo(true),
m_bPreferencesFastAnalysis(false),
m_totalSamples(0),
m_iMaxSamplesToProcess(0),
m_iCurrentSample(0) {
m_maxFramesToProcess(0),
m_currentFrame(0) {
}

bool AnalyzerBeats::initialize(TrackPointer pTrack, int sampleRate, int totalSamples) {
if (totalSamples == 0) {
bool AnalyzerBeats::initialize(TrackPointer pTrack,
mixxx::audio::SampleRate sampleRate,
SINT frameLength) {
if (frameLength <= 0) {
return false;
}

Expand Down Expand Up @@ -85,16 +86,15 @@ bool AnalyzerBeats::initialize(TrackPointer pTrack, int sampleRate, int totalSam
<< "\nFast analysis:" << m_bPreferencesFastAnalysis;

m_sampleRate = sampleRate;
m_totalSamples = totalSamples;
// In fast analysis mode, skip processing after
// kFastAnalysisSecondsToAnalyze seconds are analyzed.
if (m_bPreferencesFastAnalysis) {
m_iMaxSamplesToProcess =
mixxx::kFastAnalysisSecondsToAnalyze * m_sampleRate * mixxx::kAnalysisChannels;
m_maxFramesToProcess =
mixxx::kFastAnalysisSecondsToAnalyze * m_sampleRate;
} else {
m_iMaxSamplesToProcess = m_totalSamples;
m_maxFramesToProcess = frameLength;
}
m_iCurrentSample = 0;
m_currentFrame = 0;

// if we can load a stored track don't reanalyze it
bool bShouldAnalyze = shouldAnalyze(pTrack);
Expand All @@ -112,7 +112,7 @@ bool AnalyzerBeats::initialize(TrackPointer pTrack, int sampleRate, int totalSam
}

if (m_pPlugin) {
if (m_pPlugin->initialize(sampleRate)) {
if (m_pPlugin->initialize(m_sampleRate)) {
qDebug() << "Beat calculation started with plugin" << m_pluginId;
} else {
qDebug() << "Beat calculation will not start.";
Expand Down Expand Up @@ -191,17 +191,17 @@ bool AnalyzerBeats::shouldAnalyze(TrackPointer pTrack) const {
return true;
}

bool AnalyzerBeats::processSamples(const CSAMPLE *pIn, const int iLen) {
bool AnalyzerBeats::processSamples(const CSAMPLE* pIn, SINT count) {
VERIFY_OR_DEBUG_ASSERT(m_pPlugin) {
return false;
}

m_iCurrentSample += iLen;
if (m_iCurrentSample > m_iMaxSamplesToProcess) {
m_currentFrame += count / mixxx::kAnalysisChannels;
if (m_currentFrame > m_maxFramesToProcess) {
return true; // silently ignore all remaining samples
}

return m_pPlugin->processSamples(pIn, iLen);
return m_pPlugin->processSamples(pIn, count);
}

void AnalyzerBeats::cleanup() {
Expand Down
11 changes: 6 additions & 5 deletions src/analyzer/analyzerbeats.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ class AnalyzerBeats : public Analyzer {
static QList<mixxx::AnalyzerPluginInfo> availablePlugins();
static mixxx::AnalyzerPluginInfo defaultPlugin();

bool initialize(TrackPointer pTrack, int sampleRate, int totalSamples) override;
bool processSamples(const CSAMPLE *pIn, const int iLen) override;
bool initialize(TrackPointer pTrack,
mixxx::audio::SampleRate sampleRate,
SINT frameLength) override;
bool processSamples(const CSAMPLE* pIn, SINT count) override;
void storeResults(TrackPointer tio) override;
void cleanup() override;

Expand All @@ -46,7 +48,6 @@ class AnalyzerBeats : public Analyzer {
bool m_bPreferencesFastAnalysis;

mixxx::audio::SampleRate m_sampleRate;
SINT m_totalSamples;
int m_iMaxSamplesToProcess;
int m_iCurrentSample;
SINT m_maxFramesToProcess;
SINT m_currentFrame;
Holzhaus marked this conversation as resolved.
Show resolved Hide resolved
};
28 changes: 16 additions & 12 deletions src/analyzer/analyzerebur128.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <QtDebug>

#include "analyzer/constants.h"
#include "track/track.h"
#include "util/math.h"
#include "util/sample.h"
Expand All @@ -20,16 +21,18 @@ AnalyzerEbur128::~AnalyzerEbur128() {
cleanup(); // ...to prevent memory leaks
}

bool AnalyzerEbur128::initialize(TrackPointer tio,
int sampleRate,
int totalSamples) {
if (m_rgSettings.isAnalyzerDisabled(2, tio) || totalSamples == 0) {
bool AnalyzerEbur128::initialize(
TrackPointer pTrack,
mixxx::audio::SampleRate sampleRate,
SINT frameLength) {
if (m_rgSettings.isAnalyzerDisabled(2, pTrack) || frameLength <= 0) {
qDebug() << "Skipping AnalyzerEbur128";
return false;
}
DEBUG_ASSERT(m_pState == nullptr);
m_pState = ebur128_init(2u,
static_cast<unsigned long>(sampleRate),
m_pState = ebur128_init(
mixxx::kAnalysisChannels,
sampleRate,
EBUR128_MODE_I);
return m_pState != nullptr;
}
Expand All @@ -42,12 +45,12 @@ void AnalyzerEbur128::cleanup() {
}
}

bool AnalyzerEbur128::processSamples(const CSAMPLE *pIn, const int iLen) {
bool AnalyzerEbur128::processSamples(const CSAMPLE* pIn, SINT count) {
VERIFY_OR_DEBUG_ASSERT(m_pState) {
return false;
}
ScopedTimer t("AnalyzerEbur128::processSamples()");
size_t frames = iLen / 2;
size_t frames = count / mixxx::kAnalysisChannels;
int e = ebur128_add_frames_float(m_pState, pIn, frames);
VERIFY_OR_DEBUG_ASSERT(e == EBUR128_SUCCESS) {
qWarning() << "AnalyzerEbur128::processSamples() failed with" << e;
Expand All @@ -56,7 +59,7 @@ bool AnalyzerEbur128::processSamples(const CSAMPLE *pIn, const int iLen) {
return true;
}

void AnalyzerEbur128::storeResults(TrackPointer tio) {
void AnalyzerEbur128::storeResults(TrackPointer pTrack) {
VERIFY_OR_DEBUG_ASSERT(m_pState) {
return;
}
Expand All @@ -73,8 +76,9 @@ void AnalyzerEbur128::storeResults(TrackPointer tio) {
}

const double fReplayGain2 = kReplayGain2ReferenceLUFS - averageLufs;
mixxx::ReplayGain replayGain(tio->getReplayGain());
mixxx::ReplayGain replayGain(pTrack->getReplayGain());
replayGain.setRatio(db2ratio(fReplayGain2));
tio->setReplayGain(replayGain);
qDebug() << "ReplayGain 2.0 (libebur128) result is" << fReplayGain2 << "dB for" << tio->getFileInfo();
pTrack->setReplayGain(replayGain);
qDebug() << "ReplayGain 2.0 (libebur128) result is" << fReplayGain2
<< "dB for" << pTrack->getFileInfo();
}
8 changes: 5 additions & 3 deletions src/analyzer/analyzerebur128.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ class AnalyzerEbur128 : public Analyzer {
return rgSettings.isAnalyzerEnabled(2);
}

bool initialize(TrackPointer tio, int sampleRate, int totalSamples) override;
bool processSamples(const CSAMPLE* pIn, const int iLen) override;
void storeResults(TrackPointer tio) override;
bool initialize(TrackPointer pTrack,
mixxx::audio::SampleRate sampleRate,
SINT frameLength) override;
bool processSamples(const CSAMPLE* pIn, SINT count) override;
void storeResults(TrackPointer pTrack) override;
void cleanup() override;

private:
Expand Down
46 changes: 27 additions & 19 deletions src/analyzer/analyzergain.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#include "analyzer/analyzergain.h"

#include <replaygain.h>

#include <QtDebug>

#include "analyzer/analyzergain.h"
#include "analyzer/constants.h"
#include "track/track.h"
#include "util/math.h"
#include "util/sample.h"
Expand All @@ -11,7 +14,7 @@ AnalyzerGain::AnalyzerGain(UserSettingsPointer pConfig)
: m_rgSettings(pConfig),
m_pLeftTempBuffer(nullptr),
m_pRightTempBuffer(nullptr),
m_iBufferSize(0) {
m_bufferSize(0) {
m_pReplayGain = new ReplayGain();
}

Expand All @@ -21,36 +24,40 @@ AnalyzerGain::~AnalyzerGain() {
delete m_pReplayGain;
}

bool AnalyzerGain::initialize(TrackPointer tio, int sampleRate, int totalSamples) {
if (m_rgSettings.isAnalyzerDisabled(1, tio) || totalSamples == 0) {
bool AnalyzerGain::initialize(TrackPointer pTrack,
mixxx::audio::SampleRate sampleRate,
SINT frameLength) {
if (m_rgSettings.isAnalyzerDisabled(1, pTrack) || frameLength <= 0) {
qDebug() << "Skipping AnalyzerGain";
return false;
}

return m_pReplayGain->initialise((long)sampleRate, 2);
return m_pReplayGain->initialise(
sampleRate,
mixxx::kAnalysisChannels);
}

void AnalyzerGain::cleanup() {
}

bool AnalyzerGain::processSamples(const CSAMPLE *pIn, const int iLen) {
bool AnalyzerGain::processSamples(const CSAMPLE* pIn, SINT count) {
ScopedTimer t("AnalyzerGain::process()");

int halfLength = static_cast<int>(iLen / 2);
if (halfLength > m_iBufferSize) {
SINT numFrames = count / mixxx::kAnalysisChannels;
if (numFrames > m_bufferSize) {
delete[] m_pLeftTempBuffer;
delete[] m_pRightTempBuffer;
m_pLeftTempBuffer = new CSAMPLE[halfLength];
m_pRightTempBuffer = new CSAMPLE[halfLength];
m_iBufferSize = halfLength;
m_pLeftTempBuffer = new CSAMPLE[numFrames];
m_pRightTempBuffer = new CSAMPLE[numFrames];
m_bufferSize = numFrames;
}
SampleUtil::deinterleaveBuffer(m_pLeftTempBuffer, m_pRightTempBuffer, pIn, halfLength);
SampleUtil::applyGain(m_pLeftTempBuffer, 32767, halfLength);
SampleUtil::applyGain(m_pRightTempBuffer, 32767, halfLength);
return m_pReplayGain->process(m_pLeftTempBuffer, m_pRightTempBuffer, halfLength);
SampleUtil::deinterleaveBuffer(m_pLeftTempBuffer, m_pRightTempBuffer, pIn, numFrames);
SampleUtil::applyGain(m_pLeftTempBuffer, 32767, numFrames);
SampleUtil::applyGain(m_pRightTempBuffer, 32767, numFrames);
return m_pReplayGain->process(m_pLeftTempBuffer, m_pRightTempBuffer, numFrames);
}

void AnalyzerGain::storeResults(TrackPointer tio) {
void AnalyzerGain::storeResults(TrackPointer pTrack) {
//TODO: We are going to store values as relative peaks so that "0" means that no replaygain has been evaluated.
// This means that we are going to transform from dB to peaks and vice-versa.
// One may think to digg into replay_gain code and modify it so that
Expand All @@ -63,8 +70,9 @@ void AnalyzerGain::storeResults(TrackPointer tio) {
return;
}

mixxx::ReplayGain replayGain(tio->getReplayGain());
mixxx::ReplayGain replayGain(pTrack->getReplayGain());
replayGain.setRatio(db2ratio(fReplayGainOutput));
tio->setReplayGain(replayGain);
qDebug() << "ReplayGain 1.0 result is" << fReplayGainOutput << "dB for" << tio->getLocation();
pTrack->setReplayGain(replayGain);
qDebug() << "ReplayGain 1.0 result is" << fReplayGainOutput << "dB for"
<< pTrack->getLocation();
}
8 changes: 5 additions & 3 deletions src/analyzer/analyzergain.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ class AnalyzerGain : public Analyzer {
return rgSettings.isAnalyzerEnabled(1);
}

bool initialize(TrackPointer tio, int sampleRate, int totalSamples) override;
bool processSamples(const CSAMPLE* pIn, const int iLen) override;
bool initialize(TrackPointer pTrack,
mixxx::audio::SampleRate sampleRate,
SINT frameLength) override;
bool processSamples(const CSAMPLE* pIn, SINT count) override;
void storeResults(TrackPointer tio) override;
void cleanup() override;

Expand All @@ -31,5 +33,5 @@ class AnalyzerGain : public Analyzer {
CSAMPLE* m_pLeftTempBuffer;
CSAMPLE* m_pRightTempBuffer;
ReplayGain* m_pReplayGain;
int m_iBufferSize;
SINT m_bufferSize;
};
Loading