EchoMap 2026-07-25 6d3977c
An experimental cross-platform digital signal processing application for sound-source localisation.
Loading...
Searching...
No Matches
JSONDeserialiserHelpers.cpp
Go to the documentation of this file.
1
9
11
12#include "../Project.hpp"
13#include "../Signal.hpp"
14
15namespace echomap
16{
17
18simdjson::error_code JSONDeserialiserHelpers::get_metadata(
19 simdjson::ondemand::object& root,
20 Project& project
21)
22{
23 simdjson::ondemand::object metadata;
24 auto error = root["metadata"].get_object().get(metadata);
25 if (error)
26 return error;
27
28 std::string project_name;
29 if ((error = metadata["name"].get(project_name)))
30 return error;
31
32 project.set_name(project_name);
33 return simdjson::SUCCESS;
34}
35
36simdjson::error_code JSONDeserialiserHelpers::get_sensors(
37 simdjson::ondemand::object& root,
38 Project& project,
39 std::unordered_map<
40 std::string_view,
41 id_type>& loaded
42)
43{
44 std::vector<std::unique_ptr<Sensor>> sensors;
45 if (const auto error = root["sensors"].get(sensors))
46 return error;
47
48 for (auto&& sensor : sensors) {
49 if (!loaded.emplace(sensor->get_name(), sensor->get_id()).second)
50 throw std::runtime_error(std::format("Project contains duplicate sensor {}.", sensor->get_name()));
51 project.add_sensor(std::move(sensor));
52 }
53
54 return simdjson::SUCCESS;
55}
56
57simdjson::error_code JSONDeserialiserHelpers::get_mappings(
58 simdjson::ondemand::object& root,
59 Project& project,
60 const std::unordered_map<
61 std::string_view,
62 id_type>& signals,
63 const std::unordered_map<
64 std::string_view,
65 id_type>& sensors
66)
67{
68 simdjson::ondemand::array mappings;
69 auto error = root["mappings"].get_array().get(mappings);
70 if (error)
71 return error;
72
73 for (auto mapping : mappings) {
74 simdjson::ondemand::object mapping_obj;
75 if ((error = mapping.get_object().get(mapping_obj)))
76 return error;
77
78 std::string_view signal_name;
79 std::string_view sensor_name;
80
81 if ((error = mapping_obj["signal"].get(signal_name)))
82 return error;
83
84 if ((error = mapping_obj["sensor"].get(sensor_name)))
85 return error;
86
87 const auto signal_it = signals.find(signal_name);
88 if (signal_it == signals.end())
89 throw std::runtime_error(std::format("Channel mapping referred to non-existent signal {}.", signal_name));
90
91 const auto sensor_it = sensors.find(sensor_name);
92 if (sensor_it == sensors.end())
93 throw std::runtime_error(std::format("Channel mapping referred to non-existent sensor {}.", sensor_name));
94
95 project.add_association(signal_it->second, sensor_it->second);
96 }
97
98 return simdjson::SUCCESS;
99}
100
101void JSONDeserialiserHelpers::verify_sample_count(
102 std::uint64_t reported_sample_count,
103 const Signal& signal
104)
105{
106 if (reported_sample_count != signal.get_sample_count())
107 throw std::runtime_error(
109 "Embedded signal {} reported the incorrect number of samples: claimed {}, but received {}.",
110 signal.get_name(),
111 reported_sample_count,
112 signal.get_sample_count()
113 )
114 );
115}
116
117simdjson::error_code JSONDeserialiserHelpers::get_uniformly_sampled_signal_source(
118 simdjson::ondemand::object& source,
119 const SignalFactory& signal_factory
120)
121{
122 std::uint64_t reported_sample_count;
123 auto error = source["sample_count"].get(reported_sample_count);
124 if (error)
125 return error;
126
127 std::size_t sample_rate;
128 if ((error = source["sample_rate"].get(sample_rate)))
129 return error;
130 signal_factory.set_sample_rate(sample_rate);
131
132 float time_offset;
133 if ((error = source["time_offset"].get(time_offset)))
134 return error;
135 signal_factory.set_time_offset(time_offset);
136
137 simdjson::ondemand::array samples;
138 if ((error = source["samples"].get_array().get(samples)))
139 return error;
140
141 for (auto sample_wrapper : samples) {
142 float amplitude;
143 if ((error = sample_wrapper.get(amplitude)))
144 return error;
145 signal_factory.emplace_sample(amplitude);
146 }
147
148 verify_sample_count(reported_sample_count, signal_factory.observe_signal());
149 return error;
150}
151
152simdjson::error_code JSONDeserialiserHelpers::get_variably_sampled_signal_source(
153 simdjson::ondemand::object& source,
154 const SignalFactory& signal_factory
155)
156{
157 std::uint64_t reported_sample_count;
158 auto error = source["sample_count"].get(reported_sample_count);
159 if (error)
160 return error;
161
162 std::size_t sample_rate;
163 if ((error = get_or_default(source, "sample_rate", sample_rate, std::size_t{0})))
164 return error;
165 signal_factory.set_sample_rate(sample_rate);
166
167 float time_offset;
168 if ((error = get_or_default(source, "time_offset", time_offset, 0.0f)))
169 return error;
170 signal_factory.set_time_offset(time_offset);
171
172 simdjson::ondemand::array samples;
173 if ((error = source["samples"].get_array().get(samples)))
174 return error;
175
176 for (auto sample_wrapper : samples) {
177 simdjson::ondemand::object sample_obj;
178 if ((error = sample_wrapper.get_object().get(sample_obj)))
179 return error;
180 Signal::Sample sample_data; // NOLINT(*-pro-type-member-init) - Immediately initialised.
181 if ((error = sample_obj["time"].get(sample_data.time)))
182 return error;
183 if ((error = sample_obj["amplitude"].get(sample_data.amplitude)))
184 return error;
185 signal_factory.emplace_sample(sample_data.time, sample_data.amplitude);
186 }
187
188 verify_sample_count(reported_sample_count, signal_factory.observe_signal());
189 return error;
190}
191
192} // namespace echomap
JSONDeserialiserHelpers specification.
Audio signal class specification.
Provides various convenience functions for constructing Signal objects in exotic ways.
A single channel of discretely sampled audio data.
Definition Signal.hpp:40
T format(T... args)
The main EchoMap outermost namespace for all non-exported symbols.
T signal(T... args)