From 6ae2018e81e7e81e4906e62dc6224ad34298d9c2 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 14 Nov 2009 20:44:40 +0000 Subject: Object extension. Port resize extension. Sensible extension(s) implementation design for Ingen. Replace string port extension support in Ingen with Object port extension. Implement port resize extension in Ingen. Some test plugins for this stuff. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@2260 a436a847-0d15-0410-975c-d299462d15a1 --- src/shared/LV2Features.cpp | 35 +++++++++-------- src/shared/LV2Features.hpp | 46 ++++++++++++++++------ src/shared/LV2Object.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++ src/shared/LV2Object.hpp | 39 ++++++++++++++++++ src/shared/LV2URIMap.cpp | 12 +++++- src/shared/LV2URIMap.hpp | 20 ++++++++-- src/shared/ResourceImpl.cpp | 6 +-- src/shared/wscript | 3 +- 8 files changed, 220 insertions(+), 37 deletions(-) create mode 100644 src/shared/LV2Object.cpp create mode 100644 src/shared/LV2Object.hpp (limited to 'src/shared') diff --git a/src/shared/LV2Features.cpp b/src/shared/LV2Features.cpp index d21462c9..b57f1117 100644 --- a/src/shared/LV2Features.cpp +++ b/src/shared/LV2Features.cpp @@ -16,6 +16,7 @@ */ #include +#include #include "LV2Features.hpp" #include "LV2URIMap.hpp" @@ -26,39 +27,39 @@ namespace Shared { LV2Features::LV2Features() - : _lv2_features((LV2_Feature**)malloc(sizeof(LV2_Feature*))) +// : _lv2_features((LV2_Feature**)malloc(sizeof(LV2_Feature*))) { - _lv2_features[0] = NULL; +// _lv2_features[0] = NULL; - LV2URIMap* controller = new LV2URIMap(); - add_feature(LV2_URI_MAP_URI, controller->feature(), controller); + add_feature(LV2_URI_MAP_URI, SharedPtr(new LV2URIMap())); } -const LV2Features::Feature* +SharedPtr LV2Features::feature(const std::string& uri) { Features::const_iterator i = _features.find(uri); if (i != _features.end()) - return &i->second; + return i->second; else - return NULL; + return SharedPtr(); } void -LV2Features::add_feature(const std::string& uri, LV2_Feature* feature, void* controller) +LV2Features::add_feature(const std::string& uri, SharedPtr feature) { -#ifndef NDEBUG - Features::const_iterator i = _features.find(uri); - assert(i == _features.end()); - assert(_lv2_features[_features.size()] == NULL); -#endif - _features.insert(make_pair(uri, Feature(feature, controller))); + _features.insert(make_pair(uri, feature)); +} - _lv2_features = (LV2_Feature**)realloc(_lv2_features, sizeof(LV2_Feature*) * (_features.size() + 1)); - _lv2_features[_features.size()-1] = feature; - _lv2_features[_features.size()] = NULL; + +SharedPtr +LV2Features::lv2_features(Node* node) const +{ + FeatureArray::FeatureVector vec; + for (Features::const_iterator f = _features.begin(); f != _features.end(); ++f) + vec.push_back(f->second->feature(node)); + return SharedPtr(new FeatureArray(vec)); } diff --git a/src/shared/LV2Features.hpp b/src/shared/LV2Features.hpp index f2299c5c..78d467a5 100644 --- a/src/shared/LV2Features.hpp +++ b/src/shared/LV2Features.hpp @@ -25,11 +25,14 @@ #include #include +#include #include "slv2/slv2.h" +#include "raul/SharedPtr.hpp" namespace Ingen { namespace Shared { +class Node; /** Stuff that may need to be passed to an LV2 plugin (i.e. LV2 features). */ @@ -37,26 +40,47 @@ class LV2Features { public: LV2Features(); - struct Feature { - Feature(LV2_Feature* f, void* c=NULL) : feature(f), controller(c) {} - LV2_Feature* feature; ///< LV2 feature struct (plugin exposed) - void* controller; ///< Ingen internals, not exposed to plugin + class Feature { + public: + virtual ~Feature() {} + virtual SharedPtr feature(Node* node) = 0; }; - typedef std::map Features; + class FeatureArray { + public: + typedef std::vector< SharedPtr > FeatureVector; - const Feature* feature(const std::string& uri); + FeatureArray(FeatureVector& features) + : _features(features) + { + _array = (LV2_Feature**)malloc(sizeof(LV2_Feature) * (features.size() + 1)); + _array[features.size()] = NULL; + for (size_t i = 0; i < features.size(); ++i) + _array[i] = features[i].get(); + } - void add_feature(const std::string& uri, LV2_Feature* feature, void* controller); + ~FeatureArray() { + free(_array); + } - LV2_Feature** lv2_features() const { return _lv2_features; } + LV2_Feature** array() { return _array; } + + private: + FeatureVector _features; + LV2_Feature** _array; + }; + + SharedPtr feature(const std::string& uri); + + void add_feature(const std::string& uri, SharedPtr feature); + + SharedPtr lv2_features(Node* node) const; private: - Features _features; - LV2_Feature** _lv2_features; + typedef std::map< std::string, SharedPtr > Features; + Features _features; }; - } // namespace Shared } // namespace Ingen diff --git a/src/shared/LV2Object.cpp b/src/shared/LV2Object.cpp new file mode 100644 index 00000000..3442c004 --- /dev/null +++ b/src/shared/LV2Object.cpp @@ -0,0 +1,96 @@ +/* This file is part of Ingen. + * Copyright (C) 2009 Dave Robillard + * + * Ingen 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. + * + * Ingen 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 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 + */ + +#include +#include "raul/Atom.hpp" +#include "module/World.hpp" +#include "uri-map.lv2/uri-map.h" +#include "object.lv2/object.h" +#include "LV2Features.hpp" +#include "LV2Object.hpp" +#include "LV2URIMap.hpp" + +using namespace std; + +namespace Ingen { +namespace Shared { +namespace LV2Object { + + +bool +to_atom(World* world, LV2_Object* object, Raul::Atom& atom) +{ + SharedPtr map = PtrCast(world->lv2_features->feature(LV2_URI_MAP_URI)); + + if (object->type == map->object_class_string) { + atom = Raul::Atom((char*)(object + 1)); + return true; + } else if (object->type == map->object_class_int32) { + atom = Raul::Atom((int32_t*)(object + 1)); + return true; + } else if (object->type == map->object_class_float32) { + atom = Raul::Atom((float*)(object + 1)); + return true; + } + return false; +} + + +/** Convert an atom to an LV2 object, if possible. + * object->size should be the capacity of the object (not including header) + */ +bool +from_atom(World* world, const Raul::Atom& atom, LV2_Object* object) +{ + SharedPtr map = PtrCast(world->lv2_features->feature(LV2_URI_MAP_URI)); + + char* str; + switch (atom.type()) { + case Raul::Atom::FLOAT: + object->type = map->object_class_float32; + object->size = sizeof(float); + *(float*)(object + 1) = atom.get_float(); + break; + case Raul::Atom::INT: + object->type = map->object_class_int32; + object->size = sizeof(int32_t); + *(int32_t*)(object + 1) = atom.get_int32(); + break; + case Raul::Atom::STRING: + object->type = map->object_class_string; + object->size = std::min(object->size, (uint32_t)strlen(atom.get_string()) + 1); + str = ((char*)(object + 1)); + str[object->size - 1] = '\0'; + strncpy(str, atom.get_string(), object->size); + break; + case Raul::Atom::BLOB: + object->type = map->object_class_string; + *(uint32_t*)(object + 1) = map->uri_to_id(NULL, atom.get_blob_type()); + memcpy(((char*)(object + 1) + sizeof(uint32_t)), atom.get_blob(), + std::min(atom.data_size(), (size_t)object->size)); + default: + cerr << "Unsupported value type for toggle control" << endl; + return false; + } + return true; +} + + +} // namespace LV2Object + +} // namespace Shared +} // namespace Ingen diff --git a/src/shared/LV2Object.hpp b/src/shared/LV2Object.hpp new file mode 100644 index 00000000..1e72c4e0 --- /dev/null +++ b/src/shared/LV2Object.hpp @@ -0,0 +1,39 @@ +/* This file is part of Ingen. + * Copyright (C) 2009 Dave Robillard + * + * Ingen 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. + * + * Ingen 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 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 LV2_OBJECT_HPP +#define LV2_OBJECT_HPP + +namespace Raul { class Atom; } +typedef struct _LV2_Object LV2_Object; + +namespace Ingen { +namespace Shared { + +class World; + +namespace LV2Object { + + bool to_atom(World* world, const LV2_Object* object, Raul::Atom& atom); + bool from_atom(World* word, const Raul::Atom& atom, LV2_Object* object); + +} // namespace LV2Object + +} // namespace Shared +} // namespace Ingen + +#endif // LV2_OBJECT_HPP diff --git a/src/shared/LV2URIMap.cpp b/src/shared/LV2URIMap.cpp index e3ab6a48..65e3aa30 100644 --- a/src/shared/LV2URIMap.cpp +++ b/src/shared/LV2URIMap.cpp @@ -19,6 +19,7 @@ #include #include #include +#include "object.lv2/object.h" #include "LV2URIMap.hpp" using namespace std; @@ -28,7 +29,16 @@ namespace Shared { LV2URIMap::LV2URIMap() - : next_uri_id(1) + : uri_map() + , next_uri_id(1) + , object_class_bool(uri_to_id(NULL, LV2_OBJECT_URI "#Bool")) + , object_class_string(uri_to_id(NULL, LV2_OBJECT_URI "#String")) + , object_class_int32(uri_to_id(NULL, LV2_OBJECT_URI "#Int32")) + , object_class_float32(uri_to_id(NULL, LV2_OBJECT_URI "#Float32")) + , ui_format_events(uri_to_id(NULL, "http://lv2plug.in/ns/extensions/ui#Events")) + , midi_event(uri_to_id(NULL, "http://lv2plug.in/ns/ext/midi#MidiEvent")) + , string_transfer(uri_to_id(NULL, "http://lv2plug.in/ns/dev/string-port#StringTransfer")) + , object_transfer(uri_to_id(NULL, LV2_OBJECT_URI "#ObjectTransfer")) { uri_map_feature_data.uri_to_id = &LV2URIMap::uri_map_uri_to_id; uri_map_feature_data.callback_data = this; diff --git a/src/shared/LV2URIMap.hpp b/src/shared/LV2URIMap.hpp index f1b9c919..0dd6b0cb 100644 --- a/src/shared/LV2URIMap.hpp +++ b/src/shared/LV2URIMap.hpp @@ -28,6 +28,7 @@ #include #include "slv2/slv2.h" #include "uri-map.lv2/uri-map.h" +#include "LV2Features.hpp" namespace Ingen { namespace Shared { @@ -35,14 +36,15 @@ namespace Shared { /** Implementation of the LV2 URI Map extension */ -class LV2URIMap : public boost::noncopyable { +class LV2URIMap : public boost::noncopyable, public LV2Features::Feature { public: LV2URIMap(); - LV2_Feature* feature() { return &uri_map_feature; } + SharedPtr feature(Node*) { + return SharedPtr(&uri_map_feature, NullDeleter); + } - uint32_t uri_to_id(const char* map, - const char* uri); + uint32_t uri_to_id(const char* map, const char* uri); private: typedef std::map URIMap; @@ -55,6 +57,16 @@ private: LV2_URI_Map_Feature uri_map_feature_data; URIMap uri_map; uint32_t next_uri_id; + +public: + const uint32_t object_class_bool; + const uint32_t object_class_string; + const uint32_t object_class_int32; + const uint32_t object_class_float32; + const uint32_t ui_format_events; + const uint32_t midi_event; + const uint32_t string_transfer; + const uint32_t object_transfer; }; diff --git a/src/shared/ResourceImpl.cpp b/src/shared/ResourceImpl.cpp index b4b40116..6d028a13 100644 --- a/src/shared/ResourceImpl.cpp +++ b/src/shared/ResourceImpl.cpp @@ -110,10 +110,10 @@ ResourceImpl::type( port = true; } } else if (!strcmp(atom.get_uri(), "lv2ev:EventPort")) { - data_type = DataType::EVENT; + data_type = DataType::EVENTS; port = true; - } else if (!strcmp(atom.get_uri(), "sp:StringPort")) { - data_type = DataType::STRING; + } else if (!strcmp(atom.get_uri(), "obj:ObjectPort")) { + data_type = DataType::OBJECT; port = true; } } diff --git a/src/shared/wscript b/src/shared/wscript index 50fb7320..3f60752c 100644 --- a/src/shared/wscript +++ b/src/shared/wscript @@ -7,10 +7,11 @@ def build(bld): Builder.cpp ClashAvoider.cpp LV2Features.cpp + LV2Object.cpp LV2URIMap.cpp ResourceImpl.cpp - runtime_paths.cpp Store.cpp + runtime_paths.cpp ''' if bld.env['HAVE_LIBLO'] == 1: obj.source += ' OSCSender.cpp ' -- cgit v1.2.1