2 Copyright (C) 2012 Simon A. Eugster (Granjow) <simon.eu@gmail.com>
3 This file is part of kdenlive. See www.kdenlive.org.
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 3 of the License, or
8 (at your option) any later version.
11 #include "../src/lib/audio/audioEnvelope.h"
12 #include "../src/lib/audio/fftCorrelation.h"
14 #include <QCoreApplication>
15 #include <QStringList>
22 void printUsage(const char *path)
24 std::cout << "This executable takes two audio/video files A and B and determines " << std::endl
25 << "how much B needs to be shifted in order to be synchronized with A." << std::endl
26 << "Other than audioOffset this executable will use Fast Fourier Tranform " << std::endl
27 << "which should be faster especially for large files." << std::endl << std::endl
28 << path << " <main audio file> <second audio file>" << std::endl
29 << "\t-h, --help\n\t\tDisplay this help" << std::endl
30 << "\t--profile=<profile>\n\t\tUse the given profile for calculation (run: melt -query profiles)" << std::endl
31 << "\t--no-images\n\t\tDo not save envelope and correlation images" << std::endl
35 int main(int argc, char *argv[])
37 QCoreApplication app(argc, argv);
38 QStringList args = app.arguments();
41 std::string profile = "atsc_1080p_24";
42 bool saveImages = true;
45 foreach (QString str, args) {
47 if (str.startsWith("--profile=")) {
49 s.remove(0, QString("--profile=").length());
50 profile = s.toStdString();
53 } else if (str == "-h" || str == "--help") {
57 } else if (str == "--no-images") {
64 if (args.length() < 2) {
71 std::string fileMain(args.at(0).toStdString());
73 std::string fileSub = args.at(0).toStdString();
77 qDebug() << "Unused arguments: " << args;
84 std::cout << "Usage: " << argv[0] << " <main audio file> <second audio file>" << std::endl;
87 std::cout << "Trying to align (2)\n\t" << fileSub << "\nto fit on (1)\n\t" << fileMain
88 << "\n, result will indicate by how much (2) has to be moved." << std::endl
89 << "Profile used: " << profile << std::endl
94 Mlt::Factory::init(NULL);
96 // Load an arbitrary profile
97 Mlt::Profile prof(profile.c_str());
99 // Load the MLT producers
100 Mlt::Producer prodMain(prof, fileMain.c_str());
101 if (!prodMain.is_valid()) {
102 std::cout << fileMain << " is invalid." << std::endl;
105 Mlt::Producer prodSub(prof, fileSub.c_str());
106 if (!prodSub.is_valid()) {
107 std::cout << fileSub << " is invalid." << std::endl;
112 // Build the audio envelopes for the correlation
113 AudioEnvelope *envelopeMain = new AudioEnvelope(&prodMain);
114 envelopeMain->loadEnvelope();
115 envelopeMain->loadStdDev();
116 envelopeMain->dumpInfo();
118 AudioEnvelope *envelopeSub = new AudioEnvelope(&prodSub);
119 envelopeSub->loadEnvelope();
120 envelopeSub->loadStdDev();
121 envelopeSub->dumpInfo();
127 FFTCorrelation::correlate(envelopeMain->envelope(), envelopeMain->envelopeSize(),
128 envelopeSub->envelope(), envelopeSub->envelopeSize(),
129 &correlated, corrSize);
134 for (int i = 0; i < corrSize; i++) {
135 if (correlated[i] > max) {
140 int shift = envelopeMain->envelopeSize() - maxIndex-1;
141 qDebug() << "Max correlation value is " << max << " at " << maxIndex;
142 qDebug() << "Will have to move by " << shift << " frames";
144 std::cout << fileSub << " should be shifted by " << shift << " frames" << std::endl
145 << "\trelative to " << fileMain << std::endl
146 << "\tin a " << prodMain.get_fps() << " fps profile (" << profile << ")." << std::endl
150 QString filename = QString("correlation-fft-%1.png")
151 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss"));
152 QImage img(corrSize/2, 400, QImage::Format_ARGB32);
153 img.fill(qRgb(255,255,255));
154 for (int x = 0; x < img.width(); x++) {
155 float val = fabs(correlated[x]/max);
156 for (int y = 0; y < img.height()*val; y++) {
157 img.setPixel(x, img.height()-1-y, qRgb(50,50,50));
161 qDebug() << "Saved image to " << filename;