From 96802e971a509c309e503c23d689503c0e592edd Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 9 Sep 2018 16:36:50 +1000 Subject: [PATCH] made tone effect, doesn't yet work on NULL clips --- effects/audio/audionoiseeffect.cpp | 4 +-- effects/audio/toneeffect.cpp | 56 ++++++++++++++++++++++++++++++ effects/audio/toneeffect.h | 19 ++++++++++ effects/effect.cpp | 9 +++++ effects/effect.h | 3 ++ olive.pro | 6 ++-- panels/timeline.cpp | 18 ++++------ panels/timeline.h | 1 + playback/cacher.cpp | 3 +- playback/playback.cpp | 20 ++++++----- ui/timelineheader.cpp | 10 ++++-- ui/timelinewidget.cpp | 28 ++++++++++----- ui/timelinewidget.h | 3 +- ui/viewerwidget.cpp | 2 +- 14 files changed, 141 insertions(+), 41 deletions(-) create mode 100644 effects/audio/toneeffect.cpp create mode 100644 effects/audio/toneeffect.h diff --git a/effects/audio/audionoiseeffect.cpp b/effects/audio/audionoiseeffect.cpp index 5a90c2ace..136834db7 100644 --- a/effects/audio/audionoiseeffect.cpp +++ b/effects/audio/audionoiseeffect.cpp @@ -33,8 +33,8 @@ void AudioNoiseEffect::process_audio(double timecode_start, double timecode_end, if (mix_val->get_bool_value(timecode)) { qint16 left_sample = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); qint16 right_sample = (qint16) (((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); - left_noise_sample += left_sample; - right_noise_sample += right_sample; + left_noise_sample = mixAudioSample(left_noise_sample, left_sample); + right_noise_sample = mixAudioSample(right_noise_sample, right_sample); } samples[i+3] = (quint8) (right_noise_sample >> 8); diff --git a/effects/audio/toneeffect.cpp b/effects/audio/toneeffect.cpp new file mode 100644 index 000000000..530d00b44 --- /dev/null +++ b/effects/audio/toneeffect.cpp @@ -0,0 +1,56 @@ +#include "toneeffect.h" + +#include + +#define TONE_TYPE_SINE 0 + +#include "project/clip.h" +#include "project/sequence.h" + +ToneEffect::ToneEffect(Clip* c) : Effect(c, EFFECT_TYPE_AUDIO, AUDIO_TONE_EFFECT), sinX(0) { + type_val = add_row("Type:")->add_field(EFFECT_FIELD_COMBO); + type_val->add_combo_item("Sine", TONE_TYPE_SINE); + + freq_val = add_row("Frequency:")->add_field(EFFECT_FIELD_DOUBLE); + freq_val->set_double_minimum_value(20); + freq_val->set_double_maximum_value(20000); + freq_val->set_double_default_value(1000); + + amount_val = add_row("Amount:")->add_field(EFFECT_FIELD_DOUBLE); + amount_val->set_double_minimum_value(0); + amount_val->set_double_maximum_value(100); + amount_val->set_double_default_value(80); + + mix_val = add_row("Mix:")->add_field(EFFECT_FIELD_BOOL); + mix_val->set_bool_value(true); + + connect(freq_val, SIGNAL(changed()), this, SLOT(field_changed())); + connect(amount_val, SIGNAL(changed()), this, SLOT(field_changed())); + connect(mix_val, SIGNAL(changed()), this, SLOT(field_changed())); +} + +void ToneEffect::process_audio(double timecode_start, double timecode_end, quint8 *samples, int nb_bytes, int channel_count) { + double interval = (timecode_end - timecode_start)/nb_bytes; + for (int i=0;iget_double_value(timecode))/parent_clip->sequence->audio_frequency)*(amount_val->get_double_value(timecode)*0.01)*INT16_MAX; + qint16 right_tone_sample = left_tone_sample; + + + // mix with source audio + if (mix_val->get_bool_value(timecode)) { + qint16 left_sample = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); + qint16 right_sample = (qint16) (((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); + left_tone_sample = mixAudioSample(left_tone_sample, left_sample); + right_tone_sample = mixAudioSample(right_tone_sample, right_sample); + } + + samples[i+3] = (quint8) (right_tone_sample >> 8); + samples[i+2] = (quint8) right_tone_sample; + samples[i+1] = (quint8) (left_tone_sample >> 8); + samples[i] = (quint8) left_tone_sample; + + sinX++; + } +} diff --git a/effects/audio/toneeffect.h b/effects/audio/toneeffect.h new file mode 100644 index 000000000..28a44632e --- /dev/null +++ b/effects/audio/toneeffect.h @@ -0,0 +1,19 @@ +#ifndef TONEEFFECT_H +#define TONEEFFECT_H + +#include "../effect.h" + +class ToneEffect : public Effect { +public: + ToneEffect(Clip *c); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + + EffectField* type_val; + EffectField* freq_val; + EffectField* amount_val; + EffectField* mix_val; +private: + int sinX; +}; + +#endif // TONEEFFECT_H diff --git a/effects/effect.cpp b/effects/effect.cpp index b743b3939..efdc8bd2a 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -31,6 +31,7 @@ #include "effects/audio/paneffect.h" #include "effects/audio/volumeeffect.h" #include "effects/audio/audionoiseeffect.h" +#include "effects/audio/toneeffect.h" #include #include @@ -60,6 +61,7 @@ void init_effects() { audio_effect_names[AUDIO_VOLUME_EFFECT] = "Volume"; audio_effect_names[AUDIO_PAN_EFFECT] = "Pan"; audio_effect_names[AUDIO_NOISE_EFFECT] = "Noise"; + audio_effect_names[AUDIO_TONE_EFFECT] = "Tone"; } Effect* create_effect(int effect_id, Clip* c) { @@ -81,6 +83,7 @@ Effect* create_effect(int effect_id, Clip* c) { case AUDIO_VOLUME_EFFECT: return new VolumeEffect(c); break; case AUDIO_PAN_EFFECT: return new PanEffect(c); break; case AUDIO_NOISE_EFFECT: return new AudioNoiseEffect(c); break; + case AUDIO_TONE_EFFECT: return new ToneEffect(c); break; } } qDebug() << "[ERROR] Invalid effect ID"; @@ -814,3 +817,9 @@ QColor EffectField::get_color_value(double timecode) { void EffectField::set_color_value(QColor color) { static_cast(ui_element)->set_color(color); } + +qint16 mixAudioSample(qint16 a, qint16 b) { + qint32 mixed_sample = static_cast(a) + static_cast(b); + mixed_sample = qMax(qMin(mixed_sample, static_cast(INT16_MAX)), static_cast(INT16_MIN)); + return static_cast(mixed_sample); +} diff --git a/effects/effect.h b/effects/effect.h index 2c223a26e..cb54aaad5 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -39,6 +39,7 @@ enum AudioEffects { AUDIO_VOLUME_EFFECT, AUDIO_PAN_EFFECT, AUDIO_NOISE_EFFECT, + AUDIO_TONE_EFFECT, AUDIO_EFFECT_COUNT }; @@ -82,6 +83,8 @@ struct GLTextureCoords { double textureBottomLeftY; }; +qint16 mixAudioSample(qint16 a, qint16 b); + class EffectField : public QObject { Q_OBJECT public: diff --git a/olive.pro b/olive.pro index 8efa89f58..c4840a85b 100644 --- a/olive.pro +++ b/olive.pro @@ -78,7 +78,8 @@ SOURCES += \ effects/video/flipeffect.cpp \ effects/audio/audionoiseeffect.cpp \ effects/video/boxblureffect.cpp \ - dialogs/demonotice.cpp + dialogs/demonotice.cpp \ + effects/audio/toneeffect.cpp HEADERS += \ mainwindow.h \ @@ -133,7 +134,8 @@ HEADERS += \ effects/video/flipeffect.h \ effects/audio/audionoiseeffect.h \ effects/video/boxblureffect.h \ - dialogs/demonotice.h + dialogs/demonotice.h \ + effects/audio/toneeffect.h FORMS += \ mainwindow.ui \ diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 87469b685..462d0e139 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -1173,10 +1173,15 @@ void Timeline::on_addButton_clicked() { add_menu.addAction(solidMenuItem); QAction* barsMenuItem = new QAction(&add_menu); - barsMenuItem->setText("Bars and Tone..."); + barsMenuItem->setText("Bars..."); barsMenuItem->setData(ADD_OBJ_BARS); add_menu.addAction(barsMenuItem); + QAction* toneMenuItem = new QAction(&add_menu); + toneMenuItem->setText("Tone..."); + toneMenuItem->setData(ADD_OBJ_TONE); + add_menu.addAction(toneMenuItem); + connect(&add_menu, SIGNAL(triggered(QAction*)), this, SLOT(addMenuItem(QAction*))); add_menu.exec(QCursor::pos()); @@ -1185,15 +1190,4 @@ void Timeline::on_addButton_clicked() { void Timeline::addMenuItem(QAction* action) { creating = true; creatingObject = action->data().toInt(); - /*switch (action->data()) { - case ADD_OBJ_TITLE: - - break; - case ADD_OBJ_SOLID: - - break; - case ADD_OBJ_BARS: - - break; - }*/ } diff --git a/panels/timeline.h b/panels/timeline.h index a9a5a0daa..54e0eb983 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -13,6 +13,7 @@ #define ADD_OBJ_TITLE 0 #define ADD_OBJ_SOLID 1 #define ADD_OBJ_BARS 2 +#define ADD_OBJ_TONE 3 class QPushButton; class SourceTable; diff --git a/playback/cacher.cpp b/playback/cacher.cpp index d2155d174..78b7c7594 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -155,8 +155,7 @@ void cache_audio_worker(Clip* c, Clip* nest) { int lower_byte_index = (c->audio_buffer_write)%audio_ibuffer_size; qint16 old_sample = static_cast((audio_ibuffer[upper_byte_index] & 0xFF) << 8 | (audio_ibuffer[lower_byte_index] & 0xFF)); qint16 new_sample = static_cast((frame->data[0][c->frame_sample_index+1] & 0xFF) << 8 | (frame->data[0][c->frame_sample_index] & 0xFF)); - qint32 mixed_sample = static_cast(old_sample) + static_cast(new_sample); - mixed_sample = qMax(qMin(mixed_sample, static_cast(INT16_MAX)), static_cast(INT16_MIN)); + qint16 mixed_sample = mixAudioSample(old_sample, new_sample); audio_ibuffer[upper_byte_index] = static_cast((mixed_sample >> 8) & 0xFF); audio_ibuffer[lower_byte_index] = static_cast(mixed_sample & 0xFF); diff --git a/playback/playback.cpp b/playback/playback.cpp index 2d484f392..3bb03883d 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -92,16 +92,18 @@ void close_clip(Clip* clip) { } void cache_clip(Clip* clip, long playhead, bool write_A, bool write_B, bool reset, Clip* nest) { - if (clip->multithreaded) { - clip->cacher->playhead = playhead; - clip->cacher->write_A = write_A; - clip->cacher->write_B = write_B; - clip->cacher->reset = reset; - clip->cacher->nest = nest; + if (clip->media_type == MEDIA_TYPE_FOOTAGE) { + if (clip->multithreaded) { + clip->cacher->playhead = playhead; + clip->cacher->write_A = write_A; + clip->cacher->write_B = write_B; + clip->cacher->reset = reset; + clip->cacher->nest = nest; - clip->can_cache.wakeAll(); - } else { - cache_clip_worker(clip, playhead, write_A, write_B, reset, nest); + clip->can_cache.wakeAll(); + } else { + cache_clip_worker(clip, playhead, write_A, write_B, reset, nest); + } } } diff --git a/ui/timelineheader.cpp b/ui/timelineheader.cpp index 3933a7a90..55e20c93f 100644 --- a/ui/timelineheader.cpp +++ b/ui/timelineheader.cpp @@ -126,13 +126,17 @@ void TimelineHeader::paintEvent(QPaintEvent*) { QPainter p(this); p.setPen(Qt::gray); int interval = 0; - int multiplier = 0; + int multiplier = 0; do { multiplier++; - interval = getScreenPointFromFrame(zoom, sequence->frame_rate*multiplier); + interval = getScreenPointFromFrame(zoom, 1*multiplier); } while (interval < 10); for (int i=0;i 0) { + drawHeight = drawHeight>>1; + } + p.drawLine(i, 0, i, drawHeight); } // draw in/out selection diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 3a8a7d55d..1671095fe 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #define MAX_TEXT_WIDTH 20 @@ -542,14 +543,6 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { c->color_b = 64; c->track = g.track; - Selection s; - s.in = c->timeline_in; - s.out = c->timeline_out; - s.track = c->track; - QVector areas; - areas.append(s); - panel_timeline->delete_areas_and_relink(ta, areas); - QVector add; add.append(c); ta->add_clips(sequence, add); @@ -566,11 +559,23 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { ta->add_effect(sequence, clipIndex, VIDEO_SOLID_EFFECT); break; case ADD_OBJ_BARS: - c->name = "Bars and Tone"; + c->name = "Bars"; ta->add_effect(sequence, clipIndex, VIDEO_SOLID_EFFECT); break; + case ADD_OBJ_TONE: + c->name = "Tone"; + ta->add_effect(sequence, clipIndex, AUDIO_TONE_EFFECT); + break; } + Selection s; + s.in = c->timeline_in; + s.out = c->timeline_out; + s.track = c->track; + QVector areas; + areas.append(s); + panel_timeline->delete_areas_and_relink(ta, areas); + undo_stack.push(ta); // pretty hacky @@ -1650,7 +1655,12 @@ void TimelineWidget::redraw_clips() { if (minimumWidth() != panel_width || clip_pixmap.height() != height() || panel_height != minimumHeight()) { panel_timeline->ui->headers->setMinimumWidth(panel_width + 100); setMinimumWidth(panel_width); + int scrollOffset = (panel_height-minimumHeight()); setMinimumHeight(panel_height); + if (bottom_align) { + updateGeometry(); + container->verticalScrollBar()->setValue(container->verticalScrollBar()->value()+scrollOffset); + } clip_pixmap = QPixmap(qMax(width(), panel_width), qMax(height(), panel_height)); } diff --git a/ui/timelinewidget.h b/ui/timelinewidget.h index 29b53b242..3db08c7d1 100644 --- a/ui/timelinewidget.h +++ b/ui/timelinewidget.h @@ -14,6 +14,7 @@ struct Sequence; struct Clip; class Timeline; class TimelineAction; +class QScrollArea; bool same_sign(int a, int b); @@ -26,7 +27,7 @@ public: void redraw_clips(); - QWidget* container; + QScrollArea* container; protected: void paintEvent(QPaintEvent*); void resizeEvent(QResizeEvent*); diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 84f6af0fe..4b8e9453b 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -309,7 +309,7 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { glPopMatrix(); } else { - if (c->media_type == MEDIA_TYPE_FOOTAGE + if ((c->media_type == MEDIA_TYPE_FOOTAGE || c->media_type == MEDIA_TYPE_SOLID) && render_audio && c->lock.tryLock()) { // clip is not caching, start caching audio