[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kdenlive/refactoring_timeline] src: Qml timeline: audio thumbnails (still requires timeline <> bin 
From:       Jean-Baptiste Mardelle <null () kde ! org>
Date:       2017-02-28 20:35:16
Message-ID: E1cioUO-00051Y-OH () code ! kde ! org
[Download RAW message or body]

Git commit c5aedee4141f001523a510a1d74901998682d71f by Jean-Baptiste Mardelle.
Committed on 28/02/2017 at 20:35.
Pushed by mardelle into branch 'refactoring_timeline'.

Qml timeline: audio thumbnails (still requires timeline <> bin communication to \
extract data

M  +10   -0    src/bin/bin.cpp
M  +1    -0    src/bin/bin.h
M  +1    -0    src/timeline/clipitem.cpp
M  +4    -0    src/timeline2/model/timelineitemmodel.cpp
M  +8    -8    src/timeline2/view/qml/Clip.qml
M  +1    -1    src/timeline2/view/qml/Track.qml
M  +56   -0    src/timeline2/view/qml/timelineitems.cpp
M  +4    -0    src/timeline2/view/timelinewidget.cpp
M  +3    -0    src/timeline2/view/timelinewidget.h

https://commits.kde.org/kdenlive/c5aedee4141f001523a510a1d74901998682d71f

diff --git a/src/bin/bin.cpp b/src/bin/bin.cpp
index 1bdcedab3..555c92677 100644
--- a/src/bin/bin.cpp
+++ b/src/bin/bin.cpp
@@ -3825,3 +3825,13 @@ void Bin::saveZone(const QStringList &info, const QDir &dir)
         clip->controller()->saveZone(zone, dir);
     }
 }
+
+QVariantList Bin::audioFrameCache(const QString &id)
+{
+    ProjectClip *clip = getBinClip(id);
+    if (clip && clip->controller()) {
+        return clip->audioFrameCache;
+    } else {
+        return QVariantList();
+    }
+}
diff --git a/src/bin/bin.h b/src/bin/bin.h
index 888e3dfdd..7c8869d83 100644
--- a/src/bin/bin.h
+++ b/src/bin/bin.h
@@ -530,6 +530,7 @@ public:
     const QStringList getFolderInfo(const QModelIndex &selectedIx = QModelIndex());
     /** @brief Save a clip zone as MLT playlist */
     void saveZone(const QStringList &info, const QDir &dir);
+    QVariantList audioFrameCache(const QString &id);
 
 private slots:
     void slotAddClip();
