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