From 2eb0ef669e92456b9b56e74ad3a3a0b8493b9882 Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Thu, 10 Oct 2024 19:17:25 +0800 Subject: [PATCH 01/20] Adding RadioLanewayCrossfade transition Adding RadioLanewayCrossfade transition. See https://github.com/mixxxdj/mixxx/issues/13716 --- src/analyzer/analyzersilence.cpp | 112 +++++++++- src/analyzer/analyzersilence.h | 11 + src/library/autodj/autodjprocessor.cpp | 275 ++++++++++++++++++++++++- src/library/autodj/autodjprocessor.h | 8 +- src/library/autodj/dlgautodj.cpp | 10 +- src/track/cueinfo.h | 5 + src/widget/wtrackmenu.cpp | 4 + 7 files changed, 416 insertions(+), 9 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index a1b463a1218..6d53f972ab2 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -12,12 +12,34 @@ constexpr CSAMPLE kSilenceThreshold = 0.001f; // -60 dB // TODO: Change the above line to: //constexpr CSAMPLE kSilenceThreshold = db2ratio(-60.0f); +// These are in dBV expressed as Volts RMS (which seems, sensibly, +// the way Mixxx works). +// Don't change these to const as they are used only to feed the +// fade thresholds which are consts below themselves while we work +// out which one is best, and you'll just be adding to exe size. +#define N_10DB_FADEOUT_THRESHOLD 0.3162f +#define N_12DB_FADEOUT_THRESHOLD 0.2511f +#define N_15DB_FADEOUT_THRESHOLD 0.1778f +#define N_18DB_FADEOUT_THRESHOLD 0.1259f +#define N_20DB_FADEOUT_THRESHOLD 0.1f +#define N_24DB_FADEOUT_THRESHOLD 0.0631f +#define N_25DB_FADEOUT_THRESHOLD 0.0562f +#define N_27DB_FADEOUT_THRESHOLD 0.0447f +#define N_30DB_FADEOUT_THRESHOLD 0.0316f +#define N_40DB_FADEOUT_THRESHOLD 0.01f + +constexpr CSAMPLE kFadeInThreshold = N_27DB_FADEOUT_THRESHOLD; +constexpr CSAMPLE kFadeOutThreshold = N_12DB_FADEOUT_THRESHOLD; + + bool shouldAnalyze(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(mixxx::CueType::Intro); CuePointer pOutroCue = pTrack->findCueByType(mixxx::CueType::Outro); CuePointer pN60dBSound = pTrack->findCueByType(mixxx::CueType::N60dBSound); + CuePointer pFadeIn = pTrack->findCueByType(mixxx::CueType::FadeIn); + CuePointer pFadeOut = pTrack->findCueByType(mixxx::CueType::FadeOut); - if (!pIntroCue || !pOutroCue || !pN60dBSound || pN60dBSound->getLengthFrames() <= 0) { + if (!pFadeIn || !pFadeOut || !pIntroCue || !pOutroCue || !pN60dBSound || pN60dBSound->getLengthFrames() <= 0) { return true; } return false; @@ -30,13 +52,29 @@ Iterator first_sound(Iterator begin, Iterator end) { }); } +template +ForwardIterator last_fade_in_sound(ForwardIterator begin, ForwardIterator end) { + return std::find_if(begin, end, [](const auto elem) { + return fabs(elem) >= kFadeInThreshold; + }); +} + +template +Iterator first_fade_out_sound(Iterator begin, Iterator end) { + return std::find_if(begin, end, [](const auto elem) { + return fabs(elem) >= kFadeOutThreshold; + }); +} + } // anonymous namespace AnalyzerSilence::AnalyzerSilence(UserSettingsPointer pConfig) : m_pConfig(pConfig), m_framesProcessed(0), m_signalStart(-1), - m_signalEnd(-1) { + m_signalEnd(-1), + m_fadeThresholdFadeInEnd(-1), + m_fadeThresholdFadeOutStart(-1) { } bool AnalyzerSilence::initialize(const AnalyzerTrack& track, @@ -53,6 +91,8 @@ bool AnalyzerSilence::initialize(const AnalyzerTrack& track, m_framesProcessed = 0; m_signalStart = -1; m_signalEnd = -1; + m_fadeThresholdFadeInEnd = -1; + m_fadeThresholdFadeOutStart = -1; m_channelCount = channelCount; return true; @@ -70,6 +110,25 @@ SINT AnalyzerSilence::findLastSoundInChunk(std::span samples) { return ret; } +// static +SINT AnalyzerSilence::findFirstFadeOutChunk(std::span samples) { + // -1 is required, because the distance from the fist sample index (0) to crend() is 1, + SINT ret = std::distance(first_fade_out_sound(samples.rbegin(), samples.rend()), samples.rend()) - 1; + if (ret == -1) { + ret = samples.size(); + } + return ret; +} + +// static +SINT AnalyzerSilence::findLastFadeInChunk(std::span samples) { + SINT ret = std::distance(samples.begin(), last_fade_in_sound(samples.begin(), samples.end())); + // if (ret == samples.size()) { + // ret = 0; + // } + return ret; +} + // static bool AnalyzerSilence::verifyFirstSound( std::span samples, @@ -93,10 +152,23 @@ bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, SINT count) { m_signalStart = m_framesProcessed + firstSoundSample / m_channelCount; } } - if (m_signalStart >= 0) { + + if (m_fadeThresholdFadeInEnd < 0) { + const SINT lastSampleOfFadeIn = findLastFadeInChunk(samples); + if (lastSampleOfFadeIn < count) { + m_fadeThresholdFadeInEnd = m_framesProcessed + (lastSampleOfFadeIn / m_channelCount); + } + } + if (m_fadeThresholdFadeInEnd >= 0) { + const SINT lasttSampleBeforeFadeOut = findFirstFadeOutChunk(samples); + if (lasttSampleBeforeFadeOut < (count - 1)) { + m_fadeThresholdFadeOutStart = m_framesProcessed + (lasttSampleBeforeFadeOut / m_channelCount) + 1; + } + } + if (m_fadeThresholdFadeOutStart >= 0) { const SINT lastSoundSample = findLastSoundInChunk(samples); - if (lastSoundSample >= 0) { - m_signalEnd = m_framesProcessed + lastSoundSample / m_channelCount + 1; + if (lastSoundSample < (count - 1)) { // not only sound or silence + m_signalEnd = m_framesProcessed + (lastSoundSample / m_channelCount) + 1; } } @@ -136,6 +208,36 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { setupMainAndIntroCue(pTrack.get(), firstSoundPosition, m_pConfig.data()); setupOutroCue(pTrack.get(), lastSoundPosition); + + if (m_fadeThresholdFadeInEnd < 0) { + m_fadeThresholdFadeInEnd = 0; + } + if (m_fadeThresholdFadeOutStart < 0) { + m_fadeThresholdFadeOutStart = m_framesProcessed; + } + const auto fadeInEndPosition = mixxx::audio::FramePos(m_fadeThresholdFadeInEnd); + CuePointer pFadeIn = pTrack->findCueByType(mixxx::CueType::FadeIn); + if (pFadeIn == nullptr) { + pFadeIn = pTrack->createAndAddCue( + mixxx::CueType::FadeIn, + Cue::kNoHotCue, + firstSoundPosition, + fadeInEndPosition); + } else { + pFadeIn->setStartAndEndPosition(firstSoundPosition, fadeInEndPosition); + } + + const auto fadeOutStartPosition = mixxx::audio::FramePos(m_fadeThresholdFadeOutStart); + CuePointer pFadeOut = pTrack->findCueByType(mixxx::CueType::FadeOut); + if (pFadeOut == nullptr) { + pFadeOut = pTrack->createAndAddCue( + mixxx::CueType::FadeOut, + Cue::kNoHotCue, + fadeOutStartPosition, + lastSoundPosition); + } else { + pFadeOut->setStartAndEndPosition(fadeOutStartPosition, lastSoundPosition); + } } // static diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index baca4e54e99..40c38af5db4 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -34,6 +34,15 @@ class AnalyzerSilence : public Analyzer { UserSettings* pConfig); static void setupOutroCue(Track* pTrack, mixxx::audio::FramePos lastSoundPosition); + /// returns the index of the first sample in the buffer that is above the fade out threshold (e.g. -20 dB) + /// or samples.size() if no sample is found + /// TODO CHeck if 'samples.size()' is actually meaningful in this context. + static SINT findLastFadeInChunk(std::span samples); + + /// returns the index of the last sample in the buffer that is above that is above the fade out threshold (e.g. -20 dB) + /// or samples.size() if no sample is found + static SINT findFirstFadeOutChunk(std::span samples); + /// returns the index of the first sample in the buffer that is above -60 dB /// or samples.size() if no sample is found static SINT findFirstSoundInChunk(std::span samples); @@ -56,4 +65,6 @@ class AnalyzerSilence : public Analyzer { SINT m_framesProcessed; SINT m_signalStart; SINT m_signalEnd; + SINT m_fadeThresholdFadeInEnd; + SINT m_fadeThresholdFadeOutStart; }; diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 473663eeb69..be28e089d0f 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -334,7 +334,8 @@ void AutoDJProcessor::fadeNow() { pFromDeck->fadeBeginPos /= fromDeckDuration; pFromDeck->fadeEndPos /= fromDeckDuration; pToDeck->startPos /= toDeckDuration; - + pToDeck->playNextPos /= toDeckDuration; + pFromDeck->playNextPos /= toDeckDuration; VERIFY_OR_DEBUG_ASSERT(pFromDeck->fadeBeginPos <= 1) { pFromDeck->fadeBeginPos = 1; } @@ -567,6 +568,7 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { // One of the two decks is playing. Switch into IDLE mode and wait // until the playing deck crosses posThreshold to start fading. m_eState = ADJ_IDLE; + m_isNowStartingEarly = false; if (leftDeckPlaying) { // Load track into the right deck. emitLoadTrackToPlayer(nextTrack, pRightDeck->group, false); @@ -720,6 +722,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // sure our thresholds are configured (by calling calculateFadeThresholds // for the playing deck). m_eState = ADJ_IDLE; + m_isNowStartingEarly = false; if (!rightDeckPlaying) { // Only left deck playing! @@ -766,6 +769,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, setCrossfader(1.0); } m_eState = ADJ_IDLE; + m_isNowStartingEarly = false; // Invalidate threshold calculated for the old otherDeck // This avoids starting a fade back before the new track is // loaded into the otherDeck @@ -801,11 +805,42 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, } } + // We use thisDeck->playNextPos to start the next track earlier than thisDeck->fadeEndPos + // so in RadioLanewayCrossfade we can start a track with a slow fade in earlier, but with out + // fading the current track, so we won't bork cold endings. + if (!m_isNowStartingEarly && + (thisPlayPosition >= thisDeck->playNextPos) && + (thisPlayPosition < thisDeck->fadeBeginPos) && + thisDeck->isFromDeck && !otherDeck->loading) { + if (m_eState == ADJ_IDLE) { + m_isNowStartingEarly = true; + if (thisDeckPlaying || thisPlayPosition >= 1.0) { + const double toDeckFadeDistance = + (thisDeck->fadeEndPos - thisDeck->fadeBeginPos) * + getEndSecond(thisDeck) / getEndSecond(otherDeck); + // Re-cue the track if the user has sought forward and will miss the fadeBeginPos + if (otherDeck->playPosition() >= otherDeck->fadeBeginPos - toDeckFadeDistance) { + otherDeck->setPlayPosition(otherDeck->startPos); + } + if (m_crossfaderStartCenter) { + setCrossfader(0.0); + } else if (thisDeck->fadeBeginPos >= thisDeck->fadeEndPos) { + setCrossfader(thisDeck->isLeft() ? 1.0 : -1.0); + } + + if (!otherDeckPlaying) { + otherDeck->play(); + } + } + } + } + // If we are past this deck's posThreshold then: // - transition into fading mode, play the other deck and fade to it. // - check if fading is done and stop the deck // - update the crossfader - if (thisPlayPosition >= thisDeck->fadeBeginPos && thisDeck->isFromDeck && !otherDeck->loading) { + if ((thisPlayPosition >= thisDeck->fadeBeginPos) && + thisDeck->isFromDeck && !otherDeck->loading) { if (m_eState == ADJ_IDLE) { if (thisDeckPlaying || thisPlayPosition >= 1.0) { // Set the state as FADING. @@ -1182,6 +1217,72 @@ double AutoDJProcessor::getOutroEndSecond(DeckAttributes* pDeck) { return framePositionToSeconds(outroEndPosition, pDeck); } +double AutoDJProcessor::getMainCueSecond(DeckAttributes* pDeck) { + TrackPointer pTrack = pDeck->getLoadedTrack(); + if (!pTrack) { + return 0.0; + } + + const mixxx::audio::FramePos mainCue = pTrack->getMainCuePosition(); + if (mainCue.isValid()) { + const mixxx::audio::FramePos trackEndPosition = pDeck->trackEndPosition(); + if (mainCue <= trackEndPosition) { + return framePositionToSeconds(mainCue, pDeck); + } else { + qWarning() << "Main Cue starts after track end in:" + << pTrack->getLocation() + << "Using the first sample instead."; + } + } + return 0.0; +} + +double AutoDJProcessor::getFadeInSecond(DeckAttributes* pDeck) { + TrackPointer pTrack = pDeck->getLoadedTrack(); + if (!pTrack) { + return 0.0; + } + + CuePointer pFromTrackFadeIn = pTrack->findCueByType(mixxx::CueType::FadeIn); + if (pFromTrackFadeIn) { + const mixxx::audio::FramePos fadeInEnd = pFromTrackFadeIn->getEndPosition(); + if (fadeInEnd.isValid()) { + const mixxx::audio::FramePos trackEndPosition = pDeck->trackEndPosition(); + if (fadeInEnd <= trackEndPosition) { + return framePositionToSeconds(fadeInEnd, pDeck); + } else { + qWarning() << "Fade Sound Cue starts after track end in:" + << pTrack->getLocation() + << "Using the first sample instead."; + } + } + } + return 0.0; +} + +double AutoDJProcessor::getFadeOutSecond(DeckAttributes* pDeck) { + TrackPointer pTrack = pDeck->getLoadedTrack(); + if (!pTrack) { + return 0.0; + } + + const mixxx::audio::FramePos trackEndPosition = pDeck->trackEndPosition(); + CuePointer pFromTrackFadeOut = pTrack->findCueByType(mixxx::CueType::FadeOut); + if (pFromTrackFadeOut && pFromTrackFadeOut->getLengthFrames() > 0.0) { + const mixxx::audio::FramePos fadeOutStart = pFromTrackFadeOut->getPosition(); + if (fadeOutStart > mixxx::audio::FramePos(0.0)) { + if (fadeOutStart <= trackEndPosition) { + return framePositionToSeconds(fadeOutStart, pDeck); + } else { + qWarning() << "Fade Sound Cue ends after track end in:" + << pTrack->getLocation() + << "Using the last sample instead."; + } + } + } + return framePositionToSeconds(trackEndPosition, pDeck); +} + double AutoDJProcessor::getFirstSoundSecond(DeckAttributes* pDeck) { TrackPointer pTrack = pDeck->getLoadedTrack(); if (!pTrack) { @@ -1268,10 +1369,14 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, const double fromDeckEndPosition = getEndSecond(pFromDeck); const double toDeckEndPosition = getEndSecond(pToDeck); + // Make sure playNextPos is higher than fadeBeginPos by default + pFromDeck->playNextPos = fromDeckEndPosition; // Since the end position is measured in seconds from 0:00 it is also // the track duration. Use this alias for better readability. const double fromDeckDuration = fromDeckEndPosition; const double toDeckDuration = toDeckEndPosition; + // Make sure playNextPos is higher than fadeBeginPos by default + pToDeck->playNextPos = toDeckEndPosition; VERIFY_OR_DEBUG_ASSERT(fromDeckDuration >= kMinimumTrackDurationSec) { // Track has no duration or too short. This should not happen, because short @@ -1359,6 +1464,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } m_crossfaderStartCenter = false; + pToDeck->fadeBeginPos = toDeckEndPosition; switch (m_transitionMode) { case TransitionMode::FullIntroOutro: { // Use the outro or intro length for the transition time, whichever is @@ -1481,6 +1587,168 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, getLastSoundSecond(pFromDeck), toDeckStartSecond); } break; + case TransitionMode::RadioLanewayCrossfade: { + // This transition mode does the following: + // + // (1) If a playing (from) track has reached the FadeOut cue start, + // then a crossfade starting center is initiated, with the + // transmission time taking the fadeOutLength, or value + // from the spin box (fixed value), whichever is smaller. + // This fits the majority of cases an provides a very smooth + // crossfade on tracks with a fadeout, and excellent timing + // when a track has a sharp or cold ending. + // + // (2) If the next (to) track has a fadeInLength greater than + // 0.25 seconds then the next (to) track is started a + // fadeInLength value (playNextPos) earlier than the + // current (from) deck fadeOutStart. If the fadeOutLength + + // playNextPos difference is greater than the spin box, + // then revert to item 1 above using (fixed value) calculated + // from fadeOutLength. This covers the case where we have a + // slow fade-in of a song, for example, when Boston's "More + // Than A Feeling", comes next after a song with a cold start, + // removing the perception of a gap, while preserving the + // cold ending. (In this example it is about 3 seconds + // earlier, though the new track is not really perceptible + // during a cold ending). Note that the crossfader holds + // in the center while the next (to) track starts, and + // starts moving the fader once fadeOutStart is reached. + // + // (3) If the next (to) track has a duration of less than 15 + // seconds then this track is likely a jingle or sample. + // In which case the fadeInLength is 0 and the fadeOutLength + // is 1. This way we have a fast neat transition while + // maximizing the time for the next track to load. + + pToDeck->fadeBeginPos = toDeckEndPosition; + m_crossfaderStartCenter = true; + // Make sure we start at the center of the crossfader so the track starts at full volume + + // some safety in case user changes transition mode. + pToDeck->fadeEndPos = getLastSoundSecond(pToDeck); + pToDeck->fadeBeginPos = getFadeOutSecond(pToDeck); + if (pToDeck->fadeBeginPos == 0.0) { + pToDeck->fadeBeginPos = pToDeck->fadeEndPos; + } + + // Calculate fade in values + double fadeInStart = getMainCueSecond(pToDeck); + // Fix spurious values from incomplete data from early calls to calculateTransition + // where the track length/ratio has not been established correctly. + if (fadeInStart > (fromDeckEndPosition / 1.2)) { + // if we are most of the way to the end then something is broken. + fadeInStart = getFirstSoundSecond(pToDeck); + } + double fadeInEnd = getFadeInSecond(pToDeck); + if (fadeInStart > fadeInEnd) { + fadeInEnd = fadeInStart; + } + + toDeckStartSeconds = toDeckPositionSeconds; // Where the user might have positioned the cue + if (seekToStartPoint || toDeckPositionSeconds >= pToDeck->fadeBeginPos) { + // toDeckPosition >= pToDeck->fadeBeginPos happens when the + // user has sought or played the pToDeck track past the fadeBeginPos. + // In this case we re-cue the new track to the main cue position. + toDeckStartSeconds = getMainCueSecond(pToDeck); + if (toDeckPositionSeconds >= pToDeck->fadeBeginPos) { + // If this is still too far (was it just changed?) + // make the start at the first sound. + toDeckStartSeconds = fadeInStart; + } + } + + // If our fadeInEnd is near the end of the track.. then... + // we have a pathologically long fade in... + // it might be the track... it might be the db... + // ... but this happens on most calculateTransition save the last: + // There are multiple calls to calculateTransition it seems that fadeInEnd + // collects spurious data about the fade in position + // until the lat call (is pDeck->rateRatio() correct all the time?). + // Placing this here seems to prevent anything weird happening for a short + // next (to) tracks, except that we have no roll in period, of course. + if (fadeInEnd > (fromDeckEndPosition / 1.2)) { + fadeInEnd = fadeInStart; + } + + + // If we are still early (it might be a very short current track) then + // the FadeInLength is likely to end up as 0 which on a short track + // is probably OK in any event. + double fadeInLength = fadeInEnd - toDeckStartSeconds; + if (fadeInLength < 0.0) { + fadeInLength = 0.0; + } + + // Calculate fade out values + double fadeOutStart = getFadeOutSecond(pFromDeck); + double fadeOutEnd = getLastSoundSecond(pFromDeck); + if (fadeOutStart == 0) { + fadeOutStart = fadeOutEnd; + } + double fadeOutLength = fadeOutEnd - fadeOutStart; + + // getMainCueSecond(pToDeck) is also returning + // spurious values until the last calculateTransition call. + if (toDeckStartSeconds > pToDeck->fadeBeginPos) { + toDeckStartSeconds = getFirstSoundSecond(pToDeck); + } + + // Note as we get here pFromDeck->playNextPos == fromDeckEndPosition. + // We use this default to make sure that playNextPos is alway greater than + // pFromDeck->fadeBeginPos unless we really intend to start early. + + // If we have a long(ish) fade in then let's start the next track early. + if ((fadeInLength > 0) && ((fadeOutStart - fadeInLength) > 0.0)) { + pFromDeck->playNextPos = fadeOutStart - fadeInLength; + } + if (fromDeckPosition > fadeOutStart) { + // We have already passed fadeOutStart + // This can happen if we have just enabled auto DJ + fadeOutStart = fromDeckPosition; + // and make sure we don't start early twice because + // we need do it with fadeOutStart only now. + pFromDeck->playNextPos = fromDeckEndPosition; + } + pToDeck->startPos = toDeckStartSeconds; + pFromDeck->fadeBeginPos = fadeOutStart; + + if (fadeOutLength <= m_transitionTime) { + if ((toDeckDuration < fadeOutLength) || + (toDeckDuration < 15)) { + // make sure that the transition time is less than the next track duration. + // and make sure that tracks under 15 seconds will be preceded by very + // short transition. + if (toDeckDuration > 1.0) { + // if the next track is very short (say a few seconds long jingle or sweeper) + // make is a very fast fade (so we can get on with loading the next track). + if ((pFromDeck->playNextPos < (fadeOutStart - (toDeckDuration - 1))) && + (!pToDeck->isPlaying())) { + pFromDeck->playNextPos = (fadeOutStart - (toDeckDuration - 1)); + } + pFromDeck->fadeEndPos = fadeOutStart + 1; + } else { + // Just in case it is a pathologically short track - + // that really shouldn't be here by now anyway. + pFromDeck->playNextPos = fromDeckEndPosition; + pFromDeck->fadeEndPos = fadeOutStart + kMinimumTrackDurationSec; + } + } else { + // This is the general case where we want to do a fadeout when + // after (sound level last goes below) Cue:FadOut start. + // and we start early while for (the sound level starts below) the duration Cue:FadIn end. + pFromDeck->fadeEndPos = fadeOutEnd; + } + } else { + // if the fade out is longer than the max the user specified, + // just do a fixed fade out and don't start early. + pFromDeck->playNextPos = fromDeckEndPosition; + useFixedFadeTime(pFromDeck, + pToDeck, + fadeOutStart, + fadeOutStart + m_transitionTime, + toDeckStartSeconds); + } + } break; case TransitionMode::FixedFullTrack: default: { double startPoint; @@ -1501,9 +1769,12 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, // These are expected to be a fraction of the track length. pFromDeck->fadeBeginPos /= fromDeckDuration; pFromDeck->fadeEndPos /= fromDeckDuration; + pFromDeck->playNextPos /= fromDeckEndPosition; + pToDeck->startPos /= toDeckDuration; pToDeck->fadeBeginPos /= toDeckDuration; pToDeck->fadeEndPos /= toDeckDuration; + pToDeck->playNextPos /= toDeckDuration; pFromDeck->isFromDeck = true; pToDeck->isFromDeck = false; diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 654d77429f7..0acf5e5115b 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -118,6 +118,7 @@ class DeckAttributes : public QObject { int index; QString group; double startPos; // Set in toDeck nature + double playNextPos; // Needed for Radio Laneway Crossfade double fadeBeginPos; // set in fromDeck nature double fadeEndPos; // set in fromDeck nature bool isFromDeck; @@ -164,7 +165,8 @@ class AutoDJProcessor : public QObject { FadeAtOutroStart, FixedFullTrack, FixedSkipSilence, - FixedStartCenterSkipSilence + FixedStartCenterSkipSilence, + RadioLanewayCrossfade }; AutoDJProcessor(QObject* pParent, @@ -254,6 +256,9 @@ class AutoDJProcessor : public QObject { double getFirstSoundSecond(DeckAttributes* pDeck); double getLastSoundSecond(DeckAttributes* pDeck); double getEndSecond(DeckAttributes* pDeck); + double getMainCueSecond(DeckAttributes* pDeck); + double getFadeInSecond(DeckAttributes* pDeck); + double getFadeOutSecond(DeckAttributes* pDeck); double framePositionToSeconds(mixxx::audio::FramePos position, DeckAttributes* pDeck); TrackPointer getNextTrackFromQueue(); @@ -284,6 +289,7 @@ class AutoDJProcessor : public QObject { PlaylistTableModel* m_pAutoDJTableModel; AutoDJState m_eState; + bool m_isNowStartingEarly; double m_transitionProgress; double m_transitionTime; // the desired value set by the user TransitionMode m_transitionMode; diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 52e02e07b73..9bfc669a9e9 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -150,7 +150,13 @@ DlgAutoDJ::DlgAutoDJ(WLibrary* parent, "\n" "Skip Silence Start Full Volume:\n" "The same as Skip Silence, but starting transitions with a centered\n" - "crossfader, so that the intro starts at full volume.\n"); + "crossfader, so that the intro starts at full volume.\n" + "Radio Laneway Crossfade:\n" + "Starts the next track at full volume. Starts the crossfade when the\n" + "volume last falls below -12Db or at the spin box setting which ever\n" + "is lower, and potentially starts the next earlier if it starts below\n" + "-27Db.\n"); + pushButtonFadeNow->setToolTip(fadeBtnTooltip); pushButtonSkipNext->setToolTip(skipBtnTooltip); @@ -185,6 +191,8 @@ DlgAutoDJ::DlgAutoDJ(WLibrary* parent, static_cast(AutoDJProcessor::TransitionMode::FixedSkipSilence)); fadeModeCombobox->addItem(tr("Skip Silence Start Full Volume"), static_cast(AutoDJProcessor::TransitionMode::FixedStartCenterSkipSilence)); + fadeModeCombobox->addItem(tr("Radio Laneway Crossfade"), + static_cast(AutoDJProcessor::TransitionMode::RadioLanewayCrossfade)); fadeModeCombobox->setCurrentIndex( fadeModeCombobox->findData(static_cast(m_pAutoDJProcessor->getTransitionMode()))); connect(fadeModeCombobox, diff --git a/src/track/cueinfo.h b/src/track/cueinfo.h index c73eadcc1d0..d952dfa899a 100644 --- a/src/track/cueinfo.h +++ b/src/track/cueinfo.h @@ -19,6 +19,11 @@ enum class CueType { Outro = 7, N60dBSound = 8, // range that covers beginning and end of audible // sound; not shown to user + // sound; not shown to user + FadeIn = 9, // First time sound reaches a certain level + // (cf analyzersilence.cpp); not shown to user + FadeOut = 10 // Last time sound reaches a certain level + // (cf analyzersilence.cpp); not shown to user }; enum class CueFlag { diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index b434c37a0a3..4e92bb6b8cb 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -2156,6 +2156,10 @@ class ResetWaveformTrackPointerOperation : public mixxx::TrackPointerOperation { // same reasons that apply for reanalyze of the waveforms applies also // for the AudibleSound cue. pTrack->removeCuesOfType(mixxx::CueType::N60dBSound); + // FIX/TODO: + // Assumed this Should also apply? + pTrack->removeCuesOfType(mixxx::CueType::FadeIn); + pTrack->removeCuesOfType(mixxx::CueType::FadeOut); } AnalysisDao& m_analysisDao; From 810868631f3dbf183cbd6c38c269178afc38c3ad Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Thu, 10 Oct 2024 19:33:03 +0800 Subject: [PATCH 02/20] Fix code style issues (Wow this is fussy!). --- src/analyzer/analyzersilence.h | 9 ++--- src/library/autodj/autodjprocessor.cpp | 50 +++++++++++++------------- src/library/autodj/dlgautodj.cpp | 12 +++---- src/track/cueinfo.h | 3 +- 4 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index 40c38af5db4..fce88bcc391 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -34,13 +34,14 @@ class AnalyzerSilence : public Analyzer { UserSettings* pConfig); static void setupOutroCue(Track* pTrack, mixxx::audio::FramePos lastSoundPosition); - /// returns the index of the first sample in the buffer that is above the fade out threshold (e.g. -20 dB) - /// or samples.size() if no sample is found + /// returns the index of the first sample in the buffer that is above the + /// fade out threshold (e.g. -20 dB) or samples.size() if no sample is found /// TODO CHeck if 'samples.size()' is actually meaningful in this context. static SINT findLastFadeInChunk(std::span samples); - /// returns the index of the last sample in the buffer that is above that is above the fade out threshold (e.g. -20 dB) - /// or samples.size() if no sample is found + /// returns the index of the last sample in the buffer that is above that is + /// above the fade out threshold (e.g. -20 dB) or samples.size() if no + /// sample is found static SINT findFirstFadeOutChunk(std::span samples); /// returns the index of the first sample in the buffer that is above -60 dB diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index be28e089d0f..a84222af5d9 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -44,12 +44,9 @@ DeckAttributes::DeckAttributes(int index, m_sampleRate(group, "track_samplerate"), m_rateRatio(group, "rate_ratio"), m_pPlayer(pPlayer) { - connect(m_pPlayer, &BaseTrackPlayer::newTrackLoaded, - this, &DeckAttributes::slotTrackLoaded); - connect(m_pPlayer, &BaseTrackPlayer::loadingTrack, - this, &DeckAttributes::slotLoadingTrack); - connect(m_pPlayer, &BaseTrackPlayer::playerEmpty, - this, &DeckAttributes::slotPlayerEmpty); + connect(m_pPlayer, &BaseTrackPlayer::newTrackLoaded, this, &DeckAttributes::slotTrackLoaded); + connect(m_pPlayer, &BaseTrackPlayer::loadingTrack, this, &DeckAttributes::slotLoadingTrack); + connect(m_pPlayer, &BaseTrackPlayer::playerEmpty, this, &DeckAttributes::slotPlayerEmpty); m_playPos.connectValueChanged(this, &DeckAttributes::slotPlayPosChanged); m_play.connectValueChanged(this, &DeckAttributes::slotPlayChanged); m_introStartPos.connectValueChanged(this, &DeckAttributes::slotIntroStartPositionChanged); @@ -91,7 +88,7 @@ void DeckAttributes::slotTrackLoaded(TrackPointer pTrack) { } void DeckAttributes::slotLoadingTrack(TrackPointer pNewTrack, TrackPointer pOldTrack) { - //qDebug() << "DeckAttributes::slotLoadingTrack"; + // qDebug() << "DeckAttributes::slotLoadingTrack"; emit loadingTrack(this, pNewTrack, pOldTrack); } @@ -134,8 +131,7 @@ AutoDJProcessor::AutoDJProcessor( m_pSkipNext = new ControlPushButton( ConfigKey("[AutoDJ]", "skip_next")); - connect(m_pSkipNext, &ControlObject::valueChanged, - this, &AutoDJProcessor::controlSkipNext); + connect(m_pSkipNext, &ControlObject::valueChanged, this, &AutoDJProcessor::controlSkipNext); m_pAddRandomTrack = new ControlPushButton( ConfigKey("[AutoDJ]", "add_random_track")); @@ -146,8 +142,7 @@ AutoDJProcessor::AutoDJProcessor( m_pFadeNow = new ControlPushButton( ConfigKey("[AutoDJ]", "fade_now")); - connect(m_pFadeNow, &ControlObject::valueChanged, - this, &AutoDJProcessor::controlFadeNow); + connect(m_pFadeNow, &ControlObject::valueChanged, this, &AutoDJProcessor::controlFadeNow); m_pEnabledAutoDJ = new ControlPushButton( ConfigKey("[AutoDJ]", "enabled")); @@ -368,7 +363,7 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::skipNext() { TrackId leftId = pLeftDeck->getLoadedTrack()->getId(); TrackId rightId = pRightDeck->getLoadedTrack()->getId(); if (nextId == leftId || nextId == rightId) { - // One of the playing tracks is still on top of playlist, remove second item + // One of the playing tracks is still on top of playlist, remove second item m_pAutoDJTableModel->removeTrack(m_pAutoDJTableModel->index(1, 0)); } else { m_pAutoDJTableModel->removeTrack(m_pAutoDJTableModel->index(0, 0)); @@ -675,7 +670,7 @@ void AutoDJProcessor::crossfaderChanged(double value) { } void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, - double thisPlayPosition) { + double thisPlayPosition) { // qDebug() << "player" << pAttributes->group << "PositionChanged(" << value << ")"; if (m_eState == ADJ_DISABLED) { // nothing to do @@ -839,8 +834,8 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // - transition into fading mode, play the other deck and fade to it. // - check if fading is done and stop the deck // - update the crossfader - if ((thisPlayPosition >= thisDeck->fadeBeginPos) && - thisDeck->isFromDeck && !otherDeck->loading) { + if ((thisPlayPosition >= thisDeck->fadeBeginPos) && + thisDeck->isFromDeck && !otherDeck->loading) { if (m_eState == ADJ_IDLE) { if (thisDeckPlaying || thisPlayPosition >= 1.0) { // Set the state as FADING. @@ -934,7 +929,8 @@ TrackPointer AutoDJProcessor::getNextTrackFromQueue() { bool randomQueueEnabled = m_pConfig->getValue( ConfigKey("[Auto DJ]", "EnableRandomQueue")); int minAutoDJCrateTracks = m_pConfig->getValueString( - ConfigKey(kConfigKey, "RandomQueueMinimumAllowed")).toInt(); + ConfigKey(kConfigKey, "RandomQueueMinimumAllowed")) + .toInt(); int tracksToAdd = minAutoDJCrateTracks - m_pAutoDJTableModel->rowCount(); // In case we start off with < minimum tracks if (randomQueueEnabled && (tracksToAdd > 0)) { @@ -943,7 +939,7 @@ TrackPointer AutoDJProcessor::getNextTrackFromQueue() { while (true) { TrackPointer nextTrack = m_pAutoDJTableModel->getTrack( - m_pAutoDJTableModel->index(0, 0)); + m_pAutoDJTableModel->index(0, 0)); if (nextTrack) { if (nextTrack->getFileInfo().checkFileExists()) { @@ -1022,9 +1018,11 @@ bool AutoDJProcessor::removeTrackFromTopOfQueue(TrackPointer pTrack) { void AutoDJProcessor::maybeFillRandomTracks() { int minAutoDJCrateTracks = m_pConfig->getValueString( - ConfigKey(kConfigKey, "RandomQueueMinimumAllowed")).toInt(); + ConfigKey(kConfigKey, "RandomQueueMinimumAllowed")) + .toInt(); bool randomQueueEnabled = (((m_pConfig->getValueString( - ConfigKey("[Auto DJ]", "EnableRandomQueue")).toInt())) == 1); + ConfigKey("[Auto DJ]", "EnableRandomQueue")) + .toInt())) == 1); int tracksToAdd = minAutoDJCrateTracks - m_pAutoDJTableModel->rowCount(); if (randomQueueEnabled && (tracksToAdd > 0)) { @@ -1370,13 +1368,13 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, const double fromDeckEndPosition = getEndSecond(pFromDeck); const double toDeckEndPosition = getEndSecond(pToDeck); // Make sure playNextPos is higher than fadeBeginPos by default - pFromDeck->playNextPos = fromDeckEndPosition; + pFromDeck->playNextPos = fromDeckEndPosition; // Since the end position is measured in seconds from 0:00 it is also // the track duration. Use this alias for better readability. const double fromDeckDuration = fromDeckEndPosition; const double toDeckDuration = toDeckEndPosition; // Make sure playNextPos is higher than fadeBeginPos by default - pToDeck->playNextPos = toDeckEndPosition; + pToDeck->playNextPos = toDeckEndPosition; VERIFY_OR_DEBUG_ASSERT(fromDeckDuration >= kMinimumTrackDurationSec) { // Track has no duration or too short. This should not happen, because short @@ -1661,7 +1659,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, // we have a pathologically long fade in... // it might be the track... it might be the db... // ... but this happens on most calculateTransition save the last: - // There are multiple calls to calculateTransition it seems that fadeInEnd + // There are multiple calls to calculateTransition it seems that fadeInEnd // collects spurious data about the fade in position // until the lat call (is pDeck->rateRatio() correct all the time?). // Placing this here seems to prevent anything weird happening for a short @@ -1670,7 +1668,6 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, fadeInEnd = fadeInStart; } - // If we are still early (it might be a very short current track) then // the FadeInLength is likely to end up as 0 which on a short track // is probably OK in any event. @@ -1763,7 +1760,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, startPoint = toDeckPositionSeconds; } useFixedFadeTime(pFromDeck, pToDeck, fromDeckPosition, fromDeckEndPosition, startPoint); - } + } } // These are expected to be a fraction of the track length. @@ -1897,7 +1894,8 @@ void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTra } void AutoDJProcessor::playerLoadingTrack(DeckAttributes* pDeck, - TrackPointer pNewTrack, TrackPointer pOldTrack) { + TrackPointer pNewTrack, + TrackPointer pOldTrack) { if constexpr (sDebug) { qDebug() << this << "playerLoadingTrack" << pDeck->group << "new:" << (pNewTrack ? pNewTrack->getLocation() : "(null)") @@ -1983,7 +1981,7 @@ void AutoDJProcessor::setTransitionTime(int time) { // Update the transition time first. m_pConfig->set(ConfigKey(kConfigKey, kTransitionPreferenceName), - ConfigValue(time)); + ConfigValue(time)); m_transitionTime = time; // Then re-calculate fade thresholds for the decks. diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 9bfc669a9e9..93611639b70 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -70,8 +70,9 @@ DlgAutoDJ::DlgAutoDJ(WLibrary* parent, &WTrackTableView::setSelectedClick); QBoxLayout* box = qobject_cast(layout()); - VERIFY_OR_DEBUG_ASSERT(box) { //Assumes the form layout is a QVBox/QHBoxLayout! - } else { + VERIFY_OR_DEBUG_ASSERT(box) { // Assumes the form layout is a QVBox/QHBoxLayout! + } + else { box->removeWidget(m_pTrackTablePlaceholder); m_pTrackTablePlaceholder->hide(); box->insertWidget(1, m_pTrackTableView); @@ -82,7 +83,7 @@ DlgAutoDJ::DlgAutoDJ(WLibrary* parent, m_pTrackTableView->loadTrackModel(m_pAutoDJTableModel); // Do not set this because it disables auto-scrolling - //m_pTrackTableView->setDragDropMode(QAbstractItemView::InternalMove); + // m_pTrackTableView->setDragDropMode(QAbstractItemView::InternalMove); connect(pushButtonAutoDJ, &QPushButton::clicked, @@ -152,12 +153,11 @@ DlgAutoDJ::DlgAutoDJ(WLibrary* parent, "The same as Skip Silence, but starting transitions with a centered\n" "crossfader, so that the intro starts at full volume.\n" "Radio Laneway Crossfade:\n" - "Starts the next track at full volume. Starts the crossfade when the\n" - "volume last falls below -12Db or at the spin box setting which ever\n" + "Starts the next track at full volume. Starts the crossfade when the\n" + "volume last falls below -12Db or at the spin box setting which ever\n" "is lower, and potentially starts the next earlier if it starts below\n" "-27Db.\n"); - pushButtonFadeNow->setToolTip(fadeBtnTooltip); pushButtonSkipNext->setToolTip(skipBtnTooltip); pushButtonShuffle->setToolTip(shuffleBtnTooltip); diff --git a/src/track/cueinfo.h b/src/track/cueinfo.h index d952dfa899a..401fc8df38f 100644 --- a/src/track/cueinfo.h +++ b/src/track/cueinfo.h @@ -19,10 +19,9 @@ enum class CueType { Outro = 7, N60dBSound = 8, // range that covers beginning and end of audible // sound; not shown to user - // sound; not shown to user FadeIn = 9, // First time sound reaches a certain level // (cf analyzersilence.cpp); not shown to user - FadeOut = 10 // Last time sound reaches a certain level + FadeOut = 10 // Last time sound reaches a certain level // (cf analyzersilence.cpp); not shown to user }; From eaa9f8e54f86fc76188d6b73c2623a12cc9b7fd9 Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Thu, 10 Oct 2024 19:36:54 +0800 Subject: [PATCH 03/20] Update autodjprocessor.cpp More style issues. --- src/library/autodj/autodjprocessor.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index a84222af5d9..82062b758fb 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1691,7 +1691,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } // Note as we get here pFromDeck->playNextPos == fromDeckEndPosition. - // We use this default to make sure that playNextPos is alway greater than + // We use this default to make sure that playNextPos is always greater than // pFromDeck->fadeBeginPos unless we really intend to start early. // If we have a long(ish) fade in then let's start the next track early. @@ -1732,7 +1732,8 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } else { // This is the general case where we want to do a fadeout when // after (sound level last goes below) Cue:FadOut start. - // and we start early while for (the sound level starts below) the duration Cue:FadIn end. + // and we start early while for (the sound level starts below) + // the duration Cue:FadIn end. pFromDeck->fadeEndPos = fadeOutEnd; } } else { From 134d99bbbb3a780cc816d92bf5ac14453cdf0b2d Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Thu, 10 Oct 2024 19:41:08 +0800 Subject: [PATCH 04/20] Update analyzersilence.h Yet more code style issues (Space at end of line.) --- src/analyzer/analyzersilence.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index fce88bcc391..2798a5b1ff5 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -34,13 +34,13 @@ class AnalyzerSilence : public Analyzer { UserSettings* pConfig); static void setupOutroCue(Track* pTrack, mixxx::audio::FramePos lastSoundPosition); - /// returns the index of the first sample in the buffer that is above the + /// returns the index of the first sample in the buffer that is above the /// fade out threshold (e.g. -20 dB) or samples.size() if no sample is found /// TODO CHeck if 'samples.size()' is actually meaningful in this context. static SINT findLastFadeInChunk(std::span samples); - /// returns the index of the last sample in the buffer that is above that is - /// above the fade out threshold (e.g. -20 dB) or samples.size() if no + /// returns the index of the last sample in the buffer that is above that is + /// above the fade out threshold (e.g. -20 dB) or samples.size() if no /// sample is found static SINT findFirstFadeOutChunk(std::span samples); From 1ddbc876b960baf183376eebed1bee3842074554 Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Thu, 10 Oct 2024 23:54:13 +0800 Subject: [PATCH 05/20] Missing case in cueinfo.cpp More Code tidy Missing case in cueinfo.cpp --- src/analyzer/analyzersilence.cpp | 3 +-- src/track/cueinfo.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 6d53f972ab2..e3df817d0e0 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -10,7 +10,7 @@ namespace { // 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); +// constexpr CSAMPLE kSilenceThreshold = db2ratio(-60.0f); // These are in dBV expressed as Volts RMS (which seems, sensibly, // the way Mixxx works). @@ -31,7 +31,6 @@ constexpr CSAMPLE kSilenceThreshold = 0.001f; // -60 dB constexpr CSAMPLE kFadeInThreshold = N_27DB_FADEOUT_THRESHOLD; constexpr CSAMPLE kFadeOutThreshold = N_12DB_FADEOUT_THRESHOLD; - bool shouldAnalyze(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(mixxx::CueType::Intro); CuePointer pOutroCue = pTrack->findCueByType(mixxx::CueType::Outro); diff --git a/src/track/cueinfo.cpp b/src/track/cueinfo.cpp index 20d7ea11a0b..2b6064afe75 100644 --- a/src/track/cueinfo.cpp +++ b/src/track/cueinfo.cpp @@ -148,6 +148,12 @@ QDebug operator<<(QDebug debug, const CueType& cueType) { case CueType::N60dBSound: debug << "CueType::N60dBSound"; break; + case CueType::FadeIn: + debug << "CueType::FadeIn"; + break; + case CueType::FadeOut: + debug << "CueType::FadeOut"; + break; } return debug; } From 1e2bab4b59f5b5ed79c3b2d8e3ec357f56b2253e Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Fri, 11 Oct 2024 00:02:50 +0800 Subject: [PATCH 06/20] Update analyzersilence.cpp Code style --- src/analyzer/analyzersilence.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index e3df817d0e0..2aacfa60768 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -38,7 +38,8 @@ bool shouldAnalyze(TrackPointer pTrack) { CuePointer pFadeIn = pTrack->findCueByType(mixxx::CueType::FadeIn); CuePointer pFadeOut = pTrack->findCueByType(mixxx::CueType::FadeOut); - if (!pFadeIn || !pFadeOut || !pIntroCue || !pOutroCue || !pN60dBSound || pN60dBSound->getLengthFrames() <= 0) { + if (!pFadeIn || !pFadeOut || !pIntroCue || !pOutroCue || !pN60dBSound || + pN60dBSound->getLengthFrames() <= 0) { return true; } return false; @@ -112,7 +113,10 @@ SINT AnalyzerSilence::findLastSoundInChunk(std::span samples) { // static SINT AnalyzerSilence::findFirstFadeOutChunk(std::span samples) { // -1 is required, because the distance from the fist sample index (0) to crend() is 1, - SINT ret = std::distance(first_fade_out_sound(samples.rbegin(), samples.rend()), samples.rend()) - 1; + SINT ret = std::distance( + first_fade_out_sound(samples.rbegin(), samples.rend()), + samples.rend()) - + 1; if (ret == -1) { ret = samples.size(); } @@ -161,7 +165,8 @@ bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, SINT count) { if (m_fadeThresholdFadeInEnd >= 0) { const SINT lasttSampleBeforeFadeOut = findFirstFadeOutChunk(samples); if (lasttSampleBeforeFadeOut < (count - 1)) { - m_fadeThresholdFadeOutStart = m_framesProcessed + (lasttSampleBeforeFadeOut / m_channelCount) + 1; + m_fadeThresholdFadeOutStart = m_framesProcessed + + (lasttSampleBeforeFadeOut / m_channelCount) + 1; } } if (m_fadeThresholdFadeOutStart >= 0) { From 56653d420a4ab19544cea2189d6252f68da9fa86 Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Fri, 11 Oct 2024 00:16:22 +0800 Subject: [PATCH 07/20] Update autodjprocessor.cpp Spelling --- src/library/autodj/autodjprocessor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 82062b758fb..d0fc4375136 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1731,9 +1731,9 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } } else { // This is the general case where we want to do a fadeout when - // after (sound level last goes below) Cue:FadOut start. - // and we start early while for (the sound level starts below) - // the duration Cue:FadIn end. + // after (sound level last goes below) Cue:FadOut start + // and/or we start early until (the sound level is above) + // Cue:FadeIn end. pFromDeck->fadeEndPos = fadeOutEnd; } } else { From fde372821d93eb03c2c093a34f30c58898f316b8 Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Fri, 11 Oct 2024 00:19:01 +0800 Subject: [PATCH 08/20] Update autodjprocessor.cpp --- src/library/autodj/autodjprocessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index d0fc4375136..91e8add4ff6 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1732,7 +1732,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } else { // This is the general case where we want to do a fadeout when // after (sound level last goes below) Cue:FadOut start - // and/or we start early until (the sound level is above) + // and/or we start early until (the sound level is above) // Cue:FadeIn end. pFromDeck->fadeEndPos = fadeOutEnd; } From 854eb3e9572c375b9ce27a6a8c89a6feff169067 Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Fri, 11 Oct 2024 07:58:39 +0800 Subject: [PATCH 09/20] Update cueinfo.cpp avoiding a DEBUG_ASSERT(!"Unknown Loop Type"); --- src/track/cueinfo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/track/cueinfo.cpp b/src/track/cueinfo.cpp index 2b6064afe75..6f0ec79997a 100644 --- a/src/track/cueinfo.cpp +++ b/src/track/cueinfo.cpp @@ -23,6 +23,8 @@ void assertEndPosition( case CueType::Intro: case CueType::Outro: case CueType::Invalid: + case CueType::FadeIn: + case CueType::FadeOut: break; case CueType::Beat: // unused default: From a8465fb75b55faf17021f2832d85091d65842d1c Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Fri, 11 Oct 2024 08:17:24 +0800 Subject: [PATCH 10/20] Update dlgautodj.cpp fix up tooltip --- src/library/autodj/dlgautodj.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 93611639b70..9c115986128 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -152,11 +152,12 @@ DlgAutoDJ::DlgAutoDJ(WLibrary* parent, "Skip Silence Start Full Volume:\n" "The same as Skip Silence, but starting transitions with a centered\n" "crossfader, so that the intro starts at full volume.\n" + "\n" "Radio Laneway Crossfade:\n" "Starts the next track at full volume. Starts the crossfade when the\n" "volume last falls below -12Db or at the spin box setting which ever\n" "is lower, and potentially starts the next earlier if it starts below\n" - "-27Db.\n"); + "-27Db."); pushButtonFadeNow->setToolTip(fadeBtnTooltip); pushButtonSkipNext->setToolTip(skipBtnTooltip); From 8f5dcd87c22111cdc63f7848b031aeadf5d52bd6 Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Mon, 14 Oct 2024 09:56:12 +0800 Subject: [PATCH 11/20] Code style format (yet again) and removal of commented code. --- src/analyzer/analyzersilence.cpp | 6 +----- src/library/autodj/dlgautodj.cpp | 3 +-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 2aacfa60768..9f4e6366e95 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -115,8 +115,7 @@ SINT AnalyzerSilence::findFirstFadeOutChunk(std::span samples) { // -1 is required, because the distance from the fist sample index (0) to crend() is 1, SINT ret = std::distance( first_fade_out_sound(samples.rbegin(), samples.rend()), - samples.rend()) - - 1; + samples.rend()) - 1; if (ret == -1) { ret = samples.size(); } @@ -126,9 +125,6 @@ SINT AnalyzerSilence::findFirstFadeOutChunk(std::span samples) { // static SINT AnalyzerSilence::findLastFadeInChunk(std::span samples) { SINT ret = std::distance(samples.begin(), last_fade_in_sound(samples.begin(), samples.end())); - // if (ret == samples.size()) { - // ret = 0; - // } return ret; } diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 9c115986128..539ece414fa 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -71,8 +71,7 @@ DlgAutoDJ::DlgAutoDJ(WLibrary* parent, QBoxLayout* box = qobject_cast(layout()); VERIFY_OR_DEBUG_ASSERT(box) { // Assumes the form layout is a QVBox/QHBoxLayout! - } - else { + } else { box->removeWidget(m_pTrackTablePlaceholder); m_pTrackTablePlaceholder->hide(); box->insertWidget(1, m_pTrackTableView); From d25c6552c68bed8d1acdf5db8c77767de27a10e9 Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Mon, 14 Oct 2024 10:02:50 +0800 Subject: [PATCH 12/20] Reverting the reverted code styling --- src/analyzer/analyzersilence.cpp | 3 ++- src/library/autodj/dlgautodj.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 9f4e6366e95..e37c81dcbac 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -115,7 +115,8 @@ SINT AnalyzerSilence::findFirstFadeOutChunk(std::span samples) { // -1 is required, because the distance from the fist sample index (0) to crend() is 1, SINT ret = std::distance( first_fade_out_sound(samples.rbegin(), samples.rend()), - samples.rend()) - 1; + samples.rend()) - + 1; if (ret == -1) { ret = samples.size(); } diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 539ece414fa..9c115986128 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -71,7 +71,8 @@ DlgAutoDJ::DlgAutoDJ(WLibrary* parent, QBoxLayout* box = qobject_cast(layout()); VERIFY_OR_DEBUG_ASSERT(box) { // Assumes the form layout is a QVBox/QHBoxLayout! - } else { + } + else { box->removeWidget(m_pTrackTablePlaceholder); m_pTrackTablePlaceholder->hide(); box->insertWidget(1, m_pTrackTableView); From 8248b9896218c1f91a60bed03265282c00fa3a50 Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Thu, 17 Oct 2024 11:12:15 +0800 Subject: [PATCH 13/20] Update analyzersilence.cpp --- src/analyzer/analyzersilence.cpp | 74 +++++++++++++------------------- 1 file changed, 31 insertions(+), 43 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index e37c81dcbac..63196c6adc5 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -17,19 +17,19 @@ constexpr CSAMPLE kSilenceThreshold = 0.001f; // -60 dB // Don't change these to const as they are used only to feed the // fade thresholds which are consts below themselves while we work // out which one is best, and you'll just be adding to exe size. -#define N_10DB_FADEOUT_THRESHOLD 0.3162f -#define N_12DB_FADEOUT_THRESHOLD 0.2511f -#define N_15DB_FADEOUT_THRESHOLD 0.1778f -#define N_18DB_FADEOUT_THRESHOLD 0.1259f -#define N_20DB_FADEOUT_THRESHOLD 0.1f -#define N_24DB_FADEOUT_THRESHOLD 0.0631f -#define N_25DB_FADEOUT_THRESHOLD 0.0562f -#define N_27DB_FADEOUT_THRESHOLD 0.0447f -#define N_30DB_FADEOUT_THRESHOLD 0.0316f -#define N_40DB_FADEOUT_THRESHOLD 0.01f - -constexpr CSAMPLE kFadeInThreshold = N_27DB_FADEOUT_THRESHOLD; -constexpr CSAMPLE kFadeOutThreshold = N_12DB_FADEOUT_THRESHOLD; +#define N_10DB_FADE_THRESHOLD 0.3162f +#define N_12DB_FADE_THRESHOLD 0.2511f +#define N_15DB_FADE_THRESHOLD 0.1778f +#define N_18DB_FADE_THRESHOLD 0.1259f +#define N_20DB_FADE_THRESHOLD 0.1f +#define N_24DB_FADE_THRESHOLD 0.0631f +#define N_25DB_FADE_THRESHOLD 0.0562f +#define N_27DB_FADE_THRESHOLD 0.0447f +#define N_30DB_FADE_THRESHOLD 0.0316f +#define N_40DB_FADE_THRESHOLD 0.01f + +constexpr CSAMPLE kFadeInThreshold = N_27DB_FADE_THRESHOLD; +constexpr CSAMPLE kFadeOutThreshold = N_12DB_FADE_THRESHOLD; bool shouldAnalyze(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(mixxx::CueType::Intro); @@ -45,27 +45,14 @@ 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; +template +Iterator find_first_above_threshold(Iterator begin, + Iterator end, + Threshold threshold) { + return std::find_if(begin, end, [threshold](const auto elem) { + return fabs(elem) >= threshold; }); } - -template -ForwardIterator last_fade_in_sound(ForwardIterator begin, ForwardIterator end) { - return std::find_if(begin, end, [](const auto elem) { - return fabs(elem) >= kFadeInThreshold; - }); -} - -template -Iterator first_fade_out_sound(Iterator begin, Iterator end) { - return std::find_if(begin, end, [](const auto elem) { - return fabs(elem) >= kFadeOutThreshold; - }); -} - } // anonymous namespace AnalyzerSilence::AnalyzerSilence(UserSettingsPointer pConfig) @@ -100,35 +87,36 @@ bool AnalyzerSilence::initialize(const AnalyzerTrack& track, // static SINT AnalyzerSilence::findFirstSoundInChunk(std::span samples) { - return std::distance(samples.begin(), first_sound(samples.begin(), samples.end())); + return std::distance(samples.begin(), find_first_above_threshold(samples.begin(), samples.end(), kSilenceThreshold)); } // static SINT AnalyzerSilence::findLastSoundInChunk(std::span samples) { // -1 is required, because the distance from the fist sample index (0) to crend() is 1, - SINT ret = std::distance(first_sound(samples.rbegin(), samples.rend()), samples.rend()) - 1; + SINT ret = std::distance(find_first_above_threshold(samples.rbegin(), samples.rend(), kSilenceThreshold), samples.rend()) - 1; return ret; } -// static +// Find the number of first sound sample where the sound is above kFadeInThreshold (-27db) +SINT AnalyzerSilence::findLastFadeInChunk(std::span samples) { + SINT ret = std::distance(samples.begin(), find_first_above_threshold(samples.begin(), samples.end(), kFadeInThreshold)); + return ret; +} + +// Find the number of last sound sample where the sound is above kFadeOutThreshold (-12db) SINT AnalyzerSilence::findFirstFadeOutChunk(std::span samples) { - // -1 is required, because the distance from the fist sample index (0) to crend() is 1, + // Note we are searching backwards from the end here. SINT ret = std::distance( - first_fade_out_sound(samples.rbegin(), samples.rend()), + find_first_above_threshold(samples.rbegin(), samples.rend(), kFadeOutThreshold), samples.rend()) - 1; + // if we don't find it (track only partially loaded - and/or pathological) give us the track size. if (ret == -1) { ret = samples.size(); } return ret; } -// static -SINT AnalyzerSilence::findLastFadeInChunk(std::span samples) { - SINT ret = std::distance(samples.begin(), last_fade_in_sound(samples.begin(), samples.end())); - return ret; -} - // static bool AnalyzerSilence::verifyFirstSound( std::span samples, From e8e9854688349b3a4da47544c83f3fc3ff43bc9e Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Thu, 17 Oct 2024 11:17:02 +0800 Subject: [PATCH 14/20] Update analyzersilence.cpp Yet more code format issues. --- src/analyzer/analyzersilence.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 63196c6adc5..1a1a4924729 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -106,11 +106,13 @@ SINT AnalyzerSilence::findLastFadeInChunk(std::span samples) { // Find the number of last sound sample where the sound is above kFadeOutThreshold (-12db) SINT AnalyzerSilence::findFirstFadeOutChunk(std::span samples) { // Note we are searching backwards from the end here. - SINT ret = std::distance( - find_first_above_threshold(samples.rbegin(), samples.rend(), kFadeOutThreshold), + SINT ret = std::distance(find_first_above_threshold(samples.rbegin(), + samples.rend(), + kFadeOutThreshold), samples.rend()) - 1; - // if we don't find it (track only partially loaded - and/or pathological) give us the track size. + // if we don't find it (track only partially loaded - and/or pathological) + // give us the track size. if (ret == -1) { ret = samples.size(); } From a37bbf8acb30f406090bfe65cc66a42a7bca925b Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Thu, 17 Oct 2024 11:24:38 +0800 Subject: [PATCH 15/20] Update analyzersilence.cpp Yet even more code style issues. --- src/analyzer/analyzersilence.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 1a1a4924729..fceefa82ad0 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -87,19 +87,27 @@ bool AnalyzerSilence::initialize(const AnalyzerTrack& track, // static SINT AnalyzerSilence::findFirstSoundInChunk(std::span samples) { - return std::distance(samples.begin(), find_first_above_threshold(samples.begin(), samples.end(), kSilenceThreshold)); + return std::distance(samples.begin(), + find_first_above_threshold( + samples.begin(), samples.end(), kSilenceThreshold)); } // static SINT AnalyzerSilence::findLastSoundInChunk(std::span samples) { // -1 is required, because the distance from the fist sample index (0) to crend() is 1, - SINT ret = std::distance(find_first_above_threshold(samples.rbegin(), samples.rend(), kSilenceThreshold), samples.rend()) - 1; + SINT ret = std::distance(find_first_above_threshold(samples.rbegin(), + samples.rend(), + kSilenceThreshold), + samples.rend()) - + 1; return ret; } // Find the number of first sound sample where the sound is above kFadeInThreshold (-27db) SINT AnalyzerSilence::findLastFadeInChunk(std::span samples) { - SINT ret = std::distance(samples.begin(), find_first_above_threshold(samples.begin(), samples.end(), kFadeInThreshold)); + SINT ret = std::distance(samples.begin(), + find_first_above_threshold( + samples.begin(), samples.end(), kFadeInThreshold)); return ret; } From 21290116d11515da7f7bbb02bd25099e95b8e2ad Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Thu, 17 Oct 2024 12:23:51 +0800 Subject: [PATCH 16/20] Update analyzersilence.h Comment correction --- src/analyzer/analyzersilence.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index 2798a5b1ff5..0595db82901 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -35,12 +35,11 @@ class AnalyzerSilence : public Analyzer { static void setupOutroCue(Track* pTrack, mixxx::audio::FramePos lastSoundPosition); /// returns the index of the first sample in the buffer that is above the - /// fade out threshold (e.g. -20 dB) or samples.size() if no sample is found - /// TODO CHeck if 'samples.size()' is actually meaningful in this context. + /// fade in threshold (e.g. -27 dB). static SINT findLastFadeInChunk(std::span samples); - /// returns the index of the last sample in the buffer that is above that is - /// above the fade out threshold (e.g. -20 dB) or samples.size() if no + /// returns the index of the last sample in the buffer that is + /// above the fade out threshold (e.g. -12 dB) or samples.size() if no /// sample is found static SINT findFirstFadeOutChunk(std::span samples); From 6ac0c2208e025f3fdb72f57d015df516f0cee78f Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Sat, 19 Oct 2024 13:14:21 +0800 Subject: [PATCH 17/20] analyzersilence.cpp cf regression pull 13545 Adjust lasttSampleBeforeFadeOut (and avoid a regression with lastSoundSample) to bring it into line with https://github.com/mixxxdj/mixxx/pull/13545 (I assume I was working off an older code base.) --- src/analyzer/analyzersilence.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index fceefa82ad0..d8607c47e13 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -119,11 +119,6 @@ SINT AnalyzerSilence::findFirstFadeOutChunk(std::span samples) { kFadeOutThreshold), samples.rend()) - 1; - // if we don't find it (track only partially loaded - and/or pathological) - // give us the track size. - if (ret == -1) { - ret = samples.size(); - } return ret; } @@ -159,14 +154,14 @@ bool AnalyzerSilence::processSamples(const CSAMPLE* pIn, SINT count) { } if (m_fadeThresholdFadeInEnd >= 0) { const SINT lasttSampleBeforeFadeOut = findFirstFadeOutChunk(samples); - if (lasttSampleBeforeFadeOut < (count - 1)) { + if (lasttSampleBeforeFadeOut >= 0) { m_fadeThresholdFadeOutStart = m_framesProcessed + (lasttSampleBeforeFadeOut / m_channelCount) + 1; } } if (m_fadeThresholdFadeOutStart >= 0) { const SINT lastSoundSample = findLastSoundInChunk(samples); - if (lastSoundSample < (count - 1)) { // not only sound or silence + if (lastSoundSample >= 0) { m_signalEnd = m_framesProcessed + (lastSoundSample / m_channelCount) + 1; } } From f2cd61be6180613fa2b2ecc12081d93dd4e3d3bd Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Mon, 18 Nov 2024 17:22:39 +0800 Subject: [PATCH 18/20] Update analyzersilence.cpp Fix some comments --- src/analyzer/analyzersilence.cpp | 38 +++++++++++++++----------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index d8607c47e13..ae5893bf7a8 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -12,24 +12,22 @@ constexpr CSAMPLE kSilenceThreshold = 0.001f; // -60 dB // TODO: Change the above line to: // constexpr CSAMPLE kSilenceThreshold = db2ratio(-60.0f); -// These are in dBV expressed as Volts RMS (which seems, sensibly, -// the way Mixxx works). -// Don't change these to const as they are used only to feed the -// fade thresholds which are consts below themselves while we work -// out which one is best, and you'll just be adding to exe size. -#define N_10DB_FADE_THRESHOLD 0.3162f -#define N_12DB_FADE_THRESHOLD 0.2511f -#define N_15DB_FADE_THRESHOLD 0.1778f -#define N_18DB_FADE_THRESHOLD 0.1259f -#define N_20DB_FADE_THRESHOLD 0.1f -#define N_24DB_FADE_THRESHOLD 0.0631f -#define N_25DB_FADE_THRESHOLD 0.0562f -#define N_27DB_FADE_THRESHOLD 0.0447f -#define N_30DB_FADE_THRESHOLD 0.0316f -#define N_40DB_FADE_THRESHOLD 0.01f - -constexpr CSAMPLE kFadeInThreshold = N_27DB_FADE_THRESHOLD; -constexpr CSAMPLE kFadeOutThreshold = N_12DB_FADE_THRESHOLD; +// This comment can be deleted for full release. +// Some other values in case. These are in dBV expressed as Volts RMS +// (which seems, sensibly, the way Mixxx works). +// N_10DB_FADE_THRESHOLD 0.3162f +// N_12DB_FADE_THRESHOLD 0.2511f +// N_15DB_FADE_THRESHOLD 0.1778f +// N_18DB_FADE_THRESHOLD 0.1259f +// N_20DB_FADE_THRESHOLD 0.1f +// N_24DB_FADE_THRESHOLD 0.0631f +// N_25DB_FADE_THRESHOLD 0.0562f +// N_27DB_FADE_THRESHOLD 0.0447f +// N_30DB_FADE_THRESHOLD 0.0316f +// N_40DB_FADE_THRESHOLD 0.01f + +constexpr CSAMPLE kFadeInThreshold = 0.0447f; +constexpr CSAMPLE kFadeOutThreshold = 0.2511f; bool shouldAnalyze(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(mixxx::CueType::Intro); @@ -103,7 +101,7 @@ SINT AnalyzerSilence::findLastSoundInChunk(std::span samples) { return ret; } -// Find the number of first sound sample where the sound is above kFadeInThreshold (-27db) +// Find the index of first sound sample where the sound is above kFadeInThreshold (-27db) SINT AnalyzerSilence::findLastFadeInChunk(std::span samples) { SINT ret = std::distance(samples.begin(), find_first_above_threshold( @@ -111,7 +109,7 @@ SINT AnalyzerSilence::findLastFadeInChunk(std::span samples) { return ret; } -// Find the number of last sound sample where the sound is above kFadeOutThreshold (-12db) +// Find the index of last sound sample where the sound is above kFadeOutThreshold (-12db) SINT AnalyzerSilence::findFirstFadeOutChunk(std::span samples) { // Note we are searching backwards from the end here. SINT ret = std::distance(find_first_above_threshold(samples.rbegin(), From 2d369752a4a778eaac96d9578213f4d55bfdc76e Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Mon, 18 Nov 2024 17:26:36 +0800 Subject: [PATCH 19/20] Update analyzersilence.cpp Line endings yet AGAIN! --- src/analyzer/analyzersilence.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index ae5893bf7a8..b29c7241e31 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -13,7 +13,7 @@ constexpr CSAMPLE kSilenceThreshold = 0.001f; // -60 dB // constexpr CSAMPLE kSilenceThreshold = db2ratio(-60.0f); // This comment can be deleted for full release. -// Some other values in case. These are in dBV expressed as Volts RMS +// Some other values in case. These are in dBV expressed as Volts RMS // (which seems, sensibly, the way Mixxx works). // N_10DB_FADE_THRESHOLD 0.3162f // N_12DB_FADE_THRESHOLD 0.2511f From ccb4f99396b87f499134431313898a8a2c72fcec Mon Sep 17 00:00:00 2001 From: davidlmorris Date: Sat, 23 Nov 2024 09:46:42 +0800 Subject: [PATCH 20/20] Comment changes Comment changes --- src/analyzer/analyzersilence.cpp | 4 ++-- src/track/cueinfo.h | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index b29c7241e31..0cfe9b24b9e 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -26,8 +26,8 @@ constexpr CSAMPLE kSilenceThreshold = 0.001f; // -60 dB // N_30DB_FADE_THRESHOLD 0.0316f // N_40DB_FADE_THRESHOLD 0.01f -constexpr CSAMPLE kFadeInThreshold = 0.0447f; -constexpr CSAMPLE kFadeOutThreshold = 0.2511f; +constexpr CSAMPLE kFadeInThreshold = 0.0447f; // -27 dBV +constexpr CSAMPLE kFadeOutThreshold = 0.2511f; // -12 dBV bool shouldAnalyze(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(mixxx::CueType::Intro); diff --git a/src/track/cueinfo.h b/src/track/cueinfo.h index 401fc8df38f..b31f0d59f90 100644 --- a/src/track/cueinfo.h +++ b/src/track/cueinfo.h @@ -19,10 +19,14 @@ enum class CueType { Outro = 7, N60dBSound = 8, // range that covers beginning and end of audible // sound; not shown to user - FadeIn = 9, // First time sound reaches a certain level - // (cf analyzersilence.cpp); not shown to user - FadeOut = 10 // Last time sound reaches a certain level - // (cf analyzersilence.cpp); not shown to user + FadeIn = 9, // Range from start of track to the first sample in + // the track where the sound volume was above the + // kFadeInThreshold (cf analyzersilence.cpp); + // not shown to user + FadeOut = 10 // Range from the last sample in the track where + // the sound volume was above the kFadeOutThreshold + // to the end of the track (cf analyzersilence.cpp); + // not shown to user }; enum class CueFlag {