annotate VamPipePluginLibrary.cpp @ 98:22a09aca4b4a

Remove use of excessively bulky RequestOrResponse type, also reducing amount of code the library implementation
author Chris Cannam <c.cannam@qmul.ac.uk>
date Mon, 19 Sep 2016 16:35:05 +0100
parents 95643de89a08
children e18e15bedd72
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@69 47 static Json
c@69 48 convertRequestJson(string input)
c@69 49 {
c@69 50 string err;
c@69 51 Json j = Json::parse(input, err);
c@69 52 if (err != "") {
c@69 53 throw VampJson::Failure("invalid json: " + err);
c@69 54 }
c@69 55 if (!j.is_object()) {
c@69 56 throw VampJson::Failure("object expected at top level");
c@69 57 }
c@69 58 if (!j["type"].is_string()) {
c@69 59 throw VampJson::Failure("string expected for type field");
c@69 60 }
c@71 61 if (!j["content"].is_null() && !j["content"].is_object()) {
c@69 62 throw VampJson::Failure("object expected for content field");
c@69 63 }
c@69 64 return j;
c@69 65 }
c@69 66
c@88 67 VamPipePluginLibrary::VamPipePluginLibrary(vector<VamPipeAdapterInterface *> pp) :
c@81 68 m_useBase64(false)
c@69 69 {
c@88 70 for (VamPipeAdapterInterface *p: pp) {
c@69 71 string key = p->getStaticData().pluginKey;
c@69 72 m_adapters[key] = p;
c@69 73 }
c@69 74 }
c@69 75
c@94 76 Vamp::HostExt::ListResponse
c@69 77 VamPipePluginLibrary::listPluginData() const
c@69 78 {
c@94 79 Vamp::HostExt::ListResponse resp;
c@69 80 for (auto a: m_adapters) {
c@94 81 resp.pluginData.push_back(a.second->getStaticData());
c@69 82 }
c@94 83 return resp;
c@69 84 }
c@69 85
c@69 86 Vamp::HostExt::LoadResponse
c@69 87 VamPipePluginLibrary::loadPlugin(Vamp::HostExt::LoadRequest req) const
c@69 88 {
c@69 89 string key = req.pluginKey;
c@69 90 if (m_adapters.find(key) != m_adapters.end()) {
c@69 91 return m_adapters.at(key)->loadPlugin(req);
c@69 92 } else {
c@69 93 throw runtime_error("no adapter for plugin key " + key);
c@69 94 }
c@69 95 }
c@69 96
c@69 97 Vamp::HostExt::ConfigurationResponse
c@69 98 VamPipePluginLibrary::configurePlugin(Vamp::HostExt::ConfigurationRequest req) const
c@69 99 {
c@69 100 for (Vamp::HostExt::PluginConfiguration::ParameterMap::const_iterator i =
c@69 101 req.configuration.parameterValues.begin();
c@69 102 i != req.configuration.parameterValues.end(); ++i) {
c@69 103 req.plugin->setParameter(i->first, i->second);
c@69 104 }
c@69 105
c@69 106 if (req.configuration.currentProgram != "") {
c@69 107 req.plugin->selectProgram(req.configuration.currentProgram);
c@69 108 }
c@69 109
c@69 110 Vamp::HostExt::ConfigurationResponse response;
c@69 111
c@96 112 response.plugin = req.plugin;
c@96 113
c@69 114 if (req.plugin->initialise(req.configuration.channelCount,
c@69 115 req.configuration.stepSize,
c@69 116 req.configuration.blockSize)) {
c@69 117 response.outputs = req.plugin->getOutputDescriptors();
c@69 118 }
c@69 119
c@69 120 return response;
c@69 121 }
c@69 122
c@69 123 string
c@83 124 VamPipePluginLibrary::processRawImpl(int pluginHandle,
c@83 125 const float *const *inputBuffers,
c@83 126 int sec,
c@83 127 int nsec)
c@82 128 {
c@82 129 try {
c@82 130 if (!m_mapper.isConfigured(pluginHandle)) {
c@82 131 throw runtime_error("plugin has not been configured");
c@82 132 }
c@82 133
c@82 134 Vamp::Plugin *plugin = m_mapper.handleToPlugin(pluginHandle);
c@82 135 Vamp::RealTime timestamp(sec, nsec);
c@92 136
c@98 137 Vamp::HostExt::ProcessResponse resp;
c@98 138 resp.plugin = plugin;
c@98 139 resp.features = plugin->process(inputBuffers, timestamp);
c@98 140
c@98 141 m_useBase64 = true;
c@83 142
c@98 143 return VampJson::fromVampResponse_Process
c@98 144 (resp, m_mapper,
c@98 145 VampJson::BufferSerialisation::Base64)
c@98 146 .dump();
c@82 147
c@82 148 } catch (const std::exception &e) {
c@98 149 return VampJson::fromException(e, RRType::Process)
c@98 150 .dump();
c@82 151 }
c@82 152 }
c@82 153
c@82 154 string
c@69 155 VamPipePluginLibrary::requestJsonImpl(string req)
c@69 156 {
c@98 157 Json j = convertRequestJson(req);
c@70 158
c@98 159 RRType type;
c@70 160 try {
c@98 161 type = VampJson::getRequestResponseType(j);
c@70 162 } catch (const std::exception &e) {
c@98 163 return VampJson::fromException(e, RRType::NotValid)
c@98 164 .dump();
c@70 165 }
c@69 166
c@98 167 VampJson::BufferSerialisation serialisation =
c@98 168 (m_useBase64 ?
c@98 169 VampJson::BufferSerialisation::Base64 :
c@98 170 VampJson::BufferSerialisation::Text);
c@69 171
c@98 172 Json rj;
c@98 173
c@70 174 try {
c@98 175 switch (type) {
c@69 176
c@98 177 case RRType::List:
c@98 178 rj = VampJson::fromVampResponse_List(listPluginData());
c@98 179 break;
c@69 180
c@98 181 case RRType::Load:
c@98 182 {
c@98 183 auto req = VampJson::toVampRequest_Load(j);
c@98 184 auto resp = loadPlugin(req);
c@98 185 if (resp.plugin) {
c@98 186 m_mapper.addPlugin(resp.plugin);
c@98 187 }
c@98 188 rj = VampJson::fromVampResponse_Load(resp, m_mapper);
c@98 189 break;
c@92 190 }
c@92 191
c@98 192 case RRType::Configure:
c@98 193 {
c@98 194 auto req = VampJson::toVampRequest_Configure(j, m_mapper);
c@98 195 auto h = m_mapper.pluginToHandle(req.plugin);
c@98 196 if (m_mapper.isConfigured(h)) {
c@98 197 throw runtime_error("plugin has already been configured");
c@98 198 }
c@69 199
c@98 200 auto resp = configurePlugin(req);
c@98 201 if (!resp.outputs.empty()) {
c@98 202 m_mapper.markConfigured(h,
c@98 203 req.configuration.channelCount,
c@98 204 req.configuration.blockSize);
c@98 205 }
c@98 206
c@98 207 rj = VampJson::fromVampResponse_Configure(resp, m_mapper);
c@98 208 break;
c@98 209 }
c@98 210
c@98 211 case RRType::Process:
c@98 212 {
c@98 213 VampJson::BufferSerialisation serialisation;
c@98 214
c@98 215 auto req = VampJson::toVampRequest_Process(j, m_mapper,
c@98 216 serialisation);
c@98 217
c@98 218 auto h = m_mapper.pluginToHandle(req.plugin);
c@98 219 if (!m_mapper.isConfigured(h)) {
c@98 220 throw runtime_error("plugin has not been configured");
c@98 221 }
c@98 222
c@98 223 int channels = int(req.inputBuffers.size());
c@98 224 if (channels != m_mapper.getChannelCount(h)) {
c@98 225 throw runtime_error("wrong number of channels supplied to process");
c@98 226 }
c@98 227
c@98 228 if (serialisation == VampJson::BufferSerialisation::Base64) {
c@98 229 m_useBase64 = true;
c@98 230 }
c@98 231
c@98 232 const float **fbuffers = new const float *[channels];
c@98 233 for (int i = 0; i < channels; ++i) {
c@98 234 if (int(req.inputBuffers[i].size()) != m_mapper.getBlockSize(h)) {
c@98 235 delete[] fbuffers;
c@98 236 throw runtime_error("wrong block size supplied to process");
c@98 237 }
c@98 238 fbuffers[i] = req.inputBuffers[i].data();
c@98 239 }
c@98 240
c@98 241 Vamp::HostExt::ProcessResponse resp;
c@98 242 resp.plugin = req.plugin;
c@98 243 resp.features = req.plugin->process(fbuffers, req.timestamp);
c@98 244 delete[] fbuffers;
c@98 245
c@98 246 rj = VampJson::fromVampResponse_Process(resp, m_mapper, serialisation);
c@98 247 break;
c@98 248 }
c@98 249
c@98 250 case RRType::Finish:
c@98 251 {
c@98 252 auto req = VampJson::toVampRequest_Finish(j, m_mapper);
c@98 253 auto h = m_mapper.pluginToHandle(req.plugin);
c@98 254 if (!m_mapper.isConfigured(h)) {
c@98 255 throw runtime_error("plugin has not been configured");
c@98 256 }
c@98 257
c@98 258 Vamp::HostExt::ProcessResponse resp;
c@98 259 resp.plugin = req.plugin;
c@98 260 resp.features = req.plugin->getRemainingFeatures();
c@98 261
c@98 262 rj = VampJson::fromVampResponse_Finish(resp, m_mapper, serialisation);
c@98 263
c@98 264 m_mapper.removePlugin(h);
c@98 265 delete req.plugin;
c@98 266 break;
c@98 267 }
c@98 268
c@98 269 case RRType::NotValid:
c@98 270 rj = VampJson::fromError("invalid request", type);
c@98 271 break;
c@98 272 }
c@98 273
c@70 274 } catch (const std::exception &e) {
c@98 275 rj = VampJson::fromException(e, type);
c@69 276 }
c@98 277
c@98 278 return rj.dump();
c@69 279 }
c@69 280
c@69 281 }
c@69 282