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