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

@@ -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