Implemented parsing of loop station presets

This commit is contained in:
2022-12-27 22:47:46 +01:00
parent b2f688c178
commit 56d56947c9
16 changed files with 981 additions and 371 deletions

View File

@ -16,10 +16,13 @@ SOURCES += \
audioplayer.cpp \
drummachinesettings.cpp \
drumpadfilesmodel.cpp \
drumpadjsonconverters.cpp \
drumpadpresets.cpp \
drumpadpresetsmodel.cpp \
graphrenderer.cpp \
jsonconverters.cpp \
loopstationjsonconverters.cpp \
loopstationpresets.cpp \
main.cpp \
midicontainers.cpp \
midiinwrapper.cpp \
@ -46,10 +49,13 @@ HEADERS += \
audioplayer.h \
drummachinesettings.h \
drumpadfilesmodel.h \
drumpadjsonconverters.h \
drumpadpresets.h \
drumpadpresetsmodel.h \
graphrenderer.h \
jsonconverters.h \
loopstationjsonconverters.h \
loopstationpresets.h \
midicontainers.h \
midiinwrapper.h \
midioutwrapper.h \

376
drumpadjsonconverters.cpp Normal file
View File

@ -0,0 +1,376 @@
#include "drumpadjsonconverters.h"
#include "jsonconverters.h"
namespace json_converters {
namespace drumpad {
drumpad_presets::PresetsConfig parsePresetsConfig(const QJsonObject &jsonObj)
{
drumpad_presets::PresetsConfig presetConfig;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
if (iter.key() == "categories")
presetConfig.categories = parseCategoryVector(iter.value());
else if (iter.key() == "presets")
presetConfig.presets = parsePresetMap(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 (%1) for PresetConfig"}.arg(iter.key(), jsonTypeToString(iter->type())).toStdString()};
}
return presetConfig;
}
std::vector<drumpad_presets::Category> parseCategoryVector(const QJsonValue &jsonValue)
{
if (!jsonValue.isArray())
throw std::runtime_error{QString{"json value for vector of Category is not an array but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
std::vector<drumpad_presets::Category> vector;
for (const auto &jsonValue : jsonValue.toArray())
vector.emplace_back(parseCategory(jsonValue));
return vector;
}
std::map<QString, drumpad_presets::Preset> parsePresetMap(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for Preset map is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
std::map<QString, drumpad_presets::Preset> map;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
map[iter.key()] = parsePreset(iter.value());
return map;
}
drumpad_presets::Category parseCategory(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for Category is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
drumpad_presets::Category category;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
if (iter.key() == "title")
category.title = parseString(iter.value());
else if (iter.key() == "filter")
category.filter = parseFilter(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 (%1) for Category"}.arg(iter.key(), jsonTypeToString(iter->type())).toStdString()};
}
return category;
}
drumpad_presets::Filter parseFilter(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for Filters is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
drumpad_presets::Filter filters;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
if (iter.key() == "tags")
filters.tags = parseStringVector(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 (%1) for Filters"}.arg(iter.key(), jsonTypeToString(iter->type())).toStdString()};
}
return filters;
}
drumpad_presets::Preset parsePreset(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for Preset is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
drumpad_presets::Preset preset;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
const auto key = iter.key();
if (key == "id")
preset.id = parseString(iter.value());
else if (key == "name")
preset.name = parseString(iter.value());
else if (key == "author")
preset.author = parseString(iter.value());
else if (key == "orderBy")
preset.orderBy = parseString(iter.value());
else if (key == "version")
preset.version = parseString(iter.value());
else if (key == "tempo")
preset.tempo = parseInt(iter.value());
else if (key == "icon")
preset.icon = parseString(iter.value());
else if (key == "price")
preset.price = parseInt(iter.value());
else if (key == "priceForSession")
preset.priceForSession = parseInt(iter.value());
else if (key == "hasInfo")
preset.hasInfo = parseBool(iter.value());
else if (key == "tags")
preset.tags = parseStringVector(iter.value());
else if (key == "DELETED")
preset.DELETED = parseBool(iter.value());
else if (key == "difficulty")
preset.difficulty = parseInt(iter.value());
else if (key == "sample")
preset.sample = parseInt(iter.value());
else if (key == "audioPreview1Name")
preset.audioPreview1Name = parseString(iter.value());
else if (key == "audioPreview1URL")
preset.audioPreview1URL = parseString(iter.value());
else if (key == "audioPreview2Name")
preset.audioPreview2Name = parseString(iter.value());
else if (key == "audioPreview2URL")
preset.audioPreview2URL = parseString(iter.value());
else if (key == "imagePreview1")
preset.imagePreview1 = parseString(iter.value());
else if (key == "videoPreview")
preset.videoPreview = parseString(iter.value());
else if (key == "videoTutorial")
preset.videoTutorial = parseString(iter.value());
else if (key == "files")
preset.files = parseFileArray(iter.value());
else if (key == "beatSchool")
preset.beatSchool = parseSequenceVectorMap(iter.value());
else if (key == "easyPlay")
preset.easyPlay = parseSequenceVectorMap(iter.value());
else if (key == "timestamp")
preset.timestamp = QDateTime::fromSecsSinceEpoch(iter.value().toDouble());
else if (key == "middleDescription")
{
//preset.middleDescription = parseString(iter.value());
// example value:
// [
// {
// "type": "ButtonsRow",
// "buttons": [
// {
// "type": "ImageButton",
// "action": "openLink",
// "link": "https://www.soundcloud.com/matta-music",
// "icon": "soundcloud"
// },
// {
// "type": "ImageButton",
// "action": "openLink",
// "link": "https://www.facebook.com/MattaOfficial",
// "icon": "facebook"
// },
// {
// "type": "ImageButton",
// "action": "openLink",
// "link": "https://www.twitter.com/matta_music",
// "icon": "twitter"
// },
// {
// "type": "ImageButton",
// "action": "openLink",
// "link": "https://pro.beatport.com/artist/matta/118779",
// "icon": "beatport"
// },
// {
// "type": "ImageButton",
// "action": "openLink",
// "link": "https://www.mattaofficial.com",
// "icon": "mattaofficial"
// }
// ]
// }
// ]
}
else
throw std::runtime_error{QString{"unknown key %0 (%1) for Preset"}.arg(key, jsonTypeToString(iter->type())).toStdString()};
}
return preset;
}
std::array<drumpad_presets::File, 24> parseFileArray(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for File array is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
if (jsonObj.size() != 24)
throw std::runtime_error{QString{"json value for File array doesn't have exactly 24 entries but %0"}.arg(jsonObj.size()).toStdString()};
std::array<drumpad_presets::File, 24> array;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
bool ok;
const auto index = iter.key().toInt(&ok);
if (!ok || index < 1 || index >= 25)
throw std::runtime_error{QString{"unknown key %0 (%1) for File"}.arg(iter.key(), jsonTypeToString(iter->type())).toStdString()};
array[index - 1] = parseFile(iter.value());
}
return array;
}
drumpad_presets::File parseFile(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for File is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
drumpad_presets::File file;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
const auto key = iter.key();
if (key == "filename")
file.filename = parseString(iter.value());
else if (key == "color")
file.color = parseString(iter.value());
else if (key == "stopOnRelease")
file.stopOnRelease = parseString(iter.value());
else if (key == "looped")
file.looped = parseBool(iter.value());
else if (key == "choke")
file.choke = parseInt(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 (%1) for File"}.arg(key, jsonTypeToString(iter->type())).toStdString()};
}
return file;
}
std::vector<drumpad_presets::Sequence> parseSequenceVector(const QJsonValue &jsonValue)
{
if (!jsonValue.isArray())
throw std::runtime_error{QString{"json value for vector of Sequence is not an array but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
std::vector<drumpad_presets::Sequence> vector;
for (const auto &jsonValue : jsonValue.toArray())
vector.emplace_back(parseSequence(jsonValue));
return vector;
}
drumpad_presets::Sequence parseSequence(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for File is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
drumpad_presets::Sequence sequence;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
const auto key = iter.key();
if (key == "name")
sequence.name = parseString(iter.value());
else if (key == "id")
sequence.id = parseInt(iter.value());
else if (key == "version")
sequence.version = parseInt(iter.value());
else if (key == "orderBy")
sequence.orderBy = parseInt(iter.value());
else if (key == "sequencerSize")
sequence.sequencerSize = parseInt(iter.value());
else if (key == "pads")
sequence.pads = parseSequencePadVectorMap(iter.value());
else if (key == "embientPads")
sequence.embientPads = parseIntVectorIgnoreNulls(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 (%1) for Sequence"}.arg(key, jsonTypeToString(iter->type())).toStdString()};
}
return sequence;
}
std::map<QString, std::vector<drumpad_presets::Sequence>> parseSequenceVectorMap(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for Sequence vector map is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
std::map<QString, std::vector<drumpad_presets::Sequence>> map;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
map[iter.key()] = parseSequenceVector(iter.value());
return map;
}
drumpad_presets::SequencePad parseSequencePad(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for File is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
drumpad_presets::SequencePad sequencePad;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
if (iter.key() == "start")
sequencePad.start = parseInt(iter.value());
else if (iter.key() == "duration")
sequencePad.duration = parseInt(iter.value());
else if (iter.key() == "embient")
sequencePad.embient = parseBool(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 (%1) for Sequence"}.arg(iter.key(), jsonTypeToString(iter->type())).toStdString()};
}
return sequencePad;
}
std::vector<drumpad_presets::SequencePad> parseSequencePadVector(const QJsonValue &jsonValue)
{
if (!jsonValue.isArray())
throw std::runtime_error{QString{"json value for vector of SequencePad is not an array but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
std::vector<drumpad_presets::SequencePad> vector;
for (const auto &jsonValue : jsonValue.toArray())
vector.emplace_back(parseSequencePad(jsonValue));
return vector;
}
std::map<QString, std::vector<drumpad_presets::SequencePad>> parseSequencePadVectorMap(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for SequencePad vector map is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
std::map<QString, std::vector<drumpad_presets::SequencePad>> map;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
map[iter.key()] = parseSequencePadVector(iter.value());
return map;
}
} // namespace drumpad
} // namespace json_converters

27
drumpadjsonconverters.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include "drumpadpresets.h"
class QJsonObject;
class QJsonValue;
namespace json_converters {
namespace drumpad {
drumpad_presets::PresetsConfig parsePresetsConfig(const QJsonObject &jsonObj);
std::vector<drumpad_presets::Category> parseCategoryVector(const QJsonValue &jsonValue);
std::map<QString, drumpad_presets::Preset> parsePresetMap(const QJsonValue &jsonValue);
drumpad_presets::Category parseCategory(const QJsonValue &jsonValue);
drumpad_presets::Filter parseFilter(const QJsonValue &jsonValue);
drumpad_presets::Preset parsePreset(const QJsonValue &jsonValue);
std::array<drumpad_presets::File, 24> parseFileArray(const QJsonValue &jsonValue);
drumpad_presets::File parseFile(const QJsonValue &jsonValue);
std::vector<drumpad_presets::Sequence> parseSequenceVector(const QJsonValue &jsonValue);
drumpad_presets::Sequence parseSequence(const QJsonValue &jsonValue);
std::map<QString, std::vector<drumpad_presets::Sequence>> parseSequenceVectorMap(const QJsonValue &jsonValue);
drumpad_presets::SequencePad parseSequencePad(const QJsonValue &jsonValue);
std::vector<drumpad_presets::SequencePad> parseSequencePadVector(const QJsonValue &jsonValue);
std::map<QString, std::vector<drumpad_presets::SequencePad>> parseSequencePadVectorMap(const QJsonValue &jsonValue);
} // namespace drumpad
} // namespace json_converters

View File

@ -1,7 +1,6 @@
#include "drumpadpresets.h"
namespace drumpad_presets
{
namespace drumpad_presets {
bool File::operator==(const File &other) const
{
@ -12,4 +11,4 @@ bool File::operator==(const File &other) const
choke == other.choke;
}
}
} // namespace drumpad_presets

View File

@ -8,8 +8,8 @@
#include <QString>
#include <QDateTime>
namespace drumpad_presets
{
namespace drumpad_presets {
struct Filter
{
std::optional<std::vector<QString>> tags;
@ -84,4 +84,5 @@ struct PresetsConfig
std::optional<std::vector<Category>> categories;
std::optional<std::map<QString, Preset>> presets;
};
}
} // namespace drumpad_presets

View File

@ -4,8 +4,25 @@
#include <QJsonParseError>
namespace json_converters
namespace json_converters {
QString jsonTypeToString(QJsonValue::Type type)
{
switch (type)
{
case QJsonValue::Null: return "Null";
case QJsonValue::Bool: return "Bool";
case QJsonValue::Double: return "Double";
case QJsonValue::String: return "String";
case QJsonValue::Array: return "Array";
case QJsonValue::Object: return "Object";
case QJsonValue::Undefined: return "Undefined";
default:
qWarning() << "unknown jsonType" << type;
return QString{"unknown jsonType %0"}.arg(type);
}
}
QJsonObject loadJson(const QByteArray &buffer)
{
QJsonParseError error;
@ -22,7 +39,7 @@ QJsonObject loadJson(const QByteArray &buffer)
QString parseString(const QJsonValue &jsonValue)
{
if (!jsonValue.isString())
throw std::runtime_error{"json value for string is not a string"};
throw std::runtime_error{QString{"json value for string is not a string but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
return jsonValue.toString();
}
@ -30,7 +47,7 @@ QString parseString(const QJsonValue &jsonValue)
std::vector<QString> parseStringVector(const QJsonValue &jsonValue)
{
if (!jsonValue.isArray())
throw std::runtime_error{"json value for string vector is not an array"};
throw std::runtime_error{QString{"json value for string vector is not an array but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
std::vector<QString> vector;
@ -43,7 +60,7 @@ std::vector<QString> parseStringVector(const QJsonValue &jsonValue)
int parseInt(const QJsonValue &jsonValue)
{
if (!jsonValue.isDouble())
throw std::runtime_error{"json value for int is not a double"};
throw std::runtime_error{QString{"json value for int is not a double but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
return jsonValue.toDouble();
}
@ -51,15 +68,33 @@ int parseInt(const QJsonValue &jsonValue)
bool parseBool(const QJsonValue &jsonValue)
{
if (!jsonValue.isBool())
throw std::runtime_error{"json value for bool is not a bool"};
throw std::runtime_error{QString{"json value for bool is not a bool but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
return jsonValue.toBool();
}
bool parseBoolStr(const QJsonValue &jsonValue)
{
if (jsonValue.isBool())
return jsonValue.toBool();
else if (jsonValue.isString())
{
if (const auto &str = jsonValue.toString(); str == "true")
return true;
else if (str == "false")
return false;
else
throw std::runtime_error{QString{"json value for str-bool has invalid str value %0"}.arg(str).toStdString()};
}
else
throw std::runtime_error{QString{"json value for str-bool is not a bool or string but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
}
std::vector<int> parseIntVector(const QJsonValue &jsonValue)
{
if (!jsonValue.isArray())
throw std::runtime_error{"json value for int vector is not an array"};
throw std::runtime_error{QString{"json value for int vector is not an array but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
std::vector<int> vector;
@ -72,7 +107,7 @@ std::vector<int> parseIntVector(const QJsonValue &jsonValue)
std::vector<int> parseIntVectorIgnoreNulls(const QJsonValue &jsonValue)
{
if (!jsonValue.isArray())
throw std::runtime_error{"json value for int vector is not an array"};
throw std::runtime_error{QString{"json value for int vector is not an array but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
std::vector<int> vector;
@ -83,330 +118,24 @@ std::vector<int> parseIntVectorIgnoreNulls(const QJsonValue &jsonValue)
return vector;
}
drumpad_presets::PresetsConfig parseDrumPadPresetsConfig(const QJsonObject &jsonObj)
{
drumpad_presets::PresetsConfig presetConfig;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
if (iter.key() == "categories")
presetConfig.categories = parseCategoryVector(iter.value());
else if (iter.key() == "presets")
presetConfig.presets = parsePresetMap(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 for PresetConfig"}.arg(iter.key()).toStdString()};
}
return presetConfig;
}
std::vector<drumpad_presets::Category> parseCategoryVector(const QJsonValue &jsonValue)
template<std::size_t LENGTH>
std::array<QString, LENGTH> parseStringArray(const QJsonValue &jsonValue)
{
if (!jsonValue.isArray())
throw std::runtime_error{"json value for vector of Category is not an array"};
throw std::runtime_error{QString{"json value for array of PadType is not an array but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
std::vector<drumpad_presets::Category> vector;
const auto jsonArr = jsonValue.toArray();
for (const auto &jsonValue : jsonValue.toArray())
vector.emplace_back(parseCategory(jsonValue));
if (jsonArr.size() != LENGTH)
throw std::runtime_error{QString{"json value for PadType array doesn't have exactly %0 entries but %1"}.arg(LENGTH).arg(jsonArr.size()).toStdString()};
return vector;
}
std::array<QString, LENGTH> array;
std::map<QString, drumpad_presets::Preset> parsePresetMap(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{"json value for Preset map is not an object"};
const auto jsonObj = jsonValue.toObject();
std::map<QString, drumpad_presets::Preset> map;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
map[iter.key()] = parsePreset(iter.value());
return map;
}
drumpad_presets::Category parseCategory(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{"json value for Category is not an object"};
const auto jsonObj = jsonValue.toObject();
drumpad_presets::Category category;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
if (iter.key() == "title")
category.title = parseString(iter.value());
else if (iter.key() == "filter")
category.filter = parseFilter(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 for Category"}.arg(iter.key()).toStdString()};
}
return category;
}
drumpad_presets::Filter parseFilter(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{"json value for Filters is not an object"};
const auto jsonObj = jsonValue.toObject();
drumpad_presets::Filter filters;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
if (iter.key() == "tags")
filters.tags = parseStringVector(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 for Filters"}.arg(iter.key()).toStdString()};
}
return filters;
}
drumpad_presets::Preset parsePreset(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{"json value for Preset is not an object"};
const auto jsonObj = jsonValue.toObject();
drumpad_presets::Preset preset;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
const auto key = iter.key();
if (key == "id")
preset.id = parseString(iter.value());
else if (key == "name")
preset.name = parseString(iter.value());
else if (key == "author")
preset.author = parseString(iter.value());
else if (key == "orderBy")
preset.orderBy = parseString(iter.value());
else if (key == "version")
preset.version = parseString(iter.value());
else if (key == "tempo")
preset.tempo = parseInt(iter.value());
else if (key == "icon")
preset.icon = parseString(iter.value());
else if (key == "price")
preset.price = parseInt(iter.value());
else if (key == "priceForSession")
preset.priceForSession = parseInt(iter.value());
else if (key == "hasInfo")
preset.hasInfo = parseBool(iter.value());
else if (key == "tags")
preset.tags = parseStringVector(iter.value());
else if (key == "DELETED")
preset.DELETED = parseBool(iter.value());
else if (key == "difficulty")
preset.difficulty = parseInt(iter.value());
else if (key == "sample")
preset.sample = parseInt(iter.value());
else if (key == "audioPreview1Name")
preset.audioPreview1Name = parseString(iter.value());
else if (key == "audioPreview1URL")
preset.audioPreview1URL = parseString(iter.value());
else if (key == "audioPreview2Name")
preset.audioPreview2Name = parseString(iter.value());
else if (key == "audioPreview2URL")
preset.audioPreview2URL = parseString(iter.value());
else if (key == "imagePreview1")
preset.imagePreview1 = parseString(iter.value());
else if (key == "videoPreview")
preset.videoPreview = parseString(iter.value());
else if (key == "videoTutorial")
preset.videoTutorial = parseString(iter.value());
else if (key == "files")
preset.files = parseFileArray(iter.value());
else if (key == "beatSchool")
preset.beatSchool = parseSequenceVectorMap(iter.value());
else if (key == "easyPlay")
preset.easyPlay = parseSequenceVectorMap(iter.value());
else if (key == "timestamp")
preset.timestamp = QDateTime::fromSecsSinceEpoch(iter.value().toDouble());
else if (key == "middleDescription")
{}
else
throw std::runtime_error{QString{"unknown key %0 for Preset"}.arg(key).toStdString()};
}
return preset;
}
std::array<drumpad_presets::File, 24> parseFileArray(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{"json value for File array is not an object"};
const auto jsonObj = jsonValue.toObject();
if (jsonObj.size() != 24)
throw std::runtime_error{"json value for File array doesn't have exactly 24 entries"};
std::array<drumpad_presets::File, 24> array;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
bool ok;
const auto index = iter.key().toInt(&ok);
if (!ok || index < 1 || index >= 25)
throw std::runtime_error{QString{"unknown key %0 for File"}.arg(iter.key()).toStdString()};
array[index - 1] = parseFile(iter.value());
}
std::transform(std::cbegin(jsonArr), std::cend(jsonArr), std::begin(array), parseString);
return array;
}
drumpad_presets::File parseFile(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{"json value for File is not an object"};
template std::array<QString, 48> parseStringArray(const QJsonValue &jsonValue);
const auto jsonObj = jsonValue.toObject();
drumpad_presets::File file;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
const auto key = iter.key();
if (key == "filename")
file.filename = parseString(iter.value());
else if (key == "color")
file.color = parseString(iter.value());
else if (key == "stopOnRelease")
file.stopOnRelease = parseString(iter.value());
else if (key == "looped")
file.looped = parseBool(iter.value());
else if (key == "choke")
file.choke = parseInt(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 for File"}.arg(key).toStdString()};
}
return file;
}
std::vector<drumpad_presets::Sequence> parseSequenceVector(const QJsonValue &jsonValue)
{
if (!jsonValue.isArray())
throw std::runtime_error{"json value for vector of Sequence is not an array"};
std::vector<drumpad_presets::Sequence> vector;
for (const auto &jsonValue : jsonValue.toArray())
vector.emplace_back(parseSequence(jsonValue));
return vector;
}
drumpad_presets::Sequence parseSequence(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{"json value for File is not an object"};
const auto jsonObj = jsonValue.toObject();
drumpad_presets::Sequence sequence;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
const auto key = iter.key();
if (key == "name")
sequence.name = parseString(iter.value());
else if (key == "id")
sequence.id = parseInt(iter.value());
else if (key == "version")
sequence.version = parseInt(iter.value());
else if (key == "orderBy")
sequence.orderBy = parseInt(iter.value());
else if (key == "sequencerSize")
sequence.sequencerSize = parseInt(iter.value());
else if (key == "pads")
sequence.pads = parseSequencePadVectorMap(iter.value());
else if (key == "embientPads")
sequence.embientPads = parseIntVectorIgnoreNulls(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 for Sequence"}.arg(key).toStdString()};
}
return sequence;
}
std::map<QString, std::vector<drumpad_presets::Sequence>> parseSequenceVectorMap(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{"json value for Sequence vector map is not an object"};
const auto jsonObj = jsonValue.toObject();
std::map<QString, std::vector<drumpad_presets::Sequence>> map;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
map[iter.key()] = parseSequenceVector(iter.value());
return map;
}
drumpad_presets::SequencePad parseSequencePad(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{"json value for File is not an object"};
const auto jsonObj = jsonValue.toObject();
drumpad_presets::SequencePad sequencePad;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
if (iter.key() == "start")
sequencePad.start = parseInt(iter.value());
else if (iter.key() == "duration")
sequencePad.duration = parseInt(iter.value());
else if (iter.key() == "embient")
sequencePad.embient = parseBool(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 for Sequence"}.arg(iter.key()).toStdString()};
}
return sequencePad;
}
std::vector<drumpad_presets::SequencePad> parseSequencePadVector(const QJsonValue &jsonValue)
{
if (!jsonValue.isArray())
throw std::runtime_error{"json value for vector of SequencePad is not an array"};
std::vector<drumpad_presets::SequencePad> vector;
for (const auto &jsonValue : jsonValue.toArray())
vector.emplace_back(parseSequencePad(jsonValue));
return vector;
}
std::map<QString, std::vector<drumpad_presets::SequencePad>> parseSequencePadVectorMap(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{"json value for SequencePad vector map is not an object"};
const auto jsonObj = jsonValue.toObject();
std::map<QString, std::vector<drumpad_presets::SequencePad>> map;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
map[iter.key()] = parseSequencePadVector(iter.value());
return map;
}
}
} // namespace json_converters

View File

@ -4,31 +4,18 @@
#include <QJsonArray>
#include <QJsonObject>
#include "drumpadpresets.h"
namespace json_converters {
namespace json_converters
{
QString jsonTypeToString(QJsonValue::Type type);
QJsonObject loadJson(const QByteArray &buffer);
QString parseString(const QJsonValue &jsonValue);
std::vector<QString> parseStringVector(const QJsonValue &jsonValue);
int parseInt(const QJsonValue &jsonValue);
bool parseBool(const QJsonValue &jsonValue);
bool parseBoolStr(const QJsonValue &jsonValue);
std::vector<int> parseIntVector(const QJsonValue &jsonValue);
std::vector<int> parseIntVectorIgnoreNulls(const QJsonValue &jsonValue);
template<std::size_t LENGTH>
std::array<QString, LENGTH> parseStringArray(const QJsonValue &jsonValue);
drumpad_presets::PresetsConfig parseDrumPadPresetsConfig(const QJsonObject &jsonObj);
std::vector<drumpad_presets::Category> parseCategoryVector(const QJsonValue &jsonValue);
std::map<QString, drumpad_presets::Preset> parsePresetMap(const QJsonValue &jsonValue);
drumpad_presets::Category parseCategory(const QJsonValue &jsonValue);
drumpad_presets::Filter parseFilter(const QJsonValue &jsonValue);
drumpad_presets::Preset parsePreset(const QJsonValue &jsonValue);
std::array<drumpad_presets::File, 24> parseFileArray(const QJsonValue &jsonValue);
drumpad_presets::File parseFile(const QJsonValue &jsonValue);
std::vector<drumpad_presets::Sequence> parseSequenceVector(const QJsonValue &jsonValue);
drumpad_presets::Sequence parseSequence(const QJsonValue &jsonValue);
std::map<QString, std::vector<drumpad_presets::Sequence>> parseSequenceVectorMap(const QJsonValue &jsonValue);
drumpad_presets::SequencePad parseSequencePad(const QJsonValue &jsonValue);
std::vector<drumpad_presets::SequencePad> parseSequencePadVector(const QJsonValue &jsonValue);
std::map<QString, std::vector<drumpad_presets::SequencePad>> parseSequencePadVectorMap(const QJsonValue &jsonValue);
}
} // namespace json_converters

View File

@ -0,0 +1,239 @@
#include "loopstationjsonconverters.h"
#include <algorithm>
#include "jsonconverters.h"
namespace json_converters {
namespace loopstation {
loopstation_presets::PresetsConfig parsePresetsConfig(const QJsonObject &jsonObj)
{
loopstation_presets::PresetsConfig presetConfig;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
if (iter.key() == "categories")
presetConfig.categories = parseCategoryVector(iter.value());
else if (iter.key() == "presets")
presetConfig.presets = parsePresetMap(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 (%1) for PresetConfig"}.arg(iter.key(), jsonTypeToString(iter->type())).toStdString()};
}
return presetConfig;
}
std::vector<loopstation_presets::Category> parseCategoryVector(const QJsonValue &jsonValue)
{
if (!jsonValue.isArray())
throw std::runtime_error{QString{"json value for vector of Category is not an array but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
std::vector<loopstation_presets::Category> vector;
for (const auto &jsonValue : jsonValue.toArray())
vector.emplace_back(parseCategory(jsonValue));
return vector;
}
std::map<QString, loopstation_presets::Preset> parsePresetMap(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for Preset map is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
std::map<QString, loopstation_presets::Preset> map;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
map[iter.key()] = parsePreset(iter.value());
return map;
}
loopstation_presets::Category parseCategory(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for Category is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
loopstation_presets::Category category;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
if (iter.key() == "title")
category.title = parseString(iter.value());
else if (iter.key() == "filter")
category.filter = parseFilter(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 (%1) for Category"}.arg(iter.key(), jsonTypeToString(iter->type())).toStdString()};
}
return category;
}
loopstation_presets::Filter parseFilter(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for Filters is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
loopstation_presets::Filter filters;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
if (iter.key() == "tags")
filters.tags = parseStringVector(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 (%1) for Filters"}.arg(iter.key(), jsonTypeToString(iter->type())).toStdString()};
}
return filters;
}
loopstation_presets::Preset parsePreset(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for Preset is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
loopstation_presets::Preset preset;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
const auto key = iter.key();
if (key == "id")
preset.id = parseString(iter.value());
else if (key == "audioPreviewUrl")
preset.audioPreviewUrl = parseString(iter.value());
else if (key == "author")
preset.author = parseString(iter.value());
else if (key == "bpm")
preset.bpm = parseInt(iter.value());
else if (key == "coverUrl")
preset.coverUrl = parseString(iter.value());
else if (key == "lessons")
preset.lessons = parseLessons(iter.value());
else if (key == "loopLength")
preset.loopLength = parseInt(iter.value());
else if (key == "orderBy")
preset.orderBy = parseString(iter.value());
else if (key == "pads")
preset.pads = parseStringArray<48>(iter.value());
else if (key == "premium")
preset.premium = parseBoolStr(iter.value());
else if (key == "tags")
preset.tags = parseStringVector(iter.value());
else if (key == "title")
preset.title = parseString(iter.value());
else if (key == "beatSchool")
{
// {}
}
else if (key == "DELETED")
preset.DELETED = parseBool(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 (%1) for Preset"}.arg(key, jsonTypeToString(iter->type())).toStdString()};
}
return preset;
}
std::vector<loopstation_presets::Lesson> parseLessons(const QJsonValue &jsonValue)
{
if (!jsonValue.isArray())
throw std::runtime_error{QString{"json value for vector of Lesson is not an array but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
std::vector<loopstation_presets::Lesson> vector;
for (const auto &jsonValue : jsonValue.toArray())
vector.emplace_back(parseLesson(jsonValue));
return vector;
}
loopstation_presets::Lesson parseLesson(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for Lesson is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
loopstation_presets::Lesson lesson;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
const auto key = iter.key();
if (key == "version")
lesson.version = parseInt(iter.value());
else if (key == "name")
lesson.name = parseString(iter.value());
else if (key == "id")
lesson.id = parseInt(iter.value());
else if (key == "orderBy")
lesson.orderBy = parseInt(iter.value());
else if (key == "pads")
lesson.pads = parseLessonPadVectorMap(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 (%1) for Lesson"}.arg(key, jsonTypeToString(iter->type())).toStdString()};
}
return lesson;
}
std::map<QString, std::vector<loopstation_presets::LessonPad>> parseLessonPadVectorMap(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for LessonPad vector map is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
std::map<QString, std::vector<loopstation_presets::LessonPad>> map;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
map[iter.key()] = parseLessonPadVector(iter.value());
return map;
}
std::vector<loopstation_presets::LessonPad> parseLessonPadVector(const QJsonValue &jsonValue)
{
if (!jsonValue.isArray())
throw std::runtime_error{QString{"json value for vector of LessonPad is not an array but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
std::vector<loopstation_presets::LessonPad> vector;
for (const auto &jsonValue : jsonValue.toArray())
vector.emplace_back(parseLessonPad(jsonValue));
return vector;
}
loopstation_presets::LessonPad parseLessonPad(const QJsonValue &jsonValue)
{
if (!jsonValue.isObject())
throw std::runtime_error{QString{"json value for LessonPad is not an object but %0"}.arg(jsonTypeToString(jsonValue.type())).toStdString()};
const auto jsonObj = jsonValue.toObject();
loopstation_presets::LessonPad lessonPad;
for (auto iter = std::cbegin(jsonObj); iter != std::cend(jsonObj); iter++)
{
const auto key = iter.key();
if (key == "tap")
lessonPad.tap = parseInt(iter.value());
else
throw std::runtime_error{QString{"unknown key %0 (%1) for LessonPad"}.arg(key, jsonTypeToString(iter->type())).toStdString()};
}
return lessonPad;
}
} // namespace loopstation
} // namespace json_converters

View File

@ -0,0 +1,24 @@
#pragma once
#include "loopstationpresets.h"
class QJsonObject;
class QJsonValue;
namespace json_converters {
namespace loopstation {
loopstation_presets::PresetsConfig parsePresetsConfig(const QJsonObject &jsonObj);
std::vector<loopstation_presets::Category> parseCategoryVector(const QJsonValue &jsonValue);
std::map<QString, loopstation_presets::Preset> parsePresetMap(const QJsonValue &jsonValue);
loopstation_presets::Category parseCategory(const QJsonValue &jsonValue);
loopstation_presets::Filter parseFilter(const QJsonValue &jsonValue);
loopstation_presets::Preset parsePreset(const QJsonValue &jsonValue);
std::vector<loopstation_presets::Lesson> parseLessons(const QJsonValue &jsonValue);
loopstation_presets::Lesson parseLesson(const QJsonValue &jsonValue);
std::map<QString, std::vector<loopstation_presets::LessonPad>> parseLessonPadVectorMap(const QJsonValue &jsonValue);
std::vector<loopstation_presets::LessonPad> parseLessonPadVector(const QJsonValue &jsonValue);
loopstation_presets::LessonPad parseLessonPad(const QJsonValue &jsonValue);
} // namespace loopstation
} // namespace json_converters

2
loopstationpresets.cpp Normal file
View File

@ -0,0 +1,2 @@
#include "loopstationpresets.h"

62
loopstationpresets.h Normal file
View File

@ -0,0 +1,62 @@
#pragma once
#include <vector>
#include <map>
#include <optional>
#include <array>
#include <QString>
#include <QDateTime>
namespace loopstation_presets {
struct Filter
{
std::optional<std::vector<QString>> tags;
};
struct Category
{
std::optional<QString> title;
std::optional<Filter> filter;
};
struct LessonPad
{
std::optional<int> tap;
};
struct Lesson
{
std::optional<int> version;
std::optional<QString> name;
std::optional<int> id;
std::optional<int> orderBy;
std::optional<std::map<QString, std::vector<LessonPad>>> pads;
};
struct Preset
{
std::optional<QString> id;
std::optional<QString> audioPreviewUrl;
std::optional<QString> author;
std::optional<int> bpm;
std::optional<std::vector<Lesson>> lessons;
std::optional<QString> coverUrl;
std::optional<int> loopLength;
std::optional<QString> orderBy;
std::optional<std::array<QString, 48>> pads;
std::optional<bool> premium;
std::optional<std::vector<QString>> tags;
std::optional<QString> title;
// TODO beatschool
std::optional<bool> DELETED;
};
struct PresetsConfig
{
std::optional<std::vector<Category>> categories;
std::optional<std::map<QString, Preset>> presets;
};
} // namespace loopstation_presets

View File

@ -9,6 +9,7 @@
#include "audioformat.h"
#include "midicontainers.h"
#include "jsonconverters.h"
#include "drumpadjsonconverters.h"
#include "drummachinesettings.h"
DrumPadWidget::DrumPadWidget(QWidget *parent) :
@ -19,6 +20,7 @@ DrumPadWidget::DrumPadWidget(QWidget *parent) :
connect(m_ui->pushButtonUp, &QAbstractButton::pressed, this, &DrumPadWidget::selectPrevPreset);
connect(m_ui->pushButtonDown, &QAbstractButton::pressed, this, &DrumPadWidget::selectNextPreset);
connect(m_ui->pushButtonRefresh, &QAbstractButton::pressed, this, &DrumPadWidget::loadPresets);
connect(m_ui->sequencerWidget, &SequencerWidget::sendMidi, this, &DrumPadWidget::sendMidi);
connect(m_ui->samplesWidget, &SamplesWidget::sendMidi, this, &DrumPadWidget::sendMidi);
@ -37,8 +39,6 @@ DrumPadWidget::DrumPadWidget(QWidget *parent) :
m_ui->filesView->setModel(&m_filesModel);
connect(m_ui->presetsView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &DrumPadWidget::currentRowChanged);
connect(m_ui->pushButtonRefresh, &QAbstractButton::pressed, this, &DrumPadWidget::loadPresets);
}
DrumPadWidget::~DrumPadWidget() = default;
@ -182,7 +182,7 @@ void DrumPadWidget::requestFinished()
try
{
auto result = json_converters::parseDrumPadPresetsConfig(json_converters::loadJson(reply->readAll()));
auto result = json_converters::drumpad::parsePresetsConfig(json_converters::loadJson(reply->readAll()));
if (!result.presets)
throw std::runtime_error("presets missing in response");

View File

@ -21,7 +21,7 @@
<item>
<layout class="QVBoxLayout">
<item>
<layout class="QHBoxLayout">
<layout class="QHBoxLayout" stretch="1,0,0,0">
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="clearButtonEnabled">

View File

@ -1,13 +1,26 @@
#include "loopstationwidget.h"
#include "ui_loopstationwidget.h"
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QMessageBox>
#include "audioformat.h"
#include "midicontainers.h"
#include "jsonconverters.h"
#include "loopstationjsonconverters.h"
#include "drummachinesettings.h"
LoopStationWidget::LoopStationWidget(QWidget *parent) :
QWidget{parent},
QSplitter{parent},
m_ui{std::make_unique<Ui::LoopStationWidget>()}
{
m_ui->setupUi(this);
connect(m_ui->pushButtonUp, &QAbstractButton::pressed, this, &LoopStationWidget::selectPrevPreset);
connect(m_ui->pushButtonDown, &QAbstractButton::pressed, this, &LoopStationWidget::selectNextPreset);
connect(m_ui->pushButtonRefresh, &QAbstractButton::pressed, this, &LoopStationWidget::loadPresets);
}
LoopStationWidget::~LoopStationWidget() = default;
@ -19,7 +32,8 @@ void LoopStationWidget::writeSamples(frame_t *begin, frame_t *end)
void LoopStationWidget::injectNetworkAccessManager(QNetworkAccessManager &networkAccessManager)
{
m_networkAccessManager = &networkAccessManager;
loadPresets();
}
void LoopStationWidget::injectDecodingThread(QThread &thread)
@ -46,3 +60,66 @@ void LoopStationWidget::midiReceived(const midi::MidiMessage &message)
{
}
void LoopStationWidget::loadPresets()
{
if (!m_networkAccessManager)
{
qWarning() << "no network access manager available";
return;
}
m_ui->pushButtonRefresh->setEnabled(false);
QNetworkRequest request{QUrl{"https://brunner.ninja/komposthaufen/groovepad/presets_config_v2.json"}};
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, true);
m_reply = std::unique_ptr<QNetworkReply>(m_networkAccessManager->get(request));
connect(m_reply.get(), &QNetworkReply::finished, this, &LoopStationWidget::requestFinished);
}
void LoopStationWidget::requestFinished()
{
if (!m_reply)
{
qWarning() << "no valid reply";
return;
}
auto reply = std::move(m_reply);
if (reply->error() != QNetworkReply::NoError)
{
QMessageBox::warning(this, tr("Could not load presets!"), tr("Could not load presets!") + "\n\n" + reply->errorString());
return;
}
try
{
auto result = json_converters::loopstation::parsePresetsConfig(json_converters::loadJson(reply->readAll()));
if (!result.presets)
throw std::runtime_error("presets missing in response");
// TODO
}
catch (const std::exception &e)
{
QMessageBox::warning(this, tr("error"), tr("error") + "\n\n" + QString::fromStdString(e.what()));
}
}
void LoopStationWidget::selectFirstPreset()
{
}
void LoopStationWidget::selectPrevPreset()
{
}
void LoopStationWidget::selectNextPreset()
{
}

View File

@ -1,16 +1,17 @@
#pragma once
#include <QWidget>
#include <QSplitter>
#include <memory>
namespace Ui { class LoopStationWidget; }
namespace midi { struct MidiMessage; }
class QNetworkAccessManager;
class QNetworkReply;
class DrumMachineSettings;
struct frame_t;
class LoopStationWidget : public QWidget
class LoopStationWidget : public QSplitter
{
Q_OBJECT
@ -31,6 +32,17 @@ signals:
public slots:
void midiReceived(const midi::MidiMessage &message);
private slots:
void loadPresets();
void requestFinished();
void selectFirstPreset();
void selectPrevPreset();
void selectNextPreset();
private:
const std::unique_ptr<Ui::LoopStationWidget> m_ui;
QNetworkAccessManager *m_networkAccessManager{};
std::unique_ptr<QNetworkReply> m_reply;
};

View File

@ -1,29 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LoopStationWidget</class>
<widget class="QWidget" name="LoopStationWidget">
<widget class="QSplitter" name="LoopStationWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
<width>1014</width>
<height>442</height>
</rect>
</property>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>40</x>
<y>50</y>
<width>261</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>Hier könnte ihre LoopStation stehen.</string>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="verticalLayoutWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,0,0">
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="MidiButton" name="pushButtonUp">
<property name="maximumSize">
<size>
<width>32</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>⬆</string>
</property>
</widget>
</item>
<item>
<widget class="MidiButton" name="pushButtonDown">
<property name="maximumSize">
<size>
<width>32</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>⬇</string>
</property>
</widget>
</item>
<item>
<widget class="MidiButton" name="pushButtonRefresh">
<property name="maximumSize">
<size>
<width>32</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>↻</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTreeView" name="treeView"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="widget" native="true">
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>20</x>
<y>10</y>
<width>261</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>Hier könnte ihre LoopStation stehen.</string>
</property>
</widget>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>MidiButton</class>
<extends>QPushButton</extends>
<header>widgets/midibutton.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>