diff --git a/widgets/drumpadsampleswidget.ui b/widgets/drumpadsampleswidget.ui index ce983a9..1b4dc67 100755 --- a/widgets/drumpadsampleswidget.ui +++ b/widgets/drumpadsampleswidget.ui @@ -6,28 +6,70 @@ 0 0 - 660 - 421 + 317 + 159 - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + @@ -74,10 +116,24 @@ - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + @@ -93,13 +149,34 @@ - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + @@ -115,16 +192,44 @@ - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + @@ -140,38 +245,101 @@ - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + DrumPadSampleWidget - QWidget + QFrame
widgets/drumpadsamplewidget.h
1
diff --git a/widgets/drumpadsamplewidget.cpp b/widgets/drumpadsamplewidget.cpp index bf056d9..30b49dd 100755 --- a/widgets/drumpadsamplewidget.cpp +++ b/widgets/drumpadsamplewidget.cpp @@ -209,8 +209,7 @@ void DrumPadSampleWidget::sendColor() void DrumPadSampleWidget::updateStatus() { - QPalette pal; - + QColor newColor; if (m_file && m_file->color && m_player.buffer().isValid()) { const auto bright = m_player.playing() ? 255 : 155; @@ -224,19 +223,29 @@ void DrumPadSampleWidget::updateStatus() const auto &color = *m_file->color; if (color == "purple") - pal.setColor(QPalette::Window, QColor{bright, dark, bright}); + newColor = QColor{bright, dark, bright}; else if (color == "red") - pal.setColor(QPalette::Window, QColor{bright, dark, dark}); + newColor = QColor{bright, dark, dark}; else if (color == "yellow") - pal.setColor(QPalette::Window, QColor{bright, bright, dark}); + newColor = QColor{bright, bright, dark}; else if (color == "green") - pal.setColor(QPalette::Window, QColor{dark, bright, dark}); + newColor = QColor{dark, bright, dark}; else if (color == "blue") - pal.setColor(QPalette::Window, QColor{dark, dark, bright}); + newColor = QColor{dark, dark, bright}; else + { qWarning() << "unknown color:" << color; + newColor = QColor{dark, dark, dark}; + } + } + + if (newColor.isValid() && (!m_lastColor.isValid() || newColor != m_lastColor)) + { + QPalette pal; + pal.setColor(QPalette::Window, newColor); + m_lastColor = newColor; + setPalette(pal); } - setPalette(pal); if (m_sendColors) sendColor(); diff --git a/widgets/drumpadsamplewidget.h b/widgets/drumpadsamplewidget.h index 87b1558..49e34b7 100755 --- a/widgets/drumpadsamplewidget.h +++ b/widgets/drumpadsamplewidget.h @@ -85,4 +85,6 @@ private: quint8 m_padNr{}; bool m_sendColors{}; + + QColor m_lastColor; }; diff --git a/widgets/loopstationpresetdetailwidget.ui b/widgets/loopstationpresetdetailwidget.ui index df351da..bfac880 100644 --- a/widgets/loopstationpresetdetailwidget.ui +++ b/widgets/loopstationpresetdetailwidget.ui @@ -178,6 +178,12 @@ false + + -2147483647 + + + 2147483647 + @@ -195,6 +201,12 @@ false + + -2147483647 + + + 2147483647 + diff --git a/widgets/loopstationsampleswidget.cpp b/widgets/loopstationsampleswidget.cpp index c6333a3..5d7f6e5 100644 --- a/widgets/loopstationsampleswidget.cpp +++ b/widgets/loopstationsampleswidget.cpp @@ -9,12 +9,45 @@ LoopStationSamplesWidget::LoopStationSamplesWidget(QWidget *parent) : { m_ui->setupUi(this); + connect(m_ui->spinBoxBpm, qOverload(&QSpinBox::valueChanged), this, &LoopStationSamplesWidget::tempoChanged); + + connect(m_ui->pushButtonPlayPause, &QAbstractButton::pressed, this, &LoopStationSamplesWidget::playPausePressed); + connect(m_ui->pushButtonStop, &QAbstractButton::pressed, this, &LoopStationSamplesWidget::stopPressed); + + connect(&m_timer, &QTimer::timeout, this, &LoopStationSamplesWidget::timeout); + + m_timer.setTimerType(Qt::PreciseTimer); + quint8 padNr{}; for (LoopStationSampleWidget &widget : getWidgets()) { widget.setPadNr(padNr++); connect(&widget, &LoopStationSampleWidget::sendMidi, this, &LoopStationSamplesWidget::sendMidi); + connect(&widget, &LoopStationSampleWidget::loopEnabled, this, &LoopStationSamplesWidget::loopEnabled); } + + constexpr const auto setCategories = [](auto category, auto *widget0, auto *widget1, auto *widget2, auto *widget3, auto *widget4, auto *widget5, auto *widget6, auto *widget7){ + widget0->setCategory(category); + widget1->setCategory(category); + widget2->setCategory(category); + widget3->setCategory(category); + widget4->setCategory(category); + widget5->setCategory(category); + widget6->setCategory(category); + widget7->setCategory(category); + }; + setCategories(0, m_ui->sampleWidget0, m_ui->sampleWidget1, m_ui->sampleWidget2, m_ui->sampleWidget3, + m_ui->sampleWidget24, m_ui->sampleWidget25, m_ui->sampleWidget26, m_ui->sampleWidget27); + setCategories(1, m_ui->sampleWidget4, m_ui->sampleWidget5, m_ui->sampleWidget6, m_ui->sampleWidget7, + m_ui->sampleWidget28, m_ui->sampleWidget29, m_ui->sampleWidget30, m_ui->sampleWidget31); + setCategories(2, m_ui->sampleWidget8, m_ui->sampleWidget9, m_ui->sampleWidget10, m_ui->sampleWidget11, + m_ui->sampleWidget32, m_ui->sampleWidget33, m_ui->sampleWidget34, m_ui->sampleWidget35); + setCategories(3, m_ui->sampleWidget12, m_ui->sampleWidget13, m_ui->sampleWidget14, m_ui->sampleWidget15, + m_ui->sampleWidget36, m_ui->sampleWidget37, m_ui->sampleWidget38, m_ui->sampleWidget39); + setCategories(4, m_ui->sampleWidget16, m_ui->sampleWidget17, m_ui->sampleWidget18, m_ui->sampleWidget19, + m_ui->sampleWidget40, m_ui->sampleWidget41, m_ui->sampleWidget42, m_ui->sampleWidget43); + setCategories(5, m_ui->sampleWidget20, m_ui->sampleWidget21, m_ui->sampleWidget22, m_ui->sampleWidget23, + m_ui->sampleWidget44, m_ui->sampleWidget45, m_ui->sampleWidget46, m_ui->sampleWidget47); } LoopStationSamplesWidget::~LoopStationSamplesWidget() = default; @@ -29,17 +62,22 @@ void LoopStationSamplesWidget::setPreset(const loopstation_presets::Preset &pres { assert(preset.id); assert(preset.pads); + assert(preset.bpm); const auto &presetId = *preset.id; const auto &widgets = getWidgets(); const auto &pads = *preset.pads; + stopPressed(); + m_ui->spinBoxBpm->setValue(*preset.bpm); + auto iter = std::begin(widgets); auto iter2 = std::begin(pads); int i{}; for (; iter != std::end(widgets) && iter2 != std::end(pads); iter++, iter2++) { - ((*iter)).get().setSample(presetId, QString{"%0_%1.wav"}.arg(presetId).arg(++i, 2, 10, QLatin1Char('0')), *iter2); + auto &widget = ((*iter)).get(); + widget.setSample(presetId, QString{"%0_%1.wav"}.arg(presetId).arg(++i, 2, 10, QLatin1Char('0')), *iter2); } } @@ -79,6 +117,78 @@ void LoopStationSamplesWidget::sendColors() widget.sendColor(); } +void LoopStationSamplesWidget::timeout() +{ + if (m_pos >= 7) + { + for (LoopStationSampleWidget &widget : getWidgets()) + widget.timeout(); + m_pos = 0; + } + else + { + if (m_pos == 3) + { + for (LoopStationSampleWidget &widget : getWidgets()) + widget.timeout(); + } + + m_pos++; + } + m_ui->horizontalSlider->setValue(m_pos); +} + +void LoopStationSamplesWidget::tempoChanged(int tempo) +{ + m_timer.setInterval(1000. * 60. / tempo); +} + +void LoopStationSamplesWidget::loopEnabled(quint8 category) +{ + for (LoopStationSampleWidget &widget : getWidgets()) + { + if (widget.category() != category) + continue; + if (&widget == sender()) + continue; + widget.setLoopEnabled(false); + } + + if (!m_timer.isActive()) + { + m_pos = 0; + m_ui->horizontalSlider->setValue(m_pos); + m_timer.start(); + for (LoopStationSampleWidget &widget : getWidgets()) + widget.timeout(); + } +} + +void LoopStationSamplesWidget::playPausePressed() +{ + if (m_timer.isActive()) + m_timer.stop(); + else + { + m_timer.start(); + if (m_pos == 0) + for (LoopStationSampleWidget &widget : getWidgets()) + widget.timeout(); + } +} + +void LoopStationSamplesWidget::stopPressed() +{ + m_timer.stop(); + for (LoopStationSampleWidget &widget : getWidgets()) + { + widget.setLoopEnabled(false); + widget.stop(); + } + m_pos = 0; + m_ui->horizontalSlider->setValue(m_pos); +} + std::array, 48> LoopStationSamplesWidget::getWidgets() { return { diff --git a/widgets/loopstationsampleswidget.h b/widgets/loopstationsampleswidget.h index 6828fa8..dcc2de2 100644 --- a/widgets/loopstationsampleswidget.h +++ b/widgets/loopstationsampleswidget.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -40,8 +41,19 @@ public: signals: void sendMidi(const midi::MidiMessage &midiMsg); +private slots: + void timeout(); + void tempoChanged(int tempo); + void loopEnabled(quint8 category); + void playPausePressed(); + void stopPressed(); + private: std::array, 48> getWidgets(); const std::unique_ptr m_ui; + + QTimer m_timer; + + quint8 m_pos{}; }; diff --git a/widgets/loopstationsampleswidget.ui b/widgets/loopstationsampleswidget.ui index 54f2dfc..23d774d 100644 --- a/widgets/loopstationsampleswidget.ui +++ b/widgets/loopstationsampleswidget.ui @@ -6,126 +6,42 @@ 0 0 - 1254 - 890 + 411 + 273 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Qt::Horizontal + + + + QFrame::Panel - - - 40 - 20 - + + QFrame::Sunken - - - - - - - - - - - - - - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + Qt::Vertical @@ -138,16 +54,27 @@ - - + + + + QFrame::Panel + + + QFrame::Sunken + + - - + + + + QFrame::Panel + + + QFrame::Sunken + + - - - - + Qt::Horizontal @@ -160,72 +87,545 @@ - - - - - + + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - - - - - - - - - - - - - - - - - - - - + + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - - + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + QFrame::Panel + + + QFrame::Sunken + + - - - - - - - + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - - + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + - - + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + QFrame::Panel + + + QFrame::Sunken + + - + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Bpm: + + + + + + + BPM + + + 50 + + + 500 + + + + + + + Play/Pause + + + + + + + Stop + + + + + + + 8 + + + 1 + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + LoopStationSampleWidget - QWidget + QFrame
widgets/loopstationsamplewidget.h
1
diff --git a/widgets/loopstationsamplewidget.cpp b/widgets/loopstationsamplewidget.cpp index c927492..5907586 100644 --- a/widgets/loopstationsamplewidget.cpp +++ b/widgets/loopstationsamplewidget.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "audioformat.h" #include "audiodecoder.h" @@ -20,13 +21,24 @@ LoopStationSampleWidget::LoopStationSampleWidget(QWidget *parent) : connect(&m_player, &AudioPlayer::playingChanged, this, &LoopStationSampleWidget::updateStatus); - connect(m_ui->pushButtonPlay, &QAbstractButton::pressed, this, &LoopStationSampleWidget::pressed); + connect(m_ui->pushButtonPlay, &QAbstractButton::toggled, this, [this](bool toggled){ + if (!toggled) + return; + emit loopEnabled(m_category); + }); updateStatus(); } LoopStationSampleWidget::~LoopStationSampleWidget() = default; +void LoopStationSampleWidget::setCategory(quint8 category) +{ + m_category = category; + m_ui->labelCategory->setText(QString::number(category)); + updateStatus(); +} + void LoopStationSampleWidget::loadSettings(DrumMachineSettings &settings) { m_settings = &settings; @@ -55,11 +67,6 @@ void LoopStationSampleWidget::setSample(const QString &presetId, const QString & m_ui->labelType->setText(type); } -void LoopStationSampleWidget::pressed() -{ - m_player.restart(); -} - void LoopStationSampleWidget::injectNetworkAccessManager(QNetworkAccessManager &networkAccessManager) { m_networkAccessManager = &networkAccessManager; @@ -111,11 +118,77 @@ void LoopStationSampleWidget::sendColor() .flag = true, .note = m_ui->pushButtonPlay->learnSetting().note, .velocity = uint8_t(m_padNr+1) - }); + }); +} + +void LoopStationSampleWidget::timeout() +{ + if (m_ui->pushButtonPlay->isChecked()) + { + // if is not playing or position > 90% + if (!m_player.playing() || m_player.position() >= m_player.buffer().frameCount() * 9 / 10) + m_player.restart(); + } + else + { + // if is playing and position < 60% + if (m_player.playing() && m_player.position() < m_player.buffer().frameCount() * 6 / 10) + m_player.stop(); + } +} + +void LoopStationSampleWidget::setLoopEnabled(bool enabled) +{ + m_ui->pushButtonPlay->setChecked(enabled); +} + +void LoopStationSampleWidget::stop() +{ + m_player.stop(); } void LoopStationSampleWidget::updateStatus() { + QColor newColor; + + if (m_player.buffer().isValid()) + { + 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 +; + + if (m_category == 0) + newColor = QColor{bright, dark, bright}; + else if (m_category == 1) + newColor = QColor{bright, dark, dark}; + else if (m_category == 2) + newColor = QColor{bright, bright, dark}; + else if (m_category == 3) + newColor = QColor{dark, bright, dark}; + else if (m_category == 4) + newColor = QColor{dark, dark, bright}; + else if (m_category == 5) + newColor = QColor{dark, bright, bright}; + else + { + qWarning() << "unknown category:" << m_category; + newColor = QColor{dark, dark, dark}; + } + } + + if (newColor.isValid() && (!m_lastColor.isValid() || newColor != m_lastColor)) + { + QPalette pal; + pal.setColor(QPalette::Window, newColor); + m_lastColor = newColor; + setPalette(pal); + } + if (m_sendColors) sendColor(); diff --git a/widgets/loopstationsamplewidget.h b/widgets/loopstationsamplewidget.h index a46cbeb..474a15c 100644 --- a/widgets/loopstationsamplewidget.h +++ b/widgets/loopstationsamplewidget.h @@ -26,12 +26,13 @@ public: quint8 padNr() const { return m_padNr; } void setPadNr(quint8 padNr) { m_padNr = padNr; } + quint8 category() const { return m_category; } + void setCategory(quint8 category); + void loadSettings(DrumMachineSettings &settings); void setSample(const QString &presetId, const QString &filename, const QString &type); - void pressed(); - void injectNetworkAccessManager(QNetworkAccessManager &networkAccessManager); void injectDecodingThread(QThread &thread); @@ -42,9 +43,15 @@ public: void unsendColor(); void sendColor(); +public slots: + void timeout(); + void setLoopEnabled(bool enabled); + void stop(); + signals: void startDecoding(std::shared_ptr device); void sendMidi(const midi::MidiMessage &midiMsg); + void loopEnabled(quint8 category); private slots: void updateStatus(); @@ -70,6 +77,9 @@ private: QNetworkAccessManager *m_networkAccessManager{}; quint8 m_padNr{}; + quint8 m_category{}; bool m_sendColors{}; + + QColor m_lastColor; }; diff --git a/widgets/loopstationsamplewidget.ui b/widgets/loopstationsamplewidget.ui index f7d43b7..c0baa18 100644 --- a/widgets/loopstationsamplewidget.ui +++ b/widgets/loopstationsamplewidget.ui @@ -10,8 +10,8 @@ 300 - - Form + + true QFrame::Panel @@ -29,6 +29,19 @@
+ + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -40,8 +53,24 @@ + + true + + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -52,11 +81,25 @@ - - - TextLabel - - + + + + + TextLabel + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + diff --git a/widgets/midibutton.cpp b/widgets/midibutton.cpp index cf6e81d..9d7241b 100644 --- a/widgets/midibutton.cpp +++ b/widgets/midibutton.cpp @@ -100,7 +100,11 @@ void MidiButton::midiReceived(const midi::MidiMessage &message) { case midi::Command::NoteOn: if (message.velocity != 0) + { + if (isCheckable()) + toggle(); emit pressed(); + } else Q_FALLTHROUGH(); case midi::Command::NoteOff: @@ -113,7 +117,11 @@ void MidiButton::midiReceived(const midi::MidiMessage &message) else if (m_learnSetting.cmd == message.cmd) { if (message.velocity != 0) + { + if (isCheckable()) + toggle(); emit pressed(); + } else emit released(); } diff --git a/widgets/sequencerwidget.cpp b/widgets/sequencerwidget.cpp index c5f9f72..6bfc576 100755 --- a/widgets/sequencerwidget.cpp +++ b/widgets/sequencerwidget.cpp @@ -26,9 +26,10 @@ SequencerWidget::SequencerWidget(QWidget *parent) : connect(m_ui->horizontalSlider, &QSlider::valueChanged, this, [=](int value){ m_pos = value; updateStatusLabel(); }); - connect(&m_timer, &QTimer::timeout, this, &SequencerWidget::timeout); + m_timer.setTimerType(Qt::PreciseTimer); + updateStatusLabel(); } @@ -204,8 +205,8 @@ void SequencerWidget::sequenceSelected() m_ui->pushButtonPlayPause->setEnabled(m_selectedSequence != nullptr); m_ui->pushButtonStop->setEnabled(m_selectedSequence != nullptr); - m_pos = 0; - m_ui->horizontalSlider->setValue(0); + m_pos = m_selectedSequence ? m_pos % 8 : 0; + m_ui->horizontalSlider->setValue(m_pos); updateStatusLabel(); }