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