From: Simon A. Eugster Date: Tue, 14 Feb 2012 10:58:56 +0000 (+0100) Subject: Audio envelope calculation extracted into own class, mean and standard deviation... X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=61379786d6c8dcfd7bf0471125a1ba657acc8417;p=kdenlive Audio envelope calculation extracted into own class, mean and standard deviation added --- diff --git a/src/clipmanager.cpp b/src/clipmanager.cpp index 45f1fc9f..25d5a092 100644 --- a/src/clipmanager.cpp +++ b/src/clipmanager.cpp @@ -305,7 +305,7 @@ void ClipManager::slotGetAudioThumbs() producer.seek(z); mlt_frame = producer.get_frame(); if (mlt_frame && mlt_frame->is_valid()) { - int samples = mlt_sample_calculator(framesPerSecond, frequency, mlt_frame_get_position(mlt_frame->get_frame())); + int samples = mlt_sample_calculator(framesPerSecond, frequency, mlt_frame->get_position()); qint16* pcm = static_cast(mlt_frame->get_audio(audioFormat, frequency, channels, samples)); for (int c = 0; c < channels; c++) { QByteArray audioArray; diff --git a/testingArea/CMakeLists.txt b/testingArea/CMakeLists.txt index d08ae2b1..da4c533e 100644 --- a/testingArea/CMakeLists.txt +++ b/testingArea/CMakeLists.txt @@ -7,7 +7,7 @@ include_directories( ) include(${QT_USE_FILE}) -add_executable(audioOffset audioOffset.cpp audioInfo.cpp audioStreamInfo.cpp) +add_executable(audioOffset audioOffset.cpp audioInfo.cpp audioStreamInfo.cpp audioEnvelope.cpp) target_link_libraries(audioOffset ${QT_LIBRARIES} ${LIBMLT_LIBRARY} diff --git a/testingArea/audioEnvelope.cpp b/testingArea/audioEnvelope.cpp new file mode 100644 index 00000000..23184e32 --- /dev/null +++ b/testingArea/audioEnvelope.cpp @@ -0,0 +1,134 @@ +/*************************************************************************** + * Copyright (C) 2012 by Simon Andreas Eugster (simon.eu@gmail.com) * + * This file is part of kdenlive. See www.kdenlive.org. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "audioEnvelope.h" + +#include "audioStreamInfo.h" +#include +#include +#include +#include + +AudioEnvelope::AudioEnvelope(Mlt::Producer *producer) : + m_envelope(NULL), + m_producer(producer), + m_envelopeStdDevCalculated(false) +{ + m_info = new AudioInfo(m_producer); +} + +AudioEnvelope::~AudioEnvelope() +{ + if (m_envelope != NULL) { + delete m_envelope; + } + delete m_info; +} + + +void AudioEnvelope::loadEnvelope() +{ + Q_ASSERT(m_envelope == NULL); + + std::cout << "Loading envelope ..." << std::endl; + + m_envelopeSize = m_producer->get_length(); + + int samplingRate = m_info->info(0)->samplingRate(); + mlt_audio_format format_s16 = mlt_audio_s16; + int channels = 1; + + Mlt::Frame *frame; + int64_t position; + int samples; + + m_envelope = new uint64_t[m_envelopeSize]; + m_envelopeMax = 0; + m_envelopeMean = 0; + + QTime t; + t.start(); + for (int i = 0; i < m_envelopeSize; i++) { + + frame = m_producer->get_frame(i); + position = mlt_frame_get_position(frame->get_frame()); + samples = mlt_sample_calculator(m_producer->get_fps(), samplingRate, position); + + int16_t *data = static_cast(frame->get_audio(format_s16, samplingRate, channels, samples)); + + uint64_t sum = 0; + for (int k = 0; k < samples; k++) { + sum += fabs(data[k]); + } + m_envelope[i] = sum; + + m_envelopeMean += sum; + if (sum > m_envelopeMax) { + m_envelopeMax = sum; + } + } + m_envelopeMean /= m_envelopeSize; + std::cout << "Calculating the envelope (" << m_envelopeSize << " frames) took " + << t.elapsed() << " ms." << std::endl; +} + +int64_t AudioEnvelope::loadStdDev() +{ + if (m_envelopeStdDevCalculated) { + std::cout << "Standard deviation already calculated, not re-calculating." << std::endl; + } else { + + if (m_envelope == NULL) { + loadEnvelope(); + } + + m_envelopeStdDev = 0; + for (int i = 0; i < m_envelopeSize; i++) { + m_envelopeStdDev += sqrt((m_envelope[i]-m_envelopeMean)*(m_envelope[i]-m_envelopeMean)/m_envelopeSize); + } + m_envelopeStdDevCalculated = true; + + } + return m_envelopeStdDev; +} + +QImage AudioEnvelope::drawEnvelope() +{ + if (m_envelope == NULL) { + loadEnvelope(); + } + + QImage img(m_envelopeSize, 400, QImage::Format_ARGB32); + img.fill(qRgb(255,255,255)); + double fy; + for (int x = 0; x < img.width(); x++) { + fy = m_envelope[x]/double(m_envelopeMax) * img.height(); + for (int y = img.height()-1; y > img.height()-1-fy; y--) { + img.setPixel(x,y, qRgb(50, 50, 50)); + } + } + return img; +} + +void AudioEnvelope::dumpInfo() const +{ + if (m_envelope == NULL) { + std::cout << "Envelope not generated, no information available." << std::endl; + } else { + std::cout << "Envelope info" << std::endl + << "* size = " << m_envelopeSize << std::endl + << "* max = " << m_envelopeMax << std::endl + << "* µ = " << m_envelopeMean << std::endl + ; + if (m_envelopeStdDevCalculated) { + std::cout << "* s = " << m_envelopeStdDev << std::endl; + } + } +} diff --git a/testingArea/audioEnvelope.h b/testingArea/audioEnvelope.h new file mode 100644 index 00000000..b679d367 --- /dev/null +++ b/testingArea/audioEnvelope.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 2012 by Simon Andreas Eugster (simon.eu@gmail.com) * + * This file is part of kdenlive. See www.kdenlive.org. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef AUDIOENVELOPE_H +#define AUDIOENVELOPE_H + +#include "audioInfo.h" +#include + +class QImage; +class AudioEnvelope +{ +public: + AudioEnvelope(Mlt::Producer *producer); + ~AudioEnvelope(); + + void loadEnvelope(); + int64_t loadStdDev(); + + QImage drawEnvelope(); + + void dumpInfo() const; + +private: + uint64_t *m_envelope; + Mlt::Producer *m_producer; + AudioInfo *m_info; + + int m_envelopeSize; + uint64_t m_envelopeMax; + uint64_t m_envelopeMean; + uint64_t m_envelopeStdDev; + + bool m_envelopeStdDevCalculated; +}; + +#endif // AUDIOENVELOPE_H diff --git a/testingArea/audioOffset.cpp b/testingArea/audioOffset.cpp index d8e8eede..6eb54985 100644 --- a/testingArea/audioOffset.cpp +++ b/testingArea/audioOffset.cpp @@ -22,6 +22,7 @@ #include "audioInfo.h" #include "audioStreamInfo.h" +#include "audioEnvelope.h" int main(int argc, char *argv[]) { @@ -71,57 +72,23 @@ int main(int argc, char *argv[]) framesToFetch = 5000; } - mlt_audio_format format_s16 = mlt_audio_s16; - int samplingRate = infoMain.info(0)->samplingRate(); - int channels = 1; + AudioEnvelope envelopeMain(&prodMain); + envelopeMain.loadEnvelope(); + envelopeMain.loadStdDev(); + envelopeMain.dumpInfo(); - Mlt::Frame *frame; - int64_t position; - int samples; - - uint64_t envelope[framesToFetch]; - uint64_t max = 0; - - QTime t; - t.start(); - for (int i = 0; i < framesToFetch; i++) { - - frame = prodMain.get_frame(i); - position = mlt_frame_get_position(frame->get_frame()); - samples = mlt_sample_calculator(prodMain.get_fps(), infoMain.info(0)->samplingRate(), position); - - int16_t *data = static_cast(frame->get_audio(format_s16, samplingRate, channels, samples)); - - uint64_t sum = 0; - for (int k = 0; k < samples; k++) { - sum += fabs(data[k]); - } - envelope[i] = sum; - - if (sum > max) { - max = sum; - } - } - std::cout << "Calculating the envelope (" << framesToFetch << " frames) took " - << t.elapsed() << " ms." << std::endl; - - QImage img(framesToFetch, 400, QImage::Format_ARGB32); - img.fill(qRgb(255,255,255)); - double fy; - for (int x = 0; x < img.width(); x++) { - fy = envelope[x]/double(max) * img.height(); - for (int y = img.height()-1; y > img.height()-1-fy; y--) { - img.setPixel(x,y, qRgb(50, 50, 50)); - } - } QString outImg = QString("envelope-%1.png") .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss")); - img.save(outImg); + envelopeMain.drawEnvelope().save(outImg); std::cout << "Saved volume envelope as " << QFileInfo(outImg).absoluteFilePath().toStdString() << std::endl; + return 0; } + + +