Implemented parsing of loop station presets
This commit is contained in:
@ -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
376
drumpadjsonconverters.cpp
Normal 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
27
drumpadjsonconverters.h
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
239
loopstationjsonconverters.cpp
Normal file
239
loopstationjsonconverters.cpp
Normal 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
|
24
loopstationjsonconverters.h
Normal file
24
loopstationjsonconverters.h
Normal 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
2
loopstationpresets.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "loopstationpresets.h"
|
||||
|
62
loopstationpresets.h
Normal file
62
loopstationpresets.h
Normal 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
|
@ -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");
|
||||
|
@ -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">
|
||||
|
@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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>
|
||||
|
Reference in New Issue
Block a user