summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2016-08-14 14:49:02 +0200
committerBent Bisballe Nyeng <deva@aasimon.org>2016-08-14 14:49:02 +0200
commit7db0ce19674393a4dd9af3beed236038bcfa2e65 (patch)
treea9d1f410fbbac877919ef3a72ce0abd35eabaa43
parenta9eadcc1b483d5d30a8443e78fa4d84c8f18d6c3 (diff)
Experimental inline display added.
-rw-r--r--inline-display.h101
-rw-r--r--manifest.ttl2
-rw-r--r--plugin.h26
-rw-r--r--pluginlv2.cc39
-rw-r--r--pluginlv2.h36
-rw-r--r--plugintest.cc32
-rw-r--r--plugintest.h8
7 files changed, 244 insertions, 0 deletions
diff --git a/inline-display.h b/inline-display.h
new file mode 100644
index 0000000..886c3c8
--- /dev/null
+++ b/inline-display.h
@@ -0,0 +1,101 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+ Copyright 2016 Robin Gareus <robin@gareus.org>
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/**
+ @defgroup inlinedisplay Inline-Display
+ Support for displaying a miniaturized, non-interactive view
+ in the host's mixer strip.
+ @{
+*/
+
+#ifndef LV2_INLINE_DISPLAY_H
+#define LV2_INLINE_DISPLAY_H
+
+#include <stdint.h>
+
+#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
+
+#define LV2_INLINEDISPLAY_URI "http://harrisonconsoles.com/lv2/inlinedisplay"
+#define LV2_INLINEDISPLAY_PREFIX LV2_INLINEDISPLAY_URI "#"
+#define LV2_INLINEDISPLAY__interface LV2_INLINEDISPLAY_PREFIX "interface"
+#define LV2_INLINEDISPLAY__queue_draw LV2_INLINEDISPLAY_PREFIX "queue_draw"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Opaque handle for LV2_Inline_Display::queue_draw() */
+typedef void* LV2_Inline_Display_Handle;
+
+/** raw image pixmap format is ARGB32,
+ * the data pointer is owned by the plugin and must be valid
+ * from the first call to render until cleanup.
+ */
+typedef struct {
+ unsigned char *data;
+ int width;
+ int height;
+ int stride;
+} LV2_Inline_Display_Image_Surface;
+
+/** a LV2 Feature provided by the Host to the plugin
+ *
+ * This allows a the plugin during in realtime context to
+ * invalidate the currently displayed data and request from
+ * the host to call render() as soon as feasible.
+ */
+typedef struct {
+ /** Opaque host data */
+ LV2_Inline_Display_Handle handle;
+ /** Request from run() that the host should call render() at a later
+ * time to update the inline display
+ */
+ void (*queue_draw)(LV2_Inline_Display_Handle handle);
+} LV2_Inline_Display;
+
+/**
+ * Plugin Inline-Display Interface.
+ */
+typedef struct {
+ /**
+ * The render method. This is called by the host in the main GUI thread
+ * (non realtime, the context with access to graphics drawing APIs).
+ *
+ * The data pointer is owned by the plugin and must be valid
+ * from the first call to render until cleanup.
+ *
+ * The host specifies a maxium available area for the plugin to draw.
+ * the returned Image Surface contains the actual area which
+ * the plugin allocated.
+ *
+ * @param instance The LV2 instance
+ * @param w the max available width
+ * @param h the max available height
+ * @return pointer to a LV2_Inline_Display_Image_Surface or NULL
+ */
+ LV2_Inline_Display_Image_Surface* (*render)(
+ LV2_Handle instance,
+ uint32_t w, uint32_t h);
+} LV2_Inline_Display_Interface;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_INLINE_DISPLAY_H */
+
+/**
+ @}
+*/
diff --git a/manifest.ttl b/manifest.ttl
index 61304ed..1468215 100644
--- a/manifest.ttl
+++ b/manifest.ttl
@@ -20,6 +20,7 @@
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
@prefix state: <http://lv2plug.in/ns/ext/state#> .
@prefix pprops: <http://lv2plug.in/ns/ext/port-props#> .
+@prefix idpy: <http://harrisonconsoles.com/lv2/inlinedisplay#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@@ -34,6 +35,7 @@
<http://example.org/plugintest>
a lv2:Plugin ;
+ lv2:optionalFeature idpy:queue_draw ;
lv2:binary <plugintest_lv2.so> ;
a lv2:InstrumentPlugin ;
doap:name "LV2Test" ;
diff --git a/plugin.h b/plugin.h
index 3874fed..b8a3f64 100644
--- a/plugin.h
+++ b/plugin.h
@@ -139,6 +139,32 @@ public:
//
+ // Inline GUI (optional)
+ //
+
+ //! Return true if a GUI implementation is to be used.
+ virtual bool hasInlineGUI()
+ {
+ return false;
+ }
+
+ struct InlineDrawContext
+ {
+ std::size_t width{0}; //< Width of the render buffer.
+ std::size_t height{0}; //< Height of the render buffer.
+ std::uint8_t* data{nullptr}; //< Allocated (or reused) RGBA buffer, filled by the plugin.
+ };
+
+ //! Render call back.
+ //! \param width The client area width as specified by the host.
+ //! \param max_height The maximum allowed clieant area height as specified
+ //! by the host.
+ //! \param context The render context filled an maintained by the plugin.
+ virtual void onInlineRedraw(std::size_t width,
+ std::size_t max_height,
+ InlineDrawContext& context) {}
+
+ //
// GUI (optional)
//
diff --git a/pluginlv2.cc b/pluginlv2.cc
index 39d0e6c..c264223 100644
--- a/pluginlv2.cc
+++ b/pluginlv2.cc
@@ -114,6 +114,13 @@ LV2_Handle PluginLV2::instantiate(const struct _LV2_Descriptor* descriptor,
plugin_lv2->map = (LV2_URID_Map*)data;
}
+#ifdef DISPLAY_INTERFACE
+ if(uri == LV2_INLINEDISPLAY__queue_draw)
+ {
+ plugin_lv2->queue_draw = (LV2_Inline_Display*)data;
+ }
+#endif
+
++features;
}
@@ -348,6 +355,13 @@ void PluginLV2::run(LV2_Handle instance, uint32_t sample_count)
}
plugin_lv2->pos += sample_count;
+
+#ifdef DISPLAY_INTERFACE
+ if(plugin_lv2->queue_draw)
+ {
+ plugin_lv2->queue_draw->queue_draw(plugin_lv2->queue_draw->handle);
+ }
+#endif
}
void PluginLV2::activate(LV2_Handle instance)
@@ -440,6 +454,23 @@ static LV2_State_Interface persist = {
PluginLV2::restore
};
+LV2_Inline_Display_Image_Surface* PluginLV2::inlineRender(LV2_Handle instance,
+ uint32_t w,
+ uint32_t max_h)
+{
+ PluginLV2* plugin_lv2 = (PluginLV2*)instance;
+
+ plugin_lv2->onInlineRedraw(w, max_h, plugin_lv2->drawContext);
+
+ plugin_lv2->surf.width = plugin_lv2->drawContext.width;
+ plugin_lv2->surf.height = plugin_lv2->drawContext.height;
+ plugin_lv2->surf.stride = plugin_lv2->surf.width; // no padding
+
+ plugin_lv2->surf.data = plugin_lv2->drawContext.data;
+
+ return &plugin_lv2->surf;
+}
+
const void* PluginLV2::extensionData(const char *uri)
{
if(!strcmp(uri, LV2_STATE__interface))
@@ -447,6 +478,14 @@ const void* PluginLV2::extensionData(const char *uri)
return &persist;
}
+#ifdef DISPLAY_INTERFACE
+ static const LV2_Inline_Display_Interface display = { inlineRender };
+ if(!strcmp(uri, LV2_INLINEDISPLAY__interface))
+ {
+ return &display;
+ }
+#endif
+
return nullptr;
}
diff --git a/pluginlv2.h b/pluginlv2.h
index da10ac3..ee80f7a 100644
--- a/pluginlv2.h
+++ b/pluginlv2.h
@@ -35,6 +35,12 @@
#include <lv2/lv2plug.in/ns/ext/dynmanifest/dynmanifest.h>
#include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
+#define DISPLAY_INTERFACE
+
+#ifdef DISPLAY_INTERFACE
+#include "inline-display.h"
+#endif
+
enum class LV2Ports
{
FreeWheel = 0,
@@ -126,6 +132,25 @@ public:
std::size_t count) = 0;
//
+ // Inline GUI (optional)
+ //
+
+ //! Return true if a GUI implementation is to be used.
+ virtual bool hasInlineGUI()
+ {
+ return false;
+ }
+
+ //! Render call back.
+ //! \param width The client area width as specified by the host.
+ //! \param max_height The maximum allowed clieant area height as specified
+ //! by the host.
+ //! \param context The render context filled an maintained by the plugin.
+ virtual void onInlineRedraw(std::size_t width,
+ std::size_t max_height,
+ InlineDrawContext& context) {}
+
+ //
// GUI (optional)
//
@@ -220,6 +245,17 @@ private:
LV2_URID_Map* map{nullptr};
+#ifdef DISPLAY_INTERFACE
+ LV2_Inline_Display_Image_Surface surf;
+ LV2_Inline_Display* queue_draw{nullptr};
+
+ InlineDrawContext drawContext;
+
+ static LV2_Inline_Display_Image_Surface *inlineRender(LV2_Handle instance,
+ uint32_t w,
+ uint32_t max_h);
+#endif
+
bool active{false};
//
diff --git a/plugintest.cc b/plugintest.cc
index 48dad58..a23c44b 100644
--- a/plugintest.cc
+++ b/plugintest.cc
@@ -173,6 +173,38 @@ void PluginTest::process(size_t pos,
}
}
+bool PluginTest::hasInlineGUI()
+{
+ return true;
+}
+
+void PluginTest::onInlineRedraw(std::size_t width,
+ std::size_t max_height,
+ InlineDrawContext& context)
+{
+ std::size_t height = std::min(width / 2, max_height);
+ if (!context.data || (context.width != width))
+ {
+ delete[] context.data;
+ context.data = new std::uint8_t[width * height * 4];
+ }
+
+ context.width = width;
+ context.height = height;
+
+ for(std::size_t x = 0; x < context.width; ++x)
+ {
+ for(std::size_t y = 0; y < context.height; ++y)
+ {
+ unsigned char* p = context.data + ((x + y * context.width) * 4);
+ p[0] = 0; // B;
+ p[1] = 0; // G
+ p[2] = 255; // R
+ p[3] = 0; // A
+ }
+ }
+}
+
bool PluginTest::hasGUI()
{
return true;
diff --git a/plugintest.h b/plugintest.h
index 294eecc..f750121 100644
--- a/plugintest.h
+++ b/plugintest.h
@@ -87,6 +87,14 @@ public:
size_t count) override;
//
+ // Inline GUI
+ //
+ bool hasInlineGUI() override;
+ void onInlineRedraw(std::size_t width,
+ std::size_t max_height,
+ InlineDrawContext& context) override;
+
+ //
// GUI
//
bool hasGUI() override;