~mrp/aerodramus

84613bef223529bd5908f4a83ac46b9d73b4b4ff — Mark Penner 6 months ago d08883b
add rudimentary impulse response page
10 files changed, 32 insertions(+), 224 deletions(-)

M src/CMakeLists.txt
A src/ImpulseResponsePage.cpp
A src/ImpulseResponsePage.h
M src/MainWindow.cpp
D src/app.cpp
D src/app.h
D src/audiofile.cpp
D src/audiofile.h
D src/filelistmodel.cpp
D src/filelistmodel.h
M src/CMakeLists.txt => src/CMakeLists.txt +1 -0
@@ 2,6 2,7 @@
# SPDX-License-Identifier: BSD-2-Clause

add_executable(aerodramus-gui
    ImpulseResponsePage.cpp
    main.cpp
    MainWindow.cpp
)

A src/ImpulseResponsePage.cpp => src/ImpulseResponsePage.cpp +13 -0
@@ 0,0 1,13 @@
// SPDX-FileCopyrightText: 2023 Mark Penner <mrpenner@mailbox.org>
// SPDX-License-Identifier: GPL-3.0-or-later

#include "ImpulseResponsePage.h"

#include <QLabel>

ImpulseResponsePage::ImpulseResponsePage(const QString &fileName, QWidget *parent)
    : QTabWidget::QTabWidget(parent)
{
    QLabel *name = new QLabel(fileName);
    this->addTab(name, fileName);
}

A src/ImpulseResponsePage.h => src/ImpulseResponsePage.h +16 -0
@@ 0,0 1,16 @@
// SPDX-FileCopyrightText: 2023 Mark Penner <mrpenner@mailbox.org>
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef IMPULSERESPONSEPAGE_H
#define IMPULSERESPONSEPAGE_H

#include <QTabWidget>

class ImpulseResponsePage : public QTabWidget
{
    Q_OBJECT

public:
    ImpulseResponsePage(const QString &fileName, QWidget *parent = nullptr);
};
#endif

M src/MainWindow.cpp => src/MainWindow.cpp +2 -2
@@ 3,6 3,7 @@

#include "MainWindow.h"

#include "ImpulseResponsePage.h"
#include <KActionCollection>
#include <KLocalizedString>
#include <KStandardAction>


@@ 10,7 11,6 @@
#include <QApplication>
#include <QDockWidget>
#include <QFileDialog>
#include <QLabel>
#include <QStandardPaths>

MainWindow::MainWindow(QWidget *parent)


@@ 47,7 47,7 @@ void MainWindow::openFile()
    const QString fileNameFromDialog =
        QFileDialog::getOpenFileName(this, i18n("Open File"), QStandardPaths::standardLocations(QStandardPaths::HomeLocation)[0]);

    QLabel *page = new QLabel(fileNameFromDialog);
    ImpulseResponsePage *page = new ImpulseResponsePage(fileNameFromDialog, this);
    addPage(fileNameFromDialog, page);
}


D src/app.cpp => src/app.cpp +0 -15
@@ 1,15 0,0 @@
// SPDX-FileCopyrightText: 2023 Mark Penner <mrpenner@mailbox.org>
// SPDX-License-Identifier: GPL-3.0-or-later

#include "app.h"

App::App()
    : QObject::QObject()
{
    m_fileListModel = new FileListModel;
}
void App::appendFile(QString string)
{
    m_fileListModel->append(string);
    Q_EMIT fileListModelChanged();
}

D src/app.h => src/app.h +0 -28
@@ 1,28 0,0 @@
// SPDX-FileCopyrightText: 2023 Mark Penner <mrpenner@mailbox.org>
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef AERODRAMUS_APP_H
#define AERODRAMUS_APP_H

#include "filelistmodel.h"
#include <QObject>
#include <QtQmlIntegration>

class App : public QObject
{
    Q_OBJECT
    QML_ELEMENT
    QML_SINGLETON
    Q_PROPERTY(FileListModel *fileListModel MEMBER m_fileListModel NOTIFY fileListModelChanged)

public:
    App();

    Q_INVOKABLE void appendFile(QString string);

    Q_SIGNAL void fileListModelChanged();

private:
    FileListModel *m_fileListModel;
};
#endif

D src/audiofile.cpp => src/audiofile.cpp +0 -57
@@ 1,57 0,0 @@
// SPDX-FileCopyrightText: 2023 Mark Penner <mrpenner@mailbox.org>
// SPDX-License-Identifier: GPL-3.0-or-later

