From ca4e39449b0222f3e6194e50ce3e2d7433fd0b62 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 9 Feb 2019 22:09:42 -0800 Subject: [PATCH] made volume effect use decibels --- dialogs/mediapropertiesdialog.cpp | 7 +- effects/internal/audionoiseeffect.h | 1 + effects/internal/fillleftrighteffect.h | 1 + effects/internal/paneffect.h | 1 + effects/internal/toneeffect.h | 1 + effects/internal/voideffect.h | 1 + effects/internal/volumeeffect.cpp | 12 ++-- effects/internal/volumeeffect.h | 1 + io/math.cpp | 8 +++ io/math.h | 4 ++ io/proxygenerator.h | 4 +- project/media.cpp | 11 ++-- ui/labelslider.cpp | 89 ++++++++++++++++++++++---- ui/labelslider.h | 9 ++- 14 files changed, 117 insertions(+), 33 deletions(-) diff --git a/dialogs/mediapropertiesdialog.cpp b/dialogs/mediapropertiesdialog.cpp index 1b10f9e37..992513654 100644 --- a/dialogs/mediapropertiesdialog.cpp +++ b/dialogs/mediapropertiesdialog.cpp @@ -51,13 +51,12 @@ MediaPropertiesDialog::MediaPropertiesDialog(QWidget *parent, Media *i) : track_list->addItem(item); } for (int i=0;iaudio_tracks.size();i++) { - const FootageStream& fs = f->audio_tracks.at(i); + const FootageStream& fs = f->audio_tracks.at(i); QListWidgetItem* item = new QListWidgetItem( - tr("Audio %1: %2Hz %3 %4").arg( + tr("Audio %1: %2Hz %3").arg( QString::number(fs.file_index), QString::number(fs.audio_frequency), - QString::number(fs.audio_channels), - tr("channel(s)", "", fs.audio_channels) + tr("%n channel(s)", "", fs.audio_channels) ), track_list ); diff --git a/effects/internal/audionoiseeffect.h b/effects/internal/audionoiseeffect.h index fa1643290..0a1103fae 100644 --- a/effects/internal/audionoiseeffect.h +++ b/effects/internal/audionoiseeffect.h @@ -4,6 +4,7 @@ #include "project/effect.h" class AudioNoiseEffect : public Effect { + Q_OBJECT public: AudioNoiseEffect(Clip* c, const EffectMeta* em); void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); diff --git a/effects/internal/fillleftrighteffect.h b/effects/internal/fillleftrighteffect.h index 3b3390d2e..e8e538c6a 100644 --- a/effects/internal/fillleftrighteffect.h +++ b/effects/internal/fillleftrighteffect.h @@ -4,6 +4,7 @@ #include "project/effect.h" class FillLeftRightEffect : public Effect { + Q_OBJECT public: FillLeftRightEffect(Clip* c, const EffectMeta* em); void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); diff --git a/effects/internal/paneffect.h b/effects/internal/paneffect.h index b4f7e8b9c..8d8fb857f 100644 --- a/effects/internal/paneffect.h +++ b/effects/internal/paneffect.h @@ -4,6 +4,7 @@ #include "project/effect.h" class PanEffect : public Effect { + Q_OBJECT public: PanEffect(Clip* c, const EffectMeta* em); void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); diff --git a/effects/internal/toneeffect.h b/effects/internal/toneeffect.h index 4ad7492f4..43844595d 100644 --- a/effects/internal/toneeffect.h +++ b/effects/internal/toneeffect.h @@ -4,6 +4,7 @@ #include "project/effect.h" class ToneEffect : public Effect { + Q_OBJECT public: ToneEffect(Clip *c, const EffectMeta* em); void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); diff --git a/effects/internal/voideffect.h b/effects/internal/voideffect.h index 0376b6a73..6dd255c4d 100644 --- a/effects/internal/voideffect.h +++ b/effects/internal/voideffect.h @@ -10,6 +10,7 @@ #include "project/effect.h" class VoidEffect : public Effect { + Q_OBJECT public: VoidEffect(Clip* c, const QString& n); diff --git a/effects/internal/volumeeffect.cpp b/effects/internal/volumeeffect.cpp index 997d9a2e6..7b1824e7b 100644 --- a/effects/internal/volumeeffect.cpp +++ b/effects/internal/volumeeffect.cpp @@ -10,20 +10,20 @@ VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { EffectRow* volume_row = add_row(tr("Volume")); - volume_val = volume_row->add_field(EFFECT_FIELD_DOUBLE, "volume"); - volume_val->set_double_minimum_value(0); + volume_val = volume_row->add_field(EFFECT_FIELD_DOUBLE, "volume"); // set defaults - volume_val->set_double_default_value(100); + volume_val->set_double_default_value(1); + static_cast(volume_val->get_ui_element())->set_display_type(LABELSLIDER_DECIBEL); } void VolumeEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) { double interval = (timecode_end-timecode_start)/nb_bytes; for (int i=0;iget_double_value(timecode_start+(interval*i), true)*0.01); + double vol_val = log_volume(volume_val->get_double_value(timecode_start+(interval*i), true)); - qint32 right_samp = (qint16) (((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); - qint32 left_samp = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); + qint32 right_samp = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); + qint32 left_samp = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); left_samp *= vol_val; right_samp *= vol_val; diff --git a/effects/internal/volumeeffect.h b/effects/internal/volumeeffect.h index 870f008a9..4ae7b8e9f 100644 --- a/effects/internal/volumeeffect.h +++ b/effects/internal/volumeeffect.h @@ -4,6 +4,7 @@ #include "project/effect.h" class VolumeEffect : public Effect { + Q_OBJECT public: VolumeEffect(Clip* c, const EffectMeta* em); void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); diff --git a/io/math.cpp b/io/math.cpp index 4d71229a4..32e03f6e8 100644 --- a/io/math.cpp +++ b/io/math.cpp @@ -52,3 +52,11 @@ double cubic_t_from_x(double x_target, double a, double b, double c, double d) { return percent; } + +double amplitude_to_db(double amplitude) { + return (20.0*(qLn(amplitude)/qLn(10.0))); +} + +double db_to_amplitude(double db) { + return qPow(M_E, (db*qLn(10.0))/20.0); +} diff --git a/io/math.h b/io/math.h index ba1e7ed9e..a4f2adb4c 100644 --- a/io/math.h +++ b/io/math.h @@ -10,4 +10,8 @@ double cubic_from_t(double a, double b, double c, double d, double t); double cubic_t_from_x(double x_target, double a, double b, double c, double d); double solveCubicBezier(double p0, double p1, double p2, double p3, double x); +// decibel conversion functions +double amplitude_to_db(double amplitude); +double db_to_amplitude(double db); + #endif // MATH_H diff --git a/io/proxygenerator.h b/io/proxygenerator.h index b6bcaf294..357d9c66c 100644 --- a/io/proxygenerator.h +++ b/io/proxygenerator.h @@ -15,8 +15,8 @@ struct ProxyInfo { QString path; }; -class ProxyGenerator : public QThread -{ +class ProxyGenerator : public QThread { + Q_OBJECT public: ProxyGenerator(); void run(); diff --git a/project/media.cpp b/project/media.cpp index c17ccd9dc..66456095e 100644 --- a/project/media.cpp +++ b/project/media.cpp @@ -118,12 +118,11 @@ void Media::update_tooltip(const QString& error) { tooltip += QString::number(f->video_tracks.at(i).video_frame_rate * f->speed); } else { double adjusted_rate = f->video_tracks.at(i).video_frame_rate * f->speed; - tooltip += QString("%1 %2 (%3 %4)").arg( - QString::number(adjusted_rate * 2), - QCoreApplication::translate("Media", "field(s)", "", qCeil(adjusted_rate * 2)), - QString::number(adjusted_rate), - QCoreApplication::translate("Media", "frame(s)", "", qCeil(adjusted_rate)) - ); + + tooltip += QCoreApplication::translate("Media", "%1 field(s) (%2 frame(s))").arg( + QString::number(adjusted_rate*2.0), + QString::number(adjusted_rate) + ); } } tooltip += "\n"; diff --git a/ui/labelslider.cpp b/ui/labelslider.cpp index 92d909242..401ef8433 100644 --- a/ui/labelslider.cpp +++ b/ui/labelslider.cpp @@ -3,6 +3,7 @@ #include "project/undo.h" #include "panels/viewer.h" #include "io/config.h" +#include "io/math.h" #include "debug.h" #include @@ -38,7 +39,7 @@ void LabelSlider::set_display_type(int type) { void LabelSlider::set_value(double v, bool userSet) { set = true; - if (v != internal_value) { + if (!qFuzzyCompare(v, internal_value)) { if (min_enabled && v < min_value) { internal_value = min_value; } else if (max_enabled && v > max_value) { @@ -65,8 +66,27 @@ QString LabelSlider::valueToString(double v) { return "---"; } else { switch (display_type) { - case LABELSLIDER_FRAMENUMBER: return frame_to_timecode(v, config.timecode_view, frame_rate); - case LABELSLIDER_PERCENT: return QString::number((v*100), 'f', decimal_places) + "%"; + case LABELSLIDER_FRAMENUMBER: + return frame_to_timecode(long(v), config.timecode_view, frame_rate); + case LABELSLIDER_PERCENT: + return QString::number((v*100), 'f', decimal_places).append("%"); + case LABELSLIDER_DECIBEL: + { + QString db_str; + + // -96 dB is considered -infinity + if (amplitude_to_db(v) <= -96) { + // hex sequence for -infinity + db_str = "-\xE2\x88\x9E"; + } else { + db_str = QString::number(amplitude_to_db(v), 'f', decimal_places); + } + + // add "dB" suffix + db_str.append(" dB"); + + return db_str; + } } return QString::number(v, 'f', decimal_places); } @@ -118,7 +138,8 @@ void LabelSlider::mousePressEvent(QMouseEvent *ev) { if (ev->modifiers() & Qt::AltModifier) { // if the value is not already default, and there is a default to set - if (internal_value != default_value && !qIsNaN(default_value)) { + if (!qFuzzyCompare(internal_value, default_value) + && !qIsNaN(default_value)) { // cache current value set_previous_value(); @@ -166,11 +187,28 @@ void LabelSlider::mouseMoveEvent(QMouseEvent* event) { // ctrl + drag drags in smaller increments if (event->modifiers() & Qt::ControlModifier) diff *= 0.01; - // we'll also need to drag in smaller increments for a percent value - if (display_type == LABELSLIDER_PERCENT) diff *= 0.01; + if (display_type == LABELSLIDER_PERCENT) { + // we'll also need to drag in smaller increments for a percent value - // sets the value - set_value(internal_value + diff, true); + diff *= 0.01; + } + + // determine what the new value will be + double new_value; + + if (display_type == LABELSLIDER_DECIBEL) { + // we move in terms of dB for decibel display + + new_value = db_to_amplitude(amplitude_to_db(internal_value) + diff); + + } else { + // for most display types, just add the mouse difference + + new_value = internal_value + diff; + } + + // set internal value + set_value(new_value, true); // keep the cursor in the same location while dragging cursor().setPos(drag_start_x, drag_start_y); @@ -222,23 +260,50 @@ void LabelSlider::mouseReleaseEvent(QMouseEvent*) { // ask the user to enter a normal number value bool ok; + // value to show + double shown_value = internal_value; + if (display_type == LABELSLIDER_PERCENT) { + shown_value *= 100; + } else if (display_type == LABELSLIDER_DECIBEL) { + shown_value = amplitude_to_db(shown_value); + } + + // set correct minimum value + double shown_minimum_value; + if (min_enabled) { + // if this field has a minimum value set, use it + shown_minimum_value = min_value; + } else if (display_type == LABELSLIDER_DECIBEL) { + // minimum decibel amount is -96db + shown_minimum_value = -96; + } else { + // lowest possible minimum integer + shown_minimum_value = INT_MIN; + } + // percentages are stored 0.0 - 1.0 but displayed as 0% - 100% d = QInputDialog::getDouble( this, tr("Set Value"), tr("New value:"), - (display_type == LABELSLIDER_PERCENT) ? internal_value * 100 : internal_value, - (min_enabled) ? min_value : INT_MIN, + shown_value, + shown_minimum_value, (max_enabled) ? max_value : INT_MAX, decimal_places, &ok ); if (!ok) return; - if (display_type == LABELSLIDER_PERCENT) d *= 0.01; + + // convert shown value back to internal value + if (display_type == LABELSLIDER_PERCENT) { + d *= 0.01; + } else if (display_type == LABELSLIDER_DECIBEL) { + d = db_to_amplitude(d); + } } // if the value actually changed, trigger a change event - if (d != internal_value) { + if (!qFuzzyCompare(d, internal_value)) { set_previous_value(); set_value(d, true); } diff --git a/ui/labelslider.h b/ui/labelslider.h index 87e42fa4c..408217fd1 100644 --- a/ui/labelslider.h +++ b/ui/labelslider.h @@ -4,9 +4,12 @@ #include #include -#define LABELSLIDER_NORMAL 0 -#define LABELSLIDER_FRAMENUMBER 1 -#define LABELSLIDER_PERCENT 2 +enum LabelSliderDisplayType { + LABELSLIDER_NORMAL, + LABELSLIDER_FRAMENUMBER, + LABELSLIDER_PERCENT, + LABELSLIDER_DECIBEL +}; class LabelSlider : public QLabel {