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);