Fixed midi handling for control change and implemented tab selection with midi
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
QT = core multimedia gui widgets network
|
||||
|
||||
CONFIG += c++20
|
||||
CONFIG += c++22
|
||||
|
||||
QMAKE_CXXFLAGS += -Werror=all
|
||||
release: QMAKE_CXXFLAGS_RELEASE -= -O1
|
||||
@ -30,6 +30,7 @@ SOURCES += \
|
||||
main.cpp \
|
||||
midicontainers.cpp \
|
||||
midiinwrapper.cpp \
|
||||
midilearnsetting.cpp \
|
||||
midioutwrapper.cpp \
|
||||
synthisizer.cpp \
|
||||
treetotableproxymodel.cpp \
|
||||
@ -60,6 +61,7 @@ HEADERS += \
|
||||
drumpadpresets.h \
|
||||
drumpadpresetsmodel.h \
|
||||
drumpadpresettagsmodel.h \
|
||||
futurecpp.h \
|
||||
graphrenderer.h \
|
||||
jsonconverters.h \
|
||||
loopstationjsonconverters.h \
|
||||
@ -68,6 +70,7 @@ HEADERS += \
|
||||
loopstationpresettagsmodel.h \
|
||||
midicontainers.h \
|
||||
midiinwrapper.h \
|
||||
midilearnsetting.h \
|
||||
midioutwrapper.h \
|
||||
synthisizer.h \
|
||||
treetotableproxymodel.h \
|
||||
|
@ -3,6 +3,9 @@
|
||||
#include <QStandardPaths>
|
||||
#include <QDebug>
|
||||
|
||||
#include "midilearnsetting.h"
|
||||
#include "futurecpp.h"
|
||||
|
||||
QString DrumMachineSettings::defaultCacheDir() const
|
||||
{
|
||||
return QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
||||
@ -73,6 +76,16 @@ void DrumMachineSettings::setLastMidiOutDevice(const QString &lastMidiOutDevice)
|
||||
setValue("lastMidiOutDevice", lastMidiOutDevice);
|
||||
}
|
||||
|
||||
MidiLearnSetting DrumMachineSettings::tabWidget(quint8 index) const
|
||||
{
|
||||
return learnSetting(QString{"tabWidget%0"}.arg(index));
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setTabWidget(quint8 index, const MidiLearnSetting &value)
|
||||
{
|
||||
setLearnSetting(QString{"tabWidget%0"}.arg(index), value);
|
||||
}
|
||||
|
||||
QString DrumMachineSettings::drumpadLastPresetId() const
|
||||
{
|
||||
return value("drumpad/lastPresetId").toString();
|
||||
@ -83,144 +96,74 @@ void DrumMachineSettings::setDrumpadLastPresetId(const QString &lastPresetId)
|
||||
setValue("drumpad/lastPresetId", lastPresetId);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::drumpadChannelPrevPreset() const
|
||||
MidiLearnSetting DrumMachineSettings::drumpadPrevPreset() const
|
||||
{
|
||||
return value("drumpad/prevPreset_channel", 99).toUInt();
|
||||
return learnSetting("drumpad/prevPreset");
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setDrumpadChannelPrevPreset(quint8 channel)
|
||||
void DrumMachineSettings::setDrumpadPrevPreset(const MidiLearnSetting &value)
|
||||
{
|
||||
setValue("drumpad/prevPreset_channel", channel);
|
||||
setLearnSetting("drumpad/prevPreset", value);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::drumpadNotePrevPreset() const
|
||||
MidiLearnSetting DrumMachineSettings::drumpadNextPreset() const
|
||||
{
|
||||
return value("drumpad/prevPreset_note", 99).toUInt();
|
||||
return learnSetting("drumpad/nextPreset");
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setDrumpadNotePrevPreset(quint8 note)
|
||||
void DrumMachineSettings::setDrumpadNextPreset(const MidiLearnSetting &value)
|
||||
{
|
||||
setValue("drumpad/prevPreset_note", note);
|
||||
setLearnSetting("drumpad/nextPreset", value);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::drumpadChannelNextPreset() const
|
||||
MidiLearnSetting DrumMachineSettings::drumpadPrevSequence() const
|
||||
{
|
||||
return value("drumpad/nextPreset_channel", 99).toUInt();
|
||||
return learnSetting("drumpad/prevSequence");
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setDrumpadChannelNextPreset(quint8 channel)
|
||||
void DrumMachineSettings::setDrumpadPrevSequence(const MidiLearnSetting &value)
|
||||
{
|
||||
setValue("drumpad/nextPreset_channel", channel);
|
||||
setLearnSetting("drumpad/prevSequence", value);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::drumpadNoteNextPreset() const
|
||||
MidiLearnSetting DrumMachineSettings::drumpadNextSequence() const
|
||||
{
|
||||
return value("drumpad/nextPreset_note", 99).toUInt();
|
||||
return learnSetting("drumpad/nextSequence");
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setDrumpadNoteNextPreset(quint8 note)
|
||||
void DrumMachineSettings::setDrumpadNextSequence(const MidiLearnSetting &value)
|
||||
{
|
||||
setValue("drumpad/nextPreset_note", note);
|
||||
setLearnSetting("drumpad/nextSequence", value);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::drumpadChannelPrevSequence() const
|
||||
MidiLearnSetting DrumMachineSettings::drumpadPlayPause() const
|
||||
{
|
||||
return value("drumpad/prevSequence_channel", 99).toUInt();
|
||||
return learnSetting("drumpad/playPause");
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setDrumpadChannelPrevSequence(quint8 channel)
|
||||
void DrumMachineSettings::setDrumpadPlayPause(const MidiLearnSetting &value)
|
||||
{
|
||||
setValue("drumpad/prevSequence_channel", channel);
|
||||
setLearnSetting("drumpad/playPause", value);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::drumpadNotePrevSequence() const
|
||||
MidiLearnSetting DrumMachineSettings::drumpadStop() const
|
||||
{
|
||||
return value("drumpad/prevSequence_note", 99).toUInt();
|
||||
return learnSetting("drumpad/stop");
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setDrumpadNotePrevSequence(quint8 note)
|
||||
void DrumMachineSettings::setDrumpadStop(const MidiLearnSetting &value)
|
||||
{
|
||||
setValue("drumpad/prevSequence_note", note);
|
||||
setLearnSetting("drumpad/stop", value);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::drumpadChannelNextSequence() const
|
||||
MidiLearnSetting DrumMachineSettings::drumpadSample(quint8 pad) const
|
||||
{
|
||||
return value("drumpad/nextSequence_channel", 99).toUInt();
|
||||
return learnSetting(QString{"drumpad/pad%0"}.arg(pad));
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setDrumpadChannelNextSequence(quint8 channel)
|
||||
void DrumMachineSettings::setDrumpadSample(quint8 pad, const MidiLearnSetting &value)
|
||||
{
|
||||
setValue("drumpad/nextSequence_channel", channel);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::drumpadNoteNextSequence() const
|
||||
{
|
||||
return value("drumpad/nextSequence_note", 99).toUInt();
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setDrumpadNoteNextSequence(quint8 note)
|
||||
{
|
||||
setValue("drumpad/nextSequence_note", note);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::drumpadChannelPlayPause() const
|
||||
{
|
||||
return value("drumpad/playPause_channel", 99).toUInt();
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setDrumpadChannelPlayPause(quint8 channel)
|
||||
{
|
||||
setValue("drumpad/playPause_channel", channel);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::drumpadNotePlayPause() const
|
||||
{
|
||||
return value("drumpad/playPause_note", 99).toUInt();
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setDrumpadNotePlayPause(quint8 note)
|
||||
{
|
||||
setValue("drumpad/playPause_note", note);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::drumpadChannelStop() const
|
||||
{
|
||||
return value("drumpad/stop_channel", 99).toUInt();
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setDrumpadChannelStop(quint8 channel)
|
||||
{
|
||||
setValue("drumpad/stop_channel", channel);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::drumpadNoteStop() const
|
||||
{
|
||||
return value("drumpad/stop_note", 99).toUInt();
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setDrumpadNoteStop(quint8 note)
|
||||
{
|
||||
setValue("drumpad/stop_note", note);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::drumpadChannel(quint8 pad) const
|
||||
{
|
||||
return value(QString{"drumpad/pad%0_channel"}.arg(pad), 99).toUInt();
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setDrumpadChannel(quint8 pad, quint8 channel)
|
||||
{
|
||||
setValue(QString{"drumpad/pad%0_channel"}.arg(pad), channel);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::drumpadNote(quint8 pad) const
|
||||
{
|
||||
return value(QString{"drumpad/pad%0_note"}.arg(pad), 99).toUInt();
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setDrumpadNote(quint8 pad, quint8 note)
|
||||
{
|
||||
setValue(QString{"drumpad/pad%0_note"}.arg(pad), note);
|
||||
setLearnSetting(QString{"drumpad/pad%0"}.arg(pad), value);
|
||||
}
|
||||
|
||||
QString DrumMachineSettings::loopstationLastPresetId() const
|
||||
@ -233,42 +176,38 @@ void DrumMachineSettings::setLoopstationLastPresetId(const QString &lastPresetId
|
||||
setValue("loopstation/lastPresetId", lastPresetId);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::loopstationChannelPrevPreset() const
|
||||
MidiLearnSetting DrumMachineSettings::loopstationPrevPreset() const
|
||||
{
|
||||
return value("loopstation/prevPreset_channel", 99).toUInt();
|
||||
return learnSetting("loopstation/prevPreset");
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setLoopstationChannelPrevPreset(quint8 channel)
|
||||
void DrumMachineSettings::setLoopstationPrevPreset(const MidiLearnSetting &value)
|
||||
{
|
||||
setValue("loopstation/prevPreset_channel", channel);
|
||||
setLearnSetting("loopstation/prevPreset", value);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::loopstationNotePrevPreset() const
|
||||
MidiLearnSetting DrumMachineSettings::loopstationNextPreset() const
|
||||
{
|
||||
return value("loopstation/prevPreset_note", 99).toUInt();
|
||||
return learnSetting("loopstation/nextPreset");
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setLoopstationNotePrevPreset(quint8 note)
|
||||
void DrumMachineSettings::setLoopstationNextPreset(const MidiLearnSetting &value)
|
||||
{
|
||||
setValue("loopstation/prevPreset_note", note);
|
||||
setLearnSetting("loopstation/nextPreset", value);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::loopstationChannelNextPreset() const
|
||||
MidiLearnSetting DrumMachineSettings::learnSetting(const QString &key) const
|
||||
{
|
||||
return value("loopstation/nextPreset_channel", 99).toUInt();
|
||||
return MidiLearnSetting{
|
||||
.cmd = midi::Command(value(QString{"%0_cmd"}.arg(key), std::to_underlying(midi::Command::NoteOn)).value<std::underlying_type_t<midi::Command>>()),
|
||||
.channel = value(QString{"%0_channel"}.arg(key), 99).value<quint8>(),
|
||||
.note = value(QString{"%0_note"}.arg(key), 99).value<quint8>()
|
||||
};
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setLoopstationChannelNextPreset(quint8 channel)
|
||||
void DrumMachineSettings::setLearnSetting(const QString &key, const MidiLearnSetting &value)
|
||||
{
|
||||
setValue("loopstation/nextPreset_channel", channel);
|
||||
}
|
||||
|
||||
quint8 DrumMachineSettings::loopstationNoteNextPreset() const
|
||||
{
|
||||
return value("loopstation/nextPreset_note", 99).toUInt();
|
||||
}
|
||||
|
||||
void DrumMachineSettings::setLoopstationNoteNextPreset(quint8 note)
|
||||
{
|
||||
setValue("loopstation/nextPreset_note", note);
|
||||
setValue(QString{"%0_note"}.arg(key), std::to_underlying(value.cmd));
|
||||
setValue(QString{"%0_channel"}.arg(key), value.channel);
|
||||
setValue(QString{"%0_note"}.arg(key), value.note);
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include <QSettings>
|
||||
|
||||
struct MidiLearnSetting;
|
||||
|
||||
class DrumMachineSettings : public QSettings
|
||||
{
|
||||
public:
|
||||
@ -27,58 +29,47 @@ public:
|
||||
QString lastMidiOutDevice() const;
|
||||
void setLastMidiOutDevice(const QString &lastMidiOutDevice);
|
||||
|
||||
MidiLearnSetting tabWidget(quint8 index) const;
|
||||
void setTabWidget(quint8 index, const MidiLearnSetting &value);
|
||||
|
||||
|
||||
|
||||
QString drumpadLastPresetId() const;
|
||||
void setDrumpadLastPresetId(const QString &lastPresetId);
|
||||
|
||||
quint8 drumpadChannelPrevPreset() const;
|
||||
void setDrumpadChannelPrevPreset(quint8 channel);
|
||||
quint8 drumpadNotePrevPreset() const;
|
||||
void setDrumpadNotePrevPreset(quint8 note);
|
||||
MidiLearnSetting drumpadPrevPreset() const;
|
||||
void setDrumpadPrevPreset(const MidiLearnSetting &value);
|
||||
|
||||
quint8 drumpadChannelNextPreset() const;
|
||||
void setDrumpadChannelNextPreset(quint8 channel);
|
||||
quint8 drumpadNoteNextPreset() const;
|
||||
void setDrumpadNoteNextPreset(quint8 note);
|
||||
MidiLearnSetting drumpadNextPreset() const;
|
||||
void setDrumpadNextPreset(const MidiLearnSetting &value);
|
||||
|
||||
quint8 drumpadChannelPrevSequence() const;
|
||||
void setDrumpadChannelPrevSequence(quint8 channel);
|
||||
quint8 drumpadNotePrevSequence() const;
|
||||
void setDrumpadNotePrevSequence(quint8 note);
|
||||
MidiLearnSetting drumpadPrevSequence() const;
|
||||
void setDrumpadPrevSequence(const MidiLearnSetting &value);
|
||||
|
||||
quint8 drumpadChannelNextSequence() const;
|
||||
void setDrumpadChannelNextSequence(quint8 channel);
|
||||
quint8 drumpadNoteNextSequence() const;
|
||||
void setDrumpadNoteNextSequence(quint8 note);
|
||||
MidiLearnSetting drumpadNextSequence() const;
|
||||
void setDrumpadNextSequence(const MidiLearnSetting &value);
|
||||
|
||||
quint8 drumpadChannelPlayPause() const;
|
||||
void setDrumpadChannelPlayPause(quint8 channel);
|
||||
quint8 drumpadNotePlayPause() const;
|
||||
void setDrumpadNotePlayPause(quint8 note);
|
||||
MidiLearnSetting drumpadPlayPause() const;
|
||||
void setDrumpadPlayPause(const MidiLearnSetting &value);
|
||||
|
||||
quint8 drumpadChannelStop() const;
|
||||
void setDrumpadChannelStop(quint8 channel);
|
||||
quint8 drumpadNoteStop() const;
|
||||
void setDrumpadNoteStop(quint8 note);
|
||||
MidiLearnSetting drumpadStop() const;
|
||||
void setDrumpadStop(const MidiLearnSetting &value);
|
||||
|
||||
quint8 drumpadChannel(quint8 pad) const;
|
||||
void setDrumpadChannel(quint8 pad, quint8 channel);
|
||||
quint8 drumpadNote(quint8 pad) const;
|
||||
void setDrumpadNote(quint8 pad, quint8 note);
|
||||
MidiLearnSetting drumpadSample(quint8 pad) const;
|
||||
void setDrumpadSample(quint8 pad, const MidiLearnSetting &value);
|
||||
|
||||
|
||||
|
||||
QString loopstationLastPresetId() const;
|
||||
void setLoopstationLastPresetId(const QString &lastPresetId);
|
||||
|
||||
quint8 loopstationChannelPrevPreset() const;
|
||||
void setLoopstationChannelPrevPreset(quint8 channel);
|
||||
quint8 loopstationNotePrevPreset() const;
|
||||
void setLoopstationNotePrevPreset(quint8 note);
|
||||
MidiLearnSetting loopstationPrevPreset() const;
|
||||
void setLoopstationPrevPreset(const MidiLearnSetting &value);
|
||||
|
||||
quint8 loopstationChannelNextPreset() const;
|
||||
void setLoopstationChannelNextPreset(quint8 channel);
|
||||
quint8 loopstationNoteNextPreset() const;
|
||||
void setLoopstationNoteNextPreset(quint8 note);
|
||||
MidiLearnSetting loopstationNextPreset() const;
|
||||
void setLoopstationNextPreset(const MidiLearnSetting &value);
|
||||
|
||||
private:
|
||||
MidiLearnSetting learnSetting(const QString &key) const;
|
||||
void setLearnSetting(const QString &key, const MidiLearnSetting &value);
|
||||
};
|
||||
|
30
futurecpp.h
Normal file
30
futurecpp.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
// C++20 backports (until espressif finally updates their aged compiler suite)
|
||||
|
||||
namespace std {
|
||||
template <class To, class From>
|
||||
typename std::enable_if_t<
|
||||
sizeof(To) == sizeof(From) && std::is_trivially_copyable_v<From> && std::is_trivially_copyable_v<To>,
|
||||
To>
|
||||
// constexpr support needs compiler magic
|
||||
bit_cast(const From& src) noexcept
|
||||
{
|
||||
static_assert(std::is_trivially_constructible_v<To>,
|
||||
"This implementation additionally requires destination type to be trivially constructible");
|
||||
|
||||
To dst;
|
||||
std::memcpy(&dst, &src, sizeof(To));
|
||||
return dst;
|
||||
}
|
||||
|
||||
template <typename EnumT, typename = std::enable_if_t<std::is_enum<EnumT>{}>>
|
||||
constexpr std::underlying_type_t<EnumT> to_underlying(EnumT e) noexcept {
|
||||
return static_cast<std::underlying_type_t<EnumT>>(e);
|
||||
}
|
||||
} // namespace std
|
@ -1,6 +1,10 @@
|
||||
#include "midicontainers.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebugStateSaver>
|
||||
#include <QDataStream>
|
||||
|
||||
#include "futurecpp.h"
|
||||
|
||||
namespace midi {
|
||||
bool MidiMessage::operator==(const MidiMessage &other) const
|
||||
@ -11,13 +15,64 @@ bool MidiMessage::operator==(const MidiMessage &other) const
|
||||
note == other.note &&
|
||||
velocity == other.velocity;
|
||||
}
|
||||
}
|
||||
} // namespace midi
|
||||
|
||||
namespace {
|
||||
void registerMidiMessageMetatype()
|
||||
{
|
||||
qRegisterMetaType<midi::Command>();
|
||||
qRegisterMetaType<midi::MidiMessage>();
|
||||
|
||||
qRegisterMetaTypeStreamOperators<midi::Command>("midi::Command");
|
||||
qRegisterMetaTypeStreamOperators<midi::MidiMessage>("midi::MidiMessage");
|
||||
}
|
||||
|
||||
Q_COREAPP_STARTUP_FUNCTION(registerMidiMessageMetatype)
|
||||
} // namespace
|
||||
|
||||
QDebug operator<<(QDebug debug, const midi::MidiMessage &value)
|
||||
{
|
||||
QDebugStateSaver saver{debug};
|
||||
debug.nospace() << "midi::MidiMessage{.channel=" << value.channel << ",.cmd=" << value.cmd << ",.flag=" << value.flag << ",.note=" << value.note << ",.velocity=" << value.velocity << "}";
|
||||
return debug;
|
||||
}
|
||||
|
||||
QDataStream &operator<<(QDataStream &out, const midi::Command &value)
|
||||
{
|
||||
return out << std::to_underlying(value);
|
||||
}
|
||||
|
||||
QDataStream &operator>>(QDataStream &in, midi::Command &value)
|
||||
{
|
||||
std::underlying_type_t<midi::Command> v;
|
||||
in >> v;
|
||||
value = midi::Command(v);
|
||||
return in;
|
||||
}
|
||||
|
||||
QDataStream &operator<<(QDataStream &out, const midi::MidiMessage &value)
|
||||
{
|
||||
return out << value.channel << value.cmd << value.flag << value.note << value.velocity;
|
||||
}
|
||||
|
||||
QDataStream &operator>>(QDataStream &in, midi::MidiMessage &value)
|
||||
{
|
||||
{
|
||||
typeof(value.channel) channel;
|
||||
in >> channel;
|
||||
value.channel = channel;
|
||||
}
|
||||
{
|
||||
typeof(value.cmd) cmd;
|
||||
in >> cmd;
|
||||
value.cmd = cmd;
|
||||
}
|
||||
{
|
||||
typeof(value.flag) flag;
|
||||
in >> flag;
|
||||
value.flag = flag;
|
||||
}
|
||||
in >> value.note;
|
||||
in >> value.velocity;
|
||||
return in;
|
||||
}
|
||||
|
@ -26,6 +26,16 @@ struct MidiMessage
|
||||
|
||||
bool operator==(const MidiMessage &other) const;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace midi
|
||||
|
||||
Q_DECLARE_METATYPE(midi::Command)
|
||||
Q_DECLARE_METATYPE(midi::MidiMessage)
|
||||
|
||||
QDebug operator<<(QDebug debug, const midi::MidiMessage &value);
|
||||
|
||||
QDataStream &operator<<(QDataStream &out, const midi::Command &value);
|
||||
QDataStream &operator>>(QDataStream &in, midi::Command &value);
|
||||
|
||||
QDataStream &operator<<(QDataStream &out, const midi::MidiMessage &value);
|
||||
QDataStream &operator>>(QDataStream &in, midi::MidiMessage &value);
|
||||
|
42
midilearnsetting.cpp
Normal file
42
midilearnsetting.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include "midilearnsetting.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebugStateSaver>
|
||||
#include <QDataStream>
|
||||
|
||||
namespace {
|
||||
void registerMidiLearnMessageMetatype()
|
||||
{
|
||||
qRegisterMetaType<MidiLearnSetting>();
|
||||
|
||||
qRegisterMetaTypeStreamOperators<MidiLearnSetting>("MidiLearnSetting");
|
||||
}
|
||||
|
||||
Q_COREAPP_STARTUP_FUNCTION(registerMidiLearnMessageMetatype)
|
||||
} // namespace
|
||||
|
||||
bool MidiLearnSetting::operator==(const MidiLearnSetting &other) const
|
||||
{
|
||||
return cmd == other.cmd &&
|
||||
channel == other.channel &&
|
||||
note == other.note;
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, const MidiLearnSetting &value)
|
||||
{
|
||||
QDebugStateSaver saver{debug};
|
||||
debug.nospace() << "MidiLearnSetting{.cmd=" << value.cmd << ",.channel=" << value.channel << ",.note=" << value.note << "}";
|
||||
return debug;
|
||||
}
|
||||
|
||||
QDataStream &operator<<(QDataStream &out, const MidiLearnSetting &value)
|
||||
{
|
||||
out << value.cmd << value.channel << value.note;
|
||||
return out;
|
||||
}
|
||||
|
||||
QDataStream &operator>>(QDataStream &in, MidiLearnSetting &value)
|
||||
{
|
||||
in >> value.cmd >> value.channel >> value.note;
|
||||
return in;
|
||||
}
|
23
midilearnsetting.h
Normal file
23
midilearnsetting.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMetaType>
|
||||
|
||||
#include "midicontainers.h"
|
||||
|
||||
struct MidiLearnSetting
|
||||
{
|
||||
midi::Command cmd{midi::Command::NoteOn};
|
||||
quint8 channel{99};
|
||||
quint8 note{99};
|
||||
|
||||
bool operator==(const MidiLearnSetting &other) const;
|
||||
QDebug operator<<(QDebug debug) const;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(MidiLearnSetting);
|
||||
|
||||
QDebug operator<<(QDebug debug, const MidiLearnSetting &value);
|
||||
|
||||
QDataStream &operator<<(QDataStream &out, const MidiLearnSetting &value);
|
||||
QDataStream &operator>>(QDataStream &in, MidiLearnSetting &value);
|
@ -51,34 +51,9 @@ void DrumPadSamplesWidget::midiReceived(const midi::MidiMessage &message)
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.cmd != midi::Command::NoteOn &&
|
||||
message.cmd != midi::Command::NoteOff &&
|
||||
message.cmd != midi::Command::ControlChange)
|
||||
return;
|
||||
|
||||
for (DrumPadSampleWidget &widget : getWidgets())
|
||||
{
|
||||
if (widget.isLearning())
|
||||
{
|
||||
widget.learn(message.channel, message.note);
|
||||
}
|
||||
else if (widget.channel() == message.channel && widget.note() == message.note)
|
||||
{
|
||||
switch (message.cmd)
|
||||
{
|
||||
case midi::Command::NoteOn:
|
||||
case midi::Command::ControlChange:
|
||||
if (message.velocity != 0)
|
||||
widget.pressed(message.velocity);
|
||||
else
|
||||
Q_FALLTHROUGH();
|
||||
case midi::Command::NoteOff:
|
||||
widget.released();
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
widget.midiReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,7 +95,7 @@ void DrumPadSamplesWidget::sequencerTriggerSample(int index)
|
||||
qDebug() << "index out of range" << index;
|
||||
return;
|
||||
}
|
||||
widgets[index].get().pressed(127);
|
||||
widgets[index].get().pressed();
|
||||
}
|
||||
|
||||
void DrumPadSamplesWidget::chokeTriggered(int choke)
|
||||
|
@ -30,9 +30,8 @@ DrumPadSampleWidget::DrumPadSampleWidget(QWidget *parent) :
|
||||
|
||||
connect(&m_player, &AudioPlayer::playingChanged, this, &DrumPadSampleWidget::updateStatus);
|
||||
|
||||
connect(m_ui->pushButton, &QAbstractButton::pressed, this, [this](){ pressed(127); });
|
||||
connect(m_ui->pushButton, &QAbstractButton::released, this, &DrumPadSampleWidget::released);
|
||||
connect(m_ui->toolButtonLearn, &QAbstractButton::pressed, this, &DrumPadSampleWidget::learnPressed);
|
||||
connect(m_ui->pushButtonPlay, &QAbstractButton::pressed, this, &DrumPadSampleWidget::pressed);
|
||||
connect(m_ui->pushButtonPlay, &QAbstractButton::released, this, &DrumPadSampleWidget::released);
|
||||
|
||||
updateStatus();
|
||||
}
|
||||
@ -41,10 +40,17 @@ DrumPadSampleWidget::~DrumPadSampleWidget() = default;
|
||||
|
||||
void DrumPadSampleWidget::loadSettings(DrumMachineSettings &settings)
|
||||
{
|
||||
m_ui->channelSpinBox->setValue(settings.drumpadChannel(m_padNr));
|
||||
m_ui->noteSpinBox->setValue(settings.drumpadNote(m_padNr));
|
||||
|
||||
m_settings = &settings;
|
||||
|
||||
m_ui->pushButtonPlay->setLearnSetting(m_settings->drumpadSample(m_padNr));
|
||||
|
||||
connect(m_ui->pushButtonPlay, &MidiButton::learnSettingChanged, this, [this](const MidiLearnSetting &learnSetting){
|
||||
Q_ASSERT(m_settings);
|
||||
if (m_settings)
|
||||
m_settings->setDrumpadSample(m_padNr, learnSetting);
|
||||
else
|
||||
qWarning() << "no settings available";
|
||||
});
|
||||
}
|
||||
|
||||
void DrumPadSampleWidget::setFile(const QString &presetId, const drumpad_presets::File &file)
|
||||
@ -80,38 +86,6 @@ void DrumPadSampleWidget::setFile(const QString &presetId, const drumpad_presets
|
||||
setupLabel(file.choke, m_ui->chokeLabel);
|
||||
}
|
||||
|
||||
quint8 DrumPadSampleWidget::channel() const
|
||||
{
|
||||
return m_ui->channelSpinBox->value();
|
||||
}
|
||||
|
||||
void DrumPadSampleWidget::setChannel(quint8 channel)
|
||||
{
|
||||
m_ui->channelSpinBox->setValue(channel);
|
||||
|
||||
Q_ASSERT(m_settings);
|
||||
if (m_settings)
|
||||
m_settings->setDrumpadChannel(m_padNr, channel);
|
||||
else
|
||||
qWarning() << "no settings available";
|
||||
}
|
||||
|
||||
quint8 DrumPadSampleWidget::note() const
|
||||
{
|
||||
return m_ui->noteSpinBox->value();
|
||||
}
|
||||
|
||||
void DrumPadSampleWidget::setNote(quint8 note)
|
||||
{
|
||||
m_ui->noteSpinBox->setValue(note);
|
||||
|
||||
Q_ASSERT(m_settings);
|
||||
if (m_settings)
|
||||
m_settings->setDrumpadNote(m_padNr, note);
|
||||
else
|
||||
qWarning() << "no settings available";
|
||||
}
|
||||
|
||||
int DrumPadSampleWidget::speed() const
|
||||
{
|
||||
return m_ui->dialSpeed->value();
|
||||
@ -139,10 +113,8 @@ std::optional<int> DrumPadSampleWidget::choke() const
|
||||
return m_file->choke;
|
||||
}
|
||||
|
||||
void DrumPadSampleWidget::pressed(quint8 velocity)
|
||||
void DrumPadSampleWidget::pressed()
|
||||
{
|
||||
Q_UNUSED(velocity)
|
||||
|
||||
m_player.restart();
|
||||
|
||||
if (m_file && m_file->choke && *m_file->choke)
|
||||
@ -181,61 +153,59 @@ void DrumPadSampleWidget::writeSamples(frame_t *begin, frame_t *end)
|
||||
m_player.writeSamples(begin, end);
|
||||
}
|
||||
|
||||
void DrumPadSampleWidget::learn(quint8 channel, quint8 note)
|
||||
void DrumPadSampleWidget::midiReceived(const midi::MidiMessage &message)
|
||||
{
|
||||
setChannel(channel);
|
||||
setNote(note);
|
||||
if (m_learning)
|
||||
learnPressed();
|
||||
m_ui->pushButtonPlay->midiReceived(message);
|
||||
}
|
||||
|
||||
void DrumPadSampleWidget::unsendColor()
|
||||
{
|
||||
m_sendColors = false;
|
||||
midi::MidiMessage midiMsg;
|
||||
|
||||
midiMsg.channel = m_ui->channelSpinBox->value();
|
||||
midiMsg.cmd = midi::Command::NoteOn;
|
||||
midiMsg.flag = true;
|
||||
midiMsg.note = m_ui->noteSpinBox->value();
|
||||
midiMsg.velocity = 0;
|
||||
|
||||
emit sendMidi(midiMsg);
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonPlay->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonPlay->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonPlay->learnSetting().note,
|
||||
.velocity = 0
|
||||
});
|
||||
}
|
||||
|
||||
void DrumPadSampleWidget::sendColor()
|
||||
{
|
||||
m_sendColors = true;
|
||||
midi::MidiMessage midiMsg;
|
||||
|
||||
midiMsg.channel = m_ui->channelSpinBox->value();
|
||||
midiMsg.cmd = midi::Command::NoteOn;
|
||||
midiMsg.flag = true;
|
||||
midiMsg.note = m_ui->noteSpinBox->value();
|
||||
uint8_t velocity;
|
||||
|
||||
if (m_file && m_file->color && m_player.buffer().isValid())
|
||||
{
|
||||
const auto &color = *m_file->color;
|
||||
if (color == "purple")
|
||||
midiMsg.velocity = m_player.playing() ? 43 : 18;
|
||||
velocity = m_player.playing() ? 43 : 18;
|
||||
else if (color == "red")
|
||||
midiMsg.velocity = m_player.playing() ? 3 : 1;
|
||||
velocity = m_player.playing() ? 3 : 1;
|
||||
else if (color == "yellow")
|
||||
midiMsg.velocity = m_player.playing() ? 58 : 33;
|
||||
velocity = m_player.playing() ? 58 : 33;
|
||||
else if (color == "green")
|
||||
midiMsg.velocity = m_player.playing() ? 56 : 16;
|
||||
velocity = m_player.playing() ? 56 : 16;
|
||||
else if (color == "blue")
|
||||
midiMsg.velocity = m_player.playing() ? 49 : 51;
|
||||
velocity = m_player.playing() ? 49 : 51;
|
||||
else
|
||||
goto noColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
noColor:
|
||||
midiMsg.velocity = 0;
|
||||
velocity = 0;
|
||||
}
|
||||
|
||||
emit sendMidi(midiMsg);
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonPlay->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonPlay->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonPlay->learnSetting().note,
|
||||
.velocity = velocity
|
||||
});
|
||||
}
|
||||
|
||||
void DrumPadSampleWidget::updateStatus()
|
||||
@ -309,27 +279,6 @@ void DrumPadSampleWidget::decodingFinished(const QAudioBuffer &buffer)
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
void DrumPadSampleWidget::learnPressed()
|
||||
{
|
||||
auto palette = m_ui->toolButtonLearn->palette();
|
||||
|
||||
if (m_learning)
|
||||
{
|
||||
palette.setColor(m_ui->toolButtonLearn->backgroundRole(), m_oldColor);
|
||||
palette.setBrush(m_ui->toolButtonLearn->backgroundRole(), m_oldBrush);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_oldColor = palette.color(m_ui->toolButtonLearn->backgroundRole());
|
||||
m_oldBrush = palette.brush(m_ui->toolButtonLearn->backgroundRole());
|
||||
palette.setColor(m_ui->toolButtonLearn->backgroundRole(), Qt::red);
|
||||
palette.setBrush(m_ui->toolButtonLearn->backgroundRole(), Qt::red);
|
||||
}
|
||||
m_ui->toolButtonLearn->setPalette(palette);
|
||||
|
||||
m_learning = !m_learning;
|
||||
}
|
||||
|
||||
void DrumPadSampleWidget::startRequest()
|
||||
{
|
||||
if (m_networkAccessManager && m_file->filename)
|
||||
|
@ -31,12 +31,6 @@ public:
|
||||
|
||||
void setFile(const QString &presetId, const drumpad_presets::File &file);
|
||||
|
||||
quint8 channel() const;
|
||||
void setChannel(quint8 channel);
|
||||
|
||||
quint8 note() const;
|
||||
void setNote(quint8 note);
|
||||
|
||||
int speed() const;
|
||||
void setSpeed(int speed);
|
||||
|
||||
@ -45,7 +39,7 @@ public:
|
||||
|
||||
std::optional<int> choke() const;
|
||||
|
||||
void pressed(quint8 velocity);
|
||||
void pressed();
|
||||
void released();
|
||||
|
||||
void forceStop();
|
||||
@ -55,8 +49,7 @@ public:
|
||||
|
||||
void writeSamples(frame_t *begin, frame_t *end);
|
||||
|
||||
bool isLearning() const { return m_learning; }
|
||||
void learn(quint8 channel, quint8 note);
|
||||
void midiReceived(const midi::MidiMessage &message);
|
||||
|
||||
void unsendColor();
|
||||
void sendColor();
|
||||
@ -70,7 +63,6 @@ private slots:
|
||||
void updateStatus();
|
||||
void requestFinished();
|
||||
void decodingFinished(const QAudioBuffer &buffer);
|
||||
void learnPressed();
|
||||
|
||||
private:
|
||||
void startRequest();
|
||||
@ -92,9 +84,5 @@ private:
|
||||
|
||||
quint8 m_padNr{};
|
||||
|
||||
bool m_learning{};
|
||||
QColor m_oldColor;
|
||||
QBrush m_oldBrush;
|
||||
|
||||
bool m_sendColors{};
|
||||
};
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>140</width>
|
||||
<height>157</height>
|
||||
<width>135</width>
|
||||
<height>122</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
@ -59,7 +59,7 @@
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="MidiButton" name="pushButton">
|
||||
<widget class="MidiButton" name="pushButtonPlay">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
@ -95,23 +95,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="channelSpinBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="noteSpinBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="toolButtonLearn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
|
@ -64,15 +64,11 @@ void DrumPadWidget::loadSettings(DrumMachineSettings &settings)
|
||||
{
|
||||
m_settings = &settings;
|
||||
|
||||
m_ui->pushButtonUp->setChannel(m_settings->drumpadChannelPrevPreset());
|
||||
m_ui->pushButtonUp->setNote(m_settings->drumpadNotePrevPreset());
|
||||
m_ui->pushButtonDown->setChannel(m_settings->drumpadChannelNextPreset());
|
||||
m_ui->pushButtonDown->setNote(m_settings->drumpadNoteNextPreset());
|
||||
m_ui->pushButtonUp->setLearnSetting(m_settings->drumpadPrevPreset());
|
||||
m_ui->pushButtonDown->setLearnSetting(m_settings->drumpadNextPreset());
|
||||
|
||||
connect(m_ui->pushButtonUp, &MidiButton::channelChanged, m_settings, &DrumMachineSettings::setDrumpadChannelPrevPreset);
|
||||
connect(m_ui->pushButtonUp, &MidiButton::noteChanged, m_settings, &DrumMachineSettings::setDrumpadNotePrevPreset);
|
||||
connect(m_ui->pushButtonDown, &MidiButton::channelChanged, m_settings, &DrumMachineSettings::setDrumpadChannelNextPreset);
|
||||
connect(m_ui->pushButtonDown, &MidiButton::noteChanged, m_settings, &DrumMachineSettings::setDrumpadNoteNextPreset);
|
||||
connect(m_ui->pushButtonUp, &MidiButton::learnSettingChanged, m_settings, &DrumMachineSettings::setDrumpadPrevPreset);
|
||||
connect(m_ui->pushButtonDown, &MidiButton::learnSettingChanged, m_settings, &DrumMachineSettings::setDrumpadNextPreset);
|
||||
|
||||
m_ui->sequencerWidget->loadSettings(settings);
|
||||
m_ui->samplesWidget->loadSettings(settings);
|
||||
@ -81,17 +77,17 @@ void DrumPadWidget::loadSettings(DrumMachineSettings &settings)
|
||||
void DrumPadWidget::unsendColors()
|
||||
{
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonUp->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonUp->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonUp->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonUp->note(),
|
||||
.note = m_ui->pushButtonUp->learnSetting().note,
|
||||
.velocity = 0
|
||||
});
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonDown->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonDown->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonDown->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonDown->note(),
|
||||
.note = m_ui->pushButtonDown->learnSetting().note,
|
||||
.velocity = 0
|
||||
});
|
||||
|
||||
@ -102,17 +98,17 @@ void DrumPadWidget::unsendColors()
|
||||
void DrumPadWidget::sendColors()
|
||||
{
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonUp->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonUp->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonUp->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonUp->note(),
|
||||
.note = m_ui->pushButtonUp->learnSetting().note,
|
||||
.velocity = 127
|
||||
});
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonDown->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonDown->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonDown->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonDown->note(),
|
||||
.note = m_ui->pushButtonDown->learnSetting().note,
|
||||
.velocity = 127
|
||||
});
|
||||
|
||||
|
@ -57,31 +57,27 @@ void LoopStationWidget::loadSettings(DrumMachineSettings &settings)
|
||||
{
|
||||
m_settings = &settings;
|
||||
|
||||
m_ui->pushButtonUp->setChannel(m_settings->loopstationChannelPrevPreset());
|
||||
m_ui->pushButtonUp->setNote(m_settings->loopstationNotePrevPreset());
|
||||
m_ui->pushButtonDown->setChannel(m_settings->loopstationChannelNextPreset());
|
||||
m_ui->pushButtonDown->setNote(m_settings->loopstationNoteNextPreset());
|
||||
m_ui->pushButtonUp->setLearnSetting(m_settings->loopstationPrevPreset());
|
||||
m_ui->pushButtonDown->setLearnSetting(m_settings->loopstationNextPreset());
|
||||
|
||||
connect(m_ui->pushButtonUp, &MidiButton::channelChanged, m_settings, &DrumMachineSettings::setLoopstationChannelPrevPreset);
|
||||
connect(m_ui->pushButtonUp, &MidiButton::noteChanged, m_settings, &DrumMachineSettings::setLoopstationNotePrevPreset);
|
||||
connect(m_ui->pushButtonDown, &MidiButton::channelChanged, m_settings, &DrumMachineSettings::setLoopstationChannelNextPreset);
|
||||
connect(m_ui->pushButtonDown, &MidiButton::noteChanged, m_settings, &DrumMachineSettings::setLoopstationNoteNextPreset);
|
||||
connect(m_ui->pushButtonUp, &MidiButton::learnSettingChanged, m_settings, &DrumMachineSettings::setLoopstationPrevPreset);
|
||||
connect(m_ui->pushButtonDown, &MidiButton::learnSettingChanged, m_settings, &DrumMachineSettings::setLoopstationNextPreset);
|
||||
}
|
||||
|
||||
void LoopStationWidget::unsendColors()
|
||||
{
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonUp->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonUp->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonUp->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonUp->note(),
|
||||
.note = m_ui->pushButtonUp->learnSetting().note,
|
||||
.velocity = 0
|
||||
});
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonDown->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonDown->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonDown->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonDown->note(),
|
||||
.note = m_ui->pushButtonDown->learnSetting().note,
|
||||
.velocity = 0
|
||||
});
|
||||
}
|
||||
@ -89,17 +85,17 @@ void LoopStationWidget::unsendColors()
|
||||
void LoopStationWidget::sendColors()
|
||||
{
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonUp->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonUp->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonUp->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonUp->note(),
|
||||
.note = m_ui->pushButtonUp->learnSetting().note,
|
||||
.velocity = 127
|
||||
});
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonDown->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonDown->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonDown->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonDown->note(),
|
||||
.note = m_ui->pushButtonDown->learnSetting().note,
|
||||
.velocity = 127
|
||||
});
|
||||
}
|
||||
|
@ -303,6 +303,10 @@ void MainWindow::updateMidiOutDevices()
|
||||
|
||||
void MainWindow::loadSettings()
|
||||
{
|
||||
for (int i = 0; i < m_ui->tabWidget->count(); i++)
|
||||
m_ui->tabWidget->setLearnSetting(i, m_settings.tabWidget(i));
|
||||
connect(m_ui->tabWidget, &MidiTabWidget::learnSettingChanged, &m_settings, &DrumMachineSettings::setTabWidget);
|
||||
|
||||
m_ui->drumPadWidget->loadSettings(m_settings);
|
||||
m_ui->loopStationWidget->loadSettings(m_settings);
|
||||
m_ui->djWidget->loadSettings(m_settings);
|
||||
@ -311,6 +315,17 @@ void MainWindow::loadSettings()
|
||||
|
||||
void MainWindow::unsendColors(int index)
|
||||
{
|
||||
{
|
||||
const auto &learnSetting = m_ui->tabWidget->learnSetting(index);
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = learnSetting.channel,
|
||||
.cmd = learnSetting.cmd,
|
||||
.flag = true,
|
||||
.note = learnSetting.note,
|
||||
.velocity = 0
|
||||
});
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
m_ui->drumPadWidget->unsendColors();
|
||||
else if (index == 1)
|
||||
@ -323,6 +338,17 @@ void MainWindow::unsendColors(int index)
|
||||
|
||||
void MainWindow::sendColors(int index)
|
||||
{
|
||||
{
|
||||
const auto &learnSetting = m_ui->tabWidget->learnSetting(index);
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = learnSetting.channel,
|
||||
.cmd = learnSetting.cmd,
|
||||
.flag = true,
|
||||
.note = learnSetting.note,
|
||||
.velocity = 3
|
||||
});
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
m_ui->drumPadWidget->sendColors();
|
||||
else if (index == 1)
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <QtGlobal>
|
||||
|
||||
#include "midicontainers.h"
|
||||
#include "futurecpp.h"
|
||||
|
||||
MidiButton::MidiButton(QWidget *parent) :
|
||||
QPushButton{parent}
|
||||
@ -13,6 +14,22 @@ MidiButton::MidiButton(QWidget *parent) :
|
||||
auto action = new QAction{tr("Learn...")};
|
||||
connect(action, &QAction::triggered, this, &MidiButton::learn);
|
||||
addAction(action);
|
||||
|
||||
{
|
||||
m_actionCmd = new QAction{tr("cmd:")};
|
||||
m_actionCmd->setDisabled(true);
|
||||
addAction(m_actionCmd);
|
||||
}
|
||||
{
|
||||
m_actionChannel = new QAction{tr("channel:")};
|
||||
m_actionChannel->setDisabled(true);
|
||||
addAction(m_actionChannel);
|
||||
}
|
||||
{
|
||||
m_actionNote = new QAction{tr("note:")};
|
||||
m_actionNote->setDisabled(true);
|
||||
addAction(m_actionNote);
|
||||
}
|
||||
}
|
||||
|
||||
MidiButton::MidiButton(const QString &text, QWidget *parent) :
|
||||
@ -25,6 +42,16 @@ MidiButton::MidiButton(const QIcon &icon, const QString &text, QWidget *parent)
|
||||
{
|
||||
}
|
||||
|
||||
void MidiButton::setLearnSetting(const MidiLearnSetting &learnSetting)
|
||||
{
|
||||
if (m_learnSetting == learnSetting)
|
||||
return;
|
||||
emit learnSettingChanged(m_learnSetting = learnSetting);
|
||||
m_actionCmd->setText(tr("cmd: %0").arg(std::to_underlying(m_learnSetting.cmd)));
|
||||
m_actionChannel->setText(tr("channel: %0").arg(m_learnSetting.channel));
|
||||
m_actionNote->setText(tr("note: %0").arg(m_learnSetting.note));
|
||||
}
|
||||
|
||||
void MidiButton::learn()
|
||||
{
|
||||
auto palette = this->palette();
|
||||
@ -48,38 +75,49 @@ void MidiButton::learn()
|
||||
|
||||
void MidiButton::midiReceived(const midi::MidiMessage &message)
|
||||
{
|
||||
if (message.cmd != midi::Command::NoteOn &&
|
||||
message.cmd != midi::Command::NoteOff &&
|
||||
message.cmd != midi::Command::ControlChange)
|
||||
return;
|
||||
|
||||
if (m_learning)
|
||||
{
|
||||
if ((message.cmd != midi::Command::NoteOn && message.cmd != midi::Command::ControlChange) || message.velocity == 0)
|
||||
return;
|
||||
|
||||
setChannel(message.channel);
|
||||
setNote(message.note);
|
||||
setLearnSetting(MidiLearnSetting{
|
||||
.cmd = message.cmd == midi::Command::NoteOff ? midi::Command::NoteOn : message.cmd,
|
||||
.channel = message.channel,
|
||||
.note = message.note
|
||||
});
|
||||
|
||||
learn();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (message.channel != m_channel || message.note != m_note)
|
||||
if (message.channel != m_learnSetting.channel ||
|
||||
message.note != m_learnSetting.note)
|
||||
return;
|
||||
|
||||
switch (message.cmd)
|
||||
if (m_learnSetting.cmd == midi::Command::NoteOn || m_learnSetting.cmd == midi::Command::NoteOff)
|
||||
{
|
||||
switch (message.cmd)
|
||||
{
|
||||
case midi::Command::NoteOn:
|
||||
if (message.velocity != 0)
|
||||
emit pressed();
|
||||
else
|
||||
Q_FALLTHROUGH();
|
||||
case midi::Command::NoteOff:
|
||||
emit released();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (m_learnSetting.cmd == message.cmd)
|
||||
{
|
||||
case midi::Command::NoteOn:
|
||||
case midi::Command::ControlChange:
|
||||
if (message.velocity != 0)
|
||||
emit pressed();
|
||||
else
|
||||
Q_FALLTHROUGH();
|
||||
case midi::Command::NoteOff:
|
||||
emit released();
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
emit released();
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2,38 +2,39 @@
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
#include "midilearnsetting.h"
|
||||
|
||||
namespace midi { struct MidiMessage; }
|
||||
class QAction;
|
||||
|
||||
class MidiButton : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(quint8 channel READ channel WRITE setChannel NOTIFY channelChanged)
|
||||
Q_PROPERTY(quint8 note READ note WRITE setNote NOTIFY noteChanged)
|
||||
Q_PROPERTY(MidiLearnSetting learnSetting READ learnSetting WRITE setLearnSetting NOTIFY learnSettingChanged)
|
||||
|
||||
public:
|
||||
explicit MidiButton(QWidget *parent = nullptr);
|
||||
explicit MidiButton(const QString &text, QWidget *parent = nullptr);
|
||||
MidiButton(const QIcon& icon, const QString &text, QWidget *parent = nullptr);
|
||||
|
||||
quint8 channel() const { return m_channel; }
|
||||
void setChannel(quint8 channel) { if (channel == m_channel) return; emit channelChanged(m_channel = channel); }
|
||||
|
||||
quint8 note() const { return m_note; }
|
||||
void setNote(quint8 note) { if (note == m_note) return; emit noteChanged(m_note = note); }
|
||||
MidiLearnSetting learnSetting() const { return m_learnSetting; }
|
||||
void setLearnSetting(const MidiLearnSetting &learnSetting);
|
||||
|
||||
signals:
|
||||
void channelChanged(quint8 channel);
|
||||
void noteChanged(quint8 note);
|
||||
void learnSettingChanged(const MidiLearnSetting &learnSetting);
|
||||
|
||||
public slots:
|
||||
void learn();
|
||||
void midiReceived(const midi::MidiMessage &message);
|
||||
|
||||
private:
|
||||
quint8 m_channel{99};
|
||||
quint8 m_note{99};
|
||||
MidiLearnSetting m_learnSetting;
|
||||
|
||||
bool m_learning{};
|
||||
QColor m_oldColor;
|
||||
QBrush m_oldBrush;
|
||||
|
||||
QAction *m_actionCmd{};
|
||||
QAction *m_actionChannel{};
|
||||
QAction *m_actionNote{};
|
||||
};
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <QDebug>
|
||||
|
||||
#include "midicontainers.h"
|
||||
#include "futurecpp.h"
|
||||
|
||||
MidiTabWidget::MidiTabWidget(QWidget *parent) :
|
||||
QTabWidget{parent}
|
||||
@ -14,30 +15,16 @@ MidiTabWidget::MidiTabWidget(QWidget *parent) :
|
||||
connect(tabBar(), &QWidget::customContextMenuRequested, this, &MidiTabWidget::showContextMenu);
|
||||
}
|
||||
|
||||
quint8 MidiTabWidget::channel(int index) const
|
||||
MidiLearnSetting MidiTabWidget::learnSetting(int index) const
|
||||
{
|
||||
return m_channelNotes[index].channel;
|
||||
return m_learnSettings[index];
|
||||
}
|
||||
|
||||
void MidiTabWidget::setChannel(int index, quint8 channel)
|
||||
void MidiTabWidget::setLearnSetting(int index, const MidiLearnSetting &learnSetting)
|
||||
{
|
||||
auto &channelNote = m_channelNotes[index];
|
||||
if (channelNote.channel == channel)
|
||||
if (learnSetting == m_learnSettings[index])
|
||||
return;
|
||||
emit channelChanged(index, channelNote.channel = channel);
|
||||
}
|
||||
|
||||
quint8 MidiTabWidget::note(int index) const
|
||||
{
|
||||
return m_channelNotes[index].note;
|
||||
}
|
||||
|
||||
void MidiTabWidget::setNote(int index, quint8 note)
|
||||
{
|
||||
auto &channelNote = m_channelNotes[index];
|
||||
if (channelNote.note == note)
|
||||
return;
|
||||
emit noteChanged(index, channelNote.note = note);
|
||||
emit learnSettingChanged(index, m_learnSettings[index] = learnSetting);
|
||||
}
|
||||
|
||||
void MidiTabWidget::learn(int index)
|
||||
@ -67,18 +54,21 @@ void MidiTabWidget::midiReceived(const midi::MidiMessage &message)
|
||||
|
||||
if (m_learning)
|
||||
{
|
||||
qDebug() << "learning" << message.cmd << message.velocity << message.channel << message.note;
|
||||
setChannel(*m_learning, message.channel);
|
||||
setNote(*m_learning, message.note);
|
||||
setLearnSetting(*m_learning, MidiLearnSetting{
|
||||
.cmd = message.cmd == midi::Command::NoteOff ? midi::Command::NoteOn : message.cmd,
|
||||
.channel = message.channel,
|
||||
.note = message.note
|
||||
});
|
||||
|
||||
learn(*m_learning);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "normal" << message.cmd << message.velocity << message.channel << message.note;
|
||||
for (int i = 0; i < count(); i++)
|
||||
{
|
||||
if (message.channel != m_channelNotes[i].channel ||
|
||||
message.note != m_channelNotes[i].note)
|
||||
if (message.cmd != m_learnSettings[i].cmd ||
|
||||
message.channel != m_learnSettings[i].channel ||
|
||||
message.note != m_learnSettings[i].note)
|
||||
continue;
|
||||
|
||||
setCurrentIndex(i);
|
||||
@ -90,13 +80,13 @@ void MidiTabWidget::midiReceived(const midi::MidiMessage &message)
|
||||
void MidiTabWidget::tabInserted(int index)
|
||||
{
|
||||
QTabWidget::tabInserted(index);
|
||||
m_channelNotes.insert(std::begin(m_channelNotes) + index, ChannelNote{.channel=quint8(index)});
|
||||
m_learnSettings.insert(std::begin(m_learnSettings) + index, MidiLearnSetting{});
|
||||
}
|
||||
|
||||
void MidiTabWidget::tabRemoved(int index)
|
||||
{
|
||||
QTabWidget::tabInserted(index);
|
||||
m_channelNotes.erase(std::begin(m_channelNotes) + index);
|
||||
m_learnSettings.erase(std::begin(m_learnSettings) + index);
|
||||
}
|
||||
|
||||
void MidiTabWidget::showContextMenu(const QPoint &pos)
|
||||
@ -107,6 +97,12 @@ void MidiTabWidget::showContextMenu(const QPoint &pos)
|
||||
|
||||
QMenu menu{tabBar()};
|
||||
const auto learnAction = menu.addAction(tr("Learn..."));
|
||||
{
|
||||
const auto &learnSetting = m_learnSettings[index];
|
||||
menu.addAction(tr("cmd: %0").arg(std::to_underlying(learnSetting.cmd)))->setDisabled(true);
|
||||
menu.addAction(tr("channel: %0").arg(learnSetting.channel))->setDisabled(true);
|
||||
menu.addAction(tr("note: %0").arg(learnSetting.note))->setDisabled(true);
|
||||
}
|
||||
if (const auto selectedAction = menu.exec(tabBar()->mapToGlobal(pos));
|
||||
selectedAction == learnAction)
|
||||
{
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "midilearnsetting.h"
|
||||
|
||||
namespace midi { struct MidiMessage; }
|
||||
|
||||
class MidiTabWidget : public QTabWidget
|
||||
@ -14,15 +16,11 @@ class MidiTabWidget : public QTabWidget
|
||||
public:
|
||||
explicit MidiTabWidget(QWidget *parent = nullptr);
|
||||
|
||||
quint8 channel(int index) const;
|
||||
void setChannel(int index, quint8 channel);
|
||||
|
||||
quint8 note(int index) const;
|
||||
void setNote(int index, quint8 note);
|
||||
MidiLearnSetting learnSetting(int index) const;
|
||||
void setLearnSetting(int index, const MidiLearnSetting &learnSetting);
|
||||
|
||||
signals:
|
||||
void channelChanged(int index, quint8 channel);
|
||||
void noteChanged(int index, quint8 note);
|
||||
void learnSettingChanged(int index, const MidiLearnSetting &learnSetting);
|
||||
|
||||
public slots:
|
||||
void learn(int index);
|
||||
@ -39,10 +37,5 @@ private:
|
||||
std::optional<int> m_learning;
|
||||
QColor m_oldColor;
|
||||
|
||||
struct ChannelNote
|
||||
{
|
||||
quint8 channel{99};
|
||||
quint8 note{99};
|
||||
};
|
||||
std::vector<ChannelNote> m_channelNotes;
|
||||
std::vector<MidiLearnSetting> m_learnSettings;
|
||||
};
|
||||
|
@ -36,23 +36,15 @@ SequencerWidget::~SequencerWidget() = default;
|
||||
|
||||
void SequencerWidget::loadSettings(DrumMachineSettings &settings)
|
||||
{
|
||||
m_ui->pushButtonUp->setChannel(settings.drumpadChannelPrevSequence());
|
||||
m_ui->pushButtonUp->setNote(settings.drumpadNotePrevSequence());
|
||||
m_ui->pushButtonDown->setChannel(settings.drumpadChannelNextSequence());
|
||||
m_ui->pushButtonDown->setNote(settings.drumpadNoteNextSequence());
|
||||
m_ui->pushButtonPlayPause->setChannel(settings.drumpadChannelPlayPause());
|
||||
m_ui->pushButtonPlayPause->setNote(settings.drumpadNotePlayPause());
|
||||
m_ui->pushButtonStop->setChannel(settings.drumpadChannelStop());
|
||||
m_ui->pushButtonStop->setNote(settings.drumpadNoteStop());
|
||||
m_ui->pushButtonUp->setLearnSetting(settings.drumpadPrevSequence());
|
||||
m_ui->pushButtonDown->setLearnSetting(settings.drumpadNextSequence());
|
||||
m_ui->pushButtonPlayPause->setLearnSetting(settings.drumpadPlayPause());
|
||||
m_ui->pushButtonStop->setLearnSetting(settings.drumpadStop());
|
||||
|
||||
connect(m_ui->pushButtonUp, &MidiButton::channelChanged, &settings, &DrumMachineSettings::setDrumpadChannelPrevSequence);
|
||||
connect(m_ui->pushButtonUp, &MidiButton::noteChanged, &settings, &DrumMachineSettings::setDrumpadNotePrevSequence);
|
||||
connect(m_ui->pushButtonDown, &MidiButton::channelChanged, &settings, &DrumMachineSettings::setDrumpadChannelNextSequence);
|
||||
connect(m_ui->pushButtonDown, &MidiButton::noteChanged, &settings, &DrumMachineSettings::setDrumpadNoteNextSequence);
|
||||
connect(m_ui->pushButtonPlayPause, &MidiButton::channelChanged, &settings, &DrumMachineSettings::setDrumpadChannelPlayPause);
|
||||
connect(m_ui->pushButtonPlayPause, &MidiButton::noteChanged, &settings, &DrumMachineSettings::setDrumpadNotePlayPause);
|
||||
connect(m_ui->pushButtonStop, &MidiButton::channelChanged, &settings, &DrumMachineSettings::setDrumpadChannelStop);
|
||||
connect(m_ui->pushButtonStop, &MidiButton::noteChanged, &settings, &DrumMachineSettings::setDrumpadNoteStop);
|
||||
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::setDrumpadStop);
|
||||
}
|
||||
|
||||
void SequencerWidget::unsendColors()
|
||||
@ -60,31 +52,31 @@ void SequencerWidget::unsendColors()
|
||||
m_sendColors = false;
|
||||
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonUp->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonUp->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonUp->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonUp->note(),
|
||||
.note = m_ui->pushButtonUp->learnSetting().note,
|
||||
.velocity = 0
|
||||
});
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonDown->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonDown->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonDown->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonDown->note(),
|
||||
.note = m_ui->pushButtonDown->learnSetting().note,
|
||||
.velocity = 0
|
||||
});
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonPlayPause->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonPlayPause->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonPlayPause->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonPlayPause->note(),
|
||||
.note = m_ui->pushButtonPlayPause->learnSetting().note,
|
||||
.velocity = 0
|
||||
});
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonStop->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonStop->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonStop->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonStop->note(),
|
||||
.note = m_ui->pushButtonStop->learnSetting().note,
|
||||
.velocity = 0
|
||||
});
|
||||
}
|
||||
@ -94,31 +86,31 @@ void SequencerWidget::sendColors()
|
||||
m_sendColors = true;
|
||||
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonUp->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonUp->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonUp->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonUp->note(),
|
||||
.note = m_ui->pushButtonUp->learnSetting().note,
|
||||
.velocity = 127
|
||||
});
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonDown->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonDown->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonDown->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonDown->note(),
|
||||
.note = m_ui->pushButtonDown->learnSetting().note,
|
||||
.velocity = 127
|
||||
});
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonPlayPause->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonPlayPause->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonPlayPause->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonPlayPause->note(),
|
||||
.note = m_ui->pushButtonPlayPause->learnSetting().note,
|
||||
.velocity = 60
|
||||
});
|
||||
emit sendMidi(midi::MidiMessage {
|
||||
.channel = m_ui->pushButtonStop->channel(),
|
||||
.cmd = midi::Command::NoteOn,
|
||||
.channel = m_ui->pushButtonStop->learnSetting().channel,
|
||||
.cmd = m_ui->pushButtonStop->learnSetting().cmd,
|
||||
.flag = true,
|
||||
.note = m_ui->pushButtonStop->note(),
|
||||
.note = m_ui->pushButtonStop->learnSetting().note,
|
||||
.velocity = 3
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user