diff --git a/effects/paneffect.cpp b/effects/paneffect.cpp index dd859fbe8..0ac89037e 100644 --- a/effects/paneffect.cpp +++ b/effects/paneffect.cpp @@ -50,8 +50,8 @@ void PanEffect::save(QXmlStreamWriter *stream) { void PanEffect::process_audio(quint8 *samples, int nb_bytes) { if (pan_val->value() != 0) { for (int i=0;ivalue()*0.01f, 3); if (val < 0) { diff --git a/effects/volumeeffect.cpp b/effects/volumeeffect.cpp index a90e0ed1e..546e3c99a 100644 --- a/effects/volumeeffect.cpp +++ b/effects/volumeeffect.cpp @@ -5,6 +5,7 @@ #include #include +#include "playback/audio.h" #include "ui/labelslider.h" #include "ui/collapsiblewidget.h" @@ -50,9 +51,15 @@ void VolumeEffect::save(QXmlStreamWriter* stream) { void VolumeEffect::process_audio(quint8* samples, int nb_bytes) { if (volume_val->value() != 100) { for (int i=0;ivalue()*0.01f, 3); + qint32 samp = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); + double val = qPow(volume_val->value()*0.01, 3); samp *= val; + if (samp > INT16_MAX) { + samp = INT16_MAX; + } else if (samp < INT16_MIN) { + samp = INT16_MIN; + } + samples[i+1] = (quint8) (samp >> 8); samples[i] = (quint8) samp; } diff --git a/icons/icons.qrc b/icons/icons.qrc index e94bd87d4..facafcbdd 100644 --- a/icons/icons.qrc +++ b/icons/icons.qrc @@ -27,5 +27,7 @@ ripple-disabled.png rolling-disabled.png slip-disabled.png + slide.png + slide-disabled.png diff --git a/icons/slide-disabled.png b/icons/slide-disabled.png new file mode 100644 index 000000000..6bdb6f879 Binary files /dev/null and b/icons/slide-disabled.png differ diff --git a/icons/slide.png b/icons/slide.png new file mode 100644 index 000000000..72c9fe376 Binary files /dev/null and b/icons/slide.png differ diff --git a/io/media.h b/io/media.h index 26c34c7fe..700842dcd 100644 --- a/io/media.h +++ b/io/media.h @@ -23,7 +23,6 @@ struct MediaStream { int audio_channels; // preview thumbnail/waveform - QMutex preview_lock; bool preview_done; QImage video_preview; // TODO change to QPixmap QVector audio_preview; diff --git a/io/previewgenerator.cpp b/io/previewgenerator.cpp index 030e26fcc..e69d9daf4 100644 --- a/io/previewgenerator.cpp +++ b/io/previewgenerator.cpp @@ -105,7 +105,6 @@ void PreviewGenerator::run() { // delete [] data; s->preview_done = true; - s->preview_lock.unlock(); sws_freeContext(sws_ctx); @@ -179,7 +178,6 @@ void PreviewGenerator::run() { } for (int i=0;iaudio_tracks.size();i++) { media->audio_tracks.at(i)->preview_done = true; - media->audio_tracks.at(i)->preview_lock.unlock(); } av_frame_free(&temp_frame); for (unsigned int i=0;inb_streams;i++) { diff --git a/mainwindow.cpp b/mainwindow.cpp index 4442c39c3..32ae0a584 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -526,3 +526,8 @@ void MainWindow::on_actionSeek_to_the_End_of_Pastes_triggered() void MainWindow::on_actionAdd_Default_Transition_triggered() { if (panel_timeline->focused()) panel_timeline->add_transition(); } + +void MainWindow::on_actionSlide_Tool_triggered() +{ + if (panel_timeline->focused()) panel_timeline->ui->toolSlideButton->click(); +} diff --git a/mainwindow.h b/mainwindow.h index 8797d4151..3adbca085 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -137,6 +137,8 @@ private slots: void on_actionAdd_Default_Transition_triggered(); + void on_actionSlide_Tool_triggered(); + private: Ui::MainWindow *ui; void setup_layout(); diff --git a/mainwindow.ui b/mainwindow.ui index f480292c8..ca99fd4a9 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -125,6 +125,7 @@ + @@ -268,6 +269,9 @@ Sequence... + + Ctrl+Shift+N + @@ -571,6 +575,14 @@ Ctrl+Shift+D + + + Slide Tool + + + U + + diff --git a/olive.pro.user b/olive.pro.user index 936df18b6..0faa82619 100644 --- a/olive.pro.user +++ b/olive.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/panels/project.cpp b/panels/project.cpp index 709b86d3c..0e465b92a 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -140,7 +140,6 @@ Media* Project::import_file(QString file) { } else { MediaStream* ms = new MediaStream(); ms->preview_done = false; - ms->preview_lock.lock(); ms->file_index = i; if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { bool infinite_length = (pFormatCtx->streams[i]->avg_frame_rate.den == 0); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index b354bd242..a463c3a99 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -55,6 +55,7 @@ Timeline::Timeline(QWidget *parent) : tool_buttons.append(ui->toolRazorButton); tool_buttons.append(ui->toolSlipButton); tool_buttons.append(ui->toolRollingButton); + tool_buttons.append(ui->toolSlideButton); ui->toolArrowButton->click(); @@ -383,36 +384,7 @@ void Timeline::ripple(long ripple_point, long ripple_length) { void Timeline::decheck_tool_buttons(QObject* sender) { for (int i=0;isetChecked(false); - } - } -} - -void Timeline::on_toolEditButton_toggled(bool checked) -{ - if (checked) { - decheck_tool_buttons(sender()); - ui->timeline_area->setCursor(Qt::IBeamCursor); - tool = TIMELINE_TOOL_EDIT; - } -} - -void Timeline::on_toolArrowButton_toggled(bool checked) -{ - if (checked) { - decheck_tool_buttons(sender()); - ui->timeline_area->setCursor(Qt::ArrowCursor); - tool = TIMELINE_TOOL_POINTER; - } -} - -void Timeline::on_toolRazorButton_toggled(bool checked) -{ - if (checked) { - decheck_tool_buttons(sender()); - ui->timeline_area->setCursor(Qt::IBeamCursor); - tool = TIMELINE_TOOL_RAZOR; + tool_buttons[i]->setChecked(tool_buttons.at(i) == sender); } } @@ -436,33 +408,6 @@ bool Timeline::is_clip_selected(Clip* clip) { return false; } -void Timeline::on_toolRippleButton_toggled(bool checked) -{ - if (checked) { - decheck_tool_buttons(sender()); - ui->timeline_area->setCursor(Qt::ArrowCursor); - tool = TIMELINE_TOOL_RIPPLE; - } -} - -void Timeline::on_toolRollingButton_toggled(bool checked) -{ - if (checked) { - decheck_tool_buttons(sender()); - ui->timeline_area->setCursor(Qt::ArrowCursor); - tool = TIMELINE_TOOL_ROLLING; - } -} - -void Timeline::on_toolSlipButton_toggled(bool checked) -{ - if (checked) { - decheck_tool_buttons(sender()); - ui->timeline_area->setCursor(Qt::ArrowCursor); - tool = TIMELINE_TOOL_SLIP; - } -} - void Timeline::on_snappingButton_toggled(bool checked) { snapping = checked; @@ -849,3 +794,48 @@ long Timeline::getFrameFromScreenPoint(int x) { int Timeline::getScreenPointFromFrame(long frame) { return (int) round(frame*zoom); } + +void Timeline::on_toolArrowButton_clicked() { + decheck_tool_buttons(sender()); + ui->timeline_area->setCursor(Qt::ArrowCursor); + tool = TIMELINE_TOOL_POINTER; +} + +void Timeline::on_toolEditButton_clicked() { + decheck_tool_buttons(sender()); + ui->timeline_area->setCursor(Qt::IBeamCursor); + tool = TIMELINE_TOOL_EDIT; +} + +void Timeline::on_toolRippleButton_clicked() { + decheck_tool_buttons(sender()); + ui->timeline_area->setCursor(Qt::ArrowCursor); + tool = TIMELINE_TOOL_RIPPLE; +} + +void Timeline::on_toolRollingButton_clicked() { + decheck_tool_buttons(sender()); + ui->timeline_area->setCursor(Qt::ArrowCursor); + tool = TIMELINE_TOOL_ROLLING; +} + +void Timeline::on_toolRazorButton_clicked() +{ + decheck_tool_buttons(sender()); + ui->timeline_area->setCursor(Qt::IBeamCursor); + tool = TIMELINE_TOOL_RAZOR; +} + +void Timeline::on_toolSlipButton_clicked() +{ + decheck_tool_buttons(sender()); + ui->timeline_area->setCursor(Qt::ArrowCursor); + tool = TIMELINE_TOOL_SLIP; +} + +void Timeline::on_toolSlideButton_clicked() +{ + decheck_tool_buttons(sender()); + ui->timeline_area->setCursor(Qt::ArrowCursor); + tool = TIMELINE_TOOL_SLIDE; +} diff --git a/panels/timeline.h b/panels/timeline.h index 7dce03268..9fc8c69dc 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -35,6 +35,7 @@ struct Ghost { long ghost_length; long media_length; bool trim_in; + bool trimming; }; struct Selection { @@ -164,24 +165,27 @@ public slots: void repaint_timeline(); private slots: - void on_toolEditButton_toggled(bool checked); - - void on_toolArrowButton_toggled(bool checked); - - void on_toolRazorButton_toggled(bool checked); void on_pushButton_4_clicked(); - void on_pushButton_5_clicked(); - - void on_toolRippleButton_toggled(bool checked); - - void on_toolRollingButton_toggled(bool checked); - - void on_toolSlipButton_toggled(bool checked); + void on_pushButton_5_clicked(); void on_snappingButton_toggled(bool checked); + void on_toolSlideButton_clicked(); + + void on_toolArrowButton_clicked(); + + void on_toolEditButton_clicked(); + + void on_toolRippleButton_clicked(); + + void on_toolRollingButton_clicked(); + + void on_toolRazorButton_clicked(); + + void on_toolSlipButton_clicked(); + private: QVector tool_buttons; void decheck_tool_buttons(QObject* sender); diff --git a/panels/timeline.ui b/panels/timeline.ui index 7b17c0261..2b5930077 100644 --- a/panels/timeline.ui +++ b/panels/timeline.ui @@ -7,7 +7,7 @@ 0 0 523 - 363 + 376 @@ -233,7 +233,38 @@ :/icons/slip.png - :/icons/slip-disabled.png + :/icons/slip-disabled.png + + + + + 20 + 20 + + + + true + + + + + + + + 40 + 16777215 + + + + Slide Tool (U) + + + + + + + :/icons/slide.png + :/icons/slide-disabled.png @@ -331,7 +362,7 @@ 0 0 408 - 314 + 327 diff --git a/playback/audio.cpp b/playback/audio.cpp index 1eca26d6a..c51a6f7c7 100644 --- a/playback/audio.cpp +++ b/playback/audio.cpp @@ -57,7 +57,7 @@ void clear_audio_ibuffer() { int get_buffer_offset_from_frame(long frame) { if (frame >= audio_ibuffer_frame) { - return av_samples_get_buffer_size(NULL, av_get_channel_layout_nb_channels(sequence->audio_layout), qRound(((frame-audio_ibuffer_frame)/sequence->frame_rate)*sequence->audio_frequency), AV_SAMPLE_FMT_S16, 1); + return qFloor(av_samples_get_buffer_size(NULL, av_get_channel_layout_nb_channels(sequence->audio_layout), qRound(((frame-audio_ibuffer_frame)/sequence->frame_rate)*sequence->audio_frequency), AV_SAMPLE_FMT_S16, 1)/4)*4; } else { qDebug() << "[WARNING] get_buffer_offset_from_frame called incorrectly"; return 0; diff --git a/playback/audio.h b/playback/audio.h index 4e529e997..58f57fe88 100644 --- a/playback/audio.h +++ b/playback/audio.h @@ -3,6 +3,9 @@ #include +#define INT16_MAX 0x7fff +#define INT16_MIN (-INT16_MAX-1) + class QAudioOutput; class QIODevice; diff --git a/playback/cacher.cpp b/playback/cacher.cpp index f85b9e59b..60be3d933 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -15,6 +15,8 @@ extern "C" { } #include +#include +#include void cache_audio_worker(Clip* c) { int written = 0; @@ -94,10 +96,24 @@ void cache_audio_worker(Clip* c) { written = max_write; break; } else { - audio_ibuffer[c->audio_buffer_write%audio_ibuffer_size] += frame->data[0][c->frame_sample_index]; - c->audio_buffer_write++; - c->frame_sample_index++; - written++; + int upper_byte_index = (c->audio_buffer_write+1)%audio_ibuffer_size; + int lower_byte_index = (c->audio_buffer_write)%audio_ibuffer_size; + qint16 old_sample = (qint16) ((audio_ibuffer[upper_byte_index] & 0xFF) << 8 | (audio_ibuffer[lower_byte_index] & 0xFF)); + qint16 new_sample = (qint16) ((frame->data[0][c->frame_sample_index+1] & 0xFF) << 8 | (frame->data[0][c->frame_sample_index] & 0xFF)); + qint32 mixed_sample; + + mixed_sample = old_sample + new_sample; + if (mixed_sample > INT16_MAX) { + mixed_sample = INT16_MAX; + } else if (mixed_sample < INT16_MIN) { + mixed_sample = INT16_MIN; + } + + audio_ibuffer[upper_byte_index] = (quint8) (mixed_sample >> 8); + audio_ibuffer[lower_byte_index] = (quint8) mixed_sample; + c->audio_buffer_write+=2; + c->frame_sample_index+=2; + written+=2; } } if (c->frame_sample_index == nb_bytes) { diff --git a/ui/audiomonitor.h b/ui/audiomonitor.h index c22212412..00a04007f 100644 --- a/ui/audiomonitor.h +++ b/ui/audiomonitor.h @@ -3,6 +3,8 @@ #include +#define AUDIO_MONITOR_RESOLUTION 16 + class AudioMonitor : public QWidget { Q_OBJECT diff --git a/ui/timelinetools.h b/ui/timelinetools.h index 74f54fb9a..f09e4426b 100644 --- a/ui/timelinetools.h +++ b/ui/timelinetools.h @@ -7,7 +7,8 @@ #define TIMELINE_TOOL_RIPPLE 3 #define TIMELINE_TOOL_ROLLING 4 #define TIMELINE_TOOL_SLIP 5 -#define TIMELINE_TOOL_HAND 6 -#define TIMELINE_TOOL_ZOOM 7 +#define TIMELINE_TOOL_SLIDE 6 +#define TIMELINE_TOOL_HAND 7 +#define TIMELINE_TOOL_ZOOM 8 #endif // TIMELINETOOLS_H diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 77a046934..29e465ca6 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -52,8 +52,8 @@ void TimelineWidget::resizeEvent(QResizeEvent*) { void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { if (static_cast(event->source()) == panel_project->source_table) { + event->accept(); QPoint pos = event->pos(); - event->accept(); QList items = panel_project->source_table->selectedItems(); long entry_point = panel_timeline->getFrameFromScreenPoint(pos.x()); panel_timeline->drag_frame_start = entry_point + panel_timeline->getFrameFromScreenPoint(50); @@ -61,25 +61,35 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { for (int i=0;iget_media_from_tree(items.at(i)); - long duration = m->get_length_in_frames(sequence->frame_rate); - Ghost g = {0, entry_point, entry_point + duration}; + Ghost g; + g.clip = -1; g.media = m; - g.clip_in = 0; + g.old_clip_in = g.clip_in = 0; + g.in = entry_point; + entry_point += m->get_length_in_frames(sequence->frame_rate); + g.out = entry_point; + g.trimming = false; for (int j=0;jaudio_tracks.size();j++) { - g.track = j; + g.track = j; g.media_stream = m->audio_tracks.at(j); ignore_infinite_length = true; panel_timeline->ghosts.append(g); } for (int j=0;jvideo_tracks.size();j++) { - g.track = -1-j; + g.track = -1-j; g.media_stream = m->video_tracks.at(j); if (m->video_tracks[j]->infinite_length && !ignore_infinite_length) g.out = g.in + 100; panel_timeline->ghosts.append(g); - } - entry_point += duration; - } - init_ghosts(); + } + } + for (int i=0;ighosts.size();i++) { + Ghost& g = panel_timeline->ghosts[i]; + g.old_in = g.in; + g.old_out = g.out; + g.old_track = g.track; + } + +// init_ghosts(); panel_timeline->importing = true; } } @@ -87,7 +97,7 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { void TimelineWidget::dragMoveEvent(QDragMoveEvent *event) { if (panel_timeline->importing) { QPoint pos = event->pos(); - update_ghosts(pos); + update_ghosts(pos); panel_timeline->repaint_timeline(); } } @@ -211,6 +221,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { case TIMELINE_TOOL_RIPPLE: case TIMELINE_TOOL_SLIP: case TIMELINE_TOOL_ROLLING: + case TIMELINE_TOOL_SLIDE: { if (track_resizing) { track_resize_mouse_cache = event->pos().y(); @@ -474,10 +485,10 @@ void TimelineWidget::init_ghosts() { g.out = g.old_out = c->timeline_out; g.track = g.old_track = c->track; g.clip_in = g.old_clip_in = c->clip_in; + g.ghost_length = g.old_out - g.old_in; - if (panel_timeline->trim_target > -1 || panel_timeline->tool == TIMELINE_TOOL_SLIP) { + if (panel_timeline->trim_target > -1 || panel_timeline->tool == TIMELINE_TOOL_SLIP || panel_timeline->tool == TIMELINE_TOOL_SLIDE) { // used for trim ops - g.ghost_length = g.old_out - g.old_in; g.media_length = sequence->get_clip(g.clip)->media->get_length_in_frames(sequence->frame_rate); } } @@ -489,7 +500,7 @@ void TimelineWidget::init_ghosts() { } } -bool subvalidate_snapping(Ghost& g, long* frame_diff, long snap_point) { +bool subvalidate_snapping(const Ghost& g, long* frame_diff, long snap_point) { int snap_range = panel_timeline->get_snap_range(); long in_validator = g.old_in + *frame_diff - snap_point; long out_validator = g.old_out + *frame_diff - snap_point; @@ -508,7 +519,7 @@ bool subvalidate_snapping(Ghost& g, long* frame_diff, long snap_point) { return false; } -void validate_snapping(Ghost& g, long* frame_diff) { +void validate_snapping(const Ghost& g, long* frame_diff) { panel_timeline->snapped = false; if (panel_timeline->snapping) { if (!subvalidate_snapping(g, frame_diff, panel_timeline->playhead)) { @@ -528,48 +539,64 @@ void validate_snapping(Ghost& g, long* frame_diff) { void TimelineWidget::update_ghosts(QPoint& mouse_pos) { int mouse_track = getTrackFromScreenPoint(mouse_pos.y()); long frame_diff = panel_timeline->getFrameFromScreenPoint(mouse_pos.x()) - panel_timeline->drag_frame_start; - int track_diff = mouse_track - panel_timeline->drag_track_start; + int track_diff = (panel_timeline->tool == TIMELINE_TOOL_SLIDE) ? 0 : mouse_track - panel_timeline->drag_track_start; + long validator; - long validator; - if (panel_timeline->trim_target > -1) { // if trimming - // trim ops - - // first try to snap + // first try to snap + if (panel_timeline->tool != TIMELINE_TOOL_SLIP) { + // slipping doesn't move the clips so we don't bother snapping for it for (int i=0;ighosts.size();i++) { Ghost& g = panel_timeline->ghosts[i]; validate_snapping(g, &frame_diff); } + } - // validate ghosts - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; - Clip* c = sequence->get_clip(g.clip); + bool clips_are_movable = (panel_timeline->tool == TIMELINE_TOOL_POINTER || panel_timeline->tool == TIMELINE_TOOL_SLIDE || panel_timeline->importing); + // validate ghosts + long temp_frame_diff = frame_diff; // cache to see if we change it (thus cancelling any snap) + for (int i=0;ighosts.size();i++) { + const Ghost& g = panel_timeline->ghosts.at(i); + Clip* c = NULL; + if (g.clip != -1) c = sequence->get_clip(g.clip); + + // validate ghosts for trimming + if (panel_timeline->tool == TIMELINE_TOOL_SLIP) { + if (!sequence->get_clip(g.clip)->media_stream->infinite_length) { + // prevent slip moving a clip below 0 clip_in + validator = g.old_clip_in - frame_diff; + if (validator < 0) frame_diff += validator; + + // prevent slip moving clip beyond media length + validator += g.ghost_length; + if (validator > g.media_length) frame_diff += validator - g.media_length; + } + } else if (g.trimming) { if (g.trim_in) { - // prevent clip length from being less than 1 frame long - validator = g.ghost_length - frame_diff; - if (validator < 1) frame_diff -= (1 - validator); + // prevent clip length from being less than 1 frame long + validator = g.ghost_length - frame_diff; + if (validator < 1) frame_diff -= (1 - validator); - // prevent timeline in from going below 0 - validator = g.old_in + frame_diff; - if (validator < 0) frame_diff -= validator; + // prevent timeline in from going below 0 + validator = g.old_in + frame_diff; + if (validator < 0) frame_diff -= validator; if (!c->media_stream->infinite_length) { - // prevent clip_in from going below 0 - validator = g.old_clip_in + frame_diff; - if (validator < 0) frame_diff -= validator; + // prevent clip_in from going below 0 + validator = g.old_clip_in + frame_diff; + if (validator < 0) frame_diff -= validator; } - } else { - // prevent clip length from being less than 1 frame long - validator = g.ghost_length + frame_diff; - if (validator < 1) frame_diff += (1 - validator); + } else { + // prevent clip length from being less than 1 frame long + validator = g.ghost_length + frame_diff; + if (validator < 1) frame_diff += (1 - validator); if (!c->media_stream->infinite_length) { - // prevent clip length exceeding media length - validator = g.ghost_length + frame_diff; - if (validator > g.media_length) frame_diff -= validator - g.media_length; + // prevent clip length exceeding media length + validator = g.ghost_length + frame_diff; + if (validator > g.media_length) frame_diff -= validator - g.media_length; } - } + } // ripple ops if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) { @@ -594,112 +621,85 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) { } } } + } else if (clips_are_movable) { // validate ghosts for moving + // prevent clips from moving below 0 on the timeline + validator = g.old_in + frame_diff; + if (validator < 0) frame_diff -= validator; + + // prevent clips from crossing tracks + if (same_sign(g.old_track, panel_timeline->drag_track_start)) { + while (!same_sign(g.old_track, g.old_track + track_diff)) { + if (g.old_track < 0) { + track_diff--; + } else { + track_diff++; + } + } + } } + } + if (temp_frame_diff != frame_diff) { + panel_timeline->snapped = false; + } - // resize ghosts - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; + // apply changes to ghosts + for (int i=0;ighosts.size();i++) { + Ghost& g = panel_timeline->ghosts[i]; + if (g.trimming) { if (g.trim_in) { g.in = g.old_in + frame_diff; g.clip_in = g.old_clip_in + frame_diff; } else { g.out = g.old_out + frame_diff; } - } + } else if (clips_are_movable) { + g.track = g.old_track; + g.in = g.old_in + frame_diff; + g.out = g.old_out + frame_diff; - // resize selections + if (panel_timeline->importing) { + int abs_track_diff = abs(track_diff); + if (g.old_track < 0) { // clip is video + g.track -= abs_track_diff; + } else { // clip is audio + g.track += abs_track_diff; + } + } else if (same_sign(g.old_track, panel_timeline->drag_track_start)) { + g.track += track_diff; + } + } + } + + // apply changes to selections + if (panel_timeline->tool != TIMELINE_TOOL_SLIP) { for (int i=0;iselections.size();i++) { Selection& s = panel_timeline->selections[i]; - if (panel_timeline->trim_in_point) { - s.in = s.old_in + frame_diff; + if (panel_timeline->trim_target > -1) { + if (panel_timeline->trim_in_point) { + s.in = s.old_in + frame_diff; + } else { + s.out = s.old_out + frame_diff; + } } else { - s.out = s.old_out + frame_diff; + for (int i=0;iselections.size();i++) { + Selection& s = panel_timeline->selections[i]; + s.in = s.old_in + frame_diff; + s.out = s.old_out + frame_diff; + s.track = s.old_track; + if (panel_timeline->importing) { + int abs_track_diff = abs(track_diff); + if (s.old_track < 0) { + s.track -= abs_track_diff; + } else { + s.track += abs_track_diff; + } + } else { + if (same_sign(s.track, panel_timeline->drag_track_start)) s.track += track_diff; + } + } } } - } else if (panel_timeline->tool == TIMELINE_TOOL_POINTER || panel_timeline->importing) { // only move clips on pointer (not ripple or rolling) - // validate ghosts - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; - - // prevent clips from moving below 0 on the timeline - validator = g.old_in + frame_diff; - if (validator < 0) frame_diff -= validator; - - // prevent clips from crossing tracks - if (same_sign(g.old_track, panel_timeline->drag_track_start)) { - while (!same_sign(g.old_track, g.old_track + track_diff)) { - if (g.old_track < 0) { - track_diff--; - } else { - track_diff++; - } - } - } - - validate_snapping(g, &frame_diff); - } - - // move ghosts - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; - g.in = g.old_in + frame_diff; - g.out = g.old_out + frame_diff; - - g.track = g.old_track; - - if (panel_timeline->importing) { - int abs_track_diff = abs(track_diff); - if (g.old_track < 0) { // clip is video - g.track -= abs_track_diff; - } else { // clip is audio - g.track += abs_track_diff; - } - } else { - if (same_sign(g.old_track, panel_timeline->drag_track_start)) g.track += track_diff; - } - } - - // move selections - if (!panel_timeline->importing) { - for (int i=0;iselections.size();i++) { - Selection& s = panel_timeline->selections[i]; - s.in = s.old_in + frame_diff; - s.out = s.old_out + frame_diff; - s.track = s.old_track; - if (panel_timeline->importing) { - int abs_track_diff = abs(track_diff); - if (s.old_track < 0) { - s.track -= abs_track_diff; - } else { - s.track += abs_track_diff; - } - } else { - if (same_sign(s.track, panel_timeline->drag_track_start)) s.track += track_diff; - } - } - } - } else if (panel_timeline->tool == TIMELINE_TOOL_SLIP) { - // validate ghosts - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; - if (!sequence->get_clip(g.clip)->media_stream->infinite_length) { - // prevent slip moving a clip below 0 clip_in - validator = g.old_clip_in - frame_diff; - if (validator < 0) frame_diff += validator; - - // prevent slip moving clip beyond media length - validator += g.ghost_length; - if (validator > g.media_length) frame_diff += validator - g.media_length; - } - } - - // slip ghosts - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; - - g.clip_in = g.old_clip_in - frame_diff; - } } } @@ -786,15 +786,31 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { if (c != NULL && panel_timeline->is_clip_selected(c)) { Ghost g; g.clip = i; + g.trimming = (panel_timeline->trim_target > -1); g.trim_in = panel_timeline->trim_in_point; panel_timeline->ghosts.append(g); } } + int size = panel_timeline->ghosts.size(); if (panel_timeline->tool == TIMELINE_TOOL_ROLLING) { - int size = panel_timeline->ghosts.size(); for (int i=0;iget_clip(panel_timeline->ghosts.at(i).clip); + + // see if any ghosts are touching, in which case flip them + for (int k=0;kget_clip(panel_timeline->ghosts.at(k).clip); + if ((panel_timeline->trim_in_point && comp_clip->timeline_out == ghost_clip->timeline_in) || + (!panel_timeline->trim_in_point && comp_clip->timeline_in == ghost_clip->timeline_out)) { + panel_timeline->ghosts[k].trim_in = !panel_timeline->trim_in_point; + } + } + } + + // then look for other clips we're touching + for (int i=0;ighosts.at(i); + Clip* ghost_clip = sequence->get_clip(g.clip); for (int j=0;jclip_count();j++) { Clip* comp_clip = sequence->get_clip(j); if (comp_clip->track == ghost_clip->track) { @@ -802,20 +818,56 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { (!panel_timeline->trim_in_point && comp_clip->timeline_in == ghost_clip->timeline_out)) { // see if this clip is already selected, and if so just switch the trim_in bool found = false; - for (int k=0;kghosts.at(k).clip == j) { - panel_timeline->ghosts[k].trim_in = !panel_timeline->trim_in_point; + int duplicate_ghost_index; + for (duplicate_ghost_index=0;duplicate_ghost_indexghosts.at(duplicate_ghost_index).clip == j) { found = true; break; } } - - if (!found) { - // add ghost for this clip with opposite trim_in - Ghost g; - g.clip = j; - g.trim_in = !panel_timeline->trim_in_point; - panel_timeline->ghosts.append(g); + if (g.trim_in == panel_timeline->trim_in_point) { + if (!found) { + // add ghost for this clip with opposite trim_in + Ghost gh; + gh.clip = j; + gh.trimming = (panel_timeline->trim_target > -1); + gh.trim_in = !panel_timeline->trim_in_point; + panel_timeline->ghosts.append(gh); + } + } else { + if (found) { + panel_timeline->ghosts.removeAt(duplicate_ghost_index); + size--; + if (duplicate_ghost_index < i) i--; + } + } + } + } + } + } + } else if (panel_timeline->tool == TIMELINE_TOOL_SLIDE) { + for (int i=0;ighosts.at(i); + Clip* ghost_clip = sequence->get_clip(g.clip); + panel_timeline->ghosts[i].trimming = false; + for (int j=0;jclip_count();j++) { + Clip* c = sequence->get_clip(j); + if (c->track == ghost_clip->track) { + bool found = false; + for (int k=0;kghosts.at(k).clip == j) { + found = true; + break; + } + } + if (!found) { + bool is_in = (c->timeline_in == ghost_clip->timeline_out); + if (is_in || c->timeline_out == ghost_clip->timeline_in) { + Ghost gh; + gh.clip = j; + gh.trimming = true; + gh.trim_in = is_in; + panel_timeline->ghosts.append(gh); } } } @@ -1134,8 +1186,9 @@ void TimelineWidget::redraw_clips() { for (int j=0;jmedia_stream->audio_channels;j++) { int mid = clip_rect.top()+channel_height*j+(channel_height/2); int offset = waveform_index+(j*2); - qint8 min = (float)clip->media_stream->audio_preview[offset] / 128.0f * (channel_height/2); - qint8 max = (float)clip->media_stream->audio_preview[offset+1] / 128.0f * (channel_height/2); + + qint8 min = (double)clip->media_stream->audio_preview.at(offset) / 128.0 * (channel_height/2); + qint8 max = (double)clip->media_stream->audio_preview.at(offset+1) / 128.0 * (channel_height/2); clip_painter.drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max); } } diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 5a5bdb33a..4fd711c97 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -186,7 +186,7 @@ void ViewerWidget::paintGL() { long sample_cache_playhead = panel_timeline->ui->audio_monitor->sample_cache_offset + panel_timeline->ui->audio_monitor->sample_cache.size(); int buffer_offset, buffer_offset_adjusted; while ((buffer_offset = get_buffer_offset_from_frame(sample_cache_playhead)) < audio_ibuffer_read) { - buffer_offset_adjusted = buffer_offset%audio_ibuffer_size; + buffer_offset_adjusted = (buffer_offset)%audio_ibuffer_size; panel_timeline->ui->audio_monitor->sample_cache.append((qint16) ((audio_ibuffer[buffer_offset_adjusted+1] << 8) | audio_ibuffer[buffer_offset_adjusted])); sample_cache_playhead++; }