// This file contains the json parsing components required for the config to work #include using json = nlohmann::json; #include "config.h" // json::array -> std::vector template static void readVector(std::vector& v, const json& j) { v.clear(); v.reserve(j.size()); std::copy(j.begin(), j.end(), std::insert_iterator>(v, v.begin())); } // std::vector -> json::array template static void writeVector(json& j, const std::vector& v) { j = json::array(); std::copy(v.begin(), v.end(), std::insert_iterator(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("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 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& 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; }