215 lines
5.8 KiB
C++
Executable File
215 lines
5.8 KiB
C++
Executable File
#include "samplewidget.h"
|
|
#include "ui_samplewidget.h"
|
|
|
|
#include <QAbstractEventDispatcher>
|
|
#include <QSoundEffect>
|
|
#include <QNetworkRequest>
|
|
#include <QNetworkReply>
|
|
#include <QNetworkAccessManager>
|
|
#include <QMetaEnum>
|
|
#include <QDebug>
|
|
|
|
#include "audiodecoder.h"
|
|
|
|
namespace {
|
|
QString toString(QString value) { return value; }
|
|
QString toString(int value) { return QString::number(value); }
|
|
QString toString(bool value) { return value?"true":"false"; }
|
|
}
|
|
|
|
SampleWidget::SampleWidget(QWidget *parent) :
|
|
QFrame{parent},
|
|
m_ui{std::make_unique<Ui::SampleWidget>()}
|
|
{
|
|
m_ui->setupUi(this);
|
|
|
|
connect(&m_player, &AudioPlayer::playingChanged, this, &SampleWidget::updateStatus);
|
|
|
|
connect(m_ui->pushButton, &QAbstractButton::pressed, this, [this](){ pressed(127); });
|
|
connect(m_ui->pushButton, &QAbstractButton::released, this, &SampleWidget::released);
|
|
|
|
updateStatus();
|
|
}
|
|
|
|
SampleWidget::~SampleWidget() = default;
|
|
|
|
void SampleWidget::setFile(const QString &presetId, const presets::File &file)
|
|
{
|
|
m_presetId = presetId;
|
|
m_file = file;
|
|
|
|
startRequest();
|
|
|
|
const auto setupLabel = [&](const auto &value, QLabel *label){
|
|
QString text;
|
|
QFont font;
|
|
QPalette pal;
|
|
|
|
if (value)
|
|
text = toString(*value);
|
|
else
|
|
{
|
|
text = tr("(null)");
|
|
font.setItalic(true);
|
|
pal.setColor(label->foregroundRole(), Qt::gray);
|
|
}
|
|
|
|
label->setText(text);
|
|
label->setFont(font);
|
|
label->setPalette(pal);
|
|
};
|
|
|
|
setupLabel(file.stopOnRelease, m_ui->stopOnReleaseLabel);
|
|
setupLabel(file.looped, m_ui->loopedLabel);
|
|
setupLabel(file.choke, m_ui->chokeLabel);
|
|
}
|
|
|
|
quint8 SampleWidget::channel() const
|
|
{
|
|
return m_ui->channelSpinBox->value();
|
|
}
|
|
|
|
void SampleWidget::setChannel(quint8 channel)
|
|
{
|
|
m_ui->channelSpinBox->setValue(channel);
|
|
}
|
|
|
|
quint8 SampleWidget::note() const
|
|
{
|
|
return m_ui->noteSpinBox->value();
|
|
}
|
|
|
|
void SampleWidget::setNote(quint8 note)
|
|
{
|
|
m_ui->noteSpinBox->setValue(note);
|
|
}
|
|
|
|
std::optional<int> SampleWidget::choke() const
|
|
{
|
|
if (!m_file)
|
|
return {};
|
|
return m_file->choke;
|
|
}
|
|
|
|
void SampleWidget::pressed(quint8 velocity)
|
|
{
|
|
Q_UNUSED(velocity)
|
|
|
|
m_player.restart();
|
|
|
|
if (m_file && m_file->choke && *m_file->choke)
|
|
emit chokeTriggered(*m_file->choke);
|
|
}
|
|
|
|
void SampleWidget::released()
|
|
{
|
|
}
|
|
|
|
void SampleWidget::forceStop()
|
|
{
|
|
m_player.setPlaying(false);
|
|
}
|
|
|
|
void SampleWidget::injectNetworkAccessManager(QNetworkAccessManager &networkAccessManager)
|
|
{
|
|
m_networkAccessManager = &networkAccessManager;
|
|
if (m_file)
|
|
startRequest();
|
|
}
|
|
|
|
void SampleWidget::injectDecodingThread(QThread &thread)
|
|
{
|
|
QMetaObject::invokeMethod(QAbstractEventDispatcher::instance(&thread), [this](){
|
|
m_decoder = std::make_unique<AudioDecoder>();
|
|
connect(this, &SampleWidget::startDecoding, m_decoder.get(), &AudioDecoder::startDecoding);
|
|
connect(m_decoder.get(), &AudioDecoder::decodingFinished, this, &SampleWidget::decodingFinished);
|
|
if (m_reply && m_reply->isFinished() && m_reply->error() == QNetworkReply::NoError)
|
|
m_decoder->startDecoding(m_reply);
|
|
});
|
|
}
|
|
|
|
void SampleWidget::writeSamples(frame_t *begin, frame_t *end)
|
|
{
|
|
m_player.writeSamples(begin, end);
|
|
}
|
|
|
|
void SampleWidget::updateStatus()
|
|
{
|
|
QPalette pal;
|
|
if (m_file && m_file->color)
|
|
{
|
|
const auto bright = m_player.playing() ? 255 : 155;
|
|
const auto dark = m_player.playing() ?
|
|
#if !defined(Q_OS_WIN)
|
|
80 : 0
|
|
#else
|
|
180 : 80
|
|
#endif
|
|
;
|
|
|
|
const auto &color = *m_file->color;
|
|
if (color == "purple")
|
|
pal.setColor(QPalette::Window, QColor{bright, dark, bright});
|
|
else if (color == "red")
|
|
pal.setColor(QPalette::Window, QColor{bright, dark, dark});
|
|
else if (color == "yellow")
|
|
pal.setColor(QPalette::Window, QColor{bright, bright, dark});
|
|
else if (color == "green")
|
|
pal.setColor(QPalette::Window, QColor{dark, bright, dark});
|
|
else if (color == "blue")
|
|
pal.setColor(QPalette::Window, QColor{dark, dark, bright});
|
|
else
|
|
qWarning() << "unknown color:" << color;
|
|
}
|
|
setPalette(pal);
|
|
|
|
if (m_reply)
|
|
{
|
|
if (!m_reply->isFinished())
|
|
m_ui->statusLabel->setText(tr("Downloading..."));
|
|
else if (m_reply->error() != QNetworkReply::NoError)
|
|
m_ui->statusLabel->setText(QMetaEnum::fromType<QNetworkReply::NetworkError>().valueToKey(m_reply->error()));
|
|
else
|
|
{
|
|
if (!m_decoder)
|
|
m_ui->statusLabel->setText(tr("Waiting for decoder thread..."));
|
|
else
|
|
m_ui->statusLabel->setText(tr("Decoding"));
|
|
}
|
|
}
|
|
else
|
|
m_ui->statusLabel->setText(m_player.playing() ? tr("Playing") : tr("Ready"));
|
|
}
|
|
|
|
void SampleWidget::requestFinished()
|
|
{
|
|
qDebug() << "called" << m_reply->error() << m_reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute);
|
|
if (m_reply->error() == QNetworkReply::NoError)
|
|
{
|
|
emit startDecoding(m_reply);
|
|
}
|
|
updateStatus();
|
|
}
|
|
|
|
void SampleWidget::decodingFinished(const QAudioBuffer &buffer)
|
|
{
|
|
qDebug() << "called";
|
|
m_reply = nullptr;
|
|
m_player.setBuffer(buffer);
|
|
updateStatus();
|
|
}
|
|
|
|
void SampleWidget::startRequest()
|
|
{
|
|
if (m_networkAccessManager && m_file->filename)
|
|
{
|
|
QNetworkRequest request{QUrl{QString{"https://brunner.ninja/komposthaufen/dpm/presets/extracted/%0/%1"}.arg(m_presetId, *m_file->filename)}};
|
|
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
|
|
request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, true);
|
|
m_reply = std::shared_ptr<QNetworkReply>{m_networkAccessManager->get(request)};
|
|
connect(m_reply.get(), &QNetworkReply::finished, this, &SampleWidget::requestFinished);
|
|
}
|
|
|
|
updateStatus();
|
|
}
|