+void CustomTrackView::setAudioAlignReference()
+{
+ QList<QGraphicsItem *> selection = scene()->selectedItems();
+ if (selection.isEmpty() || selection.size() > 1) {
+ emit displayMessage(i18n("You must select exactly one clip for the audio reference."), ErrorMessage);
+ return;
+ }
+ if (m_audioCorrelator != NULL) {
+ delete m_audioCorrelator;
+ }
+ if (selection.at(0)->type() == AVWIDGET) {
+ ClipItem *clip = static_cast<ClipItem*>(selection.at(0));
+ if (clip->clipType() == AV || clip->clipType() == AUDIO) {
+ m_audioAlignmentReference = clip;
+
+ AudioEnvelope *envelope = new AudioEnvelope(clip->getProducer(clip->track()));
+ m_audioCorrelator = new AudioCorrelation(envelope);
+
+
+#ifdef DEBUG
+ envelope->drawEnvelope().save("kdenlive-audio-reference-envelope.png");
+ envelope->dumpInfo();
+#endif
+
+
+ emit displayMessage(i18n("Audio align reference set."), InformationMessage);
+ }
+ return;
+ }
+ emit displayMessage(i18n("Reference for audio alignment must contain audio data."), ErrorMessage);
+}
+
+void CustomTrackView::alignAudio()
+{
+ bool referenceOK = true;
+ if (m_audioCorrelator == NULL) {
+ referenceOK = false;
+ }
+ if (referenceOK) {
+ if (!scene()->items().contains(m_audioAlignmentReference)) {
+ // The reference item has been deleted from the timeline (or so)
+ referenceOK = false;
+ }
+ }
+ if (!referenceOK) {
+ emit displayMessage(i18n("Audio alignment reference not yet set."), InformationMessage);
+ return;
+ }
+
+ int counter = 0;
+ QList<QGraphicsItem *> selection = scene()->selectedItems();
+ foreach (QGraphicsItem *item, selection) {
+ if (item->type() == AVWIDGET) {
+
+ ClipItem *clip = static_cast<ClipItem*>(item);
+ if (clip == m_audioAlignmentReference) {
+ continue;
+ }
+
+ if (clip->clipType() == AV || clip->clipType() == AUDIO) {
+ AudioEnvelope *envelope = new AudioEnvelope(clip->getProducer(clip->track()),
+ clip->info().cropStart.frames(m_document->fps()),
+ clip->info().cropDuration.frames(m_document->fps()));
+
+ // FFT only for larger vectors. We could use it all time, but for small vectors
+ // the (anyway not noticeable) overhead is smaller with a nested for loop correlation.
+ int index = m_audioCorrelator->addChild(envelope, envelope->envelopeSize() > 200);
+ int shift = m_audioCorrelator->getShift(index);
+ counter++;
+
+
+#ifdef DEBUG
+ m_audioCorrelator->info(index)->toImage().save("kdenlive-audio-align-cross-correlation.png");
+ envelope->drawEnvelope().save("kdenlive-audio-align-envelope.png");
+ envelope->dumpInfo();
+
+ int targetPos = m_audioAlignmentReference->startPos().frames(m_document->fps()) + shift;
+ qDebug() << "Reference starts at " << m_audioAlignmentReference->startPos().frames(m_document->fps());
+ qDebug() << "We will start at " << targetPos;
+ qDebug() << "to shift by " << shift;
+ qDebug() << "(eventually)";
+ qDebug() << "(maybe)";
+#endif
+
+
+ QUndoCommand *moveCommand = new QUndoCommand();
+
+ GenTime add(shift, m_document->fps());
+ ItemInfo start = clip->info();
+
+ ItemInfo end = start;
+ end.startPos = m_audioAlignmentReference->startPos() + add - m_audioAlignmentReference->cropStart();
+ end.endPos = end.startPos + start.cropDuration;
+
+ if ( end.startPos.seconds() < 0 ) {
+ // Clip would start before 0, so crop it first
+ GenTime cropBy = -end.startPos;
+
+#ifdef DEBUG
+ qDebug() << "Need to crop clip. " << start;
+ qDebug() << "end.startPos: " << end.startPos.toString() << ", cropBy: " << cropBy.toString();
+#endif
+
+ ItemInfo resized = start;
+ resized.startPos += cropBy;
+
+ resizeClip(start, resized);
+ new ResizeClipCommand(this, start, resized, false, false, moveCommand);
+
+ start = clip->info();
+ end.startPos += cropBy;
+
+#ifdef DEBUG
+ qDebug() << "Clip cropped. " << start;
+ qDebug() << "Moving to: " << end;
+#endif
+ }
+
+ if (itemCollision(clip, end)) {
+ delete moveCommand;
+ emit displayMessage(i18n("Unable to move clip due to collision."), ErrorMessage);
+ return;
+ }
+
+ moveCommand->setText(i18n("Auto-align clip"));
+ new MoveClipCommand(this, start, end, true, moveCommand);
+ updateTrackDuration(clip->track(), moveCommand);
+ m_commandStack->push(moveCommand);
+
+ }
+ }
+ }
+
+ if (counter == 0) {
+ emit displayMessage(i18n("No audio clips selected."), ErrorMessage);
+ } else {
+ emit displayMessage(i18n("Auto-aligned %1 clips.", counter), InformationMessage);
+ }
+}
+