From 330e69b5652676653d4c49d33e503617ad476194 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Mon, 3 Oct 2016 03:51:53 +0200 Subject: Add Vamp-plugin Lua bindings (work in progress) --- libs/ardour/ardour/lua_api.h | 65 +++++++++++++++++++++++ libs/ardour/lua_api.cc | 98 +++++++++++++++++++++++++++++++++- libs/ardour/luabindings.cc | 123 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 285 insertions(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/ardour/ardour/lua_api.h b/libs/ardour/ardour/lua_api.h index bfe2e16283..85fe92f28c 100644 --- a/libs/ardour/ardour/lua_api.h +++ b/libs/ardour/ardour/lua_api.h @@ -22,12 +22,17 @@ #include #include #include +#include #include "ardour/libardour_visibility.h" #include "ardour/processor.h" #include "ardour/session.h" +namespace ARDOUR { + class Readable; +} + namespace ARDOUR { namespace LuaAPI { /** convenience constructor for DataType::NIL with managed lifetime @@ -157,6 +162,66 @@ namespace ARDOUR { namespace LuaAPI { */ int build_filename (lua_State *lua); + class Vamp { + /** Vamp Plugin Interface + * + * Vamp is an audio processing plugin system for plugins that extract descriptive information + * from audio data - typically referred to as audio analysis plugins or audio feature + * extraction plugins. + * + * This interface allows to load a plugins and directly access it using the Vamp Plugin API. + * + * A convenience method is provided to analyze Ardour::Readable objects (Regions). + */ + public: + Vamp (const std::string&, float sample_rate); + ~Vamp (); + ::Vamp::Plugin* plugin () { return _plugin; } + + /* high-level abstraction to process a single channel of the given Readable. + * + * If the plugin is not yet initialized, initialize() is called. + * + * if @cb is not nil, it is called with the immediate + * Vamp::Plugin::Features on every process call. + * + * @r readable + * @channel channel to process + * @cb lua callback function + * @return 0 on success + */ + int analyze (boost::shared_ptr, uint32_t channel, luabridge::LuaRef fn); + + /** call plugin():reset() and clear intialization flag */ + void reset (); + + /** initialize the plugin for use with analyze(). + * + * This is equivalent to plugin():initialise (1, 8192, 8192) + * and prepares a plugin for analyze. + * + * Manual initialization is only required to set plugin-parameters + * which depend on prior initialization of the plugin. + * + * @code + * vamp:reset () + * vamp:initialize () + * vamp:plugin():setParameter (0, 1.5) + * vamp:analyze (r, 0) + * @endcode + */ + bool initialize (); + + bool initialized () const { return _initialized; } + + private: + ::Vamp::Plugin* _plugin; + float _sample_rate; + framecnt_t _bufsize; + bool _initialized; + + }; + } } /* namespace */ namespace ARDOUR { namespace LuaOSC { diff --git a/libs/ardour/lua_api.cc b/libs/ardour/lua_api.cc index 201ca7de0e..2f6c995851 100644 --- a/libs/ardour/lua_api.cc +++ b/libs/ardour/lua_api.cc @@ -17,9 +17,11 @@ * */ #include +#include -#include "pbd/error.h" #include "pbd/compose.h" +#include "pbd/error.h" +#include "pbd/failed_constructor.h" #include "ardour/lua_api.h" #include "ardour/luaproc.h" @@ -27,6 +29,7 @@ #include "ardour/plugin.h" #include "ardour/plugin_insert.h" #include "ardour/plugin_manager.h" +#include "ardour/readable.h" #include "LuaBridge/LuaBridge.h" @@ -535,3 +538,96 @@ void LuaTableRef::assign (luabridge::LuaRef* rv, T key, const LuaTableEntry& s) break; } } + + +LuaAPI::Vamp::Vamp (const std::string& key, float sample_rate) + : _plugin (0) + , _sample_rate (sample_rate) + , _bufsize (8192) + , _initialized (false) +{ + using namespace ::Vamp::HostExt; + + PluginLoader* loader (PluginLoader::getInstance()); + _plugin = loader->loadPlugin (key, _sample_rate, PluginLoader::ADAPT_ALL_SAFE); + + if (!_plugin) { + PBD::error << string_compose (_("VAMP Plugin \"%1\" could not be loaded"), key) << endmsg; + throw failed_constructor (); + } +} + +LuaAPI::Vamp::~Vamp () +{ + delete _plugin; +} + +void +LuaAPI::Vamp::reset () +{ + _initialized = false; + if (_plugin) { + _plugin->reset (); + } +} + +bool +LuaAPI::Vamp::initialize () +{ + if (!_plugin || _plugin->getMinChannelCount() > 1) { + return false; + } + if (!_plugin->initialise (1, _bufsize, _bufsize)) { + return false; + } + _initialized = true; + return true; +} + +int +LuaAPI::Vamp::analyze (boost::shared_ptr r, uint32_t channel, luabridge::LuaRef cb) +{ + if (!_initialized) { + if (!initialize ()) { + return -1; + } + } + assert (_initialized); + + ::Vamp::Plugin::FeatureSet features; + float* data = new float[_bufsize]; + float* bufs[1] = { data }; + + framecnt_t len = r->readable_length(); + framepos_t pos = 0; + + int rv = 0; + while (1) { + framecnt_t to_read = std::min ((len - pos), _bufsize); + if (r->read (data, pos, to_read, channel) != to_read) { + rv = -1; + break; + } + if (to_read != _bufsize) { + memset (data + to_read, 0, (_bufsize - to_read) * sizeof (float)); + } + + features = _plugin->process (bufs, ::Vamp::RealTime::fromSeconds ((double) pos / _sample_rate)); + + if (cb.type () == LUA_TFUNCTION) { + /* TODO existing "features" binding fails here + * std::map > + */ + // cb (features, pos); // XXX + } + + pos += to_read; + + if (pos >= len) { + break; + } + } + + delete [] data; + return rv; +} diff --git a/libs/ardour/luabindings.cc b/libs/ardour/luabindings.cc index 096c0647ae..59e64d3a86 100644 --- a/libs/ardour/luabindings.cc +++ b/libs/ardour/luabindings.cc @@ -32,6 +32,7 @@ #include "ardour/audio_buffer.h" #include "ardour/audio_port.h" #include "ardour/audio_track.h" +#include "ardour/audioplaylist.h" #include "ardour/buffer_set.h" #include "ardour/chan_mapping.h" #include "ardour/dB.h" @@ -239,6 +240,10 @@ LuaBindings::stddef (lua_State* L) .beginStdVector ("StringVector") .endClass () + // std::vector + .beginStdVector ("FloatVector") + .endClass () + // register float array (uint8_t*) .registerArray ("ByteArray") @@ -437,6 +442,103 @@ LuaBindings::common (lua_State* L) .endNamespace () // Evoral + .beginNamespace ("Vamp") + + .beginClass ("RealTime") + .addConstructor () + .addFunction ("usec", &Vamp::RealTime::usec) + .addFunction ("msec", &Vamp::RealTime::msec) + .addFunction ("toString", &Vamp::RealTime::toString) + .endClass () + + .beginClass ("PluginBase") + .addFunction ("getIdentifier", &Vamp::PluginBase::getIdentifier) + .addFunction ("getName", &Vamp::PluginBase::getName) + .addFunction ("getDescription", &Vamp::PluginBase::getDescription) + .addFunction ("getMaker", &Vamp::PluginBase::getMaker) + .addFunction ("getCopyright", &Vamp::PluginBase::getCopyright) + .addFunction ("getPluginVersion", &Vamp::PluginBase::getPluginVersion) + .addFunction ("getParameterDescriptors", &Vamp::PluginBase::getParameterDescriptors) + .addFunction ("getParameter", &Vamp::PluginBase::getParameter) + .addFunction ("setParameter", &Vamp::PluginBase::setParameter) + .addFunction ("getPrograms", &Vamp::PluginBase::getPrograms) + .addFunction ("getCurrentProgram", &Vamp::PluginBase::getCurrentProgram) + .addFunction ("selectProgram", &Vamp::PluginBase::selectProgram) + .addFunction ("getType", &Vamp::PluginBase::getType) + .endClass () + + .beginNamespace ("PluginBase") + .beginClass ("ParameterDescriptor") + .addData ("identifier", &Vamp::PluginBase::ParameterDescriptor::identifier) + .addData ("name", &Vamp::PluginBase::ParameterDescriptor::name) + .addData ("description", &Vamp::PluginBase::ParameterDescriptor::description) + .addData ("unit", &Vamp::PluginBase::ParameterDescriptor::unit) + .addData ("minValue", &Vamp::PluginBase::ParameterDescriptor::minValue) + .addData ("maxValue", &Vamp::PluginBase::ParameterDescriptor::maxValue) + .addData ("defaultValue", &Vamp::PluginBase::ParameterDescriptor::defaultValue) + .addData ("isQuantized", &Vamp::PluginBase::ParameterDescriptor::isQuantized) + .addData ("quantizeStep", &Vamp::PluginBase::ParameterDescriptor::quantizeStep) + .addData ("valueNames", &Vamp::PluginBase::ParameterDescriptor::valueNames) + .endClass () + + .beginStdVector ("ParameterList") + .endClass () + .endNamespace () // Vamp::PluginBase + + .deriveClass ("Plugin") + // TODO add wrapper std::vector + .addFunction ("process", &Vamp::Plugin::process) // XXX unusable due to float * const * + .addFunction ("getRemainingFeatures", &Vamp::Plugin::getRemainingFeatures) + .endClass () + + .beginNamespace ("Plugin") + .beginClass ("OutputDescriptor") + .addData ("identifier", &Vamp::Plugin::OutputDescriptor::identifier) + .addData ("description", &Vamp::Plugin::OutputDescriptor::description) + .addData ("unit", &Vamp::Plugin::OutputDescriptor::unit) + .addData ("hasFixedBinCount", &Vamp::Plugin::OutputDescriptor::hasFixedBinCount) + .addData ("binCount", &Vamp::Plugin::OutputDescriptor::binCount) + .addData ("binNames", &Vamp::Plugin::OutputDescriptor::binNames) + .addData ("hasKnownExtents", &Vamp::Plugin::OutputDescriptor::hasKnownExtents) + .addData ("minValue", &Vamp::Plugin::OutputDescriptor::minValue) + .addData ("maxValue", &Vamp::Plugin::OutputDescriptor::maxValue) + .addData ("isQuantized", &Vamp::Plugin::OutputDescriptor::isQuantized) + .addData ("quantizeStep", &Vamp::Plugin::OutputDescriptor::quantizeStep) + .addData ("sampleType", &Vamp::Plugin::OutputDescriptor::sampleType) + .addData ("sampleRate", &Vamp::Plugin::OutputDescriptor::sampleRate) + .addData ("hasDuration", &Vamp::Plugin::OutputDescriptor::hasDuration) + .endClass () + + .beginNamespace ("OutputDescriptor") + /* Vamp::Plugin::OutputDescriptor enum */ + .beginNamespace ("SampleType") + .addConst ("OneSamplePerStep", Vamp::Plugin::OutputDescriptor::SampleType(Vamp::Plugin::OutputDescriptor::OneSamplePerStep)) + .addConst ("FixedSampleRate", Vamp::Plugin::OutputDescriptor::SampleType(Vamp::Plugin::OutputDescriptor::FixedSampleRate)) + .addConst ("VariableSampleRate", Vamp::Plugin::OutputDescriptor::SampleType(Vamp::Plugin::OutputDescriptor::VariableSampleRate)) + .endNamespace () + .endNamespace () /* Vamp::Plugin::OutputDescriptor */ + + .beginClass ("Feature") + .addData ("hasTimestamp", &Vamp::Plugin::Feature::hasTimestamp, false) + .addData ("timestamp", &Vamp::Plugin::Feature::timestamp, false) + .addData ("hasDuration", &Vamp::Plugin::Feature::hasDuration, false) + .addData ("duration", &Vamp::Plugin::Feature::duration, false) + .addData ("values", &Vamp::Plugin::Feature::values, false) + .addData ("label", &Vamp::Plugin::Feature::label, false) + .endClass () + + .beginStdVector ("OutputList") + .endClass () + + .beginStdVector ("FeatureList") + .endClass () + + .beginStdMap ("FeatureSet") + .endClass () + + .endNamespace () // Vamp::Plugin + .endNamespace () // Vamp + .beginNamespace ("ARDOUR") .beginClass ("InterThreadInfo") @@ -712,6 +814,7 @@ LuaBindings::common (lua_State* L) .endClass () .deriveWSPtrClass ("Playlist") + .addCast ("to_audioplaylist") .addFunction ("region_by_id", &Playlist::region_by_id) .addFunction ("data_type", &Playlist::data_type) .addFunction ("n_regions", &Playlist::n_regions) @@ -746,6 +849,10 @@ LuaBindings::common (lua_State* L) #endif .endClass () + .deriveWSPtrClass ("AudioPlaylist") + .addFunction ("read", &AudioPlaylist::read) + .endClass () + .deriveWSPtrClass ("Track") .addCast ("to_audio_track") .addCast ("to_midi_track") @@ -763,7 +870,14 @@ LuaBindings::common (lua_State* L) .deriveWSPtrClass ("MidiTrack") .endClass () + .beginWSPtrClass ("Readable") + .addFunction ("read", &Readable::read) + .addFunction ("readable_length", &Readable::readable_length) + .addFunction ("n_channels", &Readable::n_channels) + .endClass () + .deriveWSPtrClass ("Region") + .addCast ("to_readable") /* properties */ .addFunction ("position", &Region::position) .addFunction ("start", &Region::start) @@ -1472,6 +1586,15 @@ LuaBindings::common (lua_State* L) .addCFunction ("hsla_to_rgba", ARDOUR::LuaAPI::hsla_to_rgba) .addFunction ("usleep", Glib::usleep) .addCFunction ("build_filename", ARDOUR::LuaAPI::build_filename) + + .beginClass ("Vamp") + .addConstructor () + .addFunction ("plugin", &ARDOUR::LuaAPI::Vamp::plugin) + .addFunction ("analyze", &ARDOUR::LuaAPI::Vamp::analyze) + .addFunction ("reset", &ARDOUR::LuaAPI::Vamp::reset) + .addFunction ("initialize", &ARDOUR::LuaAPI::Vamp::initialize) + .endClass () + .endNamespace () // end LuaAPI .endNamespace ();// end ARDOUR } -- cgit v1.2.3