Skip to content

Commit

Permalink
Merge pull request #11511 from daschuer/gh11504
Browse files Browse the repository at this point in the history
Allow playing tracks longer than 6 h
  • Loading branch information
Swiftb0y authored Aug 11, 2023
2 parents 5f86124 + 2a3436e commit 48879d7
Show file tree
Hide file tree
Showing 42 changed files with 256 additions and 197 deletions.
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;
};
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

0 comments on commit 48879d7

Please sign in to comment.