From 7dd771da2752cb3d012575869d905ba1f77697bf Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 12 Feb 2011 09:11:17 +0000 Subject: Add C++ and Python bindings. git-svn-id: http://svn.drobilla.net/lad/trunk/slv2@2940 a436a847-0d15-0410-975c-d299462d15a1 --- slv2/slv2.h | 2 +- slv2/slv2mm.hpp | 157 ++++++++++++++++++++++++++++++++++++++++++++++++ swig/python/lv2_list.py | 14 +++-- swig/slv2.i | 137 +++++++----------------------------------- wscript | 26 +++++++- 5 files changed, 213 insertions(+), 123 deletions(-) create mode 100644 slv2/slv2mm.hpp diff --git a/slv2/slv2.h b/slv2/slv2.h index 2817fac..45fe597 100644 --- a/slv2/slv2.h +++ b/slv2/slv2.h @@ -842,7 +842,7 @@ SLV2_API void slv2_port_get_range(SLV2Plugin plugin, SLV2Port port, - SLV2Value* def, + SLV2Value* deflt, SLV2Value* min, SLV2Value* max); diff --git a/slv2/slv2mm.hpp b/slv2/slv2mm.hpp new file mode 100644 index 0000000..f41c2f8 --- /dev/null +++ b/slv2/slv2mm.hpp @@ -0,0 +1,157 @@ +/* SLV2 + * Copyright (C) 2007-2011 David Robillard + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef SLV2_SLV2MM_HPP__ +#define SLV2_SLV2MM_HPP__ + +#include "slv2/slv2.h" + +namespace SLV2 { + +const char* uri_to_path(const char* uri) { return slv2_uri_to_path(uri); } + +class Value { +public: + inline Value(SLV2Value value) : me(value) {} + inline Value(const Value& copy) : me(slv2_value_duplicate(copy.me)) {} + + inline ~Value() { slv2_value_free(me); } + + inline bool equals(const Value& other) const { + return slv2_value_equals(me, other.me); + } + + inline bool operator==(const Value& other) const { return equals(other); } + + inline operator SLV2Value() const { return me; } + +#define VAL_WRAP0(RetType, name) \ + inline RetType name () { return slv2_value_ ## name (me); } + + VAL_WRAP0(char*, get_turtle_token); + VAL_WRAP0(bool, is_uri); + VAL_WRAP0(const char*, as_uri); + VAL_WRAP0(bool, is_blank); + VAL_WRAP0(const char*, as_blank); + VAL_WRAP0(bool, is_literal); + VAL_WRAP0(bool, is_string); + VAL_WRAP0(const char*, as_string); + VAL_WRAP0(bool, is_float); + VAL_WRAP0(float, as_float); + VAL_WRAP0(bool, is_int); + VAL_WRAP0(int, as_int); + VAL_WRAP0(bool, is_bool); + VAL_WRAP0(bool, as_bool); + + SLV2Value me; +}; + +class Plugins { +public: + inline Plugins(SLV2Plugins c_obj) : me(c_obj) {} + + inline operator SLV2Plugins() const { return me; } + + SLV2Plugins me; +}; + +class World { +public: + inline World() : me(slv2_world_new()) {} + + inline ~World() { /*slv2_world_free(me);*/ } + +#define WORLD_WRAP_VOID0(name) \ + inline void name () { slv2_world_ ## name (me); } + +#define WORLD_WRAP0(RetType, name) \ + inline RetType name () { return slv2_world_ ## name (me); } + +#define WORLD_WRAP1(RetType, name, T1, a1) \ + inline RetType name (T1 a1) { return slv2_world_ ## name (me, a1); } + +#define WORLD_WRAP2(RetType, name, T1, a1, T2, a2) \ + inline RetType name (T1 a1, T2 a2) { return slv2_world_ ## name (me, a1, a2); } + + WORLD_WRAP2(void, set_option, const char*, uri, SLV2Value, value); + WORLD_WRAP_VOID0(free); + WORLD_WRAP_VOID0(load_all); + WORLD_WRAP1(void, load_bundle, SLV2Value, bundle_uri); + WORLD_WRAP0(SLV2PluginClass, get_plugin_class); + WORLD_WRAP0(SLV2PluginClasses, get_plugin_classes); + WORLD_WRAP0(Plugins, get_all_plugins); + // TODO: get_plugins_by_filter (takes a function parameter) + + SLV2World me; +}; + +class Port { +public: + inline Port(SLV2Port c_obj) : me(c_obj) {} + + inline operator SLV2Port() const { return me; } + + SLV2Port me; +}; + +class Plugin { +public: + inline Plugin(SLV2Plugin c_obj) : me(c_obj) {} + + inline operator SLV2Plugin() const { return me; } + +#define PLUGIN_WRAP0(RetType, name) \ + inline RetType name () { return slv2_plugin_ ## name (me); } + +#define PLUGIN_WRAP1(RetType, name, T1, a1) \ + inline RetType name (T1 a1) { return slv2_plugin_ ## name (me, a1); } + +#define PLUGIN_WRAP2(RetType, name, T1, a1, T2, a2) \ + inline RetType name (T1 a1, T2 a2) { return slv2_plugin_ ## name (me, a1, a2); } + + PLUGIN_WRAP0(bool, verify); + PLUGIN_WRAP0(Value, get_uri); + PLUGIN_WRAP0(Value, get_bundle_uri); + //PLUGIN_WRAP0(Values, get_data_uris); + PLUGIN_WRAP0(Value, get_library_uri); + PLUGIN_WRAP0(Value, get_name); + //PLUGIN_WRAP0(PluginClass, get_class); + //PLUGIN_WRAP1(Values, get_value, Value, predicate); + //PLUGIN_WRAP1(Values, get_value_by_qname, const char*, predicate); + //PLUGIN_WRAP2(Values, get_value_for_subject, Value, subject, Value, predicate); + PLUGIN_WRAP1(bool, has_feature, Value, feature_uri); + //PLUGIN_WRAP0(Values, get_supported_features); + //PLUGIN_WRAP0(Values, get_required_features); + //PLUGIN_WRAP0(Values, get_optional_features); + PLUGIN_WRAP0(uint32_t, get_num_ports); + // slv2_plugin_get_port_ranges_float + // slv2_plugin_get_num_ports_of_class + PLUGIN_WRAP0(bool, has_latency); + PLUGIN_WRAP0(uint32_t, get_latency_port_index); + PLUGIN_WRAP1(Port, get_port_by_index, uint32_t, index); + PLUGIN_WRAP1(Port, get_port_by_symbol, SLV2Value, symbol); + PLUGIN_WRAP0(Value, get_author_name); + PLUGIN_WRAP0(Value, get_author_email); + PLUGIN_WRAP0(Value, get_author_homepage); + + SLV2Plugin me; +}; + +} /* namespace SLV2 */ + +#endif /* SLV2_SLV2MM_HPP__ */ diff --git a/swig/python/lv2_list.py b/swig/python/lv2_list.py index 685b62b..ef99cf2 100755 --- a/swig/python/lv2_list.py +++ b/swig/python/lv2_list.py @@ -1,8 +1,12 @@ #!/usr/bin/env python -import slv2; -w = slv2.World() -w.load_all() +import slv2 + +world = slv2.World() +world.load_all() + +plugins = world.get_all_plugins() + +for i in plugins: + print(i.get_uri().as_uri()) -for p in w.get_all_plugins(): - print p.uri(), "-", p.name() diff --git a/swig/slv2.i b/swig/slv2.i index 5bc9a5d..7d0c664 100644 --- a/swig/slv2.i +++ b/swig/slv2.i @@ -1,125 +1,30 @@ %module slv2 %{ -#include "slv2/plugin.h" -#include "slv2/pluginclass.h" -#include "slv2/pluginclasses.h" -#include "slv2/plugininstance.h" -#include "slv2/plugins.h" -#include "slv2/port.h" #include "slv2/slv2.h" -#include "slv2/types.h" -#include "slv2/value.h" -#include "slv2/values.h" -#include "slv2/world.h" -typedef struct { SLV2World me; } World; -typedef struct { SLV2World world; SLV2Plugins me; } Plugins; -typedef struct { SLV2World world; SLV2Plugin me; } Plugin; +#include "slv2/slv2mm.hpp" %} - -%include "slv2/plugin.h" -%include "slv2/pluginclass.h" -%include "slv2/pluginclasses.h" -%include "slv2/plugininstance.h" -%include "slv2/plugins.h" -%include "slv2/port.h" %include "slv2/slv2.h" -%include "slv2/types.h" -%include "slv2/value.h" -%include "slv2/values.h" -%include "slv2/world.h" - -typedef struct { SLV2Plugin me; } Plugin; -%extend Plugin { - Plugin(SLV2Plugin p) { - Plugin* ret = (Plugin*)malloc(sizeof(Plugin)); - ret->me = p; - return ret; - } - - ~Plugin() { - /* FIXME: free SLV2Plugin here? */ - free($self); - } - - char* name() { - SLV2Value nm = slv2_plugin_get_name($self->me); - char* ret = nm ? strdup((char*)slv2_value_as_string(nm)) : strdup(""); - slv2_value_free(nm); - return ret; - } - const char* uri() { - return strdup((char*)slv2_value_as_string(slv2_plugin_get_uri($self->me))); - } -}; - -typedef struct { SLV2World world; SLV2Plugins me; } Plugins; +%include "slv2/slv2mm.hpp" +namespace SLV2 { %extend Plugins { - Plugins(SLV2World w, SLV2Plugins p) { - Plugins* ret = (Plugins*)malloc(sizeof(Plugins)); - ret->world = w; - ret->me = p; - return ret; - } - - ~Plugins() { - slv2_plugins_free($self->world, $self->me); - free($self); - } - - inline unsigned size() const { return slv2_plugins_size($self->me); } - -#ifdef PYTHON - Plugin* __getitem__(unsigned i) { - if (i < slv2_plugins_size($self->me)) - return new_Plugin(slv2_plugins_get_at($self->me, i)); - else - return NULL; - } - - inline unsigned __len__() const { return slv2_plugins_size($self->me); } - %pythoncode %{ - def __iter__(self): - class Iterator(object): - def __init__(self, plugins): - self.plugins = plugins - self.iter = 0 - - def next(self): - if self.iter < self.plugins.size(): - self.iter += 1 - return Plugin(slv2_plugins_get_at(self.plugins.me, self.iter-1)) - else: - raise StopIteration - - return Iterator(self) + def __iter__(self): + class Iterator(object): + def __init__(self, plugins): + self.plugins = plugins + self.index = 0 + + def __iter__(self): + return self + + def next(self): + self.index += 1 + if self.index < slv2_plugins_size(self.plugins.me): + return Plugin(slv2_plugins_get_at(self.plugins.me, self.index)) + else: + raise StopIteration + + return Iterator(self) %} -#endif -}; - -typedef struct { SLV2World me; } World; -%extend World { - World() { - World* ret = (World*)malloc(sizeof(World)); - ret->me = slv2_world_new(); - return ret; - } - - ~World() { - slv2_world_free($self->me); - free($self); - } - - void load_all() { slv2_world_load_all($self->me); } - void load_bundle(const char* uri) { - SLV2Value bundle_uri = slv2_value_new_uri($self->me, uri); - slv2_world_load_bundle($self->me, bundle_uri); - slv2_value_free(bundle_uri); - } - - Plugins* get_all_plugins() { - return new_Plugins($self->me, slv2_world_get_all_plugins($self->me)); - } }; - - +} diff --git a/wscript b/wscript index a525526..5d09d38 100644 --- a/wscript +++ b/wscript @@ -1,5 +1,6 @@ #!/usr/bin/env python import autowaf +import os import sys import Options @@ -60,6 +61,14 @@ def configure(conf): autowaf.configure(conf) autowaf.display_header('SLV2 Configuration') conf.check_tool('compiler_cc') + + try: + conf.load('swig python') + conf.check_python_headers() + autowaf.define(conf, 'SLV2_SWIG', 1); + except: + pass + autowaf.check_pkg(conf, 'lv2core', uselib_store='LV2CORE', mandatory=True) autowaf.check_pkg(conf, 'glib-2.0', uselib_store='GLIB', atleast_version='2.0.0', mandatory=True) @@ -126,9 +135,10 @@ def configure(conf): autowaf.display_msg(conf, "Utilities", str(conf.env['BUILD_UTILS'] == 1)) autowaf.display_msg(conf, "Jack clients", str(conf.env['USE_JACK'] == 1)) autowaf.display_msg(conf, "Unit tests", str(conf.env['BUILD_TESTS'])) - autowaf.display_msg(conf, "Dynamic Manifest Support", str(conf.env['SLV2_DYN_MANIFEST'] == 1)) + autowaf.display_msg(conf, "Dynamic manifest support", str(conf.env['SLV2_DYN_MANIFEST'] == 1)) autowaf.display_msg(conf, "Default LV2_PATH", str(conf.env['SLV2_DEFAULT_LV2_PATH'])) autowaf.display_msg(conf, "UI support", str(conf.env['SLV2_WITH_UI'] == 1)) + autowaf.display_msg(conf, "Python bindings", str(conf.env['SLV2_SWIG'] == 1)) print @@ -229,9 +239,23 @@ def build(bld): bld.install_as( '/etc/bash_completion.d/slv2', 'utils/slv2.bash_completion') + if bld.env['SLV2_SWIG']: + # Python Wrapper + bld( + features = 'cxx cxxshlib pyext', + source = 'swig/slv2.i', + target = 'swig/_slv2', + swig_flags = '-c++ -python -Wall -I.. -lslv2 -features autodoc=1', + vnum = SLV2_LIB_VERSION, + use = 'libslv2') + bld.add_post_fun(autowaf.run_ldconfig) def test(ctx): autowaf.pre_test(ctx, APPNAME) autowaf.run_tests(ctx, APPNAME, tests.split(), dirs=['./src','./test']) autowaf.post_test(ctx, APPNAME) + +def wrap(ctx): + os.chdir(out) + os.system('swig -DPYTHON -Wall -python -I/usr/include -I/usr/local/include -I.. -o slv2_python.c -oh slv2_python.h ../swig/slv2.i') -- cgit v1.2.1