annotate VamPipePluginLibrary.cpp @ 21:22e100563c4d

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