annotate VamPipePluginLibrary.cpp @ 2:4d6e60a7c80e

Some JSON fixes and a quick test program
author Chris Cannam
date Tue, 23 Aug 2016 12:04:49 +0100
parents 7cfe736fd974
children 6a792d8838c9
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@0 67 VamPipePluginLibrary::VamPipePluginLibrary(vector<VamPipeAdapterBase *> pp)
Chris@0 68 {
Chris@0 69 for (VamPipeAdapterBase *p: pp) {
Chris@0 70 string key = p->getStaticData().pluginKey;
Chris@0 71 m_adapters[key] = p;
Chris@0 72 }
Chris@0 73 }
Chris@0 74
Chris@0 75 RequestOrResponse
Chris@0 76 VamPipePluginLibrary::readRequest(string req) const
Chris@0 77 {
Chris@0 78 RequestOrResponse rr;
Chris@0 79 rr.direction = RequestOrResponse::Request;
Chris@0 80
Chris@0 81 Json j = convertRequestJson(req);
Chris@0 82
Chris@0 83 //!!! reduce, reduce
Chris@0 84 rr.type = VampJson::getRequestResponseType(j);
Chris@0 85
Chris@0 86 switch (rr.type) {
Chris@0 87
Chris@0 88 case RRType::List:
Chris@0 89 VampJson::toVampRequest_List(j); // type check only
Chris@0 90 break;
Chris@0 91 case RRType::Load:
Chris@0 92 rr.loadRequest = VampJson::toVampRequest_Load(j);
Chris@0 93 break;
Chris@0 94 case RRType::Configure:
Chris@0 95 rr.configurationRequest = VampJson::toVampRequest_Configure(j, m_mapper);
Chris@0 96 break;
Chris@0 97 case RRType::Process:
Chris@0 98 rr.processRequest = VampJson::toVampRequest_Process(j, m_mapper);
Chris@0 99 break;
Chris@0 100 case RRType::Finish:
Chris@0 101 rr.finishPlugin = VampJson::toVampRequest_Finish(j, m_mapper);
Chris@0 102 break;
Chris@0 103 case RRType::NotValid:
Chris@0 104 break;
Chris@0 105 }
Chris@0 106
Chris@0 107 return rr;
Chris@0 108 }
Chris@0 109
Chris@0 110 string
Chris@0 111 VamPipePluginLibrary::writeResponse(const RequestOrResponse &rr) const
Chris@0 112 {
Chris@0 113 Json j;
Chris@0 114
Chris@0 115 switch (rr.type) {
Chris@0 116
Chris@0 117 case RRType::List:
Chris@0 118 j = VampJson::fromVampResponse_List("", rr.listResponse);
Chris@0 119 break;
Chris@0 120 case RRType::Load:
Chris@0 121 j = VampJson::fromVampResponse_Load(rr.loadResponse, m_mapper);
Chris@0 122 break;
Chris@0 123 case RRType::Configure:
Chris@0 124 j = VampJson::fromVampResponse_Configure(rr.configurationResponse);
Chris@0 125 break;
Chris@0 126 case RRType::Process:
Chris@0 127 j = VampJson::fromVampResponse_Process(rr.processResponse);
Chris@0 128 break;
Chris@0 129 case RRType::Finish:
Chris@0 130 j = VampJson::fromVampResponse_Finish(rr.finishResponse);
Chris@0 131 break;
Chris@0 132 case RRType::NotValid:
Chris@0 133 break;
Chris@0 134 }
Chris@0 135
Chris@0 136 return j.dump();
Chris@0 137 }
Chris@0 138
Chris@0 139 vector<Vamp::HostExt::PluginStaticData>
Chris@0 140 VamPipePluginLibrary::listPluginData() const
Chris@0 141 {
Chris@0 142 vector<Vamp::HostExt::PluginStaticData> data;
Chris@0 143 for (auto a: m_adapters) {
Chris@0 144 data.push_back(a.second->getStaticData());
Chris@0 145 }
Chris@0 146 return data;
Chris@0 147 }
Chris@0 148
Chris@0 149 Vamp::HostExt::LoadResponse
Chris@0 150 VamPipePluginLibrary::loadPlugin(Vamp::HostExt::LoadRequest req) const
Chris@0 151 {
Chris@0 152 string key = req.pluginKey;
Chris@0 153 if (m_adapters.find(key) != m_adapters.end()) {
Chris@0 154 return m_adapters.at(key)->loadPlugin(req);
Chris@0 155 } else {
Chris@0 156 throw runtime_error("no adapter for plugin key " + key);
Chris@0 157 }
Chris@0 158 }
Chris@0 159
Chris@0 160 Vamp::HostExt::ConfigurationResponse
Chris@0 161 VamPipePluginLibrary::configurePlugin(Vamp::HostExt::ConfigurationRequest req) const
Chris@0 162 {
Chris@0 163 for (Vamp::HostExt::PluginConfiguration::ParameterMap::const_iterator i =
Chris@0 164 req.configuration.parameterValues.begin();
Chris@0 165 i != req.configuration.parameterValues.end(); ++i) {
Chris@0 166 req.plugin->setParameter(i->first, i->second);
Chris@0 167 }
Chris@0 168
Chris@0 169 if (req.configuration.currentProgram != "") {
Chris@0 170 req.plugin->selectProgram(req.configuration.currentProgram);
Chris@0 171 }
Chris@0 172
Chris@0 173 Vamp::HostExt::ConfigurationResponse response;
Chris@0 174
Chris@0 175 if (req.plugin->initialise(req.configuration.channelCount,
Chris@0 176 req.configuration.stepSize,
Chris@0 177 req.configuration.blockSize)) {
Chris@0 178 response.outputs = req.plugin->getOutputDescriptors();
Chris@0 179 }
Chris@0 180
Chris@0 181 return response;
Chris@0 182 }
Chris@0 183
Chris@0 184 string
Chris@0 185 VamPipePluginLibrary::requestJsonImpl(string req)
Chris@0 186 {
Chris@1 187 RequestOrResponse request;
Chris@1 188
Chris@1 189 try {
Chris@1 190 request = readRequest(req);
Chris@1 191 } catch (const std::exception &e) {
Chris@1 192 return VampJson::fromException(e, RRType::NotValid).dump();
Chris@1 193 }
Chris@0 194
Chris@0 195 RequestOrResponse response;
Chris@0 196 response.direction = RequestOrResponse::Response;
Chris@0 197 response.type = request.type;
Chris@0 198
Chris@1 199 try {
Chris@1 200 switch (request.type) {
Chris@0 201
Chris@1 202 case RRType::List:
Chris@1 203 response.listResponse = listPluginData();
Chris@1 204 response.success = true;
Chris@1 205 break;
Chris@0 206
Chris@1 207 case RRType::Load:
Chris@1 208 response.loadResponse = loadPlugin(request.loadRequest);
Chris@1 209 if (response.loadResponse.plugin) {
Chris@1 210 m_mapper.addPlugin(response.loadResponse.plugin);
Chris@1 211 response.success = true;
Chris@1 212 }
Chris@1 213 break;
Chris@0 214
Chris@1 215 case RRType::Configure:
Chris@1 216 {
Chris@1 217 auto &creq = request.configurationRequest;
Chris@1 218 auto h = m_mapper.pluginToHandle(creq.plugin);
Chris@1 219 if (m_mapper.isConfigured(h)) {
Chris@1 220 //!!! again, can't return through C abi
Chris@1 221 throw runtime_error("plugin has already been configured");
Chris@1 222 }
Chris@1 223
Chris@1 224 response.configurationResponse = configurePlugin(creq);
Chris@1 225
Chris@1 226 if (!response.configurationResponse.outputs.empty()) {
Chris@1 227 m_mapper.markConfigured
Chris@1 228 (h, creq.configuration.channelCount, creq.configuration.blockSize);
Chris@1 229 response.success = true;
Chris@1 230 }
Chris@1 231 break;
Chris@0 232 }
Chris@0 233
Chris@1 234 case RRType::Process:
Chris@1 235 {
Chris@1 236 auto &preq = request.processRequest;
Chris@1 237 auto h = m_mapper.pluginToHandle(preq.plugin);
Chris@1 238 if (!m_mapper.isConfigured(h)) {
Chris@1 239 throw runtime_error("plugin has not been configured");
Chris@1 240 }
Chris@1 241
Chris@1 242 int channels = int(preq.inputBuffers.size());
Chris@1 243 if (channels != m_mapper.getChannelCount(h)) {
Chris@1 244 throw runtime_error("wrong number of channels supplied to process");
Chris@1 245 }
Chris@1 246
Chris@1 247 const float **fbuffers = new const float *[channels];
Chris@1 248 for (int i = 0; i < channels; ++i) {
Chris@1 249 if (int(preq.inputBuffers[i].size()) != m_mapper.getBlockSize(h)) {
Chris@1 250 delete[] fbuffers;
Chris@1 251 throw runtime_error("wrong block size supplied to process");
Chris@1 252 }
Chris@1 253 fbuffers[i] = preq.inputBuffers[i].data();
Chris@1 254 }
Chris@1 255
Chris@1 256 response.processResponse.features =
Chris@1 257 preq.plugin->process(fbuffers, preq.timestamp);
Chris@0 258 response.success = true;
Chris@0 259
Chris@1 260 delete[] fbuffers;
Chris@1 261 break;
Chris@0 262 }
Chris@0 263
Chris@1 264 case RRType::Finish:
Chris@1 265 {
Chris@1 266 auto h = m_mapper.pluginToHandle(request.finishPlugin);
Chris@1 267
Chris@1 268 response.finishResponse.features =
Chris@1 269 request.finishPlugin->getRemainingFeatures();
Chris@1 270
Chris@1 271 m_mapper.removePlugin(h);
Chris@1 272 delete request.finishPlugin;
Chris@1 273 response.success = true;
Chris@1 274 break;
Chris@0 275 }
Chris@0 276
Chris@1 277 case RRType::NotValid:
Chris@1 278 break;
Chris@1 279 }
Chris@1 280
Chris@1 281 return writeResponse(response);
Chris@0 282
Chris@1 283 } catch (const std::exception &e) {
Chris@1 284 return VampJson::fromException(e, request.type).dump();
Chris@0 285 }
Chris@0 286 }
Chris@0 287
Chris@0 288 }
Chris@0 289