Line data Source code
1 : #include <filesystem>
2 : #include <fstream>
3 : #include <iostream>
4 : #include <nlohmann/json.hpp>
5 :
6 : #include "midi/midi_manager.h"
7 :
8 : namespace Amplitron {
9 :
10 : // ---------------------------------------------------------------------------
11 : // Persistence — midi_config.json
12 : // ---------------------------------------------------------------------------
13 :
14 42 : std::string MidiManager::get_config_path() {
15 : #ifdef _WIN32
16 14 : const char* appdata = std::getenv("APPDATA");
17 14 : if (!appdata) return "midi_config.json";
18 28 : std::string dir = std::string(appdata) + "\\Amplitron";
19 14 : try {
20 28 : std::filesystem::create_directories(dir);
21 0 : } catch (...) {
22 : // Ignore errors — will fall back to local path if creation fails
23 0 : }
24 14 : return dir + "\\midi_config.json";
25 : #else
26 28 : const char* home = std::getenv("HOME");
27 28 : if (!home) return "midi_config.json";
28 28 : std::string config_dir = std::string(home) + "/.config/amplitron";
29 : try {
30 28 : std::filesystem::create_directories(config_dir);
31 14 : } catch (...) {
32 : // Ignore errors — will fall back to local path if creation fails
33 0 : }
34 28 : return config_dir + "/midi_config.json";
35 : #endif
36 42 : }
37 :
38 3 : std::string MidiManager::mappings_to_json() const {
39 3 : nlohmann::ordered_json root = nlohmann::ordered_json::object();
40 3 : nlohmann::ordered_json arr = nlohmann::ordered_json::array();
41 :
42 9 : for (const auto& m : mappings_) {
43 6 : nlohmann::ordered_json jm = nlohmann::ordered_json::object();
44 6 : jm["cc"] = m.cc_number;
45 6 : jm["channel"] = m.midi_channel;
46 6 : jm["target"] = static_cast<int>(m.target_type);
47 6 : jm["mode"] = static_cast<int>(m.mode);
48 6 : jm["effect"] = m.effect_name;
49 6 : jm["param"] = m.param_name;
50 6 : arr.push_back(std::move(jm));
51 6 : }
52 :
53 3 : root["mappings"] = std::move(arr);
54 5 : return root.dump(2) + "\n";
55 3 : }
56 :
57 39 : bool MidiManager::mappings_from_json(const std::string& json_str) {
58 39 : mappings_.clear();
59 :
60 13 : try {
61 39 : auto j = nlohmann::json::parse(json_str);
62 :
63 39 : if (!j.contains("mappings") || !j["mappings"].is_array()) {
64 0 : return false;
65 : }
66 :
67 143 : for (const auto& jm : j["mappings"]) {
68 78 : MidiMapping m;
69 78 : m.cc_number = jm.value("cc", 0);
70 78 : m.midi_channel = jm.value("channel", -1);
71 78 : m.target_type = static_cast<MidiTargetType>(jm.value("target", 0));
72 78 : m.mode = static_cast<MidiMappingMode>(jm.value("mode", 0));
73 78 : m.effect_name = jm.value("effect", std::string{});
74 78 : m.param_name = jm.value("param", std::string{});
75 78 : mappings_.push_back(m);
76 78 : }
77 :
78 39 : return true;
79 39 : } catch (const nlohmann::json::exception& e) {
80 0 : std::cerr << "[midi_config] JSON parse error: " << e.what() << std::endl;
81 0 : return false;
82 0 : }
83 13 : }
84 :
85 3 : void MidiManager::save_config() const {
86 3 : std::string path = get_config_path();
87 3 : std::ofstream f(path);
88 3 : if (!f.is_open()) return;
89 4 : f << mappings_to_json();
90 3 : }
91 :
92 39 : void MidiManager::load_config() {
93 39 : std::string path = get_config_path();
94 39 : std::ifstream f(path);
95 39 : if (!f.is_open()) return;
96 :
97 52 : std::string content((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
98 :
99 39 : mappings_from_json(content);
100 39 : }
101 :
102 : } // namespace Amplitron
|