Mercurial > hg > piper-vamp-js
comparison VamPipePluginLibrary.cpp @ 0:c226df029ac8
Start on plugin-library-to-json-request-response-handler adapter
author | Chris Cannam |
---|---|
date | Mon, 22 Aug 2016 17:17:28 +0100 |
parents | |
children | 7cfe736fd974 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c226df029ac8 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 VamPipe | |
5 | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 Copyright 2015-2016 QMUL. | |
8 | |
9 Permission is hereby granted, free of charge, to any person | |
10 obtaining a copy of this software and associated documentation | |
11 files (the "Software"), to deal in the Software without | |
12 restriction, including without limitation the rights to use, copy, | |
13 modify, merge, publish, distribute, sublicense, and/or sell copies | |
14 of the Software, and to permit persons to whom the Software is | |
15 furnished to do so, subject to the following conditions: | |
16 | |
17 The above copyright notice and this permission notice shall be | |
18 included in all copies or substantial portions of the Software. | |
19 | |
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR | |
24 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |
25 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
27 | |
28 Except as contained in this notice, the names of the Centre for | |
29 Digital Music; Queen Mary, University of London; and Chris Cannam | |
30 shall not be used in advertising or otherwise to promote the sale, | |
31 use or other dealings in this Software without prior written | |
32 authorization. | |
33 */ | |
34 | |
35 #include "VamPipePluginLibrary.h" | |
36 #include "VamPipeAdapter.h" | |
37 #include "json/VampJson.h" | |
38 | |
39 using namespace std; | |
40 using namespace json11; | |
41 | |
42 namespace vampipe { | |
43 | |
44 //!!! too many explicit namespaces here | |
45 | |
46 //!!! dup with vampipe-convert | |
47 static Json | |
48 convertRequestJson(string input) | |
49 { | |
50 string err; | |
51 Json j = Json::parse(input, err); | |
52 if (err != "") { | |
53 throw VampJson::Failure("invalid json: " + err); | |
54 } | |
55 if (!j.is_object()) { | |
56 throw VampJson::Failure("object expected at top level"); | |
57 } | |
58 if (!j["type"].is_string()) { | |
59 throw VampJson::Failure("string expected for type field"); | |
60 } | |
61 if (!j["content"].is_object()) { | |
62 throw VampJson::Failure("object expected for content field"); | |
63 } | |
64 return j; | |
65 } | |
66 | |
67 VamPipePluginLibrary::VamPipePluginLibrary(vector<VamPipeAdapterBase *> pp) | |
68 { | |
69 for (VamPipeAdapterBase *p: pp) { | |
70 string key = p->getStaticData().pluginKey; | |
71 m_adapters[key] = p; | |
72 } | |
73 } | |
74 | |
75 RequestOrResponse | |
76 VamPipePluginLibrary::readRequest(string req) const | |
77 { | |
78 RequestOrResponse rr; | |
79 rr.direction = RequestOrResponse::Request; | |
80 | |
81 //!!! todo: handle exceptions (can't pass through C abi) | |
82 Json j = convertRequestJson(req); | |
83 | |
84 //!!! reduce, reduce | |
85 rr.type = VampJson::getRequestResponseType(j); | |
86 | |
87 switch (rr.type) { | |
88 | |
89 case RRType::List: | |
90 VampJson::toVampRequest_List(j); // type check only | |
91 break; | |
92 case RRType::Load: | |
93 rr.loadRequest = VampJson::toVampRequest_Load(j); | |
94 break; | |
95 case RRType::Configure: | |
96 rr.configurationRequest = VampJson::toVampRequest_Configure(j, m_mapper); | |
97 break; | |
98 case RRType::Process: | |
99 rr.processRequest = VampJson::toVampRequest_Process(j, m_mapper); | |
100 break; | |
101 case RRType::Finish: | |
102 rr.finishPlugin = VampJson::toVampRequest_Finish(j, m_mapper); | |
103 break; | |
104 case RRType::NotValid: | |
105 break; | |
106 } | |
107 | |
108 return rr; | |
109 } | |
110 | |
111 string | |
112 VamPipePluginLibrary::writeResponse(const RequestOrResponse &rr) const | |
113 { | |
114 Json j; | |
115 | |
116 switch (rr.type) { | |
117 | |
118 case RRType::List: | |
119 j = VampJson::fromVampResponse_List("", rr.listResponse); | |
120 break; | |
121 case RRType::Load: | |
122 j = VampJson::fromVampResponse_Load(rr.loadResponse, m_mapper); | |
123 break; | |
124 case RRType::Configure: | |
125 j = VampJson::fromVampResponse_Configure(rr.configurationResponse); | |
126 break; | |
127 case RRType::Process: | |
128 j = VampJson::fromVampResponse_Process(rr.processResponse); | |
129 break; | |
130 case RRType::Finish: | |
131 j = VampJson::fromVampResponse_Finish(rr.finishResponse); | |
132 break; | |
133 case RRType::NotValid: | |
134 break; | |
135 } | |
136 | |
137 return j.dump(); | |
138 } | |
139 | |
140 vector<Vamp::HostExt::PluginStaticData> | |
141 VamPipePluginLibrary::listPluginData() const | |
142 { | |
143 vector<Vamp::HostExt::PluginStaticData> data; | |
144 for (auto a: m_adapters) { | |
145 data.push_back(a.second->getStaticData()); | |
146 } | |
147 return data; | |
148 } | |
149 | |
150 Vamp::HostExt::LoadResponse | |
151 VamPipePluginLibrary::loadPlugin(Vamp::HostExt::LoadRequest req) const | |
152 { | |
153 string key = req.pluginKey; | |
154 if (m_adapters.find(key) != m_adapters.end()) { | |
155 return m_adapters.at(key)->loadPlugin(req); | |
156 } else { | |
157 throw runtime_error("no adapter for plugin key " + key); | |
158 } | |
159 } | |
160 | |
161 Vamp::HostExt::ConfigurationResponse | |
162 VamPipePluginLibrary::configurePlugin(Vamp::HostExt::ConfigurationRequest req) const | |
163 { | |
164 for (Vamp::HostExt::PluginConfiguration::ParameterMap::const_iterator i = | |
165 req.configuration.parameterValues.begin(); | |
166 i != req.configuration.parameterValues.end(); ++i) { | |
167 req.plugin->setParameter(i->first, i->second); | |
168 } | |
169 | |
170 if (req.configuration.currentProgram != "") { | |
171 req.plugin->selectProgram(req.configuration.currentProgram); | |
172 } | |
173 | |
174 Vamp::HostExt::ConfigurationResponse response; | |
175 | |
176 if (req.plugin->initialise(req.configuration.channelCount, | |
177 req.configuration.stepSize, | |
178 req.configuration.blockSize)) { | |
179 response.outputs = req.plugin->getOutputDescriptors(); | |
180 } | |
181 | |
182 return response; | |
183 } | |
184 | |
185 string | |
186 VamPipePluginLibrary::requestJsonImpl(string req) | |
187 { | |
188 RequestOrResponse request = readRequest(req); | |
189 | |
190 RequestOrResponse response; | |
191 response.direction = RequestOrResponse::Response; | |
192 response.type = request.type; | |
193 | |
194 switch (request.type) { | |
195 | |
196 case RRType::List: | |
197 response.listResponse = listPluginData(); | |
198 response.success = true; | |
199 break; | |
200 | |
201 case RRType::Load: | |
202 response.loadResponse = loadPlugin(request.loadRequest); | |
203 if (response.loadResponse.plugin) { | |
204 m_mapper.addPlugin(response.loadResponse.plugin); | |
205 response.success = true; | |
206 } | |
207 break; | |
208 | |
209 case RRType::Configure: | |
210 { | |
211 auto &creq = request.configurationRequest; | |
212 auto h = m_mapper.pluginToHandle(creq.plugin); | |
213 if (m_mapper.isConfigured(h)) { | |
214 //!!! again, can't return through C abi | |
215 throw runtime_error("plugin has already been configured"); | |
216 } | |
217 | |
218 response.configurationResponse = configurePlugin(creq); | |
219 | |
220 if (!response.configurationResponse.outputs.empty()) { | |
221 m_mapper.markConfigured | |
222 (h, creq.configuration.channelCount, creq.configuration.blockSize); | |
223 response.success = true; | |
224 } | |
225 break; | |
226 } | |
227 | |
228 case RRType::Process: | |
229 { | |
230 auto &preq = request.processRequest; | |
231 auto h = m_mapper.pluginToHandle(preq.plugin); | |
232 if (!m_mapper.isConfigured(h)) { | |
233 throw runtime_error("plugin has not been configured"); | |
234 } | |
235 | |
236 int channels = int(preq.inputBuffers.size()); | |
237 if (channels != m_mapper.getChannelCount(h)) { | |
238 throw runtime_error("wrong number of channels supplied to process"); | |
239 } | |
240 | |
241 const float **fbuffers = new const float *[channels]; | |
242 for (int i = 0; i < channels; ++i) { | |
243 if (int(preq.inputBuffers[i].size()) != m_mapper.getBlockSize(h)) { | |
244 delete[] fbuffers; | |
245 throw runtime_error("wrong block size supplied to process"); | |
246 } | |
247 fbuffers[i] = preq.inputBuffers[i].data(); | |
248 } | |
249 | |
250 response.processResponse.features = | |
251 preq.plugin->process(fbuffers, preq.timestamp); | |
252 response.success = true; | |
253 | |
254 delete[] fbuffers; | |
255 break; | |
256 } | |
257 | |
258 case RRType::Finish: | |
259 { | |
260 auto h = m_mapper.pluginToHandle(request.finishPlugin); | |
261 | |
262 response.finishResponse.features = | |
263 request.finishPlugin->getRemainingFeatures(); | |
264 | |
265 m_mapper.removePlugin(h); | |
266 delete request.finishPlugin; | |
267 response.success = true; | |
268 break; | |
269 } | |
270 | |
271 case RRType::NotValid: | |
272 break; | |
273 } | |
274 | |
275 return writeResponse(response); | |
276 } | |
277 | |
278 } | |
279 |