changeset 232:09b7eab40dbf

Begin on stub-generator for Piper Vamp wrappers
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 13 Jun 2017 08:44:07 +0100
parents 8fd9da17f951
children 82f86151bc4b
files Makefile vamp-stubber/stubber.cpp
diffstat 2 files changed, 299 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Tue Jun 13 08:43:10 2017 +0100
+++ b/Makefile	Tue Jun 13 08:44:07 2017 +0100
@@ -15,7 +15,7 @@
 TEST_SRCS 	:= test/main.cpp test/vamp-client/tst_PluginStub.cpp
 TEST_OBJS	:= $(TEST_SRCS:.cpp=.o)
 
-all:	bin bin/piper-convert bin/piper-vamp-simple-server bin/test-suite
+all:	bin bin/piper-convert bin/piper-vamp-simple-server bin/piper-vamp-stub-generator bin/test-suite
 
 bin:
 	mkdir bin
@@ -26,6 +26,9 @@
 bin/piper-vamp-simple-server: vamp-server/simple-server.o $(COMMON_OBJS)
 	c++ $(CXXFLAGS) $^ -o $@ $(LDFLAGS)
 
+bin/piper-vamp-stub-generator: vamp-stubber/stubber.o $(COMMON_OBJS)
+	c++ $(CXXFLAGS) $^ -o $@ $(LDFLAGS)
+
 bin/test-suite: $(TEST_OBJS)
 	c++ $(CXXFLAGS) $^ -o $@ $(LDFLAGS)
 	bin/test-suite
@@ -97,7 +100,24 @@
 vamp-server/simple-server.o: vamp-support/AssignedPluginHandleMapper.h
 vamp-server/simple-server.o: vamp-support/DefaultPluginOutputIdMapper.h
 vamp-server/simple-server.o: vamp-support/LoaderRequests.h
-vamp-server/simple-server.o: vamp-support/RdfTypes.h vamp-support/RdfTypes.h
+vamp-server/simple-server.o: vamp-support/RdfTypes.h
+vamp-stubber/stubber.o: vamp-json/VampJson.h
+vamp-stubber/stubber.o: vamp-support/StaticOutputDescriptor.h
+vamp-stubber/stubber.o: vamp-support/PluginStaticData.h
+vamp-stubber/stubber.o: vamp-support/StaticOutputDescriptor.h
+vamp-stubber/stubber.o: vamp-support/PluginConfiguration.h
+vamp-stubber/stubber.o: vamp-support/RequestResponse.h
+vamp-stubber/stubber.o: vamp-support/PluginStaticData.h
+vamp-stubber/stubber.o: vamp-support/PluginConfiguration.h
+vamp-stubber/stubber.o: vamp-support/PluginHandleMapper.h
+vamp-stubber/stubber.o: vamp-support/PluginOutputIdMapper.h
+vamp-stubber/stubber.o: vamp-support/PluginOutputIdMapper.h
+vamp-stubber/stubber.o: vamp-support/RequestResponseType.h
+vamp-stubber/stubber.o: vamp-support/RequestOrResponse.h
+vamp-stubber/stubber.o: vamp-support/RequestResponseType.h
+vamp-stubber/stubber.o: vamp-support/RequestResponse.h
+vamp-stubber/stubber.o: vamp-support/LoaderRequests.h vamp-support/RdfTypes.h
+vamp-stubber/stubber.o: vamp-support/RdfTypes.h
 ext/json11/json11.o: ext/json11/json11.hpp
 ext/json11/test.o: ext/json11/json11.hpp
 test/vamp-client/tst_PluginStub.o: vamp-client/Loader.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-stubber/stubber.cpp	Tue Jun 13 08:44:07 2017 +0100