#include "audiofile.h"

#include "lib/aerodramus.h"
#include <QList>
#include <QPointF>

QLineSeries *AudioFile::getWaveSeries() const
{
    return m_waveSeries;
}
void AudioFile::setWaveSeries(QLineSeries *series)
{
    m_waveSeries = series;
    Q_EMIT waveSeriesChanged();
}

int AudioFile::getLength() const
{
    return m_samples;
}

QUrl AudioFile::getFileUrl() const
{
    return m_fileUrl;
}
void AudioFile::setFileUrl(QUrl fileUrl)
{
    m_fileUrl = fileUrl;
    m_name = m_fileUrl.path();
}

QString AudioFile::getName() const
{
    return m_name;
}

void AudioFile::readFile()
{
    m_data = Aerodramus::read_file(m_fileUrl.path().toStdString());
    m_samples = m_data.size();
}

void AudioFile::graphData()
{
    readFile();
    int num_points = 20;
    QList<QPointF> line(num_points, QPointF(0, 0));
    std::vector<int> zxh = Aerodramus::zero_cross_histogram(m_data, num_points);
    for (int x = 0; x < num_points; ++x) {
        line[x] = QPointF(x, zxh.at(x) / 2.0);
    }
    m_waveSeries->replace(line);
    Q_EMIT waveSeriesChanged();
}

D src/audiofile.h => src/audiofile.h +0 -45
@@ 1,45 0,0 @@
// SPDX-FileCopyrightText: 2023 Mark Penner <mrpenner@mailbox.org>
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef AERODRAMUS_AUDIOFILE_H
#define AERODRAMUS_AUDIOFILE_H

#include <QLineSeries>
#include <QObject>
#include <QUrl>
#include <QtQmlIntegration>

class AudioFile : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QLineSeries *waveSeries READ getWaveSeries WRITE setWaveSeries NOTIFY waveSeriesChanged)
    Q_PROPERTY(int length READ getLength)
    Q_PROPERTY(QUrl fileUrl READ getFileUrl WRITE setFileUrl)
    Q_PROPERTY(QString name READ getName)
    QML_ELEMENT
public:
    QLineSeries *getWaveSeries() const;
    void setWaveSeries(QLineSeries *series);

    int getLength() const;

    QUrl getFileUrl() const;
    void setFileUrl(QUrl fileUrl);

    QString getName() const;

    void readFile();

    Q_INVOKABLE void graphData();

Q_SIGNALS:
    void waveSeriesChanged();

private:
    std::vector<float> m_data{};
    QUrl m_fileUrl{};
    QString m_name;
    QLineSeries *m_waveSeries{};
    int m_samples{};
};
#endif

D src/filelistmodel.cpp => src/filelistmodel.cpp +0 -48
@@ 1,48 0,0 @@
// SPDX-FileCopyrightText: 2023 Mark Penner <mrpenner@mailbox.org>
// SPDX-License-Identifier: GPL-3.0-or-later

#include "filelistmodel.h"

FileListModel::FileListModel(QObject *parent)
    : QAbstractListModel::QAbstractListModel(parent)
{
}

QVariant FileListModel::data(const QModelIndex &index, int role) const
{
    switch (role) {
    case Qt::DisplayRole: {
        return m_data.at(index.row());
        break;
    }
    case NameRole: {
        return m_data.at(index.row());
        break;
    }
    default:
        return QVariant();
    }
}

QHash<int, QByteArray> FileListModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[NameRole] = "name";
    return roles;
}

int FileListModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid()) {
        return 0;
    }
    return m_data.length();
}

bool FileListModel::append(QString string)
{
    Q_EMIT beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_data.append(string);
    Q_EMIT endInsertRows();
    return true;
}

D src/filelistmodel.h => src/filelistmodel.h +0 -29
@@ 1,29 0,0 @@
// SPDX-FileCopyrightText: 2023 Mark Penner <mrpenner@mailbox.org>
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef AERODRAMUS_FILELISTMODEL_H
#define AERODRAMUS_FILELISTMODEL_H

#include <QAbstractListModel>
#include <QObject>
#include <QtQmlIntegration>

class FileListModel : public QAbstractListModel
{
    Q_OBJECT
    QML_ELEMENT
public:
    FileListModel(QObject *parent = nullptr);

    enum Roles { NameRole = Qt::UserRole };

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    QHash<int, QByteArray> roleNames() const override;
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;

    Q_INVOKABLE bool append(QString string);

private:
    QList<QString> m_data{};
};
#endif