EchoMap
2026-07-25 6d3977c
An experimental cross-platform digital signal processing application for sound-source localisation.
Toggle main menu visibility
Loading...
Searching...
No Matches
JSONFullDeserialiser.cpp
1
//
2
// Created by owd on 07/07/2026.
3
4
#if !defined(__EMSCRIPTEN__) || defined(__DOXYGEN__)
5
6
#include "
JSONFullDeserialiser.hpp
"
7
8
#include "
../../../async/Worker.hpp
"
9
#include "
../../../async/tasks/LoadSignalFileTask.hpp
"
10
#include "../../Project.hpp"
11
#include "
../../Signal.hpp
"
12
#include "
../../factories/SignalFactory.hpp
"
13
#include "
../JSONDeserialiserHelpers.hpp
"
14
18
namespace
19
{
20
21
echomap::Worker
* parent_worker =
nullptr
;
22
23
auto
get_signals(
24
simdjson::ondemand::object& root,
25
const
echomap::Project
& project,
26
std::unordered_map
<
27
std::string_view
,
28
echomap::id_type>& loaded
29
)
30
{
31
// Step 1. Create our factories which detain only the signal metadata (sample rate, etc.) and source information.
32
std::vector<std::unique_ptr<echomap::SignalFactory>
> factories;
33
if
(
const
auto
error = root[
"signals"
].get(factories))
34
return
error;
35
36
/*
37
* Step 2. Group the factories by the source filenames of the signals they're constructing.
38
*
39
* The key of the map is the source filename, and the value is a bijective correspondence between the channel in the
40
* wave file and the factory designated to load the channel at the index.
41
*
42
* That is, the first slot owns the factory for constructing the signal on Channel 1, the second for Channel 2, etc.
43
* If there is a gap, the entry is the empty unique_ptr<SignalFactory>, such that it equals nullptr.
44
*/
45
std::unordered_map<std::string, std::vector<std::unique_ptr<echomap::SignalFactory>
>> slots;
46
47
for
(
auto
factory : factories | std::views::as_rvalue) {
48
const
auto
& signal = factory->observe_signal();
49
if
(!loaded.emplace(signal.get_name(), signal.get_id()).second)
50
throw
std::runtime_error
(
std::format
(
"Project contains duplicate signal {}."
, signal.get_name()));
51
52
if
(signal.observe_source().has_value()) {
53
/*
54
* If the Signal has a Source, it comes from the filesystem. Register the Signal as a destination for its
55
* source file for its channel number.
56
*/
57
auto
& slot_vector = slots[signal.observe_source()->path.c_str()];
58
const
auto
channel_num = signal.observe_source()->channel;
59
60
// Reminder: channel numbers are 1-based.
61
if
(channel_num > slot_vector.size())
62
slot_vector.resize(channel_num);
63
else
if
(slot_vector[channel_num - 1] !=
nullptr
)
64
throw
std::runtime_error
(
65
std::format
(
66
"Both signals {} and {} have requested the same channel {} from {}."
,
67
slot_vector[channel_num - 1]->observe_signal().get_name(),
68
signal.get_name(),
69
channel_num,
70
signal.observe_source()->path.c_str()
71
)
72
);
73
74
slot_vector[channel_num - 1] = std::move(factory);
75
}
76
}
77
78
/*
79
* Step 3. Once we have the factories grouped by source, and put into the bijective correspondence with the channel
80
* numbers, submit a task to the thread-safe Worker for each distinct file. The task takes ownership of the
81
* factories.
82
*
83
* The results will own the signal objects produced by the factories, which can be added to the project by the
84
* EchoMap controller (or whoever is the nominated consumer).
85
*/
86
if
(!slots.
empty
()) {
87
if
(parent_worker ==
nullptr
)
88
throw
std::runtime_error
(
89
std::format
(
90
"Need to despatch extra work to load {}, but a suitable Worker is unavailable."
,
91
project.get_name()
92
)
93
);
94
95
for
(
auto
&& [file_path, slot_vector] : slots)
96
parent_worker->submit(
97
std::make_unique<echomap::LoadSignalFileTask>
(project.get_id(), file_path, std::move(slot_vector))
98
);
99
}
100
101
return
simdjson::SUCCESS;
102
}
103
104
}
// namespace
105
106
namespace
simdjson
107
{
108
109
template
<
typename
simdjson_value>
110
auto
tag_invoke(
111
deserialize_tag
/*unused*/
,
112
simdjson_value& value,
113
echomap::Project
& project
114
)
115
{
116
ondemand::object root;
117
auto
error = echomap::JSONDeserialiserHelpers::get_root(root, value);
118
if
(error)
119
return
error;
120
121
// Metadata
122
if
((error = echomap::JSONDeserialiserHelpers::get_metadata(root, project)))
123
return
error;
124
125
// Signals
126
std::unordered_map<std::string_view, echomap::id_type>
signal_ids;
127
if
((error = get_signals(root, project, signal_ids)))
128
return
error;
129
130
// Sensors
131
std::unordered_map<std::string_view, echomap::id_type>
sensor_ids;
132
if
((error = echomap::JSONDeserialiserHelpers::get_sensors(root, project, sensor_ids)))
133
return
error;
134
135
// Channel Map
136
if
((error = echomap::JSONDeserialiserHelpers::get_mappings(root, project, signal_ids, sensor_ids)))
137
return
error;
138
139
return
SUCCESS;
140
}
141
142
}
143
144
namespace
echomap
145
{
146
147
std::unique_ptr<Project> JSONFullDeserialiser::deserialise_project(
148
const
std::filesystem::path& path,
149
Worker
*
const
worker
150
)
151
{
152
parent_worker = worker;
153
const
auto
json = simdjson::padded_string::load(path.
c_str
());
154
auto
doc = parser.iterate(json);
155
auto
project =
std::make_unique<Project>
();
156
157
if
(
const
auto
error = doc.get(*project); error)
158
throw
std::runtime_error(
159
std::format
(
160
"Could not load Project at {} due to error: {}"
,
161
path.
c_str
(),
162
simdjson::error_message(error)
163
)
164
);
165
166
return
project;
167
}
168
169
}
// namespace echomap
170
171
#endif
// __EMSCRIPTEN__
JSONDeserialiserHelpers.hpp
JSONDeserialiserHelpers specification.
JSONFullDeserialiser.hpp
JSONFullDeserialiser specification.
LoadSignalFileTask.hpp
LoadSignalFileTask specification.
SignalFactory.hpp
Wave file specification.
Signal.hpp
Audio signal class specification.
Worker.hpp
Worker specification.
std::string_view
echomap::Project
Definition
Project.hpp:26
echomap::Worker
A Worker provides an encapsulated thread-safe despatch model for submitting work and reviewing result...
Definition
Worker.hpp:45
std::unordered_map::empty
T empty(T... args)
std::format
T format(T... args)
std::make_unique
T make_unique(T... args)
echomap
The main EchoMap outermost namespace for all non-exported symbols.
Definition
ActionController.hpp:20
std::filesystem::path::c_str
T c_str(T... args)
std::runtime_error
std::unordered_map
std::vector
src
objects
persistence
native
JSONFullDeserialiser.cpp
Generated by
1.17.0