Files
DrumMachine/widgets/drumpadsequencerwidget.cpp

268 lines
9.1 KiB
C++
Raw Permalink Normal View History

#include "drumpadsequencerwidget.h"
#include "ui_drumpadsequencerwidget.h"
2020-04-25 20:53:49 +02:00
#include <algorithm>
2020-04-25 23:03:33 +02:00
#include <QDebug>
2022-12-27 21:19:21 +01:00
#include "drumpadpresets.h"
#include "drummachinesettings.h"
#include "midicontainers.h"
2020-04-25 20:53:49 +02:00
DrumPadSequencerWidget::DrumPadSequencerWidget(QWidget *parent) :
2020-04-25 20:53:49 +02:00
QWidget{parent},
m_ui{std::make_unique<Ui::DrumPadSequencerWidget>()},
m_timer{this}
2020-04-25 20:53:49 +02:00
{
m_ui->setupUi(this);
connect(m_ui->spinBoxTempo, qOverload<int>(&QSpinBox::valueChanged), this, &DrumPadSequencerWidget::tempoChanged);
connect(m_ui->comboBoxSequence, qOverload<int>(&QComboBox::currentIndexChanged), this, &DrumPadSequencerWidget::sequenceSelected);
2020-04-25 20:53:49 +02:00
connect(m_ui->pushButtonUp, &QAbstractButton::pressed, this, &DrumPadSequencerWidget::selectPrevSequence);
connect(m_ui->pushButtonDown, &QAbstractButton::pressed, this, &DrumPadSequencerWidget::selectNextSequence);
connect(m_ui->pushButtonPlayPause, &QAbstractButton::pressed, this, &DrumPadSequencerWidget::playPause);
connect(m_ui->pushButtonStop, &QAbstractButton::pressed, this, &DrumPadSequencerWidget::stop);
2020-04-25 20:53:49 +02:00
connect(m_ui->horizontalSlider, &QSlider::valueChanged, this, [=](int value){ m_pos = value; updateStatusLabel(); });
connect(&m_timer, &QTimer::timeout, this, &DrumPadSequencerWidget::timeout);
2020-04-25 20:53:49 +02:00
m_timer.setTimerType(Qt::PreciseTimer);
2020-04-25 20:53:49 +02:00
updateStatusLabel();
}
DrumPadSequencerWidget::~DrumPadSequencerWidget() = default;
2020-04-25 20:53:49 +02:00
void DrumPadSequencerWidget::loadSettings(DrumMachineSettings &settings)
{
m_settings = &settings;
m_ui->pushButtonUp->setLearnSetting(settings.drumpadPrevSequence());
m_ui->pushButtonDown->setLearnSetting(settings.drumpadNextSequence());
m_ui->pushButtonPlayPause->setLearnSetting(settings.drumpadPlayPause());
m_ui->pushButtonStop->setLearnSetting(settings.drumpadStopSequence());
connect(m_ui->pushButtonUp, &MidiButton::learnSettingChanged, &settings, &DrumMachineSettings::setDrumpadPrevSequence);
connect(m_ui->pushButtonDown, &MidiButton::learnSettingChanged, &settings, &DrumMachineSettings::setDrumpadNextSequence);
connect(m_ui->pushButtonPlayPause, &MidiButton::learnSettingChanged, &settings, &DrumMachineSettings::setDrumpadPlayPause);
connect(m_ui->pushButtonStop, &MidiButton::learnSettingChanged, &settings, &DrumMachineSettings::setDrumpadStopSequence);
}
void DrumPadSequencerWidget::unsendColors()
{
m_sendColors = false;
const quint8 color = m_settings ? m_settings->colorOff() : quint8{0};
emit sendMidi(midi::MidiMessage {
.channel = m_ui->pushButtonUp->learnSetting().channel,
.cmd = m_ui->pushButtonUp->learnSetting().cmd,
.flag = true,
.note = m_ui->pushButtonUp->learnSetting().note,
.velocity = color
});
emit sendMidi(midi::MidiMessage {
.channel = m_ui->pushButtonDown->learnSetting().channel,
.cmd = m_ui->pushButtonDown->learnSetting().cmd,
.flag = true,
.note = m_ui->pushButtonDown->learnSetting().note,
.velocity = color
});
emit sendMidi(midi::MidiMessage {
.channel = m_ui->pushButtonPlayPause->learnSetting().channel,
.cmd = m_ui->pushButtonPlayPause->learnSetting().cmd,
.flag = true,
.note = m_ui->pushButtonPlayPause->learnSetting().note,
.velocity = color
});
emit sendMidi(midi::MidiMessage {
.channel = m_ui->pushButtonStop->learnSetting().channel,
.cmd = m_ui->pushButtonStop->learnSetting().cmd,
.flag = true,
.note = m_ui->pushButtonStop->learnSetting().note,
.velocity = color
});
}
void DrumPadSequencerWidget::sendColors()
{
m_sendColors = true;
emit sendMidi(midi::MidiMessage {
.channel = m_ui->pushButtonUp->learnSetting().channel,
.cmd = m_ui->pushButtonUp->learnSetting().cmd,
.flag = true,
.note = m_ui->pushButtonUp->learnSetting().note,
.velocity = m_settings ? m_settings->drumpadColorPrevSequence() : quint8{127}
});
emit sendMidi(midi::MidiMessage {
.channel = m_ui->pushButtonDown->learnSetting().channel,
.cmd = m_ui->pushButtonDown->learnSetting().cmd,
.flag = true,
.note = m_ui->pushButtonDown->learnSetting().note,
.velocity = m_settings ? m_settings->drumpadColorNextSequence() : quint8{127}
});
emit sendMidi(midi::MidiMessage {
.channel = m_ui->pushButtonPlayPause->learnSetting().channel,
.cmd = m_ui->pushButtonPlayPause->learnSetting().cmd,
.flag = true,
.note = m_ui->pushButtonPlayPause->learnSetting().note,
.velocity = m_settings ? m_settings->drumpadColorPlayPause() : quint8{3}
});
emit sendMidi(midi::MidiMessage {
.channel = m_ui->pushButtonStop->learnSetting().channel,
.cmd = m_ui->pushButtonStop->learnSetting().cmd,
.flag = true,
.note = m_ui->pushButtonStop->learnSetting().note,
.velocity = m_settings ? m_settings->drumpadColorStopSequence() : quint8{60}
});
}
void DrumPadSequencerWidget::setPreset(const drumpad_presets::Preset &preset)
2020-04-25 20:53:49 +02:00
{
if (preset.tempo)
m_ui->spinBoxTempo->setValue(*preset.tempo);
2020-04-25 23:03:33 +02:00
for (int i = 0; i < 24; i++)
qobject_cast<QLabel*>(m_ui->gridLayout->itemAtPosition(2+(i*2), 0)->widget())->setText(*preset.files->at(i).filename);
2020-04-25 20:53:49 +02:00
m_selectedSequence = nullptr;
m_ui->horizontalSlider->setMaximum(0);
m_ui->comboBoxSequence->clear();
m_sequences.clear();
m_selectedSequence = nullptr;
2022-12-27 21:19:21 +01:00
const auto doit = [&](const QString &prefix, const std::optional<std::map<QString, std::vector<drumpad_presets::Sequence>>> &value)
2020-04-25 20:53:49 +02:00
{
if (!value)
return;
for (const auto &pair : *value)
{
for (const auto &sequence : pair.second)
{
m_ui->comboBoxSequence->addItem(QString{"%0/%1/%2"}.arg(prefix, pair.first, sequence.name?*sequence.name:"(null)"));
m_sequences.emplace_back(sequence);
}
}
};
{
QSignalBlocker blocker{m_ui->comboBoxSequence};
doit("beatSchool", preset.beatSchool);
doit("easyPlay", preset.easyPlay);
}
sequenceSelected();
}
void DrumPadSequencerWidget::midiReceived(const midi::MidiMessage &message)
{
m_ui->pushButtonUp->midiReceived(message);
m_ui->pushButtonDown->midiReceived(message);
m_ui->pushButtonPlayPause->midiReceived(message);
m_ui->pushButtonStop->midiReceived(message);
}
void DrumPadSequencerWidget::playPause()
2020-04-25 20:53:49 +02:00
{
if (m_timer.isActive())
{
m_timer.stop();
m_ui->pushButtonPlayPause->setText(tr(""));
}
else
{
m_timer.start();
m_ui->pushButtonPlayPause->setText(tr("▮▮"));
}
}
void DrumPadSequencerWidget::stop()
2020-04-25 20:53:49 +02:00
{
m_timer.stop();
m_ui->pushButtonPlayPause->setText(tr(""));
m_pos = 0;
m_ui->horizontalSlider->setValue(0);
updateStatusLabel();
}
void DrumPadSequencerWidget::tempoChanged(int tempo)
2020-04-25 20:53:49 +02:00
{
m_timer.setInterval(1000. * 60. / tempo / 4.);
}
void DrumPadSequencerWidget::sequenceSelected()
2020-04-25 20:53:49 +02:00
{
const auto index = m_ui->comboBoxSequence->currentIndex();
if (index == -1)
m_selectedSequence = nullptr;
else
m_selectedSequence = &m_sequences[index];
m_ui->horizontalSlider->setMaximum(m_selectedSequence && m_selectedSequence->sequencerSize ? *m_selectedSequence->sequencerSize-2 : 0);
m_ui->pushButtonPlayPause->setEnabled(m_selectedSequence != nullptr);
m_ui->pushButtonStop->setEnabled(m_selectedSequence != nullptr);
m_pos = m_selectedSequence ? m_pos % 8 : 0;
m_ui->horizontalSlider->setValue(m_pos);
2020-04-25 20:53:49 +02:00
updateStatusLabel();
}
void DrumPadSequencerWidget::timeout()
2020-04-25 20:53:49 +02:00
{
if (m_selectedSequence && m_selectedSequence->pads)
{
for (const auto &pair : *m_selectedSequence->pads)
{
2022-12-27 21:19:21 +01:00
const auto iter = std::find_if(std::cbegin(pair.second), std::cend(pair.second), [&](const drumpad_presets::SequencePad &sequencePad){
2020-04-25 20:53:49 +02:00
return sequencePad.start && *sequencePad.start == m_pos;
});
if (iter == std::cend(pair.second))
continue;
//TODO: iter->duration;
bool ok;
const auto index = pair.first.toInt(&ok);
if (!ok)
continue;
emit triggerSample(index);
}
}
m_pos++;
if (m_pos >= (m_selectedSequence && m_selectedSequence->sequencerSize ? *m_selectedSequence->sequencerSize-1 : -1))
m_pos = 0;
m_ui->horizontalSlider->setValue(m_pos);
updateStatusLabel();
}
void DrumPadSequencerWidget::updateStatusLabel()
2020-04-25 20:53:49 +02:00
{
m_ui->labelStatus->setText(QString{"%0 / %1"}.arg(m_pos+1).arg(m_selectedSequence && m_selectedSequence->sequencerSize ? *m_selectedSequence->sequencerSize-1 : -1));
}
void DrumPadSequencerWidget::selectPrevSequence()
{
if (const auto index = m_ui->comboBoxSequence->currentIndex(); index > 0)
m_ui->comboBoxSequence->setCurrentIndex(index - 1);
}
void DrumPadSequencerWidget::selectNextSequence()
{
if (const auto index = m_ui->comboBoxSequence->currentIndex(); index + 1 < m_ui->comboBoxSequence->count())
m_ui->comboBoxSequence->setCurrentIndex(index + 1);
}