cannam@208: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@208: /* cannam@208: Piper C++ cannam@208: cannam@208: An API for audio analysis and feature extraction plugins. cannam@208: cannam@208: Centre for Digital Music, Queen Mary, University of London. cannam@208: Copyright 2006-2017 Chris Cannam and QMUL. cannam@208: cannam@208: Permission is hereby granted, free of charge, to any person cannam@208: obtaining a copy of this software and associated documentation cannam@208: files (the "Software"), to deal in the Software without cannam@208: restriction, including without limitation the rights to use, copy, cannam@208: modify, merge, publish, distribute, sublicense, and/or sell copies cannam@208: of the Software, and to permit persons to whom the Software is cannam@208: furnished to do so, subject to the following conditions: cannam@208: cannam@208: The above copyright notice and this permission notice shall be cannam@208: included in all copies or substantial portions of the Software. cannam@208: cannam@208: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, cannam@208: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF cannam@208: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND cannam@208: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR cannam@208: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF cannam@208: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION cannam@208: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cannam@208: cannam@208: Except as contained in this notice, the names of the Centre for cannam@208: Digital Music; Queen Mary, University of London; and Chris Cannam cannam@208: shall not be used in advertising or otherwise to promote the sale, cannam@208: use or other dealings in this Software without prior written cannam@208: authorization. cannam@208: */ cannam@208: cannam@208: #ifndef PIPER_AUTO_PLUGIN_H cannam@208: #define PIPER_AUTO_PLUGIN_H cannam@208: cannam@208: #include "ProcessQtTransport.h" cannam@208: #include "../CapnpRRClient.h" cannam@208: #include "../Exceptions.h" cannam@208: cannam@208: #include cannam@208: cannam@208: namespace piper_vamp { cannam@208: namespace client { cannam@208: cannam@208: /** cannam@210: * AutoPlugin presents a Piper feature extractor in the form of a Vamp cannam@210: * plugin, managing its own single-use server instance. That is, the cannam@210: * distinguishing quality of AutoPlugin (in comparison with cannam@210: * PluginStub) is that it runs and terminates its own Piper server, cannam@210: * whose lifetime matches that of the plugin. cannam@210: * cannam@210: * Example usage: cannam@210: * cannam@210: * Vamp::Plugin *plugin = cannam@210: * new AutoPlugin("piper-server-name.exe", cannam@210: * "vamp-example-plugins:zerocrossing", cannam@210: * 44100.0f, cannam@210: * Vamp::HostExt::PluginLoader::ADAPT_ALL_SAFE, cannam@210: * nullptr); cannam@210: * plugin->initialise(...); cannam@210: * plugin->process(...); <-- in the normal way for a Vamp plugin cannam@210: * delete plugin; <-- causes the server to exit cannam@210: * cannam@210: * AutoPlugin makes use of the Loader and PluginClient interfaces, cannam@210: * providing them its own transport layer object for its single server. cannam@208: * cannam@208: * Note that any method may throw ServerCrashed, RequestTimedOut or cannam@208: * ProtocolError exceptions. cannam@208: */ cannam@208: class PiperAutoPlugin : public Vamp::Plugin cannam@208: { cannam@208: public: cannam@210: /** cannam@210: * Construct a PiperAutoPlugin that runs an instance of the Piper cannam@210: * server with the given server name (executable path), requesting cannam@210: * the given plugin key from the server. cannam@210: * cannam@210: * \param adapterFlags a bitwise OR of the values in the cannam@210: * Vamp::HostExt::PluginLoader::AdapterFlags enumeration cannam@210: * cannam@210: * \param logger an optional callback for log messages. Pass a cannam@210: * null pointer to use cerr instead. cannam@210: */ cannam@208: PiperAutoPlugin(std::string serverName, cannam@208: std::string pluginKey, cannam@208: float inputSampleRate, cannam@208: int adapterFlags, cannam@208: LogCallback *logger) : // logger may be nullptr for cerr cannam@208: Vamp::Plugin(inputSampleRate), cannam@208: m_logger(logger), cannam@208: m_transport(serverName, "capnp", logger), cannam@208: m_client(&m_transport, logger) cannam@208: { cannam@208: LoadRequest req; cannam@208: req.pluginKey = pluginKey; cannam@208: req.inputSampleRate = inputSampleRate; cannam@208: req.adapterFlags = adapterFlags; cannam@208: try { cannam@208: LoadResponse resp = m_client.load(req); cannam@208: m_plugin = resp.plugin; cannam@260: } catch (const ServerCrashed &c) { cannam@208: log(std::string("PiperAutoPlugin: Server crashed: ") + c.what()); cannam@208: m_plugin = 0; cannam@208: } cannam@208: } cannam@208: cannam@208: virtual ~PiperAutoPlugin() { cannam@208: delete m_plugin; cannam@210: // The transport is a plain data member and will be deleted cannam@210: // here, which will have the effect of terminating the server cannam@208: } cannam@208: cannam@208: bool isOK() const { cannam@208: return (m_plugin != nullptr); cannam@208: } cannam@208: cannam@280: std::string getIdentifier() const override { cannam@208: return getPlugin()->getIdentifier(); cannam@208: } cannam@208: cannam@280: std::string getName() const override { cannam@208: return getPlugin()->getName(); cannam@208: } cannam@208: cannam@280: std::string getDescription() const override { cannam@208: return getPlugin()->getDescription(); cannam@208: } cannam@208: cannam@280: std::string getMaker() const override { cannam@208: return getPlugin()->getMaker(); cannam@208: } cannam@208: cannam@280: std::string getCopyright() const override { cannam@208: return getPlugin()->getCopyright(); cannam@208: } cannam@208: cannam@280: int getPluginVersion() const override { cannam@208: return getPlugin()->getPluginVersion(); cannam@208: } cannam@208: cannam@280: ParameterList getParameterDescriptors() const override { cannam@208: return getPlugin()->getParameterDescriptors(); cannam@208: } cannam@208: cannam@280: float getParameter(std::string name) const override { cannam@208: return getPlugin()->getParameter(name); cannam@208: } cannam@208: cannam@280: void setParameter(std::string name, float value) override { cannam@208: getPlugin()->setParameter(name, value); cannam@208: } cannam@208: cannam@280: ProgramList getPrograms() const override { cannam@208: return getPlugin()->getPrograms(); cannam@208: } cannam@208: cannam@280: std::string getCurrentProgram() const override { cannam@208: return getPlugin()->getCurrentProgram(); cannam@208: } cannam@208: cannam@280: void selectProgram(std::string program) override { cannam@208: getPlugin()->selectProgram(program); cannam@208: } cannam@208: cannam@280: bool initialise(size_t inputChannels, cannam@208: size_t stepSize, cannam@280: size_t blockSize) override { cannam@208: return getPlugin()->initialise(inputChannels, stepSize, blockSize); cannam@208: } cannam@208: cannam@280: void reset() override { cannam@208: getPlugin()->reset(); cannam@208: } cannam@208: cannam@280: InputDomain getInputDomain() const override { cannam@208: return getPlugin()->getInputDomain(); cannam@208: } cannam@208: cannam@280: size_t getPreferredBlockSize() const override { cannam@208: return getPlugin()->getPreferredBlockSize(); cannam@208: } cannam@208: cannam@280: size_t getPreferredStepSize() const override { cannam@208: return getPlugin()->getPreferredStepSize(); cannam@208: } cannam@208: cannam@280: size_t getMinChannelCount() const override { cannam@208: return getPlugin()->getMinChannelCount(); cannam@208: } cannam@208: cannam@280: size_t getMaxChannelCount() const override { cannam@208: return getPlugin()->getMaxChannelCount(); cannam@208: } cannam@208: cannam@280: OutputList getOutputDescriptors() const override { cannam@208: return getPlugin()->getOutputDescriptors(); cannam@208: } cannam@208: cannam@280: FeatureSet process(const float *const *inputBuffers, cannam@280: Vamp::RealTime timestamp) override { cannam@208: return getPlugin()->process(inputBuffers, timestamp); cannam@208: } cannam@208: cannam@280: FeatureSet getRemainingFeatures() override { cannam@208: return getPlugin()->getRemainingFeatures(); cannam@208: } cannam@208: cannam@208: private: cannam@208: LogCallback *m_logger; cannam@208: ProcessQtTransport m_transport; cannam@208: CapnpRRClient m_client; cannam@208: Vamp::Plugin *m_plugin; cannam@208: Vamp::Plugin *getPlugin() const { cannam@208: if (!m_plugin) { cannam@208: log("PiperAutoPlugin: getPlugin() failed (caller should have called PiperAutoPlugin::isOK)"); cannam@208: throw std::logic_error("Plugin load failed"); cannam@208: } cannam@208: return m_plugin; cannam@208: } cannam@208: cannam@208: void log(std::string message) const { cannam@208: if (m_logger) m_logger->log(message); cannam@208: else std::cerr << message << std::endl; cannam@208: } cannam@208: }; cannam@208: cannam@208: } cannam@208: } cannam@208: cannam@208: #endif cannam@208: cannam@208: