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