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