@@ -0,0 +1,277 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+/*
+    Piper C++
+
+    An API for audio analysis and feature extraction plugins.
+
+    Centre for Digital Music, Queen Mary, University of London.
+    Copyright 2006-2016 Chris Cannam and QMUL.
+  
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation
+    files (the "Software"), to deal in the Software without
+    restriction, including without limitation the rights to use, copy,
+    modify, merge, publish, distribute, sublicense, and/or sell copies
+    of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+    Except as contained in this notice, the names of the Centre for
+    Digital Music; Queen Mary, University of London; and Chris Cannam
+    shall not be used in advertising or otherwise to promote the sale,
+    use or other dealings in this Software without prior written
+    authorization.
+*/
+
+#include "vamp-json/VampJson.h"
+#include "vamp-support/RequestOrResponse.h"
+#include "vamp-support/LoaderRequests.h"
+#include "vamp-support/RdfTypes.h"
+
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+
+#include <map>
+#include <set>
+
+// for _setmode stuff and _dup
+#ifdef _WIN32
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+// for dup, open etc
+#ifndef _WIN32
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+using namespace std;
+using namespace json11;
+using namespace piper_vamp;
+using namespace Vamp;
+
+static string myname = "piper-vamp-simple-server";
+
+static void version()
+{
+    cout << "1.0" << endl;
+    exit(0);
+}
+
+static void usage(bool successful = false)
+{
+    cerr << "\n" << myname <<
+        ": Emit stub version of main code\nfor a Piper Adapter implementation of a Vamp plugin library\n\n"
+        "    Usage: " << myname << " [-d] <soname>\n"
+        "           " << myname << " -v\n"
+        "           " << myname << " -h\n\n"
+        "    where\n"
+        "       <soname>: the Vamp plugin library name to emit stub conversion code for\n"
+        "       -d: also print debug information to stderr\n"
+        "       -v: print version number to stdout and exit\n"
+        "       -h: print this text to stderr and exit\n\n";
+    if (successful) exit(0);
+    else exit(2);
+}
+
+// We write our output to stdout, but want to ensure that the plugin
+// doesn't write anything itself. To do this we open a null file
+// descriptor and dup2() it into place of stdout in the gaps between
+// our own output activity.
+
+static int normalFd = -1;
+static int suspendedFd = -1;
+
+static void initFds(bool binary)
+{
+#ifdef _WIN32
+    if (binary) {
+        int result = _setmode(0, _O_BINARY);
+        if (result == -1) {
+            throw runtime_error("Failed to set binary mode on stdin");
+        }
+        result = _setmode(1, _O_BINARY);
+        if (result == -1) {
+            throw runtime_error("Failed to set binary mode on stdout");
+        }
+    }
+    normalFd = _dup(1);
+    suspendedFd = _open("NUL", _O_WRONLY);
+#else
+    (void)binary;
+    normalFd = dup(1);
+    suspendedFd = open("/dev/null", O_WRONLY);
+#endif
+    
+    if (normalFd < 0 || suspendedFd < 0) {
+        throw runtime_error("Failed to initialise fds for stdio suspend/resume");
+    }
+}
+
+static void suspendOutput()
+{
+#ifdef _WIN32
+    _dup2(suspendedFd, 1);
+#else
+    dup2(suspendedFd, 1);
+#endif
+}
+
+static void resumeOutput()
+{
+#ifdef _WIN32
+    _dup2(normalFd, 1);
+#else
+    dup2(normalFd, 1);
+#endif
+}
+
+ListResponse
+makeRequest(string soname, bool debug)
+{
+    ListRequest req;
+    req.from.push_back(soname);
+    return LoaderRequests().listPluginData(req);
+}
+
+struct PlausibleMetadata
+{
+    string className;
+    string adapterName;
+};
+
+PlausibleMetadata
+inventPlausibleMetadata(string key)
+{
+    PlausibleMetadata pm;
+    pm.className = "MyPlugin";//!!!
+    pm.adapterName = "myPluginAdapter";//!!!
+    return pm;
+}
+
+void
+emitFor(string soname, const ListResponse &resp, bool debug)
+{
+    cout <<
+        "\n#include \"PiperExport.h\"\n"
+        "\n"
+        "// #include your own plugin headers here\n"
+        "\n"
+        "using piper_vamp_js::PiperAdapter;\n"
+        "using piper_vamp_js::PiperPluginLibrary;\n"
+        "\n"
+        "static std::string soname(\"" << soname << "\");\n"
+        "\n";
+
+    bool first = true;
+    
+    for (const auto &plugin: resp.available) {
+        PlausibleMetadata pm = inventPlausibleMetadata(plugin.pluginKey);
+        cout << "static PiperAdapter<"
+             << pm.className
+             << "> // replace with the actual Vamp plugin class name for \""
+             << plugin.basic.identifier << "\" plugin\n" << pm.adapterName
+             << "(\n    soname,\n    ";
+        
+        string catString = "{ ";
+        first = true;
+        for (auto c: plugin.category) {
+            if (!first) catString += ", ";
+            catString += "\"" + c + "\"";
+            first = false;
+        }
+        catString += " }";
+        cout << catString << ",\n    ";
+
+        cout << "{\n    ";
+        first = true;
+        for (auto o: plugin.staticOutputInfo) {
+            if (!first) {
+                cout << ",\n    ";
+            }
+            cout << "    ";
+            string outputId = o.first;
+            const StaticOutputDescriptor &desc = o.second;
+            cout << "{ \"" << outputId << "\", { \""
+                 << desc.typeURI << "\" } }";
+            first = false;
+        }
+        cout << "\n    }\n";
+        cout << "    );\n\n";
+    }
+
+    cout << "static PiperPluginLibrary library({\n    ";
+    first = true;
+    for (const auto &plugin: resp.available) {
+        PlausibleMetadata pm = inventPlausibleMetadata(plugin.pluginKey);
+        if (!first) {
+            cout << ",\n    ";
+        }
+        cout << "&" << pm.adapterName;
+        first = false;
+    }
+    cout << "\n});\n\n";
+    cout << "PIPER_EXPORT_LIBRARY(library);\n" << endl;
+}    
+
+int main(int argc, char **argv)
+{
+    if (argc != 2 && argc != 3) {
+        usage();
+    }
+
+    bool debug = false;
+    
+    string arg = argv[1];
+    if (arg == "-h") {
+        if (argc == 2) {
+            usage(true);
+        } else {
+            usage();
+        }
+    } else if (arg == "-v") {
+        if (argc == 2) {
+            version();
+        } else {
+            usage();
+        }
+    } else if (arg == "-d") {
+        if (argc == 2) {
+            usage();
+        } else {
+            debug = true;
+            arg = argv[2];
+        }
+    }
+    
+    string soname = arg;
+
+    try {            
+        initFds(false);
+    } catch (exception &e) {
+        cerr << "ERROR: " << e.what() << endl;
+        exit(1);
+    }
+
+    suspendOutput();
+
+    ListResponse resp = makeRequest(soname, debug);
+
+    resumeOutput();
+
+    emitFor(soname, resp, debug);
+    
+    exit(0);
+}