Commit 095865eb authored by Leander Schulten's avatar Leander Schulten

GUI: AudioEventView: Add support for own/user events

parent c161c861
Pipeline #271552 passed with stage
in 13 minutes and 45 seconds
......@@ -5,14 +5,15 @@
#include <QSGGeometryNode>
using namespace Audio::Aubio;
using namespace std::chrono;
namespace GUI {
float AudioEventDataView::getX(const Audio::EventSeries *e, int sample) {
return static_cast<float>(width()) - (static_cast<float>(e->getNewestSample()) - sample) / (e->getSamplesPerSecond() / pixelPerSecond);
return static_cast<float>(width() - static_cast<qreal>(e->getNewestSample() - sample) * pixelPerSecond / e->getSamplesPerSecond());
}
AudioEventDataView::AudioEventDataView(QQuickItem *parent) : QQuickItem(parent) {
AudioEventDataView::AudioEventDataView(QQuickItem *parent) : QQuickItem(parent), ownEvents(1000) {
setFlag(ItemHasContents);
startTimer(15);
for (int osf = 0; osf <= to_integral(OnsetDetectionFunction::Last); ++osf) {
......@@ -20,8 +21,10 @@ AudioEventDataView::AudioEventDataView(QQuickItem *parent) : QQuickItem(parent)
setColor(osf, static_cast<DataType>(dt), QColor(rand() % 255, rand() % 255, rand() % 255));
}
}
ownColor = QColor(rand() % 255, rand() % 255, rand() % 255);
enableDetectionFor(OnsetDetectionFunction::KullbackLiebler, OnsetEvent);
enableDetectionFor(OnsetDetectionFunction::KullbackLiebler, OnsetValue);
start = steady_clock::now();
}
void AudioEventDataView::enableDetectionFor(OnsetDetectionFunction f, AudioEventDataView::DataType type, bool enabled) {
......@@ -64,6 +67,14 @@ void AudioEventDataView::setColor(OnsetDetectionFunction onsetDetectionFunction,
QColor AudioEventDataView::getColor(OnsetDetectionFunction onsetDetectionFunction, AudioEventDataView::DataType usage) const { return colors[to_integral(onsetDetectionFunction)][usage].second; }
void AudioEventDataView::ownTick() { ownEvents.addEvent(duration_cast<milliseconds>(steady_clock::now() - start).count()); }
void AudioEventDataView::setOwnColor(QColor ownColor) {
if (this->ownColor == ownColor) return;
this->ownColor = ownColor;
emit ownColorChanged(ownColor);
}
void AudioEventDataView::timerEvent(QTimerEvent *e) {
Q_UNUSED(e)
if (visibleForUser) {
......@@ -123,7 +134,7 @@ QSGNode *AudioEventDataView::updatePaintNode(QSGNode *node, QQuickItem::UpdatePa
}
const auto sectionHeight = height() / eventsEnabledCount;
auto sectionOffset = 0;
const auto fillEvents = [this, &sectionOffset, sectionHeight](auto geometry, const auto &data, float confidence = 1) {
const auto fillEvents = [this, &sectionOffset](auto geometry, const auto &data, auto sectionHeight, float confidence = 1) {
auto events = data->getEvents();
geometry->allocate(events->size() * 2);
auto vertexData = geometry->vertexDataAsPoint2D();
......@@ -139,14 +150,18 @@ QSGNode *AudioEventDataView::updatePaintNode(QSGNode *node, QQuickItem::UpdatePa
sectionOffset += sectionHeight;
geometry->setDrawingMode(QSGGeometry::DrawLines);
};
ownEvents.increaseNewestSampleBy(duration_cast<milliseconds>(steady_clock::now() - start).count() - ownEvents.getNewestSample());
fillEvents(getGeometry(ownColor), &ownEvents, height());
sectionOffset = 0;
for (auto &[f, data] : beatData) {
if (isDetectionEnabledFor(f, BeatEvent)) {
fillEvents(getGeometry(getColor(f, BeatEvent)), data.events, *data.confidence);
fillEvents(getGeometry(getColor(f, BeatEvent)), data.events, sectionHeight, *data.confidence);
}
}
for (auto &[f, data] : onsetData) {
if (isDetectionEnabledFor(f, OnsetEvent)) {
fillEvents(getGeometry(getColor(f, OnsetEvent)), data);
fillEvents(getGeometry(getColor(f, OnsetEvent)), data, sectionHeight);
} else if (isDetectionEnabledFor(f, OnsetValue)) {
sectionOffset += sectionHeight;
}
......@@ -162,14 +177,6 @@ QSGNode *AudioEventDataView::updatePaintNode(QSGNode *node, QQuickItem::UpdatePa
}
geometry->setDrawingMode(QSGGeometry::DrawLineStrip);
}
if (isDetectionEnabledFor(f, OnsetEvent)) {
fillEvents(getGeometry(getColor(f, OnsetEvent)), data);
}
}
for (auto &[f, data] : beatData) {
if (isDetectionEnabledFor(f, BeatEvent)) {
fillEvents(getGeometry(getColor(f, BeatEvent)), data);
}
}
while (currentReused < node->childCount()) {
auto n = node->childAtIndex(currentReused);
......
#ifndef AUDIOEVENTDATAVIEW_H
#define AUDIOEVENTDATAVIEW_H
#include "modelvector.h"
#include "audio/audiocapturemanager.h"
#include <QQuickItem>
#include <array>
#include <chrono>
#include <map>
namespace GUI {
......@@ -15,10 +17,14 @@ class AudioEventDataView : public QQuickItem {
Q_PROPERTY(bool visibleForUser MEMBER visibleForUser NOTIFY visibleForUserChanged)
Q_PROPERTY(int pixelPerSecond MEMBER pixelPerSecond NOTIFY pixelPerSecondChanged)
Q_PROPERTY(QAbstractItemModel *names READ getNames CONSTANT)
Q_PROPERTY(QColor ownColor READ getOwnColor WRITE setOwnColor NOTIFY ownColorChanged)
int pixelPerSecond = 100;
bool visibleForUser = true;
float getX(const Audio::EventSeries *e, int sample);
ModelVector<QString> names;
QColor ownColor;
Audio::EventSeries ownEvents;
std::chrono::steady_clock::time_point start;
public:
enum DataType { BeatEvent, OnsetEvent, OnsetValue, Last = OnsetValue };
......@@ -45,11 +51,17 @@ public:
Q_INVOKABLE QColor getColor(int onsetDetectionFunction, DataType usage) const { return getColor(Audio::Aubio::toOnsetDetectionFunction(onsetDetectionFunction), usage); }
[[nodiscard]] QColor getColor(Audio::Aubio::OnsetDetectionFunction onsetDetectionFunction, DataType usage) const;
Q_INVOKABLE void ownTick();
QAbstractItemModel *getNames() { return &names; }
void setOwnColor(QColor ownColor);
QColor getOwnColor() const { return ownColor; }
signals:
void visibleForUserChanged();
void pixelPerSecondChanged();
void ownColorChanged(QColor ownColor);
protected:
void timerEvent(QTimerEvent *e) override;
......
......@@ -76,6 +76,38 @@ Item {
// scroll to the bottom at start
Component.onCompleted: ScrollBar.vertical.position = 1 - ScrollBar.vertical.size;
Column{
GridLayout{
columns: 2
columnSpacing: 0
Label{
Layout.topMargin: 5
Layout.columnSpan: 2
text: "Own Events";
}
Button{
id: tickButton
Layout.preferredHeight: implicitHeight-16
text: "Tick"
onClicked: dataView.ownTick()
}
Rectangle{
Layout.preferredHeight: tickButton.implicitBackgroundHeight - 14
Layout.preferredWidth: tickButton.implicitBackgroundHeight - 14
Layout.leftMargin: 20
color: dataView.ownColor;
onColorChanged: dataView.ownColor = color;
radius: 3
MouseArea{
anchors.fill: parent
onClicked: {
colorDialog.component = parent
colorDialog.startColor = parent.color;
colorDialog.visible = true;
}
}
}
}
Repeater{
id: rootRepeater
property var names: ["Beat Events", "Onset Events", "Onset Values"]
......
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