File indexing completed on 2024-04-28 04:51:59
0001 /* 0002 SPDX-FileCopyrightText: 2012 Simon A. Eugster (Granjow) <simon.eu@gmail.com> 0003 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 */ 0005 0006 #include "audioCorrelation.h" 0007 #include "fftCorrelation.h" 0008 0009 #include "kdenlive_debug.h" 0010 #include "klocalizedstring.h" 0011 #include <QElapsedTimer> 0012 #include <cmath> 0013 #include <iostream> 0014 0015 AudioCorrelation::AudioCorrelation(std::unique_ptr<AudioEnvelope> mainTrackEnvelope) 0016 : m_mainTrackEnvelope(std::move(mainTrackEnvelope)) 0017 { 0018 // Q_ASSERT(!mainTrackEnvelope->hasComputationStarted()); 0019 connect(m_mainTrackEnvelope.get(), &AudioEnvelope::envelopeReady, this, &AudioCorrelation::slotAnnounceEnvelope); 0020 m_mainTrackEnvelope->startComputeEnvelope(); 0021 } 0022 0023 AudioCorrelation::~AudioCorrelation() 0024 { 0025 for (AudioEnvelope *envelope : qAsConst(m_children)) { 0026 delete envelope; 0027 } 0028 for (AudioCorrelationInfo *info : qAsConst(m_correlations)) { 0029 delete info; 0030 } 0031 0032 qCDebug(KDENLIVE_LOG) << "Envelope deleted."; 0033 } 0034 0035 void AudioCorrelation::slotAnnounceEnvelope() 0036 { 0037 Q_EMIT displayMessage(i18n("Audio analysis finished"), OperationCompletedMessage, 300); 0038 } 0039 0040 void AudioCorrelation::addChild(AudioEnvelope *envelope) 0041 { 0042 // We need to connect before starting the computation, to make sure 0043 // there is no race condition where the signal 'envelopeReady' is 0044 // lost. 0045 Q_ASSERT(!envelope->hasComputationStarted()); 0046 connect(envelope, &AudioEnvelope::envelopeReady, this, &AudioCorrelation::slotProcessChild); 0047 envelope->startComputeEnvelope(); 0048 } 0049 0050 void AudioCorrelation::slotProcessChild(AudioEnvelope *envelope) 0051 { 0052 // Note that at this point the computation of the envelope of the 0053 // main track might not be finished. envelope() will block until 0054 // the computation is done. 0055 const size_t sizeMain = m_mainTrackEnvelope->envelope().size(); 0056 const size_t sizeSub = envelope->envelope().size(); 0057 0058 auto *info = new AudioCorrelationInfo(sizeMain, sizeSub); 0059 qint64 *correlation = info->correlationVector(); 0060 0061 const std::vector<qint64> &envMain = m_mainTrackEnvelope->envelope(); 0062 const std::vector<qint64> &envSub = envelope->envelope(); 0063 qint64 max = 0; 0064 0065 if (sizeSub > 200) { 0066 FFTCorrelation::correlate(&envMain[0], sizeMain, &envSub[0], sizeSub, correlation); 0067 } else { 0068 correlate(&envMain[0], sizeMain, &envSub[0], sizeSub, correlation, &max); 0069 info->setMax(max); 0070 } 0071 0072 m_children.append(envelope); 0073 m_correlations.append(info); 0074 0075 Q_ASSERT(m_correlations.size() == m_children.size()); 0076 int index = m_children.indexOf(envelope); 0077 int shift = getShift(index); 0078 Q_EMIT gotAudioAlignData(envelope->clipId(), shift); 0079 } 0080 0081 int AudioCorrelation::getShift(int childIndex) const 0082 { 0083 Q_ASSERT(childIndex >= 0); 0084 Q_ASSERT(childIndex < m_correlations.size()); 0085 0086 size_t indexOffset = m_correlations.at(childIndex)->maxIndex(); 0087 indexOffset -= m_children.at(childIndex)->envelope().size(); 0088 indexOffset += m_children.at(childIndex)->offset(); 0089 0090 return int(indexOffset); 0091 } 0092 0093 AudioCorrelationInfo const *AudioCorrelation::info(int childIndex) const 0094 { 0095 Q_ASSERT(childIndex >= 0); 0096 Q_ASSERT(childIndex < m_correlations.size()); 0097 0098 return m_correlations.at(childIndex); 0099 } 0100 0101 void AudioCorrelation::correlate(const qint64 *envMain, size_t sizeMain, const qint64 *envSub, size_t sizeSub, qint64 *correlation, qint64 *out_max) 0102 { 0103 Q_ASSERT(correlation != nullptr); 0104 0105 qint64 const *left; 0106 qint64 const *right; 0107 size_t size; 0108 qint64 sum; 0109 qint64 max = 0; 0110 0111 /* 0112 Correlation: 0113 0114 SHIFT \in [-sS..sM] 0115 0116 <--sS---- 0117 [ sub ]----sM--->[ sub ] 0118 [ main ] 0119 0120 ^ correlation vector index = SHIFT + sS 0121 0122 main is fixed, sub is shifted along main. 0123 0124 */ 0125 0126 QElapsedTimer t; 0127 t.start(); 0128 for (size_t shift = -sizeSub; shift <= sizeMain; ++shift) { 0129 0130 if (shift == 0) { 0131 left = envSub - shift; 0132 right = envMain; 0133 size = std::min(sizeSub + shift, sizeMain); 0134 } else { 0135 left = envSub; 0136 right = envMain + shift; 0137 size = std::min(sizeSub, sizeMain - shift); 0138 } 0139 0140 sum = 0; 0141 for (size_t i = 0; i < size; ++i) { 0142 sum += (*left) * (*right); 0143 left++; 0144 right++; 0145 } 0146 correlation[sizeSub + shift] = qAbs(sum); 0147 0148 if (sum > max) { 0149 max = sum; 0150 } 0151 } 0152 qCDebug(KDENLIVE_LOG) << "Correlation calculated. Time taken: " << t.elapsed() << " ms."; 0153 0154 if (out_max != nullptr) { 0155 *out_max = max; 0156 } 0157 }