soundboard/src/config_json.cpp

144 lines
3.7 KiB
C++

// This file contains the json parsing components required for the config to work
#include <nlohmann/json.hpp>
using json = nlohmann::json;
#include "config.h"
// json::array -> std::vector
template<typename T>
static void readVector(std::vector<T>& v, const json& j) {
v.clear();
v.reserve(j.size());
std::copy(j.begin(), j.end(), std::insert_iterator<std::vector<T>>(v, v.begin()));
}
// std::vector -> json::array
template<typename T>
static void writeVector(json& j, const std::vector<T>& v) {
j = json::array();
std::copy(v.begin(), v.end(), std::insert_iterator<json>(j, j.begin()));
}
void from_json(const json& j, Config::AudioConfig& ac) {
readVector(ac.devices, j.value("devices", json::array()));
ac.volume = j.value("volume", 1.0);
}
void from_json(const json& j, Config::SampleConfig& sc) {
sc.file = j.value("file", "");
sc.offset = j.value("offset", 0);
sc.length = j.value("length", 0);
sc.volume = j.value("volume", 1.f);
}
void from_json(const json& j, Config::ButtonConfig& bc) {
bc.name = j.value("name", "");
bc.key = j.value("key", "");
bc.width = j.value("width", Config::ButtonConfig::DEFAULTWIDTH);
// make it possible to volume control all samples from one value
float volume = j.value("value", 1.0);
if(j.contains("samples")) {
// sample liste
readVector(bc.samples, j["samples"]);
for(Config::SampleConfig& sc : bc.samples) {
sc.volume *= volume;
}
} else if(j.contains("file")) {
bc.samples.push_back(j); // implizit cast
}
}
void from_json(const json& j, Config::ShortcutConfig& sc) {
sc.up = j.value("up", "");
sc.down = j.value("down", "");
sc.left = j.value("left", "");
sc.right = j.value("right", "");
sc.play = j.value("play", "");
sc.stop = j.value("stop", "");
}
void from_json(const json& j, Config::RootConfig& rc) {
rc.audio = j.value<Config::AudioConfig>("audio", {});
json barr = j.value("buttons", json::array());
if(barr.is_array() && !barr.empty()) {
rc.buttons.reserve(barr.size());
for(const json& line : barr) {
std::vector<Config::ButtonConfig> btns;
readVector(btns, line);
rc.buttons.push_back(btns);
}
}
rc.audioPath = j.value("audioPath", "");
rc.shortcuts = j.value("shortcuts", Config::ShortcutConfig());
}
void to_json(json& j, const Config::AudioConfig& ac) {
json devarr = json::array();
writeVector(devarr, ac.devices);
j["devices"] = devarr;
j["volume"] = ac.volume;
}
void to_json(json& j, const Config::SampleConfig& sc) {
j["file"] = sc.file;
if(sc.offset != 0)
j["offset"] = sc.offset;
if(sc.length != 0)
j["length"] = sc.length;
if(sc.volume != 1.f)
j["volume"] = sc.volume;
}
void to_json(json& j, const Config::ButtonConfig& bc) {
j["name"] = bc.name;
if(!bc.key.empty())
j["key"] = bc.key;
if(bc.width != Config::ButtonConfig::DEFAULTWIDTH)
j["width"] = bc.width;
if(bc.samples.size() == 1) {
//dont use a json array when only one sample is present (inline instead)
if(bc.samples.at(0).isValid())
to_json(j, bc.samples.at(0));
} else if(!bc.samples.empty()) {
json samples = json::array();
writeVector(samples, bc.samples);
j["samples"] = samples;
}
}
void to_json(json& j, const Config::ShortcutConfig& sc) {
j["up"] = sc.up;
j["down"] = sc.down;
j["left"] = sc.left;
j["right"] = sc.right;
j["play"] = sc.play;
j["stop"] = sc.stop;
}
void to_json(json& j, const Config::RootConfig& rc) {
j["audio"] = rc.audio;
j["audioPath"] = rc.audioPath;
json buttonarr = json::array();
for(const std::vector<Config::ButtonConfig>& row : rc.buttons) {
if(row.empty()) continue;
json jsonrow = json::array();
for(const Config::ButtonConfig& btn : row) {
jsonrow.push_back(btn); // implicit convert btn to json
}
buttonarr.push_back(jsonrow);
}
j["buttons"] = buttonarr;
j["shortcuts"] = rc.shortcuts;
}