Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

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

parent 5a01f7b7
......@@ -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();
}
}
......@@ -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();
......
/***************************************************************************
* Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
* *
......
......@@ -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:
......
......@@ -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 {
......
......@@ -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
......
......@@ -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"
......@@ -266,3 +266,7 @@ bool TimelineWidget::showThumbnails() const
return KdenliveSettings::videothumbnails();
}
bool TimelineWidget::showWaveforms() const
{
return KdenliveSettings::audiothumbnails();
}
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment