]> git.sesse.net Git - kdenlive/blob - src/lib/audio/audioEnvelope.cpp
Working on FFT based correlation
[kdenlive] / src / lib / audio / audioEnvelope.cpp
1 /***************************************************************************
2  *   Copyright (C) 2012 by Simon Andreas Eugster (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 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  ***************************************************************************/
10
11 #include "audioEnvelope.h"
12
13 #include "audioStreamInfo.h"
14 #include <QImage>
15 #include <QTime>
16 #include <cmath>
17 #include <iostream>
18
19 AudioEnvelope::AudioEnvelope(Mlt::Producer *producer, int offset, int length) :
20     m_envelope(NULL),
21     m_producer(producer),
22     m_offset(offset),
23     m_length(length),
24     m_envelopeSize(producer->get_length()),
25     m_envelopeStdDevCalculated(false),
26     m_envelopeIsNormalized(false)
27 {
28     m_info = new AudioInfo(m_producer);
29
30     Q_ASSERT(m_offset >= 0);
31     if (m_length > 0) {
32         Q_ASSERT(m_length+m_offset <= m_envelopeSize);
33         m_envelopeSize = m_length;
34     }
35 }
36
37 AudioEnvelope::~AudioEnvelope()
38 {
39     if (m_envelope != NULL) {
40         delete[] m_envelope;
41     }
42     delete m_info;
43 }
44
45
46
47 const int64_t *AudioEnvelope::envelope()
48 {
49     if (m_envelope == NULL) {
50         loadEnvelope();
51     }
52     return m_envelope;
53 }
54 int AudioEnvelope::envelopeSize() const
55 {
56     return m_envelopeSize;
57 }
58 int64_t AudioEnvelope::maxValue() const
59 {
60     return m_envelopeMax;
61 }
62
63
64
65
66 void AudioEnvelope::loadEnvelope()
67 {
68     Q_ASSERT(m_envelope == NULL);
69
70     std::cout << "Loading envelope ..." << std::endl;
71
72     int samplingRate = m_info->info(0)->samplingRate();
73     mlt_audio_format format_s16 = mlt_audio_s16;
74     int channels = 1;
75
76     Mlt::Frame *frame;
77     int64_t position;
78     int samples;
79
80     m_envelope = new int64_t[m_envelopeSize];
81     m_envelopeMax = 0;
82     m_envelopeMean = 0;
83
84     QTime t;
85     t.start();
86     int count = 0;
87     m_producer->seek(m_offset);
88     m_producer->set_speed(1.0); // This is necessary, otherwise we don't get any new frames in the 2nd run.
89     for (int i = 0; i < m_envelopeSize; i++) {
90
91         frame = m_producer->get_frame(i);
92         position = mlt_frame_get_position(frame->get_frame());
93         samples = mlt_sample_calculator(m_producer->get_fps(), samplingRate, position);
94
95         int16_t *data = static_cast<int16_t*>(frame->get_audio(format_s16, samplingRate, channels, samples));
96
97         int64_t sum = 0;
98         for (int k = 0; k < samples; k++) {
99             sum += fabs(data[k]);
100         }
101         m_envelope[i] = sum;
102
103         m_envelopeMean += sum;
104         if (sum > m_envelopeMax) {
105             m_envelopeMax = sum;
106         }
107
108         std::cout << position << "|" << m_producer->get_playtime()
109                   << "-" << m_producer->get_in() << "+" << m_producer->get_out() << " ";
110
111         delete frame;
112
113         count++;
114         if (m_length > 0 && count > m_length) {
115             break;
116         }
117     }
118     m_envelopeMean /= m_envelopeSize;
119     std::cout << "Calculating the envelope (" << m_envelopeSize << " frames) took "
120               << t.elapsed() << " ms." << std::endl;
121 }
122
123 int64_t AudioEnvelope::loadStdDev()
124 {
125     if (m_envelopeStdDevCalculated) {
126         std::cout << "Standard deviation already calculated, not re-calculating." << std::endl;
127     } else {
128
129         if (m_envelope == NULL) {
130             loadEnvelope();
131         }
132
133         m_envelopeStdDev = 0;
134         for (int i = 0; i < m_envelopeSize; i++) {
135             m_envelopeStdDev += sqrt((m_envelope[i]-m_envelopeMean)*(m_envelope[i]-m_envelopeMean)/m_envelopeSize);
136         }
137         m_envelopeStdDevCalculated = true;
138
139     }
140     return m_envelopeStdDev;
141 }
142
143 void AudioEnvelope::normalizeEnvelope(bool clampTo0)
144 {
145     if (m_envelope == NULL) {
146         loadEnvelope();
147     }
148
149     if (!m_envelopeIsNormalized) {
150
151         m_envelopeMax = 0;
152         int64_t newMean = 0;
153         for (int i = 0; i < m_envelopeSize; i++) {
154
155             m_envelope[i] -= m_envelopeMean;
156
157             if (clampTo0) {
158                 if (m_envelope[i] < 0) { m_envelope[i] = 0; }
159             }
160
161             if (m_envelope[i] > m_envelopeMax) {
162                 m_envelopeMax = m_envelope[i];
163             }
164
165             newMean += m_envelope[i];
166         }
167         m_envelopeMean = newMean / m_envelopeSize;
168
169         m_envelopeIsNormalized = true;
170     }
171
172 }
173
174 QImage AudioEnvelope::drawEnvelope()
175 {
176     if (m_envelope == NULL) {
177         loadEnvelope();
178     }
179
180     QImage img(m_envelopeSize, 400, QImage::Format_ARGB32);
181     img.fill(qRgb(255,255,255));
182     double fy;
183     for (int x = 0; x < img.width(); x++) {
184         fy = m_envelope[x]/double(m_envelopeMax) * img.height();
185         for (int y = img.height()-1; y > img.height()-1-fy; y--) {
186             img.setPixel(x,y, qRgb(50, 50, 50));
187         }
188     }
189     return img;
190 }
191
192 void AudioEnvelope::dumpInfo() const
193 {
194     if (m_envelope == NULL) {
195         std::cout << "Envelope not generated, no information available." << std::endl;
196     } else {
197         std::cout << "Envelope info" << std::endl
198                   << "* size = " << m_envelopeSize << std::endl
199                   << "* max = " << m_envelopeMax << std::endl
200                   << "* ยต = " << m_envelopeMean << std::endl
201                      ;
202         if (m_envelopeStdDevCalculated) {
203             std::cout << "* s = " << m_envelopeStdDev << std::endl;
204         }
205     }
206 }