annotate VamPipePluginLibrary.cpp @ 32:30028b3c95e4

Update to match new SDK
author Chris Cannam
date Fri, 23 Sep 2016 14:24:04 +0100
parents e18e15bedd72
children 34480328bf5c
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@30 47 Json
Chris@30 48 convertRequestJson(string input, string &err)
Chris@0 49 {
Chris@0 50 Json j = Json::parse(input, err);
Chris@0 51 if (err != "") {
Chris@30 52 err = "invalid json: " + err;
Chris@30 53 return {};
Chris@0 54 }
Chris@0 55 if (!j.is_object()) {
Chris@30 56 err = "object expected at top level";
Chris@30 57 } else if (!j["type"].is_string()) {
Chris@30 58 err = "string expected for type field";
Chris@30 59 } else if (!j["content"].is_null() && !j["content"].is_object()) {
Chris@30 60 err = "object expected for content field";
Chris@0 61 }
Chris@0 62 return j;
Chris@0 63 }
Chris@0 64
Chris@19 65 VamPipePluginLibrary::VamPipePluginLibrary(vector<VamPipeAdapterInterface *> pp) :
Chris@12 66 m_useBase64(false)
Chris@0 67 {
Chris@19 68 for (VamPipeAdapterInterface *p: pp) {
Chris@0 69 string key = p->getStaticData().pluginKey;
Chris@0 70 m_adapters[key] = p;
Chris@0 71 }
Chris@0 72 }
Chris@0 73
Chris@25 74 Vamp::HostExt::ListResponse
Chris@0 75 VamPipePluginLibrary::listPluginData() const
Chris@0 76 {
Chris@25 77 Vamp::HostExt::ListResponse resp;
Chris@0 78 for (auto a: m_adapters) {
Chris@32 79 resp.plugins.push_back(a.second->getStaticData());
Chris@0 80 }
Chris@25 81 return resp;
Chris@0 82 }
Chris@0 83
Chris@0 84 Vamp::HostExt::LoadResponse
Chris@30 85 VamPipePluginLibrary::loadPlugin(Vamp::HostExt::LoadRequest req, string &err) const
Chris@0 86 {
Chris@0 87 string key = req.pluginKey;
Chris@0 88 if (m_adapters.find(key) != m_adapters.end()) {
Chris@30 89 auto resp = m_adapters.at(key)->loadPlugin(req);
Chris@30 90 if (!resp.plugin) {
Chris@30 91 // This should not actually happen -- the load call here
Chris@30 92 // is just an object construction, not a dynamic load. But
Chris@30 93 // report it if it does...
Chris@30 94 err = "failed to construct plugin with key " + key;
Chris@30 95 }
Chris@30 96 return resp;
Chris@0 97 } else {
Chris@30 98 err = "no adapter for plugin key " + key;
Chris@30 99 return {};
Chris@0 100 }
Chris@0 101 }
Chris@0 102
Chris@0 103 Vamp::HostExt::ConfigurationResponse
Chris@30 104 VamPipePluginLibrary::configurePlugin(Vamp::HostExt::ConfigurationRequest req,
Chris@30 105 string &err) const
Chris@0 106 {
Chris@0 107 for (Vamp::HostExt::PluginConfiguration::ParameterMap::const_iterator i =
Chris@0 108 req.configuration.parameterValues.begin();
Chris@0 109 i != req.configuration.parameterValues.end(); ++i) {
Chris@0 110 req.plugin->setParameter(i->first, i->second);
Chris@0 111 }
Chris@0 112
Chris@0 113 if (req.configuration.currentProgram != "") {
Chris@0 114 req.plugin->selectProgram(req.configuration.currentProgram);
Chris@0 115 }
Chris@0 116
Chris@0 117 Vamp::HostExt::ConfigurationResponse response;
Chris@0 118
Chris@27 119 response.plugin = req.plugin;
Chris@27 120
Chris@0 121 if (req.plugin->initialise(req.configuration.channelCount,
Chris@0 122 req.configuration.stepSize,
Chris@0 123 req.configuration.blockSize)) {
Chris@0 124 response.outputs = req.plugin->getOutputDescriptors();
Chris@30 125 } else {
Chris@30 126 err = "configuration failed (wrong channel count, step size, block size?)";
Chris@0 127 }
Chris@0 128
Chris@0 129 return response;
Chris@0 130 }
Chris@0 131
Chris@0 132 string
Chris@14 133 VamPipePluginLibrary::processRawImpl(int pluginHandle,
Chris@14 134 const float *const *inputBuffers,
Chris@14 135 int sec,
Chris@14 136 int nsec)
Chris@13 137 {
Chris@30 138 Vamp::Plugin *plugin = m_mapper.handleToPlugin(pluginHandle);
Chris@30 139 if (!plugin) {
Chris@30 140 return VampJson::fromError("unknown plugin handle", RRType::Process)
Chris@29 141 .dump();
Chris@13 142 }
Chris@30 143
Chris@30 144 if (!m_mapper.isConfigured(pluginHandle)) {
Chris@30 145 return VampJson::fromError("plugin has not been configured", RRType::Process)
Chris@30 146 .dump();
Chris@30 147 }
Chris@30 148
Chris@30 149 Vamp::RealTime timestamp(sec, nsec);
Chris@30 150
Chris@30 151 Vamp::HostExt::ProcessResponse resp;
Chris@30 152 resp.plugin = plugin;
Chris@30 153 resp.features = plugin->process(inputBuffers, timestamp);
Chris@30 154
Chris@30 155 m_useBase64 = true;
Chris@30 156
Chris@30 157 return VampJson::fromVampResponse_Process
Chris@30 158 (resp, m_mapper,
Chris@30 159 VampJson::BufferSerialisation::Base64)
Chris@30 160 .dump();
Chris@13 161 }
Chris@13 162
Chris@13 163 string
Chris@0 164 VamPipePluginLibrary::requestJsonImpl(string req)
Chris@0 165 {
Chris@30 166 string err;
Chris@30 167
Chris@30 168 Json j = convertRequestJson(req, err);
Chris@30 169 if (err != "") {
Chris@30 170 return VampJson::fromError(err, RRType::NotValid).dump();
Chris@30 171 }
Chris@30 172
Chris@30 173 RRType type = VampJson::getRequestResponseType(j, err);
Chris@30 174 if (err != "") {
Chris@30 175 return VampJson::fromError(err, RRType::NotValid).dump();
Chris@1 176 }
Chris@0 177
Chris@29 178 VampJson::BufferSerialisation serialisation =
Chris@29 179 (m_useBase64 ?
Chris@29 180 VampJson::BufferSerialisation::Base64 :
Chris@29 181 VampJson::BufferSerialisation::Text);
Chris@0 182
Chris@29 183 Json rj;
Chris@29 184
Chris@30 185 switch (type) {
Chris@0 186
Chris@30 187 case RRType::List:
Chris@30 188 rj = VampJson::fromVampResponse_List(listPluginData());
Chris@30 189 break;
Chris@0 190
Chris@30 191 case RRType::Load:
Chris@30 192 {
Chris@30 193 auto req = VampJson::toVampRequest_Load(j, err);
Chris@30 194 if (err != "") {
Chris@30 195 rj = VampJson::fromError(err, type);
Chris@30 196 } else {
Chris@30 197 auto resp = loadPlugin(req, err);
Chris@30 198 if (err != "") {
Chris@30 199 rj = VampJson::fromError(err, type);
Chris@30 200 } else {
Chris@29 201 m_mapper.addPlugin(resp.plugin);
Chris@30 202 rj = VampJson::fromVampResponse_Load(resp, m_mapper);
Chris@29 203 }
Chris@23 204 }
Chris@30 205 break;
Chris@30 206 }
Chris@23 207
Chris@30 208 case RRType::Configure:
Chris@30 209 {
Chris@30 210 auto req = VampJson::toVampRequest_Configure(j, m_mapper, err);
Chris@30 211 if (err != "") {
Chris@30 212 rj = VampJson::fromError(err, type);
Chris@30 213 } else {
Chris@29 214 auto h = m_mapper.pluginToHandle(req.plugin);
Chris@30 215 if (h == m_mapper.INVALID_HANDLE) {
Chris@30 216 rj = VampJson::fromError("unknown or invalid plugin handle", type);
Chris@30 217 } else if (m_mapper.isConfigured(h)) {
Chris@30 218 rj = VampJson::fromError("plugin has already been configured", type);
Chris@30 219 } else {
Chris@30 220 auto resp = configurePlugin(req, err);
Chris@30 221 if (err != "") {
Chris@30 222 rj = VampJson::fromError(err, type);
Chris@30 223 } else {
Chris@30 224 m_mapper.markConfigured(h,
Chris@30 225 req.configuration.channelCount,
Chris@30 226 req.configuration.blockSize);
Chris@30 227 rj = VampJson::fromVampResponse_Configure(resp, m_mapper);
Chris@30 228 }
Chris@29 229 }
Chris@30 230 }
Chris@30 231 break;
Chris@30 232 }
Chris@0 233
Chris@30 234 case RRType::Process:
Chris@30 235 {
Chris@30 236 VampJson::BufferSerialisation serialisation;
Chris@30 237
Chris@30 238 auto req = VampJson::toVampRequest_Process(j, m_mapper,
Chris@30 239 serialisation, err);
Chris@30 240 if (err != "") {
Chris@30 241 rj = VampJson::fromError(err, type);
Chris@30 242 } else {
Chris@30 243 auto h = m_mapper.pluginToHandle(req.plugin);
Chris@30 244 int channels = int(req.inputBuffers.size());
Chris@30 245 if (h == m_mapper.INVALID_HANDLE) {
Chris@30 246 rj = VampJson::fromError("unknown or invalid plugin handle", type);
Chris@30 247 } else if (!m_mapper.isConfigured(h)) {
Chris@30 248 rj = VampJson::fromError("plugin has not been configured", type);
Chris@30 249 } else if (channels != m_mapper.getChannelCount(h)) {
Chris@30 250 rj = VampJson::fromError("wrong number of channels supplied", type);
Chris@30 251 } else {
Chris@30 252
Chris@30 253 if (serialisation == VampJson::BufferSerialisation::Base64) {
Chris@30 254 m_useBase64 = true;
Chris@30 255 }
Chris@30 256
Chris@30 257 size_t blockSize = m_mapper.getBlockSize(h);
Chris@30 258
Chris@30 259 const float **fbuffers = new const float *[channels];
Chris@30 260 for (int i = 0; i < channels; ++i) {
Chris@30 261 if (req.inputBuffers[i].size() != blockSize) {
Chris@30 262 delete[] fbuffers;
Chris@30 263 fbuffers = 0;
Chris@30 264 rj = VampJson::fromError("wrong block size supplied", type);
Chris@30 265 break;
Chris@30 266 }
Chris@30 267 fbuffers[i] = req.inputBuffers[i].data();
Chris@30 268 }
Chris@30 269
Chris@30 270 if (fbuffers) {
Chris@30 271 Vamp::HostExt::ProcessResponse resp;
Chris@30 272 resp.plugin = req.plugin;
Chris@30 273 resp.features = req.plugin->process(fbuffers, req.timestamp);
Chris@30 274 delete[] fbuffers;
Chris@30 275 rj = VampJson::fromVampResponse_Process
Chris@30 276 (resp, m_mapper, serialisation);
Chris@30 277 }
Chris@29 278 }
Chris@30 279 }
Chris@30 280 break;
Chris@30 281 }
Chris@29 282
Chris@30 283 case RRType::Finish:
Chris@30 284 {
Chris@30 285 auto req = VampJson::toVampRequest_Finish(j, m_mapper, err);
Chris@30 286 if (err != "") {
Chris@30 287 rj = VampJson::fromError(err, type);
Chris@30 288 } else {
Chris@30 289 auto h = m_mapper.pluginToHandle(req.plugin);
Chris@30 290 if (h == m_mapper.INVALID_HANDLE) {
Chris@30 291 rj = VampJson::fromError("unknown or invalid plugin handle", type);
Chris@30 292 } else if (!m_mapper.isConfigured(h)) {
Chris@30 293 rj = VampJson::fromError("plugin has not been configured", type);
Chris@30 294 } else {
Chris@30 295
Chris@30 296 Vamp::HostExt::ProcessResponse resp;
Chris@30 297 resp.plugin = req.plugin;
Chris@30 298 resp.features = req.plugin->getRemainingFeatures();
Chris@30 299
Chris@30 300 rj = VampJson::fromVampResponse_Finish
Chris@30 301 (resp, m_mapper, serialisation);
Chris@30 302
Chris@30 303 m_mapper.removePlugin(h);
Chris@30 304 delete req.plugin;
Chris@30 305 }
Chris@29 306 }
Chris@30 307 break;
Chris@30 308 }
Chris@29 309
Chris@30 310 case RRType::NotValid:
Chris@30 311 rj = VampJson::fromError("invalid request", type);
Chris@30 312 break;
Chris@0 313 }
Chris@29 314
Chris@29 315 return rj.dump();
Chris@0 316 }
Chris@0 317
Chris@0 318 }
Chris@0 319