From 81f817aa8b11a453695459b3ae67605d0bd497f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 29 May 2022 01:29:41 +0200 Subject: [PATCH 01/25] Verify the first sound and issue a warning in mixxx.log --- .../cachingreader/cachingreaderworker.cpp | 34 ++++++++++++++++++- .../cachingreader/cachingreaderworker.h | 3 ++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp index 4629e10b8d3..4910acb3aa4 100644 --- a/src/engine/cachingreader/cachingreaderworker.cpp +++ b/src/engine/cachingreader/cachingreaderworker.cpp @@ -68,6 +68,32 @@ ReaderStatusUpdate CachingReaderWorker::processReadRequest( } } + if (m_firstSoundFrameToVerify.isValid()) { + SINT end = static_cast(m_firstSoundFrameToVerify.toLowerFrameBoundary().value()); + const int firstSoundIndex = + CachingReaderChunk::indexForFrame(static_cast( + m_firstSoundFrameToVerify.toLowerFrameBoundary() + .value())); + if (pChunk->getIndex() == firstSoundIndex) { + CSAMPLE sampleBuffer[4]; + pChunk->readBufferedSampleFrames(sampleBuffer, mixxx::IndexRange::forward(end - 1, 2)); + constexpr CSAMPLE kSilenceThreshold = 0.001f; + if ((fabs(sampleBuffer[0]) < fabs(kSilenceThreshold) && + fabs(sampleBuffer[1]) < kSilenceThreshold) && + !(fabs(sampleBuffer[2]) < kSilenceThreshold && + fabs(sampleBuffer[3]) < kSilenceThreshold)) { + qDebug() << "First sound found at the previously stored position"; + } else { + // This can happen in case of track edits or replacements, changed encoders or encoding issues. + qWarning() << "First sound has been moved! The beatgrid and " + "other annotations are no longer valid" + << sampleBuffer[0] << sampleBuffer[1] + << sampleBuffer[2] << sampleBuffer[3]; + } + m_firstSoundFrameToVerify = mixxx::audio::FramePos(); + } + } + ReaderStatusUpdate result; result.init(status, pChunk, m_pAudioSource ? m_pAudioSource->frameIndexRange() : mixxx::IndexRange()); return result; @@ -111,7 +137,7 @@ void CachingReaderWorker::run() { } } else if (m_pChunkReadRequestFIFO->read(&request, 1) == 1) { // Read the requested chunk and send the result - const ReaderStatusUpdate update(processReadRequest(request)); + const ReaderStatusUpdate update = processReadRequest(request); m_pReaderStatusFIFO->writeBlocking(&update, 1); } else { Event::end(m_tag); @@ -221,6 +247,12 @@ void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) { CachingReaderChunk::frames2samples( m_pAudioSource->frameLength()); + CuePointer pAudibleSound = + pTrack->findCueByType(mixxx::CueType::AudibleSound); + if (pAudibleSound) { + m_firstSoundFrameToVerify = pAudibleSound->getPosition(); + } + // The engine must not request any chunks before receiving the // trackLoaded() signal DEBUG_ASSERT(!m_pChunkReadRequestFIFO->readAvailable()); diff --git a/src/engine/cachingreader/cachingreaderworker.h b/src/engine/cachingreader/cachingreaderworker.h index 1eb4126c1f1..b7219fe9cb9 100644 --- a/src/engine/cachingreader/cachingreaderworker.h +++ b/src/engine/cachingreader/cachingreaderworker.h @@ -6,6 +6,7 @@ #include #include +#include "audio/frame.h" #include "engine/cachingreader/cachingreaderchunk.h" #include "engine/engineworker.h" #include "sources/audiosource.h" @@ -150,6 +151,8 @@ class CachingReaderWorker : public EngineWorker { // The current audio source of the track loaded mixxx::AudioSourcePointer m_pAudioSource; + mixxx::audio::FramePos m_firstSoundFrameToVerify; + // Temporary buffer for reading samples from all channels // before conversion to a stereo signal. mixxx::SampleBuffer m_tempReadBuffer; From 416746f073f39d6180bed5cddf634b2677b27125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 29 May 2022 22:46:06 +0200 Subject: [PATCH 02/25] Use kSilenceThreshold directly and add a coment that it must not be changed --- src/analyzer/analyzersilence.cpp | 9 ++++----- src/analyzer/analyzersilence.h | 1 - 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 625afd0d190..fd3fd43f124 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -6,9 +6,9 @@ namespace { -constexpr CSAMPLE kSilenceThreshold = 0.001f; -// TODO: Change the above line to: -//constexpr CSAMPLE kSilenceThreshold = db2ratio(-60.0f); +// This threshold must not be changed, because this value is also used to +// verify that the track samples have not changed since the last analysis +constexpr CSAMPLE kSilenceThreshold = 0.001f; // -60 dB bool shouldAnalyze(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(mixxx::CueType::Intro); @@ -25,7 +25,6 @@ bool shouldAnalyze(TrackPointer pTrack) { AnalyzerSilence::AnalyzerSilence(UserSettingsPointer pConfig) : m_pConfig(pConfig), - m_fThreshold(kSilenceThreshold), m_iFramesProcessed(0), m_bPrevSilence(true), m_iSignalStart(-1), @@ -59,7 +58,7 @@ bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, const int iLen) { fMax = math_max(fMax, fAbs); } - bool bSilence = fMax < m_fThreshold; + bool bSilence = fMax < kSilenceThreshold; if (m_bPrevSilence && !bSilence) { if (m_iSignalStart < 0) { diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index 8e3bf0784ad..7c1da2ce736 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -19,7 +19,6 @@ class AnalyzerSilence : public Analyzer { private: UserSettingsPointer m_pConfig; - CSAMPLE m_fThreshold; int m_iFramesProcessed; bool m_bPrevSilence; int m_iSignalStart; From b2998361c6b27e3b61935f03bdf2fd0261fa1d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 29 May 2022 23:26:35 +0200 Subject: [PATCH 03/25] Use SINT as Length parameter of Analyzer::processSamples() --- src/analyzer/analyzer.h | 4 ++-- src/analyzer/analyzerbeats.cpp | 2 +- src/analyzer/analyzerbeats.h | 6 +++--- src/analyzer/analyzerebur128.cpp | 2 +- src/analyzer/analyzerebur128.h | 2 +- src/analyzer/analyzergain.cpp | 2 +- src/analyzer/analyzergain.h | 2 +- src/analyzer/analyzerkey.cpp | 2 +- src/analyzer/analyzerkey.h | 4 ++-- src/analyzer/analyzersilence.cpp | 4 ++-- src/analyzer/analyzersilence.h | 2 +- src/analyzer/analyzerwaveform.cpp | 8 ++++---- src/analyzer/analyzerwaveform.h | 2 +- src/analyzer/constants.h | 2 +- src/analyzer/plugins/analyzerkeyfinder.cpp | 2 +- src/analyzer/plugins/analyzerkeyfinder.h | 2 +- src/analyzer/plugins/analyzerplugin.h | 2 +- src/analyzer/plugins/analyzerqueenmarybeats.cpp | 2 +- src/analyzer/plugins/analyzerqueenmarybeats.h | 2 +- src/analyzer/plugins/analyzerqueenmarykey.cpp | 2 +- src/analyzer/plugins/analyzerqueenmarykey.h | 2 +- src/analyzer/plugins/analyzersoundtouchbeats.cpp | 2 +- src/analyzer/plugins/analyzersoundtouchbeats.h | 2 +- src/test/analyzersilence_test.cpp | 4 ++-- 24 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/analyzer/analyzer.h b/src/analyzer/analyzer.h index 815514c56f8..fac1c6ee8eb 100644 --- a/src/analyzer/analyzer.h +++ b/src/analyzer/analyzer.h @@ -35,7 +35,7 @@ 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 iLen) = 0; // Update the track object with the analysis results after // processing finished successfully, i.e. all available audio @@ -74,7 +74,7 @@ class AnalyzerWithState final { return m_active = m_analyzer->initialize(tio, sampleRate, totalSamples); } - void processSamples(const CSAMPLE* pIn, const int iLen) { + void processSamples(const CSAMPLE* pIn, SINT iLen) { if (m_active) { m_active = m_analyzer->processSamples(pIn, iLen); if (!m_active) { diff --git a/src/analyzer/analyzerbeats.cpp b/src/analyzer/analyzerbeats.cpp index f3c0bd6846c..9c530c1d315 100644 --- a/src/analyzer/analyzerbeats.cpp +++ b/src/analyzer/analyzerbeats.cpp @@ -195,7 +195,7 @@ bool AnalyzerBeats::shouldAnalyze(TrackPointer pTrack) const { return true; } -bool AnalyzerBeats::processSamples(const CSAMPLE *pIn, const int iLen) { +bool AnalyzerBeats::processSamples(const CSAMPLE* pIn, SINT iLen) { VERIFY_OR_DEBUG_ASSERT(m_pPlugin) { return false; } diff --git a/src/analyzer/analyzerbeats.h b/src/analyzer/analyzerbeats.h index e1a375dd9cc..739f81a8e0b 100644 --- a/src/analyzer/analyzerbeats.h +++ b/src/analyzer/analyzerbeats.h @@ -29,7 +29,7 @@ class AnalyzerBeats : public Analyzer { bool initialize(TrackPointer pTrack, mixxx::audio::SampleRate sampleRate, int totalSamples) override; - bool processSamples(const CSAMPLE *pIn, const int iLen) override; + bool processSamples(const CSAMPLE* pIn, SINT iLen) override; void storeResults(TrackPointer tio) override; void cleanup() override; @@ -49,6 +49,6 @@ class AnalyzerBeats : public Analyzer { mixxx::audio::SampleRate m_sampleRate; SINT m_totalSamples; - int m_iMaxSamplesToProcess; - int m_iCurrentSample; + SINT m_iMaxSamplesToProcess; + SINT m_iCurrentSample; }; diff --git a/src/analyzer/analyzerebur128.cpp b/src/analyzer/analyzerebur128.cpp index a3b534da4cd..cc4df238f4e 100644 --- a/src/analyzer/analyzerebur128.cpp +++ b/src/analyzer/analyzerebur128.cpp @@ -42,7 +42,7 @@ void AnalyzerEbur128::cleanup() { } } -bool AnalyzerEbur128::processSamples(const CSAMPLE *pIn, const int iLen) { +bool AnalyzerEbur128::processSamples(const CSAMPLE* pIn, SINT iLen) { VERIFY_OR_DEBUG_ASSERT(m_pState) { return false; } diff --git a/src/analyzer/analyzerebur128.h b/src/analyzer/analyzerebur128.h index 07ffca23ff2..f08fb29c44c 100644 --- a/src/analyzer/analyzerebur128.h +++ b/src/analyzer/analyzerebur128.h @@ -17,7 +17,7 @@ class AnalyzerEbur128 : public Analyzer { bool initialize(TrackPointer tio, mixxx::audio::SampleRate sampleRate, int totalSamples) override; - bool processSamples(const CSAMPLE* pIn, const int iLen) override; + bool processSamples(const CSAMPLE* pIn, SINT iLen) override; void storeResults(TrackPointer tio) override; void cleanup() override; diff --git a/src/analyzer/analyzergain.cpp b/src/analyzer/analyzergain.cpp index 0a3c2321349..9e505714739 100644 --- a/src/analyzer/analyzergain.cpp +++ b/src/analyzer/analyzergain.cpp @@ -31,7 +31,7 @@ bool AnalyzerGain::initialize(TrackPointer tio, void AnalyzerGain::cleanup() { } -bool AnalyzerGain::processSamples(const CSAMPLE *pIn, const int iLen) { +bool AnalyzerGain::processSamples(const CSAMPLE* pIn, SINT iLen) { ScopedTimer t("AnalyzerGain::process()"); int halfLength = static_cast(iLen / 2); diff --git a/src/analyzer/analyzergain.h b/src/analyzer/analyzergain.h index 904b66556f9..a33c9ea88db 100644 --- a/src/analyzer/analyzergain.h +++ b/src/analyzer/analyzergain.h @@ -26,7 +26,7 @@ class AnalyzerGain : public Analyzer { bool initialize(TrackPointer tio, mixxx::audio::SampleRate sampleRate, int totalSamples) override; - bool processSamples(const CSAMPLE* pIn, const int iLen) override; + bool processSamples(const CSAMPLE* pIn, SINT iLen) override; void storeResults(TrackPointer tio) override; void cleanup() override; diff --git a/src/analyzer/analyzerkey.cpp b/src/analyzer/analyzerkey.cpp index b92d6729cc1..59fe6d0bf66 100644 --- a/src/analyzer/analyzerkey.cpp +++ b/src/analyzer/analyzerkey.cpp @@ -150,7 +150,7 @@ bool AnalyzerKey::shouldAnalyze(TrackPointer tio) const { return true; } -bool AnalyzerKey::processSamples(const CSAMPLE *pIn, const int iLen) { +bool AnalyzerKey::processSamples(const CSAMPLE* pIn, SINT iLen) { VERIFY_OR_DEBUG_ASSERT(m_pPlugin) { return false; } diff --git a/src/analyzer/analyzerkey.h b/src/analyzer/analyzerkey.h index a4e40c22c20..76b6ec03eed 100644 --- a/src/analyzer/analyzerkey.h +++ b/src/analyzer/analyzerkey.h @@ -22,7 +22,7 @@ class AnalyzerKey : public Analyzer { bool initialize(TrackPointer tio, mixxx::audio::SampleRate sampleRate, int totalSamples) override; - bool processSamples(const CSAMPLE *pIn, const int iLen) override; + bool processSamples(const CSAMPLE* pIn, SINT iLen) override; void storeResults(TrackPointer tio) override; void cleanup() override; @@ -38,7 +38,7 @@ class AnalyzerKey : public Analyzer { int m_iSampleRate; int m_iTotalSamples; int m_iMaxSamplesToProcess; - int m_iCurrentSample; + SINT m_iCurrentSample; bool m_bPreferencesKeyDetectionEnabled; bool m_bPreferencesFastAnalysisEnabled; diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index fd3fd43f124..0213daf2c7d 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -49,8 +49,8 @@ bool AnalyzerSilence::initialize(TrackPointer pTrack, return true; } -bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, const int iLen) { - for (int i = 0; i < iLen; i += mixxx::kAnalysisChannels) { +bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, SINT iLen) { + for (SINT i = 0; i < iLen; i += mixxx::kAnalysisChannels) { // Compute max of channels in this sample frame CSAMPLE fMax = CSAMPLE_ZERO; for (SINT ch = 0; ch < mixxx::kAnalysisChannels; ++ch) { diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index 7c1da2ce736..194e53ff4d2 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -13,7 +13,7 @@ class AnalyzerSilence : public Analyzer { bool initialize(TrackPointer pTrack, mixxx::audio::SampleRate sampleRate, int totalSamples) override; - bool processSamples(const CSAMPLE* pIn, const int iLen) override; + bool processSamples(const CSAMPLE* pIn, SINT iLen) override; void storeResults(TrackPointer pTrack) override; void cleanup() override; diff --git a/src/analyzer/analyzerwaveform.cpp b/src/analyzer/analyzerwaveform.cpp index c1bb6a66fc1..3abcd42bfa6 100644 --- a/src/analyzer/analyzerwaveform.cpp +++ b/src/analyzer/analyzerwaveform.cpp @@ -168,7 +168,7 @@ void AnalyzerWaveform::destroyFilters() { } } -bool AnalyzerWaveform::processSamples(const CSAMPLE* buffer, const int bufferLength) { +bool AnalyzerWaveform::processSamples(const CSAMPLE* buffer, SINT bufferLength) { VERIFY_OR_DEBUG_ASSERT(m_waveform) { return false; } @@ -176,8 +176,8 @@ bool AnalyzerWaveform::processSamples(const CSAMPLE* buffer, const int bufferLen return false; } - //this should only append once if bufferLength is constant - if (bufferLength > (int)m_buffers[0].size()) { + // this should only append once if bufferLength is constant + if (bufferLength > static_cast(m_buffers[0].size())) { m_buffers[Low].resize(bufferLength); m_buffers[Mid].resize(bufferLength); m_buffers[High].resize(bufferLength); @@ -190,7 +190,7 @@ bool AnalyzerWaveform::processSamples(const CSAMPLE* buffer, const int bufferLen m_waveform->setSaveState(Waveform::SaveState::NotSaved); m_waveformSummary->setSaveState(Waveform::SaveState::NotSaved); - for (int i = 0; i < bufferLength; i += 2) { + for (SINT i = 0; i < bufferLength; i += 2) { // Take max value, not average of data CSAMPLE cover[2] = {fabs(buffer[i]), fabs(buffer[i + 1])}; CSAMPLE clow[2] = {fabs(m_buffers[Low][i]), fabs(m_buffers[Low][i + 1])}; diff --git a/src/analyzer/analyzerwaveform.h b/src/analyzer/analyzerwaveform.h index 0c19875c69a..8a12ba574c7 100644 --- a/src/analyzer/analyzerwaveform.h +++ b/src/analyzer/analyzerwaveform.h @@ -143,7 +143,7 @@ class AnalyzerWaveform : public Analyzer { bool initialize(TrackPointer tio, mixxx::audio::SampleRate sampleRate, int totalSamples) override; - bool processSamples(const CSAMPLE* buffer, const int bufferLength) override; + bool processSamples(const CSAMPLE* buffer, SINT bufferLength) override; void storeResults(TrackPointer tio) override; void cleanup() override; diff --git a/src/analyzer/constants.h b/src/analyzer/constants.h index d014aae440f..a84e0b307c2 100644 --- a/src/analyzer/constants.h +++ b/src/analyzer/constants.h @@ -14,6 +14,6 @@ constexpr SINT kAnalysisSamplesPerChunk = kAnalysisFramesPerChunk * kAnalysisChannels; // Only analyze the first minute in fast-analysis mode. -constexpr int kFastAnalysisSecondsToAnalyze = 60; +constexpr SINT kFastAnalysisSecondsToAnalyze = 60; } // namespace mixxx diff --git a/src/analyzer/plugins/analyzerkeyfinder.cpp b/src/analyzer/plugins/analyzerkeyfinder.cpp index 85a7efddf1c..bec7b9aa5d4 100644 --- a/src/analyzer/plugins/analyzerkeyfinder.cpp +++ b/src/analyzer/plugins/analyzerkeyfinder.cpp @@ -86,7 +86,7 @@ bool AnalyzerKeyFinder::initialize(mixxx::audio::SampleRate sampleRate) { return true; } -bool AnalyzerKeyFinder::processSamples(const CSAMPLE* pIn, const int iLen) { +bool AnalyzerKeyFinder::processSamples(const CSAMPLE* pIn, SINT iLen) { DEBUG_ASSERT(iLen % kAnalysisChannels == 0); if (m_audioData.getSampleCount() == 0) { m_audioData.addToSampleCount(iLen); diff --git a/src/analyzer/plugins/analyzerkeyfinder.h b/src/analyzer/plugins/analyzerkeyfinder.h index 237608d98d8..4bfdaeb4b5e 100644 --- a/src/analyzer/plugins/analyzerkeyfinder.h +++ b/src/analyzer/plugins/analyzerkeyfinder.h @@ -20,7 +20,7 @@ class AnalyzerKeyFinder : public AnalyzerKeyPlugin { } bool initialize(mixxx::audio::SampleRate sampleRate) override; - bool processSamples(const CSAMPLE* pIn, const int iLen) override; + bool processSamples(const CSAMPLE* pIn, SINT iLen) override; bool finalize() override; KeyChangeList getKeyChanges() const override { diff --git a/src/analyzer/plugins/analyzerplugin.h b/src/analyzer/plugins/analyzerplugin.h index 98cbd078d4f..bbda64ce4ce 100644 --- a/src/analyzer/plugins/analyzerplugin.h +++ b/src/analyzer/plugins/analyzerplugin.h @@ -61,7 +61,7 @@ class AnalyzerPlugin { virtual AnalyzerPluginInfo info() const = 0; virtual bool initialize(mixxx::audio::SampleRate sampleRate) = 0; - virtual bool processSamples(const CSAMPLE* pIn, const int iLen) = 0; + virtual bool processSamples(const CSAMPLE* pIn, SINT iLen) = 0; virtual bool finalize() = 0; }; diff --git a/src/analyzer/plugins/analyzerqueenmarybeats.cpp b/src/analyzer/plugins/analyzerqueenmarybeats.cpp index f259d6f73e4..8166238149e 100644 --- a/src/analyzer/plugins/analyzerqueenmarybeats.cpp +++ b/src/analyzer/plugins/analyzerqueenmarybeats.cpp @@ -65,7 +65,7 @@ bool AnalyzerQueenMaryBeats::initialize(mixxx::audio::SampleRate sampleRate) { return true; } -bool AnalyzerQueenMaryBeats::processSamples(const CSAMPLE* pIn, const int iLen) { +bool AnalyzerQueenMaryBeats::processSamples(const CSAMPLE* pIn, SINT iLen) { DEBUG_ASSERT(iLen % kAnalysisChannels == 0); if (!m_pDetectionFunction) { return false; diff --git a/src/analyzer/plugins/analyzerqueenmarybeats.h b/src/analyzer/plugins/analyzerqueenmarybeats.h index bab39d63e24..39bc9a3b829 100644 --- a/src/analyzer/plugins/analyzerqueenmarybeats.h +++ b/src/analyzer/plugins/analyzerqueenmarybeats.h @@ -33,7 +33,7 @@ class AnalyzerQueenMaryBeats : public AnalyzerBeatsPlugin { } bool initialize(mixxx::audio::SampleRate sampleRate) override; - bool processSamples(const CSAMPLE* pIn, const int iLen) override; + bool processSamples(const CSAMPLE* pIn, SINT iLen) override; bool finalize() override; bool supportsBeatTracking() const override { diff --git a/src/analyzer/plugins/analyzerqueenmarykey.cpp b/src/analyzer/plugins/analyzerqueenmarykey.cpp index 8f6a9c59394..4dd11e17198 100644 --- a/src/analyzer/plugins/analyzerqueenmarykey.cpp +++ b/src/analyzer/plugins/analyzerqueenmarykey.cpp @@ -76,7 +76,7 @@ bool AnalyzerQueenMaryKey::initialize(mixxx::audio::SampleRate sampleRate) { }); } -bool AnalyzerQueenMaryKey::processSamples(const CSAMPLE* pIn, const int iLen) { +bool AnalyzerQueenMaryKey::processSamples(const CSAMPLE* pIn, SINT iLen) { DEBUG_ASSERT(iLen % kAnalysisChannels == 0); if (!m_pKeyMode) { return false; diff --git a/src/analyzer/plugins/analyzerqueenmarykey.h b/src/analyzer/plugins/analyzerqueenmarykey.h index 5883e96c3c8..d38dffa767d 100644 --- a/src/analyzer/plugins/analyzerqueenmarykey.h +++ b/src/analyzer/plugins/analyzerqueenmarykey.h @@ -33,7 +33,7 @@ class AnalyzerQueenMaryKey : public AnalyzerKeyPlugin { } bool initialize(mixxx::audio::SampleRate sampleRate) override; - bool processSamples(const CSAMPLE* pIn, const int iLen) override; + bool processSamples(const CSAMPLE* pIn, SINT iLen) override; bool finalize() override; KeyChangeList getKeyChanges() const override { diff --git a/src/analyzer/plugins/analyzersoundtouchbeats.cpp b/src/analyzer/plugins/analyzersoundtouchbeats.cpp index 4d490f68e6f..ab9569f86d7 100644 --- a/src/analyzer/plugins/analyzersoundtouchbeats.cpp +++ b/src/analyzer/plugins/analyzersoundtouchbeats.cpp @@ -20,7 +20,7 @@ bool AnalyzerSoundTouchBeats::initialize(mixxx::audio::SampleRate sampleRate) { return true; } -bool AnalyzerSoundTouchBeats::processSamples(const CSAMPLE* pIn, const int iLen) { +bool AnalyzerSoundTouchBeats::processSamples(const CSAMPLE* pIn, SINT iLen) { if (!m_pSoundTouch) { return false; } diff --git a/src/analyzer/plugins/analyzersoundtouchbeats.h b/src/analyzer/plugins/analyzersoundtouchbeats.h index 9e1fd236d3f..58ceb7b07db 100644 --- a/src/analyzer/plugins/analyzersoundtouchbeats.h +++ b/src/analyzer/plugins/analyzersoundtouchbeats.h @@ -30,7 +30,7 @@ class AnalyzerSoundTouchBeats : public AnalyzerBeatsPlugin { } bool initialize(mixxx::audio::SampleRate sampleRate) override; - bool processSamples(const CSAMPLE* pIn, const int iLen) override; + bool processSamples(const CSAMPLE* pIn, SINT iLen) override; bool finalize() override; bool supportsBeatTracking() const override { diff --git a/src/test/analyzersilence_test.cpp b/src/test/analyzersilence_test.cpp index 34fe8db23aa..1dbf3a0c444 100644 --- a/src/test/analyzersilence_test.cpp +++ b/src/test/analyzersilence_test.cpp @@ -46,12 +46,12 @@ class AnalyzerSilenceTest : public MixxxTest { AnalyzerSilence analyzerSilence; TrackPointer pTrack; std::vector pTrackSampleData; - int nTrackSampleDataLength; // in samples + SINT nTrackSampleDataLength; // in samples }; TEST_F(AnalyzerSilenceTest, SilenceTrack) { // Fill the entire buffer with silence - for (int i = 0; i < nTrackSampleDataLength; i++) { + for (SINT i = 0; i < nTrackSampleDataLength; i++) { pTrackSampleData[i] = 0.0; } From 3708324705d54c2de883ca978e0bdac828b443d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 30 May 2022 01:30:48 +0200 Subject: [PATCH 04/25] Extract static functions to find the first and the last sound --- src/analyzer/analyzersilence.cpp | 56 ++++++++++++++++++-------------- src/analyzer/analyzersilence.h | 9 ++++- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 0213daf2c7d..e652bda8f51 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -26,7 +26,6 @@ bool shouldAnalyze(TrackPointer pTrack) { AnalyzerSilence::AnalyzerSilence(UserSettingsPointer pConfig) : m_pConfig(pConfig), m_iFramesProcessed(0), - m_bPrevSilence(true), m_iSignalStart(-1), m_iSignalEnd(-1) { } @@ -42,34 +41,49 @@ bool AnalyzerSilence::initialize(TrackPointer pTrack, } m_iFramesProcessed = 0; - m_bPrevSilence = true; m_iSignalStart = -1; m_iSignalEnd = -1; return true; } -bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, SINT iLen) { - for (SINT i = 0; i < iLen; i += mixxx::kAnalysisChannels) { - // Compute max of channels in this sample frame - CSAMPLE fMax = CSAMPLE_ZERO; - for (SINT ch = 0; ch < mixxx::kAnalysisChannels; ++ch) { - CSAMPLE fAbs = fabs(pIn[i + ch]); - fMax = math_max(fMax, fAbs); +// static +SINT AnalyzerSilence::findFirstSound(const CSAMPLE* pIn, SINT iLen) { + for (SINT i = 0; i < iLen; ++i) { + if (fabs(pIn[i]) >= kSilenceThreshold) { + return i; } + } + return -1; +} - bool bSilence = fMax < kSilenceThreshold; - - if (m_bPrevSilence && !bSilence) { - if (m_iSignalStart < 0) { - m_iSignalStart = m_iFramesProcessed + i / mixxx::kAnalysisChannels; - } - } else if (!m_bPrevSilence && bSilence) { - m_iSignalEnd = m_iFramesProcessed + i / mixxx::kAnalysisChannels; +// static +SINT AnalyzerSilence::findLastSound(const CSAMPLE* pIn, SINT iLen, SINT firstSound) { + DEBUG_ASSERT(firstSound >= -1); + SINT lastSound = firstSound; + for (SINT i = firstSound + 1; i < iLen; ++i) { + if (fabs(pIn[i]) >= kSilenceThreshold) { + lastSound = i; } + } + return lastSound; +} - m_bPrevSilence = bSilence; +bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, SINT iLen) { + SINT firstSoundSample = -1; + if (m_iSignalStart < 0) { + firstSoundSample = findFirstSound(pIn, iLen); + if (firstSoundSample >= 0) { + m_iSignalStart = m_iFramesProcessed + firstSoundSample / mixxx::kAnalysisChannels; + } + } + if (m_iSignalStart >= 0) { + SINT lastSoundSample = findLastSound(pIn, iLen, firstSoundSample); + if (lastSoundSample >= 0) { + m_iSignalEnd = m_iFramesProcessed + lastSoundSample / mixxx::kAnalysisChannels + 1; + } } + m_iFramesProcessed += iLen / mixxx::kAnalysisChannels; return true; } @@ -85,12 +99,6 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { m_iSignalEnd = m_iFramesProcessed; } - // If track didn't end with silence, place signal end marker - // on the end of the track. - if (!m_bPrevSilence) { - m_iSignalEnd = m_iFramesProcessed; - } - const auto firstSoundPosition = mixxx::audio::FramePos(m_iSignalStart); const auto lastSoundPosition = mixxx::audio::FramePos(m_iSignalEnd); diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index 194e53ff4d2..bd4c7253853 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -17,10 +17,17 @@ class AnalyzerSilence : public Analyzer { void storeResults(TrackPointer pTrack) override; void cleanup() override; + /// returns the index of the first sample in the buffer that is above -60 dB + /// or -1 if no sample is found + static SINT findFirstSound(const CSAMPLE* pIn, SINT iLen); + /// returns the index of the last sample in the buffer that is above -60 dB + /// or -1 if no sample is found. signalStart can be set to a known sample above + /// -60 dB or -1 to start with the following index. + static SINT findLastSound(const CSAMPLE* pIn, SINT iLen, SINT signalStart); + private: UserSettingsPointer m_pConfig; int m_iFramesProcessed; - bool m_bPrevSilence; int m_iSignalStart; int m_iSignalEnd; }; From 2ba9fe343f464225ea78d3ad678c29fe814dc806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 30 May 2022 02:21:16 +0200 Subject: [PATCH 05/25] Move verifyFirstSound to the AnalyzerSilence class --- src/analyzer/analyzersilence.cpp | 15 +++++++ src/analyzer/analyzersilence.h | 9 ++++ .../cachingreader/cachingreaderworker.cpp | 43 ++++++++----------- .../cachingreader/cachingreaderworker.h | 2 + 4 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index e652bda8f51..81c4d291c3c 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -69,6 +69,21 @@ SINT AnalyzerSilence::findLastSound(const CSAMPLE* pIn, SINT iLen, SINT firstSou return lastSound; } +// static +bool AnalyzerSilence::verifyFirstSound( + const CSAMPLE* pIn, SINT iLen, mixxx::audio::FramePos firstSoundFrame) { + if (mixxx::audio::FramePos(findFirstSound(pIn, iLen) / + mixxx::kAnalysisChannels) == firstSoundFrame) { + qDebug() << "First sound found at the previously stored position"; + return true; + } + + // This can happen in case of track edits or replacements, changed encoders or encoding issues. + qWarning() << "First sound has been moved! The beatgrid and " + "other annotations are no longer valid"; + return false; +} + bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, SINT iLen) { SINT firstSoundSample = -1; if (m_iSignalStart < 0) { diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index bd4c7253853..69dbcda402b 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -1,6 +1,7 @@ #pragma once #include "analyzer/analyzer.h" +#include "audio/frame.h" #include "preferences/usersettings.h" class CuePointer; @@ -20,11 +21,19 @@ class AnalyzerSilence : public Analyzer { /// returns the index of the first sample in the buffer that is above -60 dB /// or -1 if no sample is found static SINT findFirstSound(const CSAMPLE* pIn, SINT iLen); + /// returns the index of the last sample in the buffer that is above -60 dB /// or -1 if no sample is found. signalStart can be set to a known sample above /// -60 dB or -1 to start with the following index. static SINT findLastSound(const CSAMPLE* pIn, SINT iLen, SINT signalStart); + /// Returns true if the first sound if found at the given frame and logs a warning message if not. + /// This can be uses to detect changes since the last analysis run and is an indicator for + /// file edits or decoder changes/issues + static bool verifyFirstSound(const CSAMPLE* pIn, + SINT iLen, + mixxx::audio::FramePos firstSoundFrame); + private: UserSettingsPointer m_pConfig; int m_iFramesProcessed; diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp index 4910acb3aa4..37ad0491a49 100644 --- a/src/engine/cachingreader/cachingreaderworker.cpp +++ b/src/engine/cachingreader/cachingreaderworker.cpp @@ -4,6 +4,7 @@ #include #include +#include "analyzer/analyzersilence.h" #include "control/controlobject.h" #include "moc_cachingreaderworker.cpp" #include "sources/soundsourceproxy.h" @@ -68,31 +69,7 @@ ReaderStatusUpdate CachingReaderWorker::processReadRequest( } } - if (m_firstSoundFrameToVerify.isValid()) { - SINT end = static_cast(m_firstSoundFrameToVerify.toLowerFrameBoundary().value()); - const int firstSoundIndex = - CachingReaderChunk::indexForFrame(static_cast( - m_firstSoundFrameToVerify.toLowerFrameBoundary() - .value())); - if (pChunk->getIndex() == firstSoundIndex) { - CSAMPLE sampleBuffer[4]; - pChunk->readBufferedSampleFrames(sampleBuffer, mixxx::IndexRange::forward(end - 1, 2)); - constexpr CSAMPLE kSilenceThreshold = 0.001f; - if ((fabs(sampleBuffer[0]) < fabs(kSilenceThreshold) && - fabs(sampleBuffer[1]) < kSilenceThreshold) && - !(fabs(sampleBuffer[2]) < kSilenceThreshold && - fabs(sampleBuffer[3]) < kSilenceThreshold)) { - qDebug() << "First sound found at the previously stored position"; - } else { - // This can happen in case of track edits or replacements, changed encoders or encoding issues. - qWarning() << "First sound has been moved! The beatgrid and " - "other annotations are no longer valid" - << sampleBuffer[0] << sampleBuffer[1] - << sampleBuffer[2] << sampleBuffer[3]; - } - m_firstSoundFrameToVerify = mixxx::audio::FramePos(); - } - } + verifyFirstSound(pChunk); ReaderStatusUpdate result; result.init(status, pChunk, m_pAudioSource ? m_pAudioSource->frameIndexRange() : mixxx::IndexRange()); @@ -268,3 +245,19 @@ void CachingReaderWorker::quitWait() { m_semaRun.release(); wait(); } + +void CachingReaderWorker::verifyFirstSound(const CachingReaderChunk* pChunk) { + if (m_firstSoundFrameToVerify.isValid()) { + SINT end = static_cast(m_firstSoundFrameToVerify.toLowerFrameBoundary().value()); + const int firstSoundIndex = + CachingReaderChunk::indexForFrame(static_cast( + m_firstSoundFrameToVerify.toLowerFrameBoundary() + .value())); + if (pChunk->getIndex() == firstSoundIndex) { + CSAMPLE sampleBuffer[4]; + pChunk->readBufferedSampleFrames(sampleBuffer, mixxx::IndexRange::forward(end - 1, 2)); + AnalyzerSilence::verifyFirstSound(sampleBuffer, 4, mixxx::audio::FramePos(1)); + m_firstSoundFrameToVerify = mixxx::audio::FramePos(); + } + } +} diff --git a/src/engine/cachingreader/cachingreaderworker.h b/src/engine/cachingreader/cachingreaderworker.h index b7219fe9cb9..982a2da45c7 100644 --- a/src/engine/cachingreader/cachingreaderworker.h +++ b/src/engine/cachingreader/cachingreaderworker.h @@ -148,6 +148,8 @@ class CachingReaderWorker : public EngineWorker { ReaderStatusUpdate processReadRequest( const CachingReaderChunkReadRequest& request); + void verifyFirstSound(const CachingReaderChunk* pChunk); + // The current audio source of the track loaded mixxx::AudioSourcePointer m_pAudioSource; From dd4342a24f6b4a327191ab168928eb90ad3bf5cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 31 May 2022 23:14:33 +0200 Subject: [PATCH 06/25] Initalize nTrackSampleDataLength --- src/test/analyzersilence_test.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/analyzersilence_test.cpp b/src/test/analyzersilence_test.cpp index 1dbf3a0c444..f14283309d2 100644 --- a/src/test/analyzersilence_test.cpp +++ b/src/test/analyzersilence_test.cpp @@ -17,7 +17,8 @@ constexpr double kTonePitchHz = 1000.0; // 1kHz class AnalyzerSilenceTest : public MixxxTest { protected: AnalyzerSilenceTest() - : analyzerSilence(config()) { + : analyzerSilence(config()), + nTrackSampleDataLength(0) { } void SetUp() override { From 9111c7b20f9568882bc90932676c3f5a231c9b5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 5 Jun 2022 12:13:43 +0200 Subject: [PATCH 07/25] Move writing the mixxx.log entries out of AnalyzerSilence::verifyFirstSound() --- src/analyzer/analyzersilence.cpp | 12 ++---------- src/engine/cachingreader/cachingreaderworker.cpp | 8 +++++++- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 81c4d291c3c..0a255887782 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -72,16 +72,8 @@ SINT AnalyzerSilence::findLastSound(const CSAMPLE* pIn, SINT iLen, SINT firstSou // static bool AnalyzerSilence::verifyFirstSound( const CSAMPLE* pIn, SINT iLen, mixxx::audio::FramePos firstSoundFrame) { - if (mixxx::audio::FramePos(findFirstSound(pIn, iLen) / - mixxx::kAnalysisChannels) == firstSoundFrame) { - qDebug() << "First sound found at the previously stored position"; - return true; - } - - // This can happen in case of track edits or replacements, changed encoders or encoding issues. - qWarning() << "First sound has been moved! The beatgrid and " - "other annotations are no longer valid"; - return false; + return (mixxx::audio::FramePos(findFirstSound(pIn, iLen) / + mixxx::kAnalysisChannels) == firstSoundFrame); } bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, SINT iLen) { diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp index 37ad0491a49..d5504a8a7aa 100644 --- a/src/engine/cachingreader/cachingreaderworker.cpp +++ b/src/engine/cachingreader/cachingreaderworker.cpp @@ -256,7 +256,13 @@ void CachingReaderWorker::verifyFirstSound(const CachingReaderChunk* pChunk) { if (pChunk->getIndex() == firstSoundIndex) { CSAMPLE sampleBuffer[4]; pChunk->readBufferedSampleFrames(sampleBuffer, mixxx::IndexRange::forward(end - 1, 2)); - AnalyzerSilence::verifyFirstSound(sampleBuffer, 4, mixxx::audio::FramePos(1)); + if (AnalyzerSilence::verifyFirstSound(sampleBuffer, 4, mixxx::audio::FramePos(1))) { + qDebug() << "First sound found at the previously stored position"; + } else { + // This can happen in case of track edits or replacements, changed encoders or encoding issues. + qWarning() << "First sound has been moved! The beatgrid and " + "other annotations are no longer valid"; + } m_firstSoundFrameToVerify = mixxx::audio::FramePos(); } } From 837e8796c2d422078473b4e6c1c0ee1cf418336f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 5 Jun 2022 12:24:03 +0200 Subject: [PATCH 08/25] Rename function to findFirstSoundInChunk()/findLasttSoundInChunk() --- src/analyzer/analyzersilence.cpp | 10 +++++----- src/analyzer/analyzersilence.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 0a255887782..8f3e1ad7b89 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -48,7 +48,7 @@ bool AnalyzerSilence::initialize(TrackPointer pTrack, } // static -SINT AnalyzerSilence::findFirstSound(const CSAMPLE* pIn, SINT iLen) { +SINT AnalyzerSilence::findFirstSoundInChunk(const CSAMPLE* pIn, SINT iLen) { for (SINT i = 0; i < iLen; ++i) { if (fabs(pIn[i]) >= kSilenceThreshold) { return i; @@ -58,7 +58,7 @@ SINT AnalyzerSilence::findFirstSound(const CSAMPLE* pIn, SINT iLen) { } // static -SINT AnalyzerSilence::findLastSound(const CSAMPLE* pIn, SINT iLen, SINT firstSound) { +SINT AnalyzerSilence::findLastSoundInChunk(const CSAMPLE* pIn, SINT iLen, SINT firstSound) { DEBUG_ASSERT(firstSound >= -1); SINT lastSound = firstSound; for (SINT i = firstSound + 1; i < iLen; ++i) { @@ -72,20 +72,20 @@ SINT AnalyzerSilence::findLastSound(const CSAMPLE* pIn, SINT iLen, SINT firstSou // static bool AnalyzerSilence::verifyFirstSound( const CSAMPLE* pIn, SINT iLen, mixxx::audio::FramePos firstSoundFrame) { - return (mixxx::audio::FramePos(findFirstSound(pIn, iLen) / + return (mixxx::audio::FramePos(findFirstSoundInChunk(pIn, iLen) / mixxx::kAnalysisChannels) == firstSoundFrame); } bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, SINT iLen) { SINT firstSoundSample = -1; if (m_iSignalStart < 0) { - firstSoundSample = findFirstSound(pIn, iLen); + firstSoundSample = findFirstSoundInChunk(pIn, iLen); if (firstSoundSample >= 0) { m_iSignalStart = m_iFramesProcessed + firstSoundSample / mixxx::kAnalysisChannels; } } if (m_iSignalStart >= 0) { - SINT lastSoundSample = findLastSound(pIn, iLen, firstSoundSample); + SINT lastSoundSample = findLastSoundInChunk(pIn, iLen, firstSoundSample); if (lastSoundSample >= 0) { m_iSignalEnd = m_iFramesProcessed + lastSoundSample / mixxx::kAnalysisChannels + 1; } diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index 69dbcda402b..4848bdf26ab 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -20,12 +20,12 @@ class AnalyzerSilence : public Analyzer { /// returns the index of the first sample in the buffer that is above -60 dB /// or -1 if no sample is found - static SINT findFirstSound(const CSAMPLE* pIn, SINT iLen); + static SINT findFirstSoundInChunk(const CSAMPLE* pIn, SINT iLen); /// returns the index of the last sample in the buffer that is above -60 dB /// or -1 if no sample is found. signalStart can be set to a known sample above /// -60 dB or -1 to start with the following index. - static SINT findLastSound(const CSAMPLE* pIn, SINT iLen, SINT signalStart); + static SINT findLastSoundInChunk(const CSAMPLE* pIn, SINT iLen, SINT signalStart); /// Returns true if the first sound if found at the given frame and logs a warning message if not. /// This can be uses to detect changes since the last analysis run and is an indicator for From d410c06df4599efd1041276368cb025964243660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 5 Jun 2022 12:56:25 +0200 Subject: [PATCH 09/25] Refactor silence detections that the last sound is processed backwards --- src/analyzer/analyzersilence.cpp | 25 +++++++++++++------------ src/analyzer/analyzersilence.h | 4 ++-- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 8f3e1ad7b89..34bd24c7f60 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -49,24 +49,24 @@ bool AnalyzerSilence::initialize(TrackPointer pTrack, // static SINT AnalyzerSilence::findFirstSoundInChunk(const CSAMPLE* pIn, SINT iLen) { - for (SINT i = 0; i < iLen; ++i) { + SINT i = 0; + for (; i < iLen; ++i) { if (fabs(pIn[i]) >= kSilenceThreshold) { - return i; + break; } } - return -1; + return i; } // static -SINT AnalyzerSilence::findLastSoundInChunk(const CSAMPLE* pIn, SINT iLen, SINT firstSound) { - DEBUG_ASSERT(firstSound >= -1); - SINT lastSound = firstSound; - for (SINT i = firstSound + 1; i < iLen; ++i) { +SINT AnalyzerSilence::findLastSoundInChunk(const CSAMPLE* pIn, SINT iLen) { + SINT i = iLen - 1; + for (; i >= 0; --i) { if (fabs(pIn[i]) >= kSilenceThreshold) { - lastSound = i; + break; } } - return lastSound; + return i; } // static @@ -80,13 +80,14 @@ bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, SINT iLen) { SINT firstSoundSample = -1; if (m_iSignalStart < 0) { firstSoundSample = findFirstSoundInChunk(pIn, iLen); - if (firstSoundSample >= 0) { + if (firstSoundSample < iLen) { m_iSignalStart = m_iFramesProcessed + firstSoundSample / mixxx::kAnalysisChannels; } } if (m_iSignalStart >= 0) { - SINT lastSoundSample = findLastSoundInChunk(pIn, iLen, firstSoundSample); - if (lastSoundSample >= 0) { + SINT lastSoundSample = findLastSoundInChunk(pIn, iLen); + if (lastSoundSample > -1 && // only silence + lastSoundSample < iLen - 1) { // only sound m_iSignalEnd = m_iFramesProcessed + lastSoundSample / mixxx::kAnalysisChannels + 1; } } diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index 4848bdf26ab..ff913423fe8 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -19,13 +19,13 @@ class AnalyzerSilence : public Analyzer { void cleanup() override; /// returns the index of the first sample in the buffer that is above -60 dB - /// or -1 if no sample is found + /// or iLen if no sample is found static SINT findFirstSoundInChunk(const CSAMPLE* pIn, SINT iLen); /// returns the index of the last sample in the buffer that is above -60 dB /// or -1 if no sample is found. signalStart can be set to a known sample above /// -60 dB or -1 to start with the following index. - static SINT findLastSoundInChunk(const CSAMPLE* pIn, SINT iLen, SINT signalStart); + static SINT findLastSoundInChunk(const CSAMPLE* pIn, SINT iLen); /// Returns true if the first sound if found at the given frame and logs a warning message if not. /// This can be uses to detect changes since the last analysis run and is an indicator for From d342d6ce09f9af702e55e1dd9176a23cde86ed7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 5 Jun 2022 17:19:46 +0200 Subject: [PATCH 10/25] Check return value of findFirstSoundInChunk() explicit --- src/analyzer/analyzersilence.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 34bd24c7f60..3b0710bdb68 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -72,20 +72,23 @@ SINT AnalyzerSilence::findLastSoundInChunk(const CSAMPLE* pIn, SINT iLen) { // static bool AnalyzerSilence::verifyFirstSound( const CSAMPLE* pIn, SINT iLen, mixxx::audio::FramePos firstSoundFrame) { - return (mixxx::audio::FramePos(findFirstSoundInChunk(pIn, iLen) / - mixxx::kAnalysisChannels) == firstSoundFrame); + const SINT firstSoundSample = findFirstSoundInChunk(pIn, iLen); + if (firstSoundSample < iLen) { + return (mixxx::audio::FramePos(findFirstSoundInChunk(pIn, iLen) / + mixxx::kAnalysisChannels) == firstSoundFrame); + } + return false; } bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, SINT iLen) { - SINT firstSoundSample = -1; if (m_iSignalStart < 0) { - firstSoundSample = findFirstSoundInChunk(pIn, iLen); + const SINT firstSoundSample = findFirstSoundInChunk(pIn, iLen); if (firstSoundSample < iLen) { m_iSignalStart = m_iFramesProcessed + firstSoundSample / mixxx::kAnalysisChannels; } } if (m_iSignalStart >= 0) { - SINT lastSoundSample = findLastSoundInChunk(pIn, iLen); + const SINT lastSoundSample = findLastSoundInChunk(pIn, iLen); if (lastSoundSample > -1 && // only silence lastSoundSample < iLen - 1) { // only sound m_iSignalEnd = m_iFramesProcessed + lastSoundSample / mixxx::kAnalysisChannels + 1; From b94f7887e139d5c026d66340670c2e10e2f315d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 5 Jun 2022 22:16:54 +0200 Subject: [PATCH 11/25] Fix comment for findLastSoundInChunk() --- src/analyzer/analyzersilence.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index ff913423fe8..5ba65b5fede 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -23,8 +23,7 @@ class AnalyzerSilence : public Analyzer { static SINT findFirstSoundInChunk(const CSAMPLE* pIn, SINT iLen); /// returns the index of the last sample in the buffer that is above -60 dB - /// or -1 if no sample is found. signalStart can be set to a known sample above - /// -60 dB or -1 to start with the following index. + /// or -1 if no sample is found. static SINT findLastSoundInChunk(const CSAMPLE* pIn, SINT iLen); /// Returns true if the first sound if found at the given frame and logs a warning message if not. From 2a9fbca5b939e1e77fc42b85a91fdcc4da77135a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 5 Sep 2022 13:57:41 +0200 Subject: [PATCH 12/25] Explain why the uncoditinal verifyFirstSound() should be replaced --- src/engine/cachingreader/cachingreaderworker.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp index d5504a8a7aa..e6a352fe5ab 100644 --- a/src/engine/cachingreader/cachingreaderworker.cpp +++ b/src/engine/cachingreader/cachingreaderworker.cpp @@ -69,6 +69,16 @@ ReaderStatusUpdate CachingReaderWorker::processReadRequest( } } + // This call here assumes that the caching reader will read the first sound cue at + // one of the first chunks. The check serves as a sanity check to ensure that the + // sample data has not changed since it has ben analyzed. This could happen because + // of a change in actual audio data or because the file was decoded using a different + // decoder + // This is part of a first prove of concept and needs to be replaces with a different + // solution which is still under discussion. This might be also extended + // to further checks whether a automatic offset adjustment is possible or a the + // sample position metadata shall be treated as outdated. + // Failures of the sanity check only result in an entry into the log at the moment. verifyFirstSound(pChunk); ReaderStatusUpdate result; From 407dc21b972635281f79ce1a398c61ca0b70b718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 6 Sep 2022 00:57:45 +0200 Subject: [PATCH 13/25] Restore TODO --- src/analyzer/analyzersilence.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 3b0710bdb68..1e602c34760 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -9,6 +9,8 @@ namespace { // This threshold must not be changed, because this value is also used to // verify that the track samples have not changed since the last analysis constexpr CSAMPLE kSilenceThreshold = 0.001f; // -60 dB +// TODO: Change the above line to: +//constexpr CSAMPLE kSilenceThreshold = db2ratio(-60.0f); bool shouldAnalyze(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(mixxx::CueType::Intro); From 828b6dbcb68ed15d385d3697f450048d0eaa805e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 6 Sep 2022 01:57:47 +0200 Subject: [PATCH 14/25] reduce nesting --- .../cachingreader/cachingreaderworker.cpp | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp index e6a352fe5ab..ffaa42ae0d4 100644 --- a/src/engine/cachingreader/cachingreaderworker.cpp +++ b/src/engine/cachingreader/cachingreaderworker.cpp @@ -257,23 +257,25 @@ void CachingReaderWorker::quitWait() { } void CachingReaderWorker::verifyFirstSound(const CachingReaderChunk* pChunk) { - if (m_firstSoundFrameToVerify.isValid()) { + if (!m_firstSoundFrameToVerify.isValid()) { + return; + } + + const int firstSoundIndex = + CachingReaderChunk::indexForFrame(static_cast( + m_firstSoundFrameToVerify.toLowerFrameBoundary() + .value())); + if (pChunk->getIndex() == firstSoundIndex) { + CSAMPLE sampleBuffer[4]; SINT end = static_cast(m_firstSoundFrameToVerify.toLowerFrameBoundary().value()); - const int firstSoundIndex = - CachingReaderChunk::indexForFrame(static_cast( - m_firstSoundFrameToVerify.toLowerFrameBoundary() - .value())); - if (pChunk->getIndex() == firstSoundIndex) { - CSAMPLE sampleBuffer[4]; - pChunk->readBufferedSampleFrames(sampleBuffer, mixxx::IndexRange::forward(end - 1, 2)); - if (AnalyzerSilence::verifyFirstSound(sampleBuffer, 4, mixxx::audio::FramePos(1))) { - qDebug() << "First sound found at the previously stored position"; - } else { - // This can happen in case of track edits or replacements, changed encoders or encoding issues. - qWarning() << "First sound has been moved! The beatgrid and " - "other annotations are no longer valid"; - } - m_firstSoundFrameToVerify = mixxx::audio::FramePos(); + pChunk->readBufferedSampleFrames(sampleBuffer, mixxx::IndexRange::forward(end - 1, 2)); + if (AnalyzerSilence::verifyFirstSound(sampleBuffer, 4, mixxx::audio::FramePos(1))) { + qDebug() << "First sound found at the previously stored position"; + } else { + // This can happen in case of track edits or replacements, changed encoders or encoding issues. + qWarning() << "First sound has been moved! The beatgrid and " + "other annotations are no longer valid"; } + m_firstSoundFrameToVerify = mixxx::audio::FramePos(); } } From 43faef4e60c013e6493df85f46fd5d0fcc95766f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 6 Sep 2022 07:57:04 +0200 Subject: [PATCH 15/25] Use kNumSoundFrameToVerify and explain why two frames are sufficient --- src/engine/cachingreader/cachingreaderworker.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp index ffaa42ae0d4..30fbfc6f8f2 100644 --- a/src/engine/cachingreader/cachingreaderworker.cpp +++ b/src/engine/cachingreader/cachingreaderworker.cpp @@ -17,6 +17,9 @@ namespace { mixxx::Logger kLogger("CachingReaderWorker"); +// we need the last silence frame and the first sound frame +constexpr SINT kNumSoundFrameToVerify = 2; + } // anonymous namespace CachingReaderWorker::CachingReaderWorker( @@ -266,10 +269,13 @@ void CachingReaderWorker::verifyFirstSound(const CachingReaderChunk* pChunk) { m_firstSoundFrameToVerify.toLowerFrameBoundary() .value())); if (pChunk->getIndex() == firstSoundIndex) { - CSAMPLE sampleBuffer[4]; + CSAMPLE sampleBuffer[kNumSoundFrameToVerify * mixxx::kEngineChannelCount]; SINT end = static_cast(m_firstSoundFrameToVerify.toLowerFrameBoundary().value()); - pChunk->readBufferedSampleFrames(sampleBuffer, mixxx::IndexRange::forward(end - 1, 2)); - if (AnalyzerSilence::verifyFirstSound(sampleBuffer, 4, mixxx::audio::FramePos(1))) { + pChunk->readBufferedSampleFrames(sampleBuffer, + mixxx::IndexRange::forward(end - 1, kNumSoundFrameToVerify)); + if (AnalyzerSilence::verifyFirstSound(sampleBuffer, + std::size(sampleBuffer), + mixxx::audio::FramePos(1))) { qDebug() << "First sound found at the previously stored position"; } else { // This can happen in case of track edits or replacements, changed encoders or encoding issues. From d993c034a553e16063abf6f530fc1acad00e141e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 6 Sep 2022 08:30:56 +0200 Subject: [PATCH 16/25] Apply std::span refactoring Co-authored-by: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> --- src/analyzer/analyzersilence.cpp | 46 +++++++++---------- src/analyzer/analyzersilence.h | 8 ++-- .../cachingreader/cachingreaderworker.cpp | 4 +- src/util/math.h | 13 +++--- 4 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 1e602c34760..c78d1846ed0 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -23,6 +23,13 @@ bool shouldAnalyze(TrackPointer pTrack) { return false; } +template +Iterator first_sound(Iterator begin, Iterator end) { + return std::find_if(begin, end, [](const auto elem) { + return fabs(elem) >= kSilenceThreshold; + }); +} + } // anonymous namespace AnalyzerSilence::AnalyzerSilence(UserSettingsPointer pConfig) @@ -50,47 +57,38 @@ bool AnalyzerSilence::initialize(TrackPointer pTrack, } // static -SINT AnalyzerSilence::findFirstSoundInChunk(const CSAMPLE* pIn, SINT iLen) { - SINT i = 0; - for (; i < iLen; ++i) { - if (fabs(pIn[i]) >= kSilenceThreshold) { - break; - } - } - return i; +SINT AnalyzerSilence::findFirstSoundInChunk(std::span samples) { + return std::distance(samples.begin(), first_sound(samples.begin(), samples.end())); } // static -SINT AnalyzerSilence::findLastSoundInChunk(const CSAMPLE* pIn, SINT iLen) { - SINT i = iLen - 1; - for (; i >= 0; --i) { - if (fabs(pIn[i]) >= kSilenceThreshold) { - break; - } - } - return i; +/// returns a std::reverse_iterator +SINT AnalyzerSilence::findLastSoundInChunk(std::span samples) { + // -1 is required, because the distance from the fist sample index (0) to crend() is 1, + return std::distance(first_sound(samples.rbegin(), samples.rend()), samples.rend()) - 1; } // static bool AnalyzerSilence::verifyFirstSound( - const CSAMPLE* pIn, SINT iLen, mixxx::audio::FramePos firstSoundFrame) { - const SINT firstSoundSample = findFirstSoundInChunk(pIn, iLen); - if (firstSoundSample < iLen) { - return (mixxx::audio::FramePos(findFirstSoundInChunk(pIn, iLen) / - mixxx::kAnalysisChannels) == firstSoundFrame); + std::span samples, + mixxx::audio::FramePos firstSoundFrame) { + const SINT firstSoundSample = findFirstSoundInChunk(samples); + if (firstSoundSample < static_cast(samples.size())) { + return mixxx::audio::FramePos::fromEngineSamplePos(firstSoundSample) == firstSoundFrame; } return false; } bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, SINT iLen) { + std::span samples = mixxx::spanutil::spanFromPtrLen(pIn, iLen); if (m_iSignalStart < 0) { - const SINT firstSoundSample = findFirstSoundInChunk(pIn, iLen); - if (firstSoundSample < iLen) { + const SINT firstSoundSample = findFirstSoundInChunk(samples); + if (firstSoundSample < static_cast(samples.size())) { m_iSignalStart = m_iFramesProcessed + firstSoundSample / mixxx::kAnalysisChannels; } } if (m_iSignalStart >= 0) { - const SINT lastSoundSample = findLastSoundInChunk(pIn, iLen); + const SINT lastSoundSample = findLastSoundInChunk(samples); if (lastSoundSample > -1 && // only silence lastSoundSample < iLen - 1) { // only sound m_iSignalEnd = m_iFramesProcessed + lastSoundSample / mixxx::kAnalysisChannels + 1; diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index 5ba65b5fede..1df5fb87181 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -3,6 +3,7 @@ #include "analyzer/analyzer.h" #include "audio/frame.h" #include "preferences/usersettings.h" +#include "util/span.h" class CuePointer; @@ -20,17 +21,16 @@ class AnalyzerSilence : public Analyzer { /// returns the index of the first sample in the buffer that is above -60 dB /// or iLen if no sample is found - static SINT findFirstSoundInChunk(const CSAMPLE* pIn, SINT iLen); + static SINT findFirstSoundInChunk(std::span samples); /// returns the index of the last sample in the buffer that is above -60 dB /// or -1 if no sample is found. - static SINT findLastSoundInChunk(const CSAMPLE* pIn, SINT iLen); + static SINT findLastSoundInChunk(std::span samples); /// Returns true if the first sound if found at the given frame and logs a warning message if not. /// This can be uses to detect changes since the last analysis run and is an indicator for /// file edits or decoder changes/issues - static bool verifyFirstSound(const CSAMPLE* pIn, - SINT iLen, + static bool verifyFirstSound(std::span samples, mixxx::audio::FramePos firstSoundFrame); private: diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp index 30fbfc6f8f2..5915b2d12d9 100644 --- a/src/engine/cachingreader/cachingreaderworker.cpp +++ b/src/engine/cachingreader/cachingreaderworker.cpp @@ -12,6 +12,7 @@ #include "util/compatibility/qmutex.h" #include "util/event.h" #include "util/logger.h" +#include "util/span.h" namespace { @@ -273,8 +274,7 @@ void CachingReaderWorker::verifyFirstSound(const CachingReaderChunk* pChunk) { SINT end = static_cast(m_firstSoundFrameToVerify.toLowerFrameBoundary().value()); pChunk->readBufferedSampleFrames(sampleBuffer, mixxx::IndexRange::forward(end - 1, kNumSoundFrameToVerify)); - if (AnalyzerSilence::verifyFirstSound(sampleBuffer, - std::size(sampleBuffer), + if (AnalyzerSilence::verifyFirstSound(std::span(sampleBuffer), mixxx::audio::FramePos(1))) { qDebug() << "First sound found at the previously stored position"; } else { diff --git a/src/util/math.h b/src/util/math.h index 09334c7af7f..e93914d8d29 100644 --- a/src/util/math.h +++ b/src/util/math.h @@ -34,7 +34,8 @@ constexpr T math_clamp(T value, T min, T max) { // to manually convert so they are aware of the conversion. template // since we also want to this to work on size_t and ptrdiff_t, is_integer would be too strict. -requires(std::is_arithmetic_v && !std::is_floating_point_v) constexpr bool even(T value) { +//requires(std::is_arithmetic_v && !std::is_floating_point_v) +constexpr bool even(T value) { return value % 2 == 0; } @@ -72,14 +73,14 @@ roundToFraction(double value, int denominator) { } template -requires std::is_floating_point_v - CMATH_CONSTEXPR T ratio2db(T a) { +//requires std::is_floating_point_v +CMATH_CONSTEXPR T ratio2db(T a) { return log10(a) * 20; } template -requires std::is_floating_point_v - CMATH_CONSTEXPR T db2ratio(T a) { +//requires std::is_floating_point_v +CMATH_CONSTEXPR T db2ratio(T a) { return static_cast(pow(10, a / 20)); } @@ -87,7 +88,7 @@ requires std::is_floating_point_v /// https://en.wikipedia.org/wiki/Sign_function template -requires std::is_arithmetic_v +//requires std::is_arithmetic_v constexpr T sgn(const T a) { // silence -Wtype-limits if constexpr (std::is_unsigned_v) { From eb0339f9402662a8d75b693018142b9203a54183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 7 Sep 2022 08:12:03 +0200 Subject: [PATCH 17/25] AnalyzerGain: Removed unused member variable --- src/analyzer/analyzergain.cpp | 5 ++--- src/analyzer/analyzergain.h | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/analyzer/analyzergain.cpp b/src/analyzer/analyzergain.cpp index 9e505714739..0d300e94d3a 100644 --- a/src/analyzer/analyzergain.cpp +++ b/src/analyzer/analyzergain.cpp @@ -8,8 +8,7 @@ #include "util/timer.h" AnalyzerGain::AnalyzerGain(UserSettingsPointer pConfig) - : m_rgSettings(pConfig), - m_iBufferSize(0) { + : m_rgSettings(pConfig) { m_pReplayGain = new ReplayGain(); } @@ -35,7 +34,7 @@ bool AnalyzerGain::processSamples(const CSAMPLE* pIn, SINT iLen) { ScopedTimer t("AnalyzerGain::process()"); int halfLength = static_cast(iLen / 2); - if (halfLength > m_iBufferSize) { + if (halfLength > 0) { m_pLeftTempBuffer.resize(halfLength); m_pRightTempBuffer.resize(halfLength); } diff --git a/src/analyzer/analyzergain.h b/src/analyzer/analyzergain.h index a33c9ea88db..8c07a84d81c 100644 --- a/src/analyzer/analyzergain.h +++ b/src/analyzer/analyzergain.h @@ -35,5 +35,4 @@ class AnalyzerGain : public Analyzer { std::vector m_pLeftTempBuffer; std::vector m_pRightTempBuffer; ReplayGain* m_pReplayGain; - int m_iBufferSize; }; From 438f8ea6723cb18ccf7b5944853b4f66f4bb2754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 7 Sep 2022 08:12:47 +0200 Subject: [PATCH 18/25] More SINT in analyzers --- src/analyzer/analyzer.h | 2 +- src/analyzer/analyzerbeats.cpp | 2 +- src/analyzer/analyzerbeats.h | 2 +- src/analyzer/analyzerebur128.cpp | 2 +- src/analyzer/analyzerebur128.h | 2 +- src/analyzer/analyzergain.cpp | 2 +- src/analyzer/analyzergain.h | 2 +- src/analyzer/analyzerkey.cpp | 2 +- src/analyzer/analyzerkey.h | 2 +- src/analyzer/analyzersilence.cpp | 2 +- src/analyzer/analyzersilence.h | 8 ++++---- src/analyzer/analyzerwaveform.cpp | 2 +- src/analyzer/analyzerwaveform.h | 2 +- 13 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/analyzer/analyzer.h b/src/analyzer/analyzer.h index fac1c6ee8eb..67470d633c6 100644 --- a/src/analyzer/analyzer.h +++ b/src/analyzer/analyzer.h @@ -24,7 +24,7 @@ class Analyzer { // 3. If the initialization failed log the internal error and return false. virtual bool initialize(TrackPointer tio, mixxx::audio::SampleRate sampleRate, - int totalSamples) = 0; + SINT totalSamples) = 0; ///////////////////////////////////////////////////////////////////////// // All following methods will only be invoked after initialize() diff --git a/src/analyzer/analyzerbeats.cpp b/src/analyzer/analyzerbeats.cpp index 9c530c1d315..579790e58b8 100644 --- a/src/analyzer/analyzerbeats.cpp +++ b/src/analyzer/analyzerbeats.cpp @@ -43,7 +43,7 @@ AnalyzerBeats::AnalyzerBeats(UserSettingsPointer pConfig, bool enforceBpmDetecti bool AnalyzerBeats::initialize(TrackPointer pTrack, mixxx::audio::SampleRate sampleRate, - int totalSamples) { + SINT totalSamples) { if (totalSamples == 0) { return false; } diff --git a/src/analyzer/analyzerbeats.h b/src/analyzer/analyzerbeats.h index 739f81a8e0b..2ff85fb31ef 100644 --- a/src/analyzer/analyzerbeats.h +++ b/src/analyzer/analyzerbeats.h @@ -28,7 +28,7 @@ class AnalyzerBeats : public Analyzer { bool initialize(TrackPointer pTrack, mixxx::audio::SampleRate sampleRate, - int totalSamples) override; + SINT totalSamples) override; bool processSamples(const CSAMPLE* pIn, SINT iLen) override; void storeResults(TrackPointer tio) override; void cleanup() override; diff --git a/src/analyzer/analyzerebur128.cpp b/src/analyzer/analyzerebur128.cpp index cc4df238f4e..7d51bf3d93b 100644 --- a/src/analyzer/analyzerebur128.cpp +++ b/src/analyzer/analyzerebur128.cpp @@ -22,7 +22,7 @@ AnalyzerEbur128::~AnalyzerEbur128() { bool AnalyzerEbur128::initialize(TrackPointer tio, mixxx::audio::SampleRate sampleRate, - int totalSamples) { + SINT totalSamples) { if (m_rgSettings.isAnalyzerDisabled(2, tio) || totalSamples == 0) { qDebug() << "Skipping AnalyzerEbur128"; return false; diff --git a/src/analyzer/analyzerebur128.h b/src/analyzer/analyzerebur128.h index f08fb29c44c..98272eade5a 100644 --- a/src/analyzer/analyzerebur128.h +++ b/src/analyzer/analyzerebur128.h @@ -16,7 +16,7 @@ class AnalyzerEbur128 : public Analyzer { bool initialize(TrackPointer tio, mixxx::audio::SampleRate sampleRate, - int totalSamples) override; + SINT totalSamples) override; bool processSamples(const CSAMPLE* pIn, SINT iLen) override; void storeResults(TrackPointer tio) override; void cleanup() override; diff --git a/src/analyzer/analyzergain.cpp b/src/analyzer/analyzergain.cpp index 0d300e94d3a..18cdb513afa 100644 --- a/src/analyzer/analyzergain.cpp +++ b/src/analyzer/analyzergain.cpp @@ -18,7 +18,7 @@ AnalyzerGain::~AnalyzerGain() { bool AnalyzerGain::initialize(TrackPointer tio, mixxx::audio::SampleRate sampleRate, - int totalSamples) { + SINT totalSamples) { if (m_rgSettings.isAnalyzerDisabled(1, tio) || totalSamples == 0) { qDebug() << "Skipping AnalyzerGain"; return false; diff --git a/src/analyzer/analyzergain.h b/src/analyzer/analyzergain.h index 8c07a84d81c..1170c74b1d3 100644 --- a/src/analyzer/analyzergain.h +++ b/src/analyzer/analyzergain.h @@ -25,7 +25,7 @@ class AnalyzerGain : public Analyzer { bool initialize(TrackPointer tio, mixxx::audio::SampleRate sampleRate, - int totalSamples) override; + SINT totalSamples) override; bool processSamples(const CSAMPLE* pIn, SINT iLen) override; void storeResults(TrackPointer tio) override; void cleanup() override; diff --git a/src/analyzer/analyzerkey.cpp b/src/analyzer/analyzerkey.cpp index 59fe6d0bf66..ffa8b0e5bb1 100644 --- a/src/analyzer/analyzerkey.cpp +++ b/src/analyzer/analyzerkey.cpp @@ -43,7 +43,7 @@ AnalyzerKey::AnalyzerKey(const KeyDetectionSettings& keySettings) bool AnalyzerKey::initialize(TrackPointer tio, mixxx::audio::SampleRate sampleRate, - int totalSamples) { + SINT totalSamples) { if (totalSamples == 0) { return false; } diff --git a/src/analyzer/analyzerkey.h b/src/analyzer/analyzerkey.h index 76b6ec03eed..825bbdbfd3e 100644 --- a/src/analyzer/analyzerkey.h +++ b/src/analyzer/analyzerkey.h @@ -21,7 +21,7 @@ class AnalyzerKey : public Analyzer { bool initialize(TrackPointer tio, mixxx::audio::SampleRate sampleRate, - int totalSamples) override; + SINT totalSamples) override; bool processSamples(const CSAMPLE* pIn, SINT iLen) override; void storeResults(TrackPointer tio) override; void cleanup() override; diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index c78d1846ed0..f4a7d02267f 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -41,7 +41,7 @@ AnalyzerSilence::AnalyzerSilence(UserSettingsPointer pConfig) bool AnalyzerSilence::initialize(TrackPointer pTrack, mixxx::audio::SampleRate sampleRate, - int totalSamples) { + SINT totalSamples) { Q_UNUSED(sampleRate); Q_UNUSED(totalSamples); diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index 1df5fb87181..39f7464cc16 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -14,7 +14,7 @@ class AnalyzerSilence : public Analyzer { bool initialize(TrackPointer pTrack, mixxx::audio::SampleRate sampleRate, - int totalSamples) override; + SINT totalSamples) override; bool processSamples(const CSAMPLE* pIn, SINT iLen) override; void storeResults(TrackPointer pTrack) override; void cleanup() override; @@ -35,7 +35,7 @@ class AnalyzerSilence : public Analyzer { private: UserSettingsPointer m_pConfig; - int m_iFramesProcessed; - int m_iSignalStart; - int m_iSignalEnd; + SINT m_iFramesProcessed; + SINT m_iSignalStart; + SINT m_iSignalEnd; }; diff --git a/src/analyzer/analyzerwaveform.cpp b/src/analyzer/analyzerwaveform.cpp index 3abcd42bfa6..d48f35fe107 100644 --- a/src/analyzer/analyzerwaveform.cpp +++ b/src/analyzer/analyzerwaveform.cpp @@ -35,7 +35,7 @@ AnalyzerWaveform::~AnalyzerWaveform() { bool AnalyzerWaveform::initialize(TrackPointer tio, mixxx::audio::SampleRate sampleRate, - int totalSamples) { + SINT totalSamples) { if (totalSamples == 0) { qWarning() << "AnalyzerWaveform::initialize - no waveform/waveform summary"; return false; diff --git a/src/analyzer/analyzerwaveform.h b/src/analyzer/analyzerwaveform.h index 8a12ba574c7..39870c06a2c 100644 --- a/src/analyzer/analyzerwaveform.h +++ b/src/analyzer/analyzerwaveform.h @@ -142,7 +142,7 @@ class AnalyzerWaveform : public Analyzer { bool initialize(TrackPointer tio, mixxx::audio::SampleRate sampleRate, - int totalSamples) override; + SINT totalSamples) override; bool processSamples(const CSAMPLE* buffer, SINT bufferLength) override; void storeResults(TrackPointer tio) override; void cleanup() override; From c5317b07214fa61263c19b20955c7f1ee85b653b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 10 Dec 2022 17:54:04 +0100 Subject: [PATCH 19/25] fixup math Uncomment "requires" in math.h --- src/util/math.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/util/math.h b/src/util/math.h index e93914d8d29..d250c30bdc5 100644 --- a/src/util/math.h +++ b/src/util/math.h @@ -34,8 +34,7 @@ constexpr T math_clamp(T value, T min, T max) { // to manually convert so they are aware of the conversion. template // since we also want to this to work on size_t and ptrdiff_t, is_integer would be too strict. -//requires(std::is_arithmetic_v && !std::is_floating_point_v) -constexpr bool even(T value) { +requires(std::is_arithmetic_v && !std::is_floating_point_v) constexpr bool even(T value) { return value % 2 == 0; } @@ -73,14 +72,14 @@ roundToFraction(double value, int denominator) { } template -//requires std::is_floating_point_v -CMATH_CONSTEXPR T ratio2db(T a) { +requires std::is_floating_point_v + CMATH_CONSTEXPR T ratio2db(T a) { return log10(a) * 20; } template -//requires std::is_floating_point_v -CMATH_CONSTEXPR T db2ratio(T a) { +requires std::is_floating_point_v + CMATH_CONSTEXPR T db2ratio(T a) { return static_cast(pow(10, a / 20)); } @@ -88,8 +87,7 @@ CMATH_CONSTEXPR T db2ratio(T a) { /// https://en.wikipedia.org/wiki/Sign_function template -//requires std::is_arithmetic_v -constexpr T sgn(const T a) { +requires std::is_arithmetic_v constexpr T sgn(const T a) { // silence -Wtype-limits if constexpr (std::is_unsigned_v) { return static_cast(a > T(0)); From 4a3b0593bb0452d6e4446b6a2c5f04a122b0b4fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 10 Dec 2022 17:38:05 +0100 Subject: [PATCH 20/25] Rename AudibleSound to 60dBSound to emphasize that this cue point has a fixed threshold. --- src/analyzer/analyzersilence.cpp | 21 +++++++++--------- .../cachingreader/cachingreaderworker.cpp | 8 +++---- src/engine/controls/cuecontrol.cpp | 22 +++++++++---------- src/library/autodj/autodjprocessor.cpp | 12 +++++----- src/track/cueinfo.cpp | 4 ++-- src/track/cueinfo.h | 4 ++-- src/widget/whotcuebutton.cpp | 4 ++-- 7 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 15d01fe801e..58748750009 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -16,9 +16,9 @@ constexpr CSAMPLE kSilenceThreshold = 0.001f; // -60 dB bool shouldAnalyze(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(mixxx::CueType::Intro); CuePointer pOutroCue = pTrack->findCueByType(mixxx::CueType::Outro); - CuePointer pAudibleSound = pTrack->findCueByType(mixxx::CueType::AudibleSound); + CuePointer pN60dBSound = pTrack->findCueByType(mixxx::CueType::N60dBSound); - if (!pIntroCue || !pOutroCue || !pAudibleSound || pAudibleSound->getLengthFrames() <= 0) { + if (!pIntroCue || !pOutroCue || !pN60dBSound || pN60dBSound->getLengthFrames() <= 0) { return true; } return false; @@ -114,21 +114,20 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { const auto firstSoundPosition = mixxx::audio::FramePos(m_iSignalStart); const auto lastSoundPosition = mixxx::audio::FramePos(m_iSignalEnd); - CuePointer pAudibleSound = pTrack->findCueByType(mixxx::CueType::AudibleSound); - if (pAudibleSound == nullptr) { - pAudibleSound = pTrack->createAndAddCue( - mixxx::CueType::AudibleSound, + CuePointer pN60dBSound = pTrack->findCueByType(mixxx::CueType::N60dBSound); + if (pN60dBSound == nullptr) { + pN60dBSound = pTrack->createAndAddCue( + mixxx::CueType::N60dBSound, Cue::kNoHotCue, firstSoundPosition, lastSoundPosition); } else { - // The user has no way to directly edit the AudibleSound cue. If the user + // The user has no way to directly edit the N60dBSound cue. If the user // has deleted the Intro or Outro Cue, this analysis will be rerun when - // the track is loaded again. In this case, adjust the AudibleSound Cue's + // the track is loaded again. In this case, adjust the N60dBSound Cue's // positions. This could be helpful, for example, when the track length - // is changed in a different program, or the silence detection threshold - // is changed. - pAudibleSound->setStartAndEndPosition(firstSoundPosition, lastSoundPosition); + // is changed in a different program. + pN60dBSound->setStartAndEndPosition(firstSoundPosition, lastSoundPosition); } CuePointer pIntroCue = pTrack->findCueByType(mixxx::CueType::Intro); diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp index 5915b2d12d9..d161159053e 100644 --- a/src/engine/cachingreader/cachingreaderworker.cpp +++ b/src/engine/cachingreader/cachingreaderworker.cpp @@ -238,10 +238,10 @@ void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) { CachingReaderChunk::frames2samples( m_pAudioSource->frameLength()); - CuePointer pAudibleSound = - pTrack->findCueByType(mixxx::CueType::AudibleSound); - if (pAudibleSound) { - m_firstSoundFrameToVerify = pAudibleSound->getPosition(); + CuePointer pN60dBSound = + pTrack->findCueByType(mixxx::CueType::N60dBSound); + if (pN60dBSound) { + m_firstSoundFrameToVerify = pN60dBSound->getPosition(); } // The engine must not request any chunks before receiving the diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 98ebd662b98..dc433b8f053 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -571,14 +571,14 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { } break; case SeekOnLoadMode::FirstSound: { - CuePointer pAudibleSound = - pNewTrack->findCueByType(mixxx::CueType::AudibleSound); - mixxx::audio::FramePos audibleSoundPosition = mixxx::audio::kInvalidFramePos; - if (pAudibleSound) { - audibleSoundPosition = pAudibleSound->getPosition(); + CuePointer pN60dBSound = + pNewTrack->findCueByType(mixxx::CueType::N60dBSound); + mixxx::audio::FramePos n60dBSoundPosition; + if (pN60dBSound) { + n60dBSoundPosition = pN60dBSound->getPosition(); } - if (audibleSoundPosition.isValid()) { - seekOnLoad(audibleSoundPosition); + if (n60dBSoundPosition.isValid()) { + seekOnLoad(n60dBSoundPosition); } else { seekOnLoad(mixxx::audio::kStartFramePos); } @@ -1267,10 +1267,10 @@ void CueControl::hintReader(gsl::not_null pHintList) { appendCueHint(pHintList, pControl->getPosition(), Hint::Type::HotCue); } - CuePointer pAudibleSound = - m_pLoadedTrack->findCueByType(mixxx::CueType::AudibleSound); - if (pAudibleSound) { - const mixxx::audio::FramePos frame = pAudibleSound->getPosition(); + CuePointer pN60dBSound = + m_pLoadedTrack->findCueByType(mixxx::CueType::N60dBSound); + if (pN60dBSound) { + const mixxx::audio::FramePos frame = pN60dBSound->getPosition(); appendCueHint(pHintList, frame, Hint::Type::FirstSound); } diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 2f5e71c1f90..a3a9ab35f3f 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1132,9 +1132,9 @@ double AutoDJProcessor::getFirstSoundSecond(DeckAttributes* pDeck) { return 0.0; } - CuePointer pFromTrackAudibleSound = pTrack->findCueByType(mixxx::CueType::AudibleSound); - if (pFromTrackAudibleSound) { - const mixxx::audio::FramePos firstSound = pFromTrackAudibleSound->getPosition(); + CuePointer pFromTrackN60dBSound = pTrack->findCueByType(mixxx::CueType::N60dBSound); + if (pFromTrackN60dBSound) { + const mixxx::audio::FramePos firstSound = pFromTrackN60dBSound->getPosition(); if (firstSound.isValid()) { return framePositionToSeconds(firstSound, pDeck); } @@ -1148,9 +1148,9 @@ double AutoDJProcessor::getLastSoundSecond(DeckAttributes* pDeck) { return 0.0; } - CuePointer pFromTrackAudibleSound = pTrack->findCueByType(mixxx::CueType::AudibleSound); - if (pFromTrackAudibleSound) { - Cue::StartAndEndPositions pos = pFromTrackAudibleSound->getStartAndEndPosition(); + CuePointer pFromTrackN60dBSound = pTrack->findCueByType(mixxx::CueType::N60dBSound); + if (pFromTrackN60dBSound) { + Cue::StartAndEndPositions pos = pFromTrackN60dBSound->getStartAndEndPosition(); if (pos.endPosition > mixxx::audio::kStartFramePos && (pos.endPosition - pos.startPosition) > 0) { return framePositionToSeconds(pos.endPosition, pDeck); diff --git a/src/track/cueinfo.cpp b/src/track/cueinfo.cpp index 6c2e79723d7..3c87d6fdab4 100644 --- a/src/track/cueinfo.cpp +++ b/src/track/cueinfo.cpp @@ -116,8 +116,8 @@ QDebug operator<<(QDebug debug, const CueType& cueType) { case CueType::Outro: debug << "CueType::Outro"; break; - case CueType::AudibleSound: - debug << "CueType::AudibleSound"; + case CueType::N60dBSound: + debug << "CueType::N60dBSound"; break; } return debug; diff --git a/src/track/cueinfo.h b/src/track/cueinfo.h index db6dacfb916..3c50c844378 100644 --- a/src/track/cueinfo.h +++ b/src/track/cueinfo.h @@ -17,8 +17,8 @@ enum class CueType { Jump = 5, Intro = 6, Outro = 7, - AudibleSound = 8, // range that covers beginning and end of audible - // sound; not shown to user + N60dBSound = 8, // range that covers beginning and end of audible + // sound; not shown to user }; enum class CueFlag { diff --git a/src/widget/whotcuebutton.cpp b/src/widget/whotcuebutton.cpp index d8d954f1582..917bc197665 100644 --- a/src/widget/whotcuebutton.cpp +++ b/src/widget/whotcuebutton.cpp @@ -200,8 +200,8 @@ void WHotcueButton::slotTypeChanged(double type) { case mixxx::CueType::Outro: m_type = QStringLiteral("outro"); break; - case mixxx::CueType::AudibleSound: - m_type = QStringLiteral("audiblesound"); + case mixxx::CueType::N60dBSound: + m_type = QStringLiteral("n60dbsound"); break; default: DEBUG_ASSERT(!"Unknown cue type!"); From 8012a2b0890e3b3d3f8ce690bf9c59ec195d7301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 11 Dec 2022 23:21:12 +0100 Subject: [PATCH 21/25] Avoid long lines in comments --- src/analyzer/analyzersilence.h | 7 ++++--- src/engine/cachingreader/cachingreaderworker.cpp | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index f69c94cd355..af8d4ce89aa 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -28,9 +28,10 @@ class AnalyzerSilence : public Analyzer { /// or -1 if no sample is found. static SINT findLastSoundInChunk(std::span samples); - /// Returns true if the first sound if found at the given frame and logs a warning message if not. - /// This can be uses to detect changes since the last analysis run and is an indicator for - /// file edits or decoder changes/issues + /// Returns true if the first sound if found at the given frame and logs a + /// warning message if not. This can be uses to detect changes since the + /// last analysis run and is an indicator for file edits or decoder + /// changes/issues static bool verifyFirstSound(std::span samples, mixxx::audio::FramePos firstSoundFrame); diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp index d161159053e..6575b1b8dd2 100644 --- a/src/engine/cachingreader/cachingreaderworker.cpp +++ b/src/engine/cachingreader/cachingreaderworker.cpp @@ -278,7 +278,8 @@ void CachingReaderWorker::verifyFirstSound(const CachingReaderChunk* pChunk) { mixxx::audio::FramePos(1))) { qDebug() << "First sound found at the previously stored position"; } else { - // This can happen in case of track edits or replacements, changed encoders or encoding issues. + // This can happen in case of track edits or replacements, changed + // encoders or encoding issues. qWarning() << "First sound has been moved! The beatgrid and " "other annotations are no longer valid"; } From 684479826c19cb5b97b9eb57ffdb55715c986e6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 12 Dec 2022 06:57:50 +0100 Subject: [PATCH 22/25] Add line break after "requires" --- src/util/math.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/math.h b/src/util/math.h index d250c30bdc5..09334c7af7f 100644 --- a/src/util/math.h +++ b/src/util/math.h @@ -87,7 +87,8 @@ requires std::is_floating_point_v /// https://en.wikipedia.org/wiki/Sign_function template -requires std::is_arithmetic_v constexpr T sgn(const T a) { +requires std::is_arithmetic_v +constexpr T sgn(const T a) { // silence -Wtype-limits if constexpr (std::is_unsigned_v) { return static_cast(a > T(0)); From d937a08a311308b8813bcb3aaa041dea94d92027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 13 Dec 2022 01:11:58 +0100 Subject: [PATCH 23/25] Added test AnalyzerSilenceTest,verifyFirstSound --- src/test/analyzersilence_test.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/test/analyzersilence_test.cpp b/src/test/analyzersilence_test.cpp index f14283309d2..f738936c783 100644 --- a/src/test/analyzersilence_test.cpp +++ b/src/test/analyzersilence_test.cpp @@ -213,4 +213,26 @@ TEST_F(AnalyzerSilenceTest, RespectUserEdits) { EXPECT_DOUBLE_EQ(kManualOutroPosition.value(), pOutroCue->getLengthFrames()); } +TEST_F(AnalyzerSilenceTest, verifyFirstSound) { + const CSAMPLE s[] = { + 0.0000f, + 0.0000f, + -0.0002f, + -0.0002f, + 0.0004f, + 0.0004f, + -0.0008f, + -0.0008f, + 0.0010f, + 0.0010f, + 0.0011f, + 0.0010f, + -0.0020f, + -0.0020f}; + std::span samples = s; + + EXPECT_EQ(false, AnalyzerSilence::verifyFirstSound(samples, mixxx::audio::FramePos(5))); + EXPECT_EQ(true, AnalyzerSilence::verifyFirstSound(samples, mixxx::audio::FramePos(4))); +} + } // namespace From 96ed9410147bd4fb9edc8be6227c03299b08393c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 13 Dec 2022 01:21:27 +0100 Subject: [PATCH 24/25] Added a comment about the temprary nature of thes first sound verification --- src/engine/cachingreader/cachingreaderworker.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp index 6575b1b8dd2..9cf0e698042 100644 --- a/src/engine/cachingreader/cachingreaderworker.cpp +++ b/src/engine/cachingreader/cachingreaderworker.cpp @@ -238,6 +238,8 @@ void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) { CachingReaderChunk::frames2samples( m_pAudioSource->frameLength()); + // This code is a workaround until we have found a better solution to + // verify and correct offsets. CuePointer pN60dBSound = pTrack->findCueByType(mixxx::CueType::N60dBSound); if (pN60dBSound) { From 9f99531524358de303162703965b94d8bf9c8467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 13 Dec 2022 01:50:24 +0100 Subject: [PATCH 25/25] findLastSoundInChunk() returns samples.size() if no sample is found --- src/analyzer/analyzersilence.cpp | 12 +++++++----- src/analyzer/analyzersilence.h | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 58748750009..7b8ad2b113d 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -63,10 +63,13 @@ SINT AnalyzerSilence::findFirstSoundInChunk(std::span samples) { } // static -/// returns a std::reverse_iterator SINT AnalyzerSilence::findLastSoundInChunk(std::span samples) { // -1 is required, because the distance from the fist sample index (0) to crend() is 1, - return std::distance(first_sound(samples.rbegin(), samples.rend()), samples.rend()) - 1; + SINT ret = std::distance(first_sound(samples.rbegin(), samples.rend()), samples.rend()) - 1; + if (ret == -1) { + ret = samples.size(); + } + return ret; } // static @@ -84,14 +87,13 @@ bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, SINT iLen) { std::span samples = mixxx::spanutil::spanFromPtrLen(pIn, iLen); if (m_iSignalStart < 0) { const SINT firstSoundSample = findFirstSoundInChunk(samples); - if (firstSoundSample < static_cast(samples.size())) { + if (firstSoundSample < iLen) { m_iSignalStart = m_iFramesProcessed + firstSoundSample / mixxx::kAnalysisChannels; } } if (m_iSignalStart >= 0) { const SINT lastSoundSample = findLastSoundInChunk(samples); - if (lastSoundSample > -1 && // only silence - lastSoundSample < iLen - 1) { // only sound + if (lastSoundSample < iLen - 1) { // not only sound or silence m_iSignalEnd = m_iFramesProcessed + lastSoundSample / mixxx::kAnalysisChannels + 1; } } diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index af8d4ce89aa..d4e37347f88 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -21,11 +21,11 @@ class AnalyzerSilence : public Analyzer { void cleanup() override; /// returns the index of the first sample in the buffer that is above -60 dB - /// or iLen if no sample is found + /// or samples.size() if no sample is found static SINT findFirstSoundInChunk(std::span samples); /// returns the index of the last sample in the buffer that is above -60 dB - /// or -1 if no sample is found. + /// or samples.size() if no sample is found static SINT findLastSoundInChunk(std::span samples); /// Returns true if the first sound if found at the given frame and logs a