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