summaryrefslogtreecommitdiff
path: root/ttlgen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ttlgen.cc')
-rw-r--r--ttlgen.cc255
1 files changed, 255 insertions, 0 deletions
diff --git a/ttlgen.cc b/ttlgen.cc
new file mode 100644
index 0000000..77780d0
--- /dev/null
+++ b/ttlgen.cc
@@ -0,0 +1,255 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * ttlgen.cc
+ *
+ * Fri Jul 15 09:27:19 CEST 2016
+ * Copyright 2016 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of PluginGizmo.
+ *
+ * PluginGizmo is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * PluginGizmo 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with PluginGizmo; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <iostream>
+#include <fstream>
+#include <dlfcn.h>
+
+#include "pluginlv2.h"
+
+typedef PluginLV2* create_t();
+
+static void header(std::ostream& output)
+{
+ output << "\
+# LV2 Plugin\n\
+# Copyright 2019 Bent Bisballe Nyeng <deva@aasimon.org>\n\
+#\n\
+# Permission to use, copy, modify, and/or distribute this software for any\n\
+# purpose with or without fee is hereby granted, provided that the above\n\
+# copyright notice and this permission notice appear in all copies.\n\
+#\n\
+# THIS SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n\
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n\
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n\
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n\
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n\
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n\
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\
+";
+}
+
+static void includes(std::ostream& output)
+{
+ output << "\
+@prefix doap: <http://usefulinc.com/ns/doap#> .\n\
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n\
+@prefix atom: <http://lv2plug.in/ns/ext/atom#> .\n\
+@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .\n\
+@prefix state: <http://lv2plug.in/ns/ext/state#> .\n\
+@prefix pprops: <http://lv2plug.in/ns/ext/port-props#> .\n\
+@prefix idpy: <http://harrisonconsoles.com/lv2/inlinedisplay#> .\n\
+@prefix time: <http://lv2plug.in/ns/ext/time#> .\n\
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n\
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n\
+";
+}
+
+static void ui(Plugin& plugin, const std::string& pluginfile, std::ostream& output)
+{
+ if(!plugin.hasGUI())
+ {
+ return;
+ }
+
+ output << "\
+<" << plugin.getURI() << "/lv2#ui>\n\
+ a ui:X11UI ;\n\
+ lv2:requiredFeature ui:resize ;\n\
+ lv2:extensionData ui:resize ;\n\
+ lv2:requiredFeature ui:idleInterface ;\n\
+ lv2:extensionData ui:idleInterface ;\n\
+ lv2:requiredFeature <http://lv2plug.in/ns/ext/instance-access> ;\n\
+ ui:binary <" << pluginfile << "> .\n";
+}
+
+static void ports(Plugin& plugin, std::ostream& output)
+{
+ std::size_t port_index = 2;
+ for(std::size_t i = 0; i < plugin.getNumberOfMidiInputs(); ++i)
+ {
+ output << "\
+ , [\n\
+ a atom:AtomPort ,\n\
+ lv2:InputPort;\n\
+ atom:bufferType atom:Sequence ;\n\
+ atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ;\n\
+ lv2:index " << port_index << " ;\n\
+ lv2:symbol \"control\" ;\n\
+ lv2:name \"Control\"\n\
+ ]";
+ ++port_index;
+ }
+
+ for(std::size_t i = 0; i < plugin.getNumberOfMidiOutputs(); ++i)
+ {
+ output << "\
+ , [\n\
+ a atom:AtomPort ,\n\
+ lv2:OutputPort;\n\
+ atom:bufferType atom:Sequence ;\n\
+ atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ;\n\
+ lv2:index " << port_index << " ;\n\
+ lv2:symbol \"control\" ;\n\
+ lv2:name \"Control\"\n\
+ ]";
+ ++port_index;
+ }
+
+ std::size_t input_port_index = 1;
+ for(std::size_t i = 0; i < plugin.getNumberOfAudioInputs(); ++i)
+ {
+ output << "\
+ , [\n\
+ a lv2:AudioPort ,\n\
+ lv2:InputPort ;\n\
+ lv2:index " << port_index << " ;\n\
+ lv2:symbol \"in" << input_port_index << "\" ;\n\
+ lv2:name \"In" << input_port_index << "\"\n\
+ ]";
+ ++port_index;
+ ++input_port_index;
+ }
+
+ std::size_t output_port_index = 1;
+ for(std::size_t i = 0; i < plugin.getNumberOfAudioOutputs(); ++i)
+ {
+ output << "\
+ , [\n\
+ a lv2:AudioPort ,\n\
+ lv2:OutputPort ;\n\
+ lv2:index " << port_index << " ;\n\
+ lv2:symbol \"out" << output_port_index << "\" ;\n\
+ lv2:name \"Out" << output_port_index << "\"\n\
+ ]";
+ ++port_index;
+ ++output_port_index;
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ if(argc != 3)
+ {
+ std::cerr << "Missing argument.\n";
+ std::cout << "Usage: " << argv[0] << " <plugin binary> <output file>\n";
+ return 1;
+ }
+
+ std::string library = argv[1];
+ auto seppos = library.rfind("/");
+ std::string binary = library;
+ if(seppos != std::string::npos)
+ {
+ binary = library.substr(seppos + 1);
+ }
+
+ // load the plugin library
+ void* plugin = dlopen(library.data(), RTLD_LAZY);
+ if(!plugin)
+ {
+ std::cerr << "Cannot load library: " << dlerror() << std::endl;
+ std::cerr << "Library must have absolute path or prefix ./myplugin.so.\n";
+ return 1;
+ }
+
+ // reset errors
+ dlerror();
+
+ // load the symbols
+ create_t* create_plugin = (create_t*) dlsym(plugin, "createEffectInstance");
+ const char* dlsym_error = dlerror();
+ if(dlsym_error)
+ {
+ std::cerr << "Cannot load symbol create: " << dlsym_error << '\n';
+ return 1;
+ }
+
+ std::ofstream output(argv[2]);
+
+ // create an instance of the class
+ Plugin* p = create_plugin();
+
+ header(output);
+ output << std::endl;
+ includes(output);
+ output << std::endl;
+ ui(*p, binary, output);
+ output << std::endl;
+
+ output << "\
+<" << p->getURI() << "/lv2>\n\
+ a lv2:Plugin ;\n\
+ lv2:binary <" << binary << "> ;\n \
+ a lv2:InstrumentPlugin ;\n\
+ doap:name \"" << p->getEffectName() << "\" ;\n\
+ doap:maintainer [\n\
+ foaf:name \"" << p->getVendorString() << "\" ;\n\
+ foaf:homepage <" << p->getHomepage() << "> ;\n\
+ ] ;\n\
+ doap:license <http://usefulinc.com/doap/licenses/gpl> ;\n\
+ ui:ui <" << p->getURI() << "/lv2#ui> ;\n\
+ doap:license <http://opensource.org/licenses/gpl-3.0> ;\n\
+ lv2:optionalFeature <http://lv2plug.in/ns/ext/uri-map> ;\n\
+ lv2:optionalFeature <http://lv2plug.in/ns/ext/event> ;\n\
+ lv2:optionalFeature idpy:queue_draw ;\n\
+ lv2:extensionData state:interface ;\n\
+ lv2:port [\n\
+ a lv2:InputPort, lv2:ControlPort ;\n\
+ lv2:index 0 ;\n\
+ lv2:symbol \"lv2_freewheel\" ;\n\
+ lv2:name \"Freewheel\" ;\n\
+ lv2:default 0.0 ;\n\
+ lv2:minimum 0.0 ;\n\
+ lv2:maximum 1.0 ;\n\
+ lv2:designation <http://lv2plug.in/ns/lv2core#freeWheeling> ;\n\
+ lv2:portProperty <http://lv2plug.in/ns/lv2core#freeWheeling> ;\n\
+ lv2:portProperty lv2:toggled ;\n\
+ lv2:portProperty pprops:hasStrictBounds;\n\
+ ] , [\n\
+ a lv2:OutputPort, lv2:ControlPort ;\n\
+ lv2:designation <http://lv2plug.in/ns/lv2core#latency>;\n\
+ lv2:index 1;\n\
+ lv2:symbol \"latency\";\n\
+ lv2:name \"Latency\";\n\
+ lv2:minimum 0;\n\
+ lv2:maximum 192000;\n\
+ lv2:portProperty lv2:reportsLatency, lv2:integer;\n\
+ ]";
+
+ ports(*p, output);
+
+ output << " .\n";
+
+ // FIXME: The plugin is never deleted, but since we're terminating now anyway
+ // it doesn't matter much...
+
+ // unload the plugin library
+ dlclose(plugin);
+
+ return 0;
+}