diff --git a/src/timeline/clipitem.cpp b/src/timeline/clipitem.cpp
index 7bbe3229d..7ac113915 100644
--- a/src/timeline/clipitem.cpp
+++ b/src/timeline/clipitem.cpp
@@ -1,3 +1,4 @@
+
 /***************************************************************************
  *   Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
  *                                                                         *
diff --git a/src/timeline2/model/timelineitemmodel.cpp \
b/src/timeline2/model/timelineitemmodel.cpp index bc7e124bf..f2d5665b1 100644
--- a/src/timeline2/model/timelineitemmodel.cpp
+++ b/src/timeline2/model/timelineitemmodel.cpp
@@ -219,6 +219,10 @@ QVariant TimelineItemModel::data(const QModelIndex &index, int \
role) const  case ServiceRole:
             return clip->getProperty("mlt_service");
             break;
+        case AudioLevelsRole:
+            //TODO: get data from bin clip when interface is ready
+            //return \
QVariant::fromValue(pCore->bin()->audioFrameCache(clip->getProperty("kdenlive:id"))); \
+            return QVariant();  case IsBlankRole: //probably useless
             return false;
         case StartRole:
diff --git a/src/timeline2/view/qml/Clip.qml b/src/timeline2/view/qml/Clip.qml
index 43769087a..4ac8df10c 100644
--- a/src/timeline2/view/qml/Clip.qml
+++ b/src/timeline2/view/qml/Clip.qml
@@ -93,16 +93,16 @@ Rectangle {
         isAudio = track.isAudio
         height = track.height
         y = track.y
-        //generateWaveform()
+        generateWaveform()
     }
 
-    /*function generateWaveform() {
+    function generateWaveform() {
         // This is needed to make the model have the correct count.
         // Model as a property expression is not working in all cases.
         waveformRepeater.model = Math.ceil(waveform.innerWidth / waveform.maxWidth)
         for (var i = 0; i < waveformRepeater.count; i++)
             waveformRepeater.itemAt(0).update()
-    }*/
+    }
 
     function imagePath(time) {
         if (isAudio || isBlank || isTransition) {
@@ -112,7 +112,7 @@ Rectangle {
         }
     }
 
-    //onAudioLevelsChanged: generateWaveform()
+    onAudioLevelsChanged: generateWaveform()
 
     Image {
         id: outThumbnail
@@ -155,7 +155,7 @@ Rectangle {
 
     Row {
         id: waveform
-        visible: !isBlank //&& settings.timelineShowWaveforms
+        visible: timeline.showWaveforms()
         height: isAudio? parent.height : parent.height / 2
         anchors.left: parent.left
         anchors.bottom: parent.bottom
@@ -164,18 +164,18 @@ Rectangle {
         property int maxWidth: 10000
         property int innerWidth: clipRoot.width - clipRoot.border.width * 2
 
-        /*Repeater {
+        Repeater {
             id: waveformRepeater
             TimelineWaveform {
                 width: Math.min(waveform.innerWidth, waveform.maxWidth)
                 height: waveform.height
-                fillColor: getColor()
+                fillColor: 'red'
                 property int channels: 2
                 inPoint: Math.round((clipRoot.inPoint + index * waveform.maxWidth / \
                timeScale) * speed) * channels
                 outPoint: inPoint + Math.round(width / timeScale * speed) * channels
                 levels: audioLevels
             }
-        }*/
+        }
     }
 
     Rectangle {
diff --git a/src/timeline2/view/qml/Track.qml b/src/timeline2/view/qml/Track.qml
index 5d28ede8a..7f2f2ba0c 100644
--- a/src/timeline2/view/qml/Track.qml
+++ b/src/timeline2/view/qml/Track.qml
@@ -74,7 +74,7 @@ Column{
             binId: model.binId
             isAudio: false //model.audio
             isTransition: false //model.isTransition
-            audioLevels: false //model.audioLevels
+            audioLevels: model.audioLevels
             width: model.duration * timeScale
             height: parent.height
             modelStart: model.start
diff --git a/src/timeline2/view/qml/timelineitems.cpp \
b/src/timeline2/view/qml/timelineitems.cpp index 1eb65617e..aec276ace 100644
--- a/src/timeline2/view/qml/timelineitems.cpp
+++ b/src/timeline2/view/qml/timelineitems.cpp
@@ -37,9 +37,65 @@ class TimelinePlayhead : public QQuickPaintedItem
     }
 };
 
+class TimelineWaveform : public QQuickPaintedItem
+{
+    Q_OBJECT
+    Q_PROPERTY(QVariant levels MEMBER m_audioLevels NOTIFY propertyChanged)
+    Q_PROPERTY(QColor fillColor MEMBER m_color NOTIFY propertyChanged)
+    Q_PROPERTY(int inPoint MEMBER m_inPoint NOTIFY inPointChanged)
+    Q_PROPERTY(int outPoint MEMBER m_outPoint NOTIFY outPointChanged)
+
+public:
+    TimelineWaveform()
+    {
+        setAntialiasing(QPainter::Antialiasing);
+        connect(this, SIGNAL(propertyChanged()), this, SLOT(update()));
+    }
+
+    void paint(QPainter *painter)
+    {
+        QVariantList data = m_audioLevels.toList();
+        if (data.isEmpty())
+            return;
+
+        const qreal indicesPrPixel = qreal(m_outPoint - m_inPoint) / width();
+
+        QPainterPath path;
+        path.moveTo(-1, height());
+        int i = 0;
+        for (; i < width(); ++i)
+        {
+            int idx = m_inPoint + int(i * indicesPrPixel);
+            if (idx + 1 >= data.length())
+                break;
+            qreal level = qMax(data.at(idx).toReal(), data.at(idx + 1).toReal()) / \
256; +            path.lineTo(i, height() - level * height());
+        }
+        path.lineTo(i, height());
+        painter->fillPath(path, m_color.lighter());
+
+        QPen pen(painter->pen());
+        pen.setColor(m_color.darker());
+        painter->strokePath(path, pen);
+    }
+
+signals:
+    void propertyChanged();
+    void inPointChanged();
+    void outPointChanged();
+
+private:
+    QVariant m_audioLevels;
+    int m_inPoint;
+    int m_outPoint;
+    QColor m_color;
+};
 
 void registerTimelineItems()
 {
     qmlRegisterType<TimelineTriangle>("Kdenlive.Controls", 1, 0, \
                "TimelineTriangle");
     qmlRegisterType<TimelinePlayhead>("Kdenlive.Controls", 1, 0, \
"TimelinePlayhead"); +    qmlRegisterType<TimelineWaveform>("Kdenlive.Controls", 1, \
0, "TimelineWaveform");  }
+
+#include "timelineitems.moc"
diff --git a/src/timeline2/view/timelinewidget.cpp \
b/src/timeline2/view/timelinewidget.cpp index cd35f672d..b30bec084 100644
--- a/src/timeline2/view/timelinewidget.cpp
+++ b/src/timeline2/view/timelinewidget.cpp
@@ -266,3 +266,7 @@ bool TimelineWidget::showThumbnails() const
     return KdenliveSettings::videothumbnails();
 }
 
+bool TimelineWidget::showWaveforms() const
+{
+    return KdenliveSettings::audiothumbnails();
+}
diff --git a/src/timeline2/view/timelinewidget.h \
b/src/timeline2/view/timelinewidget.h index ab36ea535..261044349 100644
--- a/src/timeline2/view/timelinewidget.h
+++ b/src/timeline2/view/timelinewidget.h
@@ -138,6 +138,9 @@ public:
     /* @brief Do we want to display video thumbnails
      */
     Q_INVOKABLE bool showThumbnails() const;
+    /* @brief Do we want to display audio thumbnails
+     */
+    Q_INVOKABLE bool showWaveforms() const;
 
 protected:
     void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic