diff --git a/mainwindow.cpp b/mainwindow.cpp index 6d90ca898..66198b6d8 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -923,3 +923,7 @@ void MainWindow::on_actionNest_triggered() { } } } + +void MainWindow::on_actionToggle_Show_All_triggered() { + if (sequence != NULL) panel_timeline->toggle_show_all(); +} diff --git a/mainwindow.h b/mainwindow.h index 513de35bd..da61a9aa9 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -199,6 +199,8 @@ private slots: void on_actionNest_triggered(); + void on_actionToggle_Show_All_triggered(); + private: Ui::MainWindow *ui; void setup_layout(); diff --git a/mainwindow.ui b/mainwindow.ui index 1b6a5ec1e..506187947 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -137,6 +137,7 @@ + @@ -848,6 +849,14 @@ Nest + + + Toggle Show All + + + \ + + diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 1d69d48ed..183539296 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -64,7 +64,8 @@ Timeline::Timeline(QWidget *parent) : transition_tool_clip(-1), transition_tool_init(false), transition_tool_proc(false), - move_insert(false) + move_insert(false), + showing_all(false) { default_track_height = (QGuiApplication::primaryScreen()->logicalDotsPerInch() / 96) * TRACK_DEFAULT_HEIGHT; @@ -145,6 +146,16 @@ void Timeline::next_cut() { if (seek_enabled) panel_sequence_viewer->seek(n_cut); } +void Timeline::toggle_show_all() { + showing_all = !showing_all; + if (showing_all) { + old_zoom = zoom; + set_zoom_value((double) (ui->timeline_area->width() - 200) / (double) sequence->getEndFrame()); + } else { + set_zoom_value(old_zoom); + } +} + int Timeline::get_track_height_size(bool video) { if (video) { return video_track_heights.size(); @@ -345,14 +356,19 @@ int lerp(int a, int b, double t) { return ((1.0 - t) * a) + (t * b); } -void Timeline::set_zoom(bool in) { - zoom *= (in) ? 2 : 0.5; +void Timeline::set_zoom_value(double v) { + zoom = v; ui->headers->update_zoom(zoom); repaint_timeline(); - // TODO find a way to gradually move towards target_scroll instead of just setting it? - int target_scroll = getScreenPointFromFrame(zoom, sequence->playhead)-(ui->editAreas->width()>>1); - ui->horizontalScrollBar->setValue(target_scroll); + // TODO find a way to gradually move towards target_scroll instead of just setting it? + int target_scroll = getScreenPointFromFrame(zoom, sequence->playhead)-(ui->editAreas->width()>>1); + ui->horizontalScrollBar->setValue(target_scroll); +} + +void Timeline::set_zoom(bool in) { + showing_all = false; + set_zoom_value(zoom * ((in) ? 2 : 0.5)); } void Timeline::decheck_tool_buttons(QObject* sender) { diff --git a/panels/timeline.h b/panels/timeline.h index 77a980c3e..3528c3e0e 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -97,6 +97,7 @@ public: void delete_in_out(bool ripple); void previous_cut(); void next_cut(); + void toggle_show_all(); int getTimelineScreenPointFromFrame(long frame); long getTimelineFrameFromScreenPoint(int x); @@ -116,6 +117,8 @@ public: long drag_frame_start; int drag_track_start; void update_effect_controls(); + bool showing_all; + double old_zoom; QVector video_track_heights; QVector audio_track_heights; @@ -216,6 +219,7 @@ private slots: void transition_menu_select(QAction*); private: + void set_zoom_value(double v); QVector tool_buttons; void decheck_tool_buttons(QObject* sender); void set_tool(int tool); diff --git a/panels/viewer.cpp b/panels/viewer.cpp index dadbb17a9..f704256a8 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -35,7 +35,8 @@ Viewer::Viewer(QWidget *parent) : seq(NULL), playing(false), created_sequence(false), - cue_recording_internal(false) + cue_recording_internal(false), + just_played(false) { ui->setupUi(this); ui->headers->viewer = this; @@ -283,17 +284,26 @@ void Viewer::play() { return; } playhead_start = seq->playhead; - start_msecs = QDateTime::currentMSecsSinceEpoch(); playing = true; + just_played = true; set_playpause_icon(false); - playback_updater.start(); + start_msecs = QDateTime::currentMSecsSinceEpoch(); timer_update(); - audio_thread->notifyReceiver(); + } +} + +void Viewer::play_wake() { + if (just_played) { + start_msecs = QDateTime::currentMSecsSinceEpoch(); + playback_updater.start(); + audio_thread->notifyReceiver(); + just_played = false; } } void Viewer::pause() { playing = false; + just_played = false; set_playpause_icon(true); playback_updater.stop(); @@ -394,8 +404,10 @@ void Viewer::set_media(int type, void* media) { seq->name = footage->name; seq->using_workarea = footage->using_inout; - seq->workarea_in = footage->in; - seq->workarea_out = footage->out; + if (footage->using_inout) { + seq->workarea_in = footage->in; + seq->workarea_out = footage->out; + } seq->frame_rate = 30; diff --git a/panels/viewer.h b/panels/viewer.h index da294f8ce..61625ed02 100644 --- a/panels/viewer.h +++ b/panels/viewer.h @@ -50,6 +50,7 @@ public: long playhead_start; qint64 start_msecs; QTimer playback_updater; + bool just_played; void cue_recording(long start, long end, int track); void uncue_recording(); @@ -69,6 +70,7 @@ public: Ui::Viewer *ui; public slots: + void play_wake(); private slots: void on_pushButton_clicked(); diff --git a/playback/cacher.cpp b/playback/cacher.cpp index d8a0d3530..82228bd3e 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -9,6 +9,8 @@ #include "panels/timeline.h" #include "panels/project.h" #include "playback/audio.h" +#include "panels/panels.h" +#include "panels/viewer.h" #include "debug.h" extern "C" { @@ -37,8 +39,6 @@ double bytes_to_seconds(int nb_bytes, int nb_channels, int sample_rate) { } void apply_audio_effects(Clip* c, double timecode_start, AVFrame* frame, int nb_bytes, QVector nests) { - dout << c->name << timecode_start; - // perform all aud io effects double timecode_end; timecode_end = timecode_start + bytes_to_seconds(nb_bytes, frame->channels, frame->sample_rate); @@ -306,8 +306,8 @@ void cache_audio_worker(Clip* c, bool scrubbing, QVector& nests) { } } - int offset = (audio_ibuffer_read + AUDIO_BUFFER_PADDING) - c->audio_buffer_write; - if (offset > 0) { + int offset = audio_ibuffer_read - c->audio_buffer_write; + if (offset > 0) { c->audio_buffer_write += offset; c->frame_sample_index += offset; } @@ -341,7 +341,9 @@ void cache_audio_worker(Clip* c, bool scrubbing, QVector& nests) { apply_audio_effects(c, bytes_to_seconds(frame->pts, frame->channels, frame->sample_rate), frame, nb_bytes, nests); c->frame->pts += nb_bytes; c->frame_sample_index = 0; - if (c->audio_buffer_write == 0) c->audio_buffer_write = get_buffer_offset_from_frame(sequence, qMax(timeline_in, c->audio_target_frame)); + if (c->audio_buffer_write == 0) { + c->audio_buffer_write = get_buffer_offset_from_frame(sequence, qMax(timeline_in, c->audio_target_frame)); + } int offset = audio_ibuffer_read - c->audio_buffer_write; if (offset > 0) { c->audio_buffer_write += offset; @@ -361,6 +363,10 @@ void cache_audio_worker(Clip* c, bool scrubbing, QVector& nests) { long buffer_timeline_out = get_buffer_offset_from_frame(sequence, timeline_out); audio_write_lock.lock(); + dout << "starting fsi:" << c->frame_sample_index << "abw:" << c->audio_buffer_write; + + + while (c->frame_sample_index < nb_bytes && c->audio_buffer_write < audio_ibuffer_read+(audio_ibuffer_size>>1) && c->audio_buffer_write < buffer_timeline_out) { @@ -403,6 +409,9 @@ void cache_audio_worker(Clip* c, bool scrubbing, QVector& nests) { break; } } + + QMetaObject::invokeMethod(panel_footage_viewer, "play_wake", Qt::QueuedConnection); + QMetaObject::invokeMethod(panel_sequence_viewer, "play_wake", Qt::QueuedConnection); } void cache_video_worker(Clip* c, long playhead) { diff --git a/ui/sourcetable.cpp b/ui/sourcetable.cpp index b2324bbcd..dc184da98 100644 --- a/ui/sourcetable.cpp +++ b/ui/sourcetable.cpp @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include SourceTable::SourceTable(QWidget* parent) : QTreeWidget(parent) { editing_item = NULL; @@ -29,6 +32,8 @@ SourceTable::SourceTable(QWidget* parent) : QTreeWidget(parent) { connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu())); } + + void SourceTable::show_context_menu() { QMenu menu(this); @@ -45,6 +50,15 @@ void SourceTable::show_context_menu() { if (type == MEDIA_TYPE_FOOTAGE) { QAction* replace_action = menu.addAction("Replace/Relink Media"); connect(replace_action, SIGNAL(triggered(bool)), panel_project, SLOT(replace_selected_file())); + +#if defined(Q_OS_WIN) + QAction* reveal_in_explorer = menu.addAction("Reveal in Explorer"); +#elif defined(Q_OS_MAC) + QAction* reveal_in_explorer = menu.addAction("Reveal in Finder"); +#else + QAction* reveal_in_explorer = menu.addAction("Reveal in File Manager"); +#endif + connect(reveal_in_explorer, SIGNAL(triggered(bool)), this, SLOT(reveal_in_browser())); } if (type != MEDIA_TYPE_FOLDER) { QAction* replace_clip_media = menu.addAction("Replace Clips Using This Media"); @@ -114,6 +128,29 @@ void SourceTable::create_seq_from_selected() { } } +void SourceTable::reveal_in_browser() { + Media* m = get_footage_from_tree(selectedItems().at(0)); + +#if defined(Q_OS_WIN) + QStringList args; + args << "/select," << QDir::toNativeSeparators(m->url); + QProcess::startDetached("explorer", args); +#elif defined(Q_OS_MAC) + QStringList args; + args << "-e"; + args << "tell application \"Finder\""; + args << "-e"; + args << "activate"; + args << "-e"; + args << "select POSIX file \""+m->url+"\""; + args << "-e"; + args << "end tell"; + QProcess::startDetached("osascript", args); +#else + QDesktopServices::openUrl(QUrl::fromLocalFile(m->url.left(m->url.lastIndexOf('/')))); +#endif +} + void SourceTable::item_renamed(QTreeWidgetItem* item) { if (editing_item == item) { MediaRename* mr = new MediaRename(); diff --git a/ui/sourcetable.h b/ui/sourcetable.h index 13b55e109..77b9a590b 100644 --- a/ui/sourcetable.h +++ b/ui/sourcetable.h @@ -29,6 +29,7 @@ private slots: void item_renamed(QTreeWidgetItem *item); void show_context_menu(); void create_seq_from_selected(); + void reveal_in_browser(); }; #endif // SOURCETABLE_H diff --git a/ui/timelineheader.cpp b/ui/timelineheader.cpp index 8ad183855..fc3877828 100644 --- a/ui/timelineheader.cpp +++ b/ui/timelineheader.cpp @@ -6,10 +6,10 @@ #include "project/undo.h" #include "panels/viewer.h" #include "io/config.h" +#include "debug.h" #include #include -#include #include #include @@ -82,6 +82,9 @@ void TimelineHeader::set_out_point(long new_out) { } else if (new_in > new_out) { new_in = 0; } + + dout << new_in << new_out; + undo_stack.push(new SetTimelineInOutCommand(viewer->seq, true, new_in, new_out)); update_parents(); } diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 7c6e012e4..2f86b7e9b 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -1488,7 +1488,7 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos) { } else { s.out = s.old_out + frame_diff; } - } else { + } else if (clips_are_movable) { for (int i=0;iselections.size();i++) { Selection& s = sequence->selections[i]; s.in = s.old_in + frame_diff; diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index ff0f3590e..71c3bd953 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -235,6 +235,8 @@ GLuint ViewerWidget::compose_sequence(QVector& nests, bool render_audio) } } + int audio_track_count = 0; + QVector current_clips; for (int i=0;iclips.size();i++) { @@ -258,6 +260,7 @@ GLuint ViewerWidget::compose_sequence(QVector& nests, bool render_audio) open_clip(c, !rendering); } clip_is_active = true; + if (c->track >= 0) audio_track_count++; } else if (c->open) { close_clip(c); } @@ -486,6 +489,10 @@ GLuint ViewerWidget::compose_sequence(QVector& nests, bool render_audio) } } + if (audio_track_count == 0) { + viewer->play_wake(); + } + glPopMatrix(); if (!nests.isEmpty() && nests.last()->fbo != NULL) {