Skip to content

Commit b22931c

Browse files
committed
Implement generic property system for internal devices
1 parent b310392 commit b22931c

34 files changed

Lines changed: 833 additions & 344 deletions

src/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ set(HEADER_FILES
8686
domain/mixer_unit.hpp
8787
domain/note_data.hpp
8888
domain/note_data_manipulator.hpp
89+
domain/parameter.hpp
90+
domain/parameter_container.hpp
8991
domain/pattern.hpp
9092
domain/pitch_bend_automation.hpp
9193
domain/pitch_bend_data.hpp
@@ -194,6 +196,8 @@ set(SOURCE_FILES
194196
domain/mixer_unit.cpp
195197
domain/note_data.cpp
196198
domain/note_data_manipulator.cpp
199+
domain/parameter.cpp
200+
domain/parameter_container.cpp
197201
domain/pattern.cpp
198202
domain/pitch_bend_automation.cpp
199203
domain/pitch_bend_data.cpp

src/application/service/application_service.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ QString ApplicationService::webSiteUrl() const
7676
return Constants::webSiteUrl();
7777
}
7878

79+
QString ApplicationService::samplerDeviceName() const
80+
{
81+
return Constants::samplerDeviceName();
82+
}
83+
7984
void ApplicationService::acceptUnsavedChangesDialog()
8085
{
8186
juzzlin::L(TAG).info() << "Unsaved changes accepted";

src/application/service/application_service.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class ApplicationService : public QObject
5454
Q_INVOKABLE bool isMidiFile(const QString & filePath) const;
5555
Q_INVOKABLE QString license() const;
5656
Q_INVOKABLE QString webSiteUrl() const;
57+
Q_INVOKABLE QString samplerDeviceName() const;
5758

5859
Q_INVOKABLE QStringList recentFiles() const;
5960
Q_INVOKABLE void addRecentFile(QString filePath);

src/application/service/device_service.cpp

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include <QXmlStreamReader>
2424
#include <QXmlStreamWriter>
2525

26+
#include <set>
27+
2628
namespace noteahead {
2729

2830
DeviceService::DeviceService(AudioEngineS audioEngine, QObject * parent)
@@ -56,36 +58,36 @@ bool DeviceService::isInternalDevice(const QString & portName) const
5658

5759
void DeviceService::processMidiNoteOn(const QString & portName, uint8_t note, uint8_t velocity)
5860
{
59-
if (auto dev = device(portName.toStdString()); dev) {
61+
if (const auto dev = device(portName.toStdString()); dev) {
6062
dev->processMidiNoteOn(note, velocity);
6163
}
6264
}
6365

6466
void DeviceService::processMidiNoteOff(const QString & portName, uint8_t note)
6567
{
66-
if (auto dev = device(portName.toStdString()); dev) {
68+
if (const auto dev = device(portName.toStdString()); dev) {
6769
dev->processMidiNoteOff(note);
6870
}
6971
}
7072

7173
void DeviceService::processMidiCc(const QString & portName, uint8_t controller, uint8_t value, uint8_t channel)
7274
{
73-
if (auto dev = device(portName.toStdString()); dev) {
75+
if (const auto dev = device(portName.toStdString()); dev) {
7476
dev->processMidiCc(controller, value, channel);
7577
}
7678
}
7779

7880
void DeviceService::processMidiAllNotesOff(const QString & portName)
7981
{
80-
if (auto dev = device(portName.toStdString()); dev) {
82+
if (const auto dev = device(portName.toStdString()); dev) {
8183
dev->processMidiAllNotesOff();
8284
}
8385
}
8486

8587
void DeviceService::processMidiAllNotesOff()
8688
{
8789
for (const auto & name : internalDeviceNames()) {
88-
if (auto dev = device(name.toStdString()); dev) {
90+
if (const auto dev = device(name.toStdString()); dev) {
8991
dev->processMidiAllNotesOff();
9092
}
9193
}
@@ -94,12 +96,41 @@ void DeviceService::processMidiAllNotesOff()
9496
QStringList DeviceService::internalDeviceNames() const
9597
{
9698
QStringList names;
97-
if (device(Constants::samplerDeviceName().toStdString())) {
98-
names << Constants::samplerDeviceName();
99+
const auto samplerName = Constants::samplerDeviceName();
100+
if (device(samplerName.toStdString())) {
101+
names << samplerName;
99102
}
100103
return names;
101104
}
102105

106+
QStringList DeviceService::categories() const
107+
{
108+
std::set<QString> categories;
109+
for (const auto & name : internalDeviceNames()) {
110+
if (const auto dev = device(name.toStdString()); dev) {
111+
categories.insert(QString::fromStdString(dev->category()));
112+
}
113+
}
114+
QStringList result;
115+
for (const auto & c : categories) {
116+
result << c;
117+
}
118+
return result;
119+
}
120+
121+
QStringList DeviceService::devicesByCategory(const QString & category) const
122+
{
123+
QStringList devices;
124+
for (const auto & name : internalDeviceNames()) {
125+
if (const auto dev = device(name.toStdString()); dev) {
126+
if (QString::fromStdString(dev->category()) == category) {
127+
devices << name;
128+
}
129+
}
130+
}
131+
return devices;
132+
}
133+
103134
void DeviceService::setProjectPath(const std::string & projectPath)
104135
{
105136
if (const auto sampler = std::dynamic_pointer_cast<SamplerDevice>(device(Constants::samplerDeviceName().toStdString())); sampler) {
@@ -110,21 +141,42 @@ void DeviceService::setProjectPath(const std::string & projectPath)
110141
void DeviceService::serializeToXml(QXmlStreamWriter & writer) const
111142
{
112143
writer.writeStartElement(Constants::NahdXml::xmlKeyDevices());
113-
if (const auto sampler = std::dynamic_pointer_cast<SamplerDevice>(device(Constants::samplerDeviceName().toStdString())); sampler) {
114-
sampler->serializeToXml(writer);
144+
for (const auto & name : internalDeviceNames()) {
145+
if (const auto dev = device(name.toStdString()); dev) {
146+
dev->serializeToXml(writer);
147+
}
115148
}
116149
writer.writeEndElement(); // Devices
117150
}
118151

119152
void DeviceService::deserializeFromXml(QXmlStreamReader & reader)
120153
{
121-
while (!reader.atEnd() && !(reader.isEndElement() && reader.name() == Constants::NahdXml::xmlKeyDevices())) {
122-
if (reader.isStartElement() && reader.name() == Constants::NahdXml::xmlKeySampler()) {
123-
if (const auto sampler = std::dynamic_pointer_cast<SamplerDevice>(device(Constants::samplerDeviceName().toStdString())); sampler) {
154+
const auto samplerName = Constants::samplerDeviceName().toStdString();
155+
const auto samplersCategory = Constants::NahdXml::xmlValueSamplers();
156+
157+
while (reader.readNextStartElement()) {
158+
const auto name = reader.name();
159+
if (name == Constants::NahdXml::xmlKeyDevice()) {
160+
const auto category = reader.attributes().value(Constants::NahdXml::xmlKeyCategory()).toString();
161+
const auto deviceName = reader.attributes().value(Constants::NahdXml::xmlKeyName()).toString().toStdString();
162+
if (category == samplersCategory) {
163+
if (const auto sampler = std::dynamic_pointer_cast<SamplerDevice>(device(samplerName)); sampler) {
164+
sampler->deserializeFromXml(reader);
165+
}
166+
} else if (auto dev = device(deviceName)) {
167+
dev->deserializeFromXml(reader);
168+
} else {
169+
reader.skipCurrentElement();
170+
}
171+
} else if (name == Constants::NahdXml::xmlKeySampler()) {
172+
if (const auto sampler = std::dynamic_pointer_cast<SamplerDevice>(device(samplerName)); sampler) {
124173
sampler->deserializeFromXml(reader);
174+
} else {
175+
reader.skipCurrentElement();
125176
}
177+
} else {
178+
reader.skipCurrentElement();
126179
}
127-
reader.readNext();
128180
}
129181
emit dataChanged();
130182
}

src/application/service/device_service.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ class DeviceService : public QObject
5353

5454
QStringList internalDeviceNames() const;
5555

56+
Q_INVOKABLE QStringList categories() const;
57+
Q_INVOKABLE QStringList devicesByCategory(const QString & category) const;
58+
5659
void setProjectPath(const std::string & projectPath);
5760

5861
void serializeToXml(QXmlStreamWriter & writer) const;

src/application/service/sampler_controller.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,19 @@ void SamplerController::initialize()
218218
emit channelModeChanged();
219219
}
220220

221+
void SamplerController::reset()
222+
{
223+
if (m_sampler) {
224+
m_sampler->reset();
225+
emit selectedPadPanChanged();
226+
emit selectedPadVolumeChanged();
227+
emit selectedPadCutoffChanged();
228+
emit selectedPadHpfCutoffChanged();
229+
emit selectedPadStartOffsetChanged();
230+
emit channelModeChanged();
231+
}
232+
}
233+
221234
void SamplerController::accept()
222235
{
223236
// State already updated in domain, nothing to do but close dialog which is handled by QML

src/application/service/sampler_controller.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class SamplerController : public QObject
7979
Q_INVOKABLE QVariantList getWaveformData(int numPoints);
8080

8181
Q_INVOKABLE void initialize();
82+
Q_INVOKABLE void reset();
8283
Q_INVOKABLE void accept();
8384
Q_INVOKABLE void reject();
8485

src/common/constants.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,41 @@ QString xmlKeyDevices()
679679
return "Devices";
680680
}
681681

682+
QString xmlKeyDevice()
683+
{
684+
return "Device";
685+
}
686+
687+
QString xmlKeyCategory()
688+
{
689+
return "category";
690+
}
691+
692+
QString xmlKeyParameter()
693+
{
694+
return "Parameter";
695+
}
696+
697+
QString xmlKeyMin()
698+
{
699+
return "min";
700+
}
701+
702+
QString xmlKeyMax()
703+
{
704+
return "max";
705+
}
706+
707+
QString xmlKeyDefault()
708+
{
709+
return "default";
710+
}
711+
712+
QString xmlKeyScale()
713+
{
714+
return "scale";
715+
}
716+
682717
QString xmlKeySampler()
683718
{
684719
return "Sampler";
@@ -689,6 +724,11 @@ QString xmlKeySample()
689724
return "Sample";
690725
}
691726

727+
QString xmlKeySamples()
728+
{
729+
return "Samples";
730+
}
731+
692732
QString xmlKeySamplePath() { return "path"; }
693733
QString xmlKeyChannelMode() { return "channelMode"; }
694734
QString xmlKeyStartOffset() { return "startOffset"; }
@@ -710,6 +750,11 @@ QString xmlValueRandom()
710750
return "Random";
711751
}
712752

753+
QString xmlValueSamplers()
754+
{
755+
return "Samplers";
756+
}
757+
713758
} // namespace NahdXml
714759

715760
} // namespace noteahead::Constants

src/common/constants.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,16 @@ QString xmlKeySideChainTarget();
203203
QString xmlKeySideChainSettings();
204204

205205
QString xmlKeyDevices();
206+
QString xmlKeyDevice();
207+
QString xmlKeyCategory();
208+
QString xmlKeyParameter();
209+
QString xmlKeyMin();
210+
QString xmlKeyMax();
211+
QString xmlKeyDefault();
212+
QString xmlKeyScale();
206213
QString xmlKeySampler();
207214
QString xmlKeySample();
215+
QString xmlKeySamples();
208216
QString xmlKeySamplePath();
209217
QString xmlKeyChannelMode();
210218
QString xmlKeyStartOffset();
@@ -213,6 +221,7 @@ QString xmlValueFalse();
213221
QString xmlValueTrue();
214222
QString xmlValueSineWave();
215223
QString xmlValueRandom();
224+
QString xmlValueSamplers();
216225

217226
} // namespace NahdXml
218227
} // namespace noteahead::Constants

src/domain/devices/device.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
// along with Noteahead. If not, see <http://www.gnu.org/licenses/>.
1515

1616
#include "device.hpp"
17+
#include "../../common/constants.hpp"
18+
#include "../../common/utils.hpp"
19+
20+
#include <QXmlStreamReader>
21+
#include <QXmlStreamWriter>
1722

1823
namespace noteahead {
1924

@@ -27,4 +32,33 @@ void Device::setId(size_t id)
2732
m_id = id;
2833
}
2934

35+
void Device::serializeToXml(QXmlStreamWriter & writer) const
36+
{
37+
writer.writeStartElement(Constants::NahdXml::xmlKeyDevice());
38+
serializeAttributesToXml(writer);
39+
serializeParametersToXml(writer);
40+
writer.writeEndElement(); // Device
41+
}
42+
43+
void Device::deserializeFromXml(QXmlStreamReader & reader)
44+
{
45+
deserializeAttributesFromXml(reader);
46+
reader.readNext();
47+
deserializeParametersFromXml(reader);
48+
}
49+
50+
void Device::serializeAttributesToXml(QXmlStreamWriter & writer) const
51+
{
52+
writer.writeAttribute(Constants::NahdXml::xmlKeyId(), QString::number(m_id));
53+
writer.writeAttribute(Constants::NahdXml::xmlKeyName(), QString::fromStdString(name()));
54+
writer.writeAttribute(Constants::NahdXml::xmlKeyCategory(), QString::fromStdString(category()));
55+
}
56+
57+
void Device::deserializeAttributesFromXml(QXmlStreamReader & reader)
58+
{
59+
if (const auto id = Utils::Xml::readUIntAttribute(reader, Constants::NahdXml::xmlKeyId(), false); id.has_value()) {
60+
m_id = id.value();
61+
}
62+
}
63+
3064
} // namespace noteahead

0 commit comments

Comments
 (0)