annotate VamPipePluginLibrary.cpp @ 100:708bd44f8019

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