From 6fd68feb9a59933adb0b284c48f1b216957cebd2 Mon Sep 17 00:00:00 2001 From: morrolinux Date: Sun, 17 Mar 2019 15:28:18 +0100 Subject: [PATCH] automated audio cut working --- dialogs/silencedialog.cpp | 192 ++++++++++++++++++++++++++++++++++++++ dialogs/silencedialog.h | 58 ++++++++++++ global/global.cpp | 13 +++ global/global.h | 5 + olive.pro | 2 + panels/timeline.cpp | 19 ++++ panels/timeline.h | 1 + ui/timelinewidget.cpp | 1 + 8 files changed, 291 insertions(+) create mode 100644 dialogs/silencedialog.cpp create mode 100644 dialogs/silencedialog.h diff --git a/dialogs/silencedialog.cpp b/dialogs/silencedialog.cpp new file mode 100644 index 000000000..2bac8e540 --- /dev/null +++ b/dialogs/silencedialog.cpp @@ -0,0 +1,192 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include "silencedialog.h" + +#include +#include +#include +#include +#include + +#include "timeline/sequence.h" +#include "rendering/renderfunctions.h" +#include "panels/panels.h" +#include "panels/timeline.h" + +SilenceDialog::SilenceDialog(QWidget *parent, QVector clips) : QDialog(parent) { + setWindowTitle(tr("Cut silence")); + + clips_ = clips; + + QVBoxLayout* main_layout = new QVBoxLayout(this); + QGridLayout* grid = new QGridLayout(); + grid->setSpacing(6); + + grid->addWidget(new QLabel(tr("Attack Threshold:"), this), 0, 0); + attack_threshold = new LabelSlider(this); + attack_threshold->SetDecimalPlaces(0); + grid->addWidget(attack_threshold, 0, 1); + + grid->addWidget(new QLabel(tr("Attack Time:"), this), 1, 0); + attack_time = new LabelSlider(this); + attack_time->SetDecimalPlaces(0); + grid->addWidget(attack_time, 1, 1); + + grid->addWidget(new QLabel(tr("Release Threshold:"), this), 2, 0); + release_threshold = new LabelSlider(this); + release_threshold->SetDecimalPlaces(0); + grid->addWidget(release_threshold, 2, 1); + + grid->addWidget(new QLabel(tr("Release Time:"), this), 3, 0); + release_time = new LabelSlider(this); + release_time->SetDecimalPlaces(0); + grid->addWidget(release_time, 3, 1); + + main_layout->addLayout(grid); + + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + buttonBox->setCenterButtons(true); + main_layout->addWidget(buttonBox); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + + run(); // is it ok to call it here? +} + +void SilenceDialog::run() { + + default_attack_threshold = 5; + current_attack_threshold = 5; + default_attack_time = 2; + current_attack_time = 2; + default_release_threshold = 2; + current_release_threshold = 2; + default_release_time = 5; + current_release_time = 5; + + attack_threshold->SetMinimum(1); + attack_threshold->setEnabled(true); + attack_threshold->SetDefault(default_attack_threshold); + attack_threshold->SetValue(current_attack_threshold); + + attack_time->SetMinimum(1); + attack_time->setEnabled(true); + attack_time->SetDefault(default_attack_time); + attack_time->SetValue(current_attack_time); + + release_threshold->SetMinimum(1); + release_threshold->setEnabled(true); + release_threshold->SetDefault(default_release_threshold); + release_threshold->SetValue(current_release_threshold); + + release_time->SetMinimum(1); + release_time->setEnabled(true); + release_time->SetDefault(default_release_time); + release_time->SetValue(current_release_time); + +} + +void SilenceDialog::accept() { + + current_attack_threshold = attack_threshold->value(); + current_attack_time = attack_time->value(); + current_release_threshold = release_threshold->value(); + current_release_time = release_time->value(); + + cut_silence(); + + update_ui(true); + QDialog::accept(); +} + +void SilenceDialog::cut_silence() { + + Clip* clip = clips_[0]; + int clip_start = clip->timeline_in(); + const FootageStream* ms = clip->media_stream(); + long media_length = clip->media_length(); + int preview_size = ms->audio_preview.length(); + float chunk_size = (float)preview_size/media_length; // how many audio samples to read for each fotogram + + int sample_size = qMax(current_attack_time, current_release_time)+1; + + bool attack = false; // status flags + bool release = false; + + qint8 * vols = NULL; + vols = new qint8[sample_size]; + for(int i=0; iaudio_preview.at(k))))); + } + vols[circular_index] = tmp; + + //for debug: + //qInfo() << "i:" << i <<" - "<< i/30 <<":"<< i%30 << " - volume:" << vols[circular_index] <<"\n"; + + int overthreshold = 0; + int cut_idx = 0; //how much to cut (backwards) + + // if current volume value is above threshold + if (vols[circular_index] >= current_attack_threshold && !attack){ // if we get one sample over the threshold + for(int k=0; k current_attack_threshold){ + overthreshold++; + cut_idx = k+1; + } + } + // if we reached threshold over the set tolerance + if(overthreshold >= current_attack_time){ + panel_timeline->split_at_position(i-cut_idx); // cut at the first occurence + attack = true; + release = false; + //qInfo() << "\n\n Current vol: "<= current_release_time){ // must be <= sample_size + attack = false; + release = true; + panel_timeline->split_at_position(i); + //qInfo() << "\n\n Current vol: "<. + +***/ + +#ifndef SILENCEDIALOG_H +#define SILENCEDIALOG_H + +#include +#include + +#include "timeline/clip.h" +#include "ui/labelslider.h" + +class SilenceDialog : public QDialog +{ + Q_OBJECT +public: + SilenceDialog(QWidget* parent, QVector clips); + + void run(); +private slots: + void cut_silence(); + void accept(); +private: + QVector clips_; + + LabelSlider* attack_threshold; + LabelSlider* release_threshold; + LabelSlider* attack_time; + LabelSlider* release_time; + + int default_attack_threshold; + int current_attack_threshold; + int default_release_threshold; + int current_release_threshold; + int default_attack_time; + int current_attack_time; + int default_release_time; + int current_release_time; +}; + +#endif // SILENCEDIALOG_H diff --git a/global/global.cpp b/global/global.cpp index 16a59c9c6..9477f046c 100644 --- a/global/global.cpp +++ b/global/global.cpp @@ -38,6 +38,7 @@ #include "dialogs/aboutdialog.h" #include "dialogs/speeddialog.h" #include "dialogs/actionsearch.h" +#include "dialogs/silencedialog.h" #include "timeline/sequence.h" #include "ui/mediaiconservice.h" #include "ui/mainwindow.h" @@ -362,6 +363,18 @@ void OliveGlobal::open_speed_dialog() { } } +void OliveGlobal::open_cut_silence_dialog() { + if (olive::ActiveSequence != nullptr) { + + QVector selected_clips = olive::ActiveSequence->SelectedClips(); + + if (!selected_clips.isEmpty()) { + SilenceDialog s(olive::MainWindow, selected_clips); + s.exec(); + } + } +} + void OliveGlobal::clear_undo_stack() { olive::UndoStack.clear(); } diff --git a/global/global.h b/global/global.h index 6a9d57617..4b38f35c7 100644 --- a/global/global.h +++ b/global/global.h @@ -239,6 +239,11 @@ public slots: */ void open_speed_dialog(); + /** + * @brief Open the cut silence dialog. + */ + void open_cut_silence_dialog(); + /** * @brief Open the Action Search overlay. */ diff --git a/olive.pro b/olive.pro index 95509fe66..c36e4910f 100644 --- a/olive.pro +++ b/olive.pro @@ -91,6 +91,7 @@ SOURCES += \ dialogs/demonotice.cpp \ timeline/marker.cpp \ dialogs/speeddialog.cpp \ + dialogs/silencedialog.cpp \ dialogs/mediapropertiesdialog.cpp \ project/projectmodel.cpp \ project/loadthread.cpp \ @@ -221,6 +222,7 @@ HEADERS += \ project/projectmodel.h \ project/loadthread.h \ dialogs/loaddialog.h \ + dialogs/silencedialog.h \ global/debug.h \ global/path.h \ effects/internal/transformeffect.h \ diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 37c276d9b..fe97e7788 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -138,6 +138,25 @@ void Timeline::Retranslate() { UpdateTitle(); } +void Timeline::split_at_position(int pos) { + ComboAction* ca = new ComboAction(); + split_cache.clear(); + + if (olive::ActiveSequence->selections.size() > 0) { + // see if whole clips are selected + QVector pre_clips; + QVector post_clips; + for (int j=0;jclips.size();j++) { + Clip* clip = olive::ActiveSequence->clips.at(j).get(); + if (clip != nullptr && olive::ActiveSequence->IsClipSelected(clip, true)) { + split_clip_and_relink(ca,j,pos,true); + + } + } + olive::UndoStack.push(ca); + } +} + void Timeline::previous_cut() { if (olive::ActiveSequence != nullptr && olive::ActiveSequence->playhead > 0) { diff --git a/panels/timeline.h b/panels/timeline.h index 028c8977f..c3338d370 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -237,6 +237,7 @@ public slots: void deselect(); void toggle_links(); void split_at_playhead(); + void split_at_position(int pos); void ripple_delete(); void ripple_delete_empty_space(); void toggle_enable_on_selected_clips(); diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 2de81a528..18af4faf5 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -122,6 +122,7 @@ void TimelineWidget::show_context_menu(const QPoint& pos) { menu.addSeparator(); menu.addAction(tr("&Speed/Duration"), olive::Global.get(), SLOT(open_speed_dialog())); + menu.addAction(tr("&Cut Silence"), olive::Global.get(), SLOT(open_cut_silence_dialog())); QAction* autoscaleAction = menu.addAction(tr("Auto-s&cale"), this, SLOT(toggle_autoscale())); autoscaleAction->setCheckable(true);