]> git.sesse.net Git - kdenlive/blob - testingArea/audioOffset.cpp
Const'ref
[kdenlive] / testingArea / audioOffset.cpp
1 /*
2 Copyright (C) 2012  Simon A. Eugster (Granjow)  <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 3 of the License, or
8 (at your option) any later version.
9 */
10
11 #include <QMap>
12 #include <QFile>
13 #include <QTime>
14 #include <QImage>
15 #include <QDebug>
16 #include <QFileInfo>
17 #include <QDateTime>
18 #include <QStringList>
19 #include <QCoreApplication>
20 #include <mlt++/Mlt.h>
21 #include <iostream>
22 #include <cstdlib>
23 #include <cmath>
24
25 #include "../src/lib/audio/audioInfo.h"
26 #include "../src/lib/audio/audioStreamInfo.h"
27 #include "../src/lib/audio/audioEnvelope.h"
28 #include "../src/lib/audio/audioCorrelation.h"
29
30 void printUsage(const char *path)
31 {
32     std::cout << "This executable takes two audio/video files A and B and determines " << std::endl
33               << "how much B needs to be shifted in order to be synchronized with A." << std::endl << std::endl
34               << path << " <main audio file> <second audio file>" << std::endl
35               << "\t-h, --help\n\t\tDisplay this help" << std::endl
36               << "\t--fft\n\t\tUse Fourier Transform (FFT) to calculate the offset. This only takes" << std::endl
37               << "\t\tO(n log n) time compared to O(n²) when using normal correlation and should be " << std::endl
38               << "\t\tfaster for large data (several minutes)." << std::endl
39               << "\t--profile=<profile>\n\t\tUse the given profile for calculation (run: melt -query profiles)" << std::endl
40               << "\t--no-images\n\t\tDo not save envelope and correlation images" << std::endl
41                  ;
42 }
43
44 int main(int argc, char *argv[])
45 {
46     QCoreApplication app(argc, argv);
47     QStringList args = app.arguments();
48     args.removeAt(0);
49
50     std::string profile = "atsc_1080p_24";
51     bool saveImages = true;
52     bool useFFT = false;
53
54     // Load arguments
55     foreach (const QString &str, args) {
56
57         if (str.startsWith("--profile=")) {
58             QString s = str;
59             s.remove(0, QString("--profile=").length());
60             profile = s.toStdString();
61             args.removeOne(str);
62
63         } else if (str == "-h" || str == "--help") {
64             printUsage(argv[0]);
65             return 0;
66
67         } else if (str == "--no-images") {
68             saveImages = false;
69             args.removeOne(str);
70
71         } else if (str == "--fft") {
72             useFFT = true;
73             args.removeOne(str);
74         }
75
76     }
77
78     if (args.length() < 2) {
79         printUsage(argv[0]);
80         return 1;
81     }
82
83
84
85     std::string fileMain(args.at(0).toStdString());
86     args.removeFirst();
87     std::string fileSub = args.at(0).toStdString();
88     args.removeFirst();
89
90
91     qDebug() << "Unused arguments: " << args;
92
93
94     if (argc > 2) {
95         fileMain = argv[1];
96         fileSub = argv[2];
97     } else {
98         std::cout << "Usage: " << argv[0] << " <main audio file> <second audio file>" << std::endl;
99         return 0;
100     }
101     std::cout << "Trying to align (2)\n\t" << fileSub << "\nto fit on (1)\n\t" << fileMain
102               << "\n, result will indicate by how much (2) has to be moved." << std::endl
103               << "Profile used: " << profile << std::endl
104                  ;
105     if (useFFT) {
106         std::cout << "Will use FFT based correlation." << std::endl;
107     }
108
109
110     // Initialize MLT
111     Mlt::Factory::init(NULL);
112
113     // Load an arbitrary profile
114     Mlt::Profile prof(profile.c_str());
115
116     // Load the MLT producers
117     Mlt::Producer prodMain(prof, fileMain.c_str());
118     if (!prodMain.is_valid()) {
119         std::cout << fileMain << " is invalid." << std::endl;
120         return 2;
121     }
122     Mlt::Producer prodSub(prof, fileSub.c_str());
123     if (!prodSub.is_valid()) {
124         std::cout << fileSub << " is invalid." << std::endl;
125         return 2;
126     }
127
128
129     // Build the audio envelopes for the correlation
130     AudioEnvelope *envelopeMain = new AudioEnvelope(fileMain.c_str(), &prodMain);
131     envelopeMain->loadEnvelope();
132     envelopeMain->loadStdDev();
133     envelopeMain->dumpInfo();
134
135     AudioEnvelope *envelopeSub = new AudioEnvelope(fileSub.c_str(), &prodSub);
136     envelopeSub->loadEnvelope();
137     envelopeSub->loadStdDev();
138     envelopeSub->dumpInfo();
139
140     // Calculate the correlation and hereby the audio shift
141     AudioCorrelation corr(envelopeMain);
142     int index = corr.addChild(envelopeSub, useFFT);
143
144     int shift = corr.getShift(index);
145     std::cout << " Should be shifted by " << shift << " frames: " << fileSub << std::endl
146               << "\trelative to " << fileMain << std::endl
147               << "\tin a " << prodMain.get_fps() << " fps profile (" << profile << ")." << std::endl;
148
149
150     if (saveImages) {
151         QString outImg = QString::fromLatin1("envelope-main-%1.png")
152                 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss"));
153         envelopeMain->drawEnvelope().save(outImg);
154         std::cout << "Saved volume envelope as "
155                   << QFileInfo(outImg).absoluteFilePath().toStdString()
156                   << std::endl;
157         outImg = QString::fromLatin1("envelope-sub-%1.png")
158                 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss"));
159         envelopeSub->drawEnvelope().save(outImg);
160         std::cout << "Saved volume envelope as "
161                   << QFileInfo(outImg).absoluteFilePath().toStdString()
162                   << std::endl;
163         outImg = QString::fromLatin1("correlation-%1.png")
164                 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss"));
165         corr.info(index)->toImage().save(outImg);
166         std::cout << "Saved correlation image as "
167                   << QFileInfo(outImg).absoluteFilePath().toStdString()
168                   << std::endl;
169     }
170
171
172     //    Mlt::Factory::close();
173
174
175     return 0;
176
177 }
178
179
180