]> git.sesse.net Git - kdenlive/blob - src/lib/audio/audioCorrelation.cpp
2e3219b7561b5c8608cc0df7eba87d1d4a594235
[kdenlive] / src / lib / audio / audioCorrelation.cpp
1 /*
2 Copyright (C) 2012  Simon A. Eugster (Granjow)  <simon.eu@gmail.com>
3 This file is part of kdenlive. See www.kdenlive.org.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 */
10
11 #include "audioCorrelation.h"
12 #include "fftCorrelation.h"
13
14 #include <QTime>
15 #include <cmath>
16 #include <iostream>
17
18 AudioCorrelation::AudioCorrelation(AudioEnvelope *mainTrackEnvelope) :
19     m_mainTrackEnvelope(mainTrackEnvelope)
20 {
21     m_mainTrackEnvelope->normalizeEnvelope();
22 }
23
24 AudioCorrelation::~AudioCorrelation()
25 {
26     delete m_mainTrackEnvelope;
27     foreach (AudioEnvelope *envelope, m_children) {
28         delete envelope;
29     }
30     foreach (AudioCorrelationInfo *info, m_correlations) {
31         delete info;
32     }
33
34     std::cout << "Envelope deleted." << std::endl;
35 }
36
37 int AudioCorrelation::addChild(AudioEnvelope *envelope, bool useFFT)
38 {
39     envelope->normalizeEnvelope();
40
41     const int sizeMain = m_mainTrackEnvelope->envelopeSize();
42     const int sizeSub = envelope->envelopeSize();
43
44     AudioCorrelationInfo *info = new AudioCorrelationInfo(sizeMain, sizeSub);
45     int64_t *correlation = info->correlationVector();
46
47     const int64_t *envMain = m_mainTrackEnvelope->envelope();
48     const int64_t *envSub = envelope->envelope();
49     int64_t max = 0;
50
51     if (useFFT) {
52         FFTCorrelation::correlate(envMain, sizeMain,
53                                   envSub, sizeSub,
54                                   correlation);
55     } else {
56         correlate(envMain, sizeMain,
57                   envSub, sizeSub,
58                   correlation,
59                   &max);
60         info->setMax(max);
61     }
62
63
64     m_children.append(envelope);
65     m_correlations.append(info);
66
67     Q_ASSERT(m_correlations.size() == m_children.size());
68
69     return m_children.indexOf(envelope);
70 }
71
72 int AudioCorrelation::getShift(int childIndex) const
73 {
74     Q_ASSERT(childIndex >= 0);
75     Q_ASSERT(childIndex < m_correlations.size());
76
77     int indexOffset = m_correlations.at(childIndex)->maxIndex();
78     indexOffset -= m_children.at(childIndex)->envelopeSize();
79
80     return indexOffset;
81 }
82
83 AudioCorrelationInfo const* AudioCorrelation::info(int childIndex) const
84 {
85     Q_ASSERT(childIndex >= 0);
86     Q_ASSERT(childIndex < m_correlations.size());
87
88     return m_correlations.at(childIndex);
89 }
90
91
92 void AudioCorrelation::correlate(const int64_t *envMain, int sizeMain,
93                                  const int64_t *envSub, int sizeSub,
94                                  int64_t *correlation,
95                                  int64_t *out_max)
96 {
97     Q_ASSERT(correlation != NULL);
98
99     int64_t const* left;
100     int64_t const* right;
101     int size;
102     int64_t sum;
103     int64_t max = 0;
104
105
106     /*
107       Correlation:
108
109       SHIFT \in [-sS..sM]
110
111       <--sS----
112       [  sub  ]----sM--->[ sub ]
113                [  main  ]
114
115             ^ correlation vector index = SHIFT + sS
116
117       main is fixed, sub is shifted along main.
118
119     */
120
121
122     QTime t;
123     t.start();
124     for (int shift = -sizeSub; shift <= sizeMain; shift++) {
125
126         if (shift <= 0) {
127             left = envSub-shift;
128             right = envMain;
129             size = std::min(sizeSub+shift, sizeMain);
130         } else {
131             left = envSub;
132             right = envMain+shift;
133             size = std::min(sizeSub, sizeMain-shift);
134         }
135
136         sum = 0;
137         for (int i = 0; i < size; ++i) {
138             sum += (*left) * (*right);
139             left++;
140             right++;
141         }
142         correlation[sizeSub+shift] = qAbs(sum);
143
144         if (sum > max) {
145             max = sum;
146         }
147
148     }
149     std::cout << "Correlation calculated. Time taken: " << t.elapsed() << " ms." << std::endl;
150
151     if (out_max != NULL) {
152         *out_max = max;
153     }
154 }