commit f8670208e8281ee02d59b49f173096bbc8bd1031
Author: falkTX <falktx@gmail.com>
Date: Tue, 24 Dec 2013 04:23:30 +0000
Initial commit
Diffstat:
87 files changed, 18657 insertions(+), 0 deletions(-)
diff --git a/dgl/App.hpp b/dgl/App.hpp
@@ -0,0 +1,54 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DGL_APP_HPP_INCLUDED
+#define DGL_APP_HPP_INCLUDED
+
+#include "Base.hpp"
+
+START_NAMESPACE_DGL
+
+class Window;
+
+// -----------------------------------------------------------------------
+
+class App
+{
+public:
+ App();
+ ~App();
+
+ void idle();
+ void exec();
+ void quit();
+ bool isQuiting() const;
+
+private:
+ struct PrivateData;
+ PrivateData* const pData;
+ friend class Window;
+
+ void addWindow(Window* const window);
+ void removeWindow(Window* const window);
+ void oneShown();
+ void oneHidden();
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
+
+#endif // DGL_APP_HPP_INCLUDED
diff --git a/dgl/Base.hpp b/dgl/Base.hpp
@@ -0,0 +1,143 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DGL_BASE_HPP_INCLUDED
+#define DGL_BASE_HPP_INCLUDED
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+# define DGL_OS_WINDOWS 1
+#elif defined(__APPLE__)
+# define DGL_OS_MAC 1
+#elif defined(__HAIKU__)
+# define DGL_OS_HAIKU 1
+#elif defined(__linux__)
+# define DGL_OS_LINUX 1
+#endif
+
+#if defined(HAVE_CPP11_SUPPORT)
+# define PROPER_CPP11_SUPPORT
+#elif defined(__GNUC__) && (__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__))
+# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
+# define PROPER_CPP11_SUPPORT
+# if (__GNUC__ * 100 + __GNUC_MINOR__) < 407
+# define override // gcc4.7+ only
+# endif
+# endif
+#endif
+
+#ifndef PROPER_CPP11_SUPPORT
+# ifndef __clang__
+# define noexcept throw()
+# endif
+# define override
+# define nullptr (0)
+#endif
+
+#ifndef DGL_NAMESPACE
+# define DGL_NAMESPACE DGL
+#endif
+
+#define START_NAMESPACE_DGL namespace DGL_NAMESPACE {
+#define END_NAMESPACE_DGL }
+#define USE_NAMESPACE_DGL using namespace DGL_NAMESPACE;
+
+#if DGL_OS_MAC
+# include <OpenGL/gl.h>
+#else
+# include <GL/gl.h>
+#endif
+
+#if defined(GL_BGR_EXT) && ! defined(GL_BGR)
+# define GL_BGR GL_BGR_EXT
+#endif
+
+#if defined(GL_BGRA_EXT) && ! defined(GL_BGRA)
+# define GL_BGRA GL_BGRA_EXT
+#endif
+
+#ifndef GL_CLAMP_TO_BORDER
+# define GL_CLAMP_TO_BORDER 0x812D
+#endif
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+/*
+ * Convenience symbols for ASCII control characters.
+ */
+enum Char {
+ CHAR_BACKSPACE = 0x08,
+ CHAR_ESCAPE = 0x1B,
+ CHAR_DELETE = 0x7F
+};
+
+/*
+ * Special (non-Unicode) keyboard keys.
+ */
+enum Key {
+ KEY_F1 = 1,
+ KEY_F2,
+ KEY_F3,
+ KEY_F4,
+ KEY_F5,
+ KEY_F6,
+ KEY_F7,
+ KEY_F8,
+ KEY_F9,
+ KEY_F10,
+ KEY_F11,
+ KEY_F12,
+ KEY_LEFT,
+ KEY_UP,
+ KEY_RIGHT,
+ KEY_DOWN,
+ KEY_PAGE_UP,
+ KEY_PAGE_DOWN,
+ KEY_HOME,
+ KEY_END,
+ KEY_INSERT,
+ KEY_SHIFT,
+ KEY_CTRL,
+ KEY_ALT,
+ KEY_SUPER
+};
+
+/*
+ * Keyboard modifier flags.
+ */
+enum Modifier {
+ MODIFIER_SHIFT = 1 << 0, /**< Shift key */
+ MODIFIER_CTRL = 1 << 1, /**< Control key */
+ MODIFIER_ALT = 1 << 2, /**< Alt/Option key */
+ MODIFIER_SUPER = 1 << 3 /**< Mod4/Command/Windows key */
+};
+
+/*
+ * Cross-platform sleep function.
+ */
+void sleep(unsigned int secs);
+
+/*
+ * Cross-platform msleep function.
+ */
+void msleep(unsigned int msecs);
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
+
+#endif // DGL_BASE_HPP_INCLUDED
diff --git a/dgl/CairoWidget.hpp b/dgl/CairoWidget.hpp
@@ -0,0 +1,142 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DGL_CAIRO_WIDGET_HPP_INCLUDED
+#define DGL_CAIRO_WIDGET_HPP_INCLUDED
+
+#include "Widget.hpp"
+
+#include <cairo.h>
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+class CairoWidget : public Widget
+{
+public:
+ CairoWidget(Window& parent)
+ : Widget(parent),
+ fContext(nullptr),
+ fSurface(nullptr),
+ fTextureId(0)
+ {
+ }
+
+protected:
+ virtual void cairoDisplay(cairo_t* const context) = 0;
+
+private:
+ void onReshape(int width, int height) override
+ {
+ // handle resize
+ setSize(width, height);
+ Widget::onReshape(width, height);
+
+ // free previous if needed
+ onClose();
+
+ // create new
+ fSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
+ fContext = cairo_create(fSurface);
+
+ glGenTextures(1, &fTextureId);
+ }
+
+ void onClose() override
+ {
+ if (fContext != nullptr)
+ {
+ cairo_destroy(fContext);
+ fContext = nullptr;
+ }
+
+ if (fSurface != nullptr)
+ {
+ cairo_surface_destroy(fSurface);
+ fSurface = nullptr;
+ }
+
+ if (fTextureId != 0)
+ {
+ glDeleteTextures(1, &fTextureId);
+ fTextureId = 0;
+ }
+ }
+
+ void onDisplay() override
+ {
+ // wait for first resize
+ if (fSurface == nullptr || fContext == nullptr)
+ {
+ glClear(GL_COLOR_BUFFER_BIT);
+ return;
+ }
+
+ const int width = getWidth();
+ const int height = getHeight();
+
+ // draw cairo stuff
+ cairoDisplay(fContext);
+
+ // get cairo surface data (RGB24)
+ unsigned char* const surfaceData = cairo_image_surface_get_data(fSurface);
+
+ // enable GL texture
+ glEnable(GL_TEXTURE_RECTANGLE_ARB);
+
+ // set texture params
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ // bind texture to surface data
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, fTextureId);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, surfaceData);
+
+ // draw the texture
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glBegin(GL_QUADS);
+ glTexCoord2i(0, height);
+ glVertex2i(0, height);
+
+ glTexCoord2i(width, height);
+ glVertex2i(width, height);
+
+ glTexCoord2i(width, 0);
+ glVertex2i(width, 0);
+
+ glTexCoord2i(0, 0);
+ glVertex2i(0, 0);
+ glEnd();
+
+ // cleanup
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+ }
+
+private:
+ cairo_t* fContext;
+ cairo_surface_t* fSurface;
+ GLuint fTextureId;
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
+
+#endif // DGL_CAIRO_WIDGET_HPP_INCLUDED
diff --git a/dgl/Geometry.hpp b/dgl/Geometry.hpp
@@ -0,0 +1,133 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DGL_GEOMETRY_HPP_INCLUDED
+#define DGL_GEOMETRY_HPP_INCLUDED
+
+#include "Base.hpp"
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+template<typename T>
+class Point
+{
+public:
+ Point() noexcept;
+ Point(T x, T y) noexcept;
+ Point(const Point<T>& pos) noexcept;
+
+ T getX() const noexcept;
+ T getY() const noexcept;
+
+ void setX(T x) noexcept;
+ void setY(T y) noexcept;
+
+ void move(T x, T y) noexcept;
+ void move(const Point<T>& pos) noexcept;
+
+ Point<T>& operator=(const Point<T>& pos) noexcept;
+ Point<T>& operator+=(const Point<T>& pos) noexcept;
+ Point<T>& operator-=(const Point<T>& pos) noexcept;
+ bool operator==(const Point<T>& pos) const noexcept;
+ bool operator!=(const Point<T>& pos) const noexcept;
+
+private:
+ T fX, fY;
+ template<typename> friend class Rectangle;
+};
+
+// -----------------------------------------------------------------------
+
+template<typename T>
+class Size
+{
+public:
+ Size() noexcept;
+ Size(T width, T height) noexcept;
+ Size(const Size<T>& size) noexcept;
+
+ T getWidth() const noexcept;
+ T getHeight() const noexcept;
+
+ void setWidth(T width) noexcept;
+ void setHeight(T height) noexcept;
+
+ Size<T>& operator=(const Size<T>& size) noexcept;
+ Size<T>& operator+=(const Size<T>& size) noexcept;
+ Size<T>& operator-=(const Size<T>& size) noexcept;
+ Size<T>& operator*=(T m) noexcept;
+ Size<T>& operator/=(T d) noexcept;
+ bool operator==(const Size<T>& size) const noexcept;
+ bool operator!=(const Size<T>& size) const noexcept;
+
+private:
+ T fWidth, fHeight;
+ template<typename> friend class Rectangle;
+};
+
+// -----------------------------------------------------------------------
+
+template<typename T>
+class Rectangle
+{
+public:
+ Rectangle() noexcept;
+ Rectangle(T x, T y, T width, T height) noexcept;
+ Rectangle(T x, T y, const Size<T>& size) noexcept;
+ Rectangle(const Point<T>& pos, T width, T height) noexcept;
+ Rectangle(const Point<T>& pos, const Size<T>& size) noexcept;
+ Rectangle(const Rectangle<T>& rect) noexcept;
+
+ T getX() const noexcept;
+ T getY() const noexcept;
+ T getWidth() const noexcept;
+ T getHeight() const noexcept;
+
+ const Point<T>& getPos() const noexcept;
+ const Size<T>& getSize() const noexcept;
+
+ bool contains(T x, T y) const noexcept;
+ bool contains(const Point<T>& pos) const noexcept;
+ bool containsX(T x) const noexcept;
+ bool containsY(T y) const noexcept;
+
+ void setX(T x) noexcept;
+ void setY(T y) noexcept;
+ void setPos(T x, T y) noexcept;
+ void setPos(const Point<T>& pos) noexcept;
+
+ void move(T x, T y) noexcept;
+ void move(const Point<T>& pos) noexcept;
+
+ void setWidth(T width) noexcept;
+ void setHeight(T height) noexcept;
+ void setSize(T width, T height) noexcept;
+ void setSize(const Size<T>& size) noexcept;
+
+ Rectangle<T>& operator=(const Rectangle<T>& rect) noexcept;
+
+private:
+ Point<T> fPos;
+ Size<T> fSize;
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
+
+#endif // DGL_GEOMETRY_HPP_INCLUDED
diff --git a/dgl/Image.hpp b/dgl/Image.hpp
@@ -0,0 +1,66 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DGL_IMAGE_HPP_INCLUDED
+#define DGL_IMAGE_HPP_INCLUDED
+
+#include "Geometry.hpp"
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+class Image
+{
+public:
+ Image() noexcept;
+ Image(const char* rawData, int width, int height, GLenum format = GL_BGRA, GLenum type = GL_UNSIGNED_BYTE) noexcept;
+ Image(const char* rawData, const Size<int>& size, GLenum format = GL_BGRA, GLenum type = GL_UNSIGNED_BYTE) noexcept;
+ Image(const Image& image) noexcept;
+
+ void loadFromMemory(const char* rawData, int width, int height, GLenum format = GL_BGRA, GLenum type = GL_UNSIGNED_BYTE) noexcept;
+ void loadFromMemory(const char* rawData, const Size<int>& size, GLenum format = GL_BGRA, GLenum type = GL_UNSIGNED_BYTE) noexcept;
+
+ bool isValid() const noexcept;
+
+ int getWidth() const noexcept;
+ int getHeight() const noexcept;
+ const Size<int>& getSize() const noexcept;
+
+ const char* getRawData() const noexcept;
+ GLenum getFormat() const noexcept;
+ GLenum getType() const noexcept;
+
+ void draw() const;
+ void draw(int x, int y) const;
+ void draw(const Point<int>& pos) const;
+
+ Image& operator=(const Image& image) noexcept;
+ bool operator==(const Image& image) const noexcept;
+ bool operator!=(const Image& image) const noexcept;
+
+private:
+ const char* fRawData;
+ Size<int> fSize;
+ GLenum fFormat;
+ GLenum fType;
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
+
+#endif // DGL_IMAGE_HPP_INCLUDED
diff --git a/dgl/ImageAboutWindow.hpp b/dgl/ImageAboutWindow.hpp
@@ -0,0 +1,56 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DGL_IMAGE_ABOUT_WINDOW_HPP_INCLUDED
+#define DGL_IMAGE_ABOUT_WINDOW_HPP_INCLUDED
+
+#include "Image.hpp"
+#include "Widget.hpp"
+#include "Window.hpp"
+
+#ifdef PROPER_CPP11_SUPPORT
+# include <cstdint>
+#else
+# include <stdint.h>
+#endif
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+class ImageAboutWindow : public Window,
+ public Widget
+{
+public:
+ ImageAboutWindow(App& app, Window& parent, const Image& image = Image());
+ ImageAboutWindow(Widget* widget, const Image& image = Image());
+
+ void setImage(const Image& image);
+
+protected:
+ void onDisplay() override;
+ bool onMouse(int button, bool press, int x, int y) override;
+ bool onKeyboard(bool press, uint32_t key) override;
+
+private:
+ Image fImgBackground;
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
+
+#endif // DGL_IMAGE_ABOUT_WINDOW_HPP_INCLUDED
diff --git a/dgl/ImageButton.hpp b/dgl/ImageButton.hpp
@@ -0,0 +1,64 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DGL_IMAGE_BUTTON_HPP_INCLUDED
+#define DGL_IMAGE_BUTTON_HPP_INCLUDED
+
+#include "Image.hpp"
+#include "Widget.hpp"
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+class ImageButton : public Widget
+{
+public:
+ class Callback
+ {
+ public:
+ virtual ~Callback() {}
+ virtual void imageButtonClicked(ImageButton* imageButton, int button) = 0;
+ };
+
+ ImageButton(Window& parent, const Image& image);
+ ImageButton(Widget* widget, const Image& image);
+ ImageButton(Window& parent, const Image& imageNormal, const Image& imageHover, const Image& imageDown);
+ ImageButton(Widget* widget, const Image& imageNormal, const Image& imageHover, const Image& imageDown);
+ ImageButton(const ImageButton& imageButton);
+
+ void setCallback(Callback* callback);
+
+protected:
+ void onDisplay() override;
+ bool onMouse(int button, bool press, int x, int y) override;
+ bool onMotion(int x, int y) override;
+
+private:
+ Image fImageNormal;
+ Image fImageHover;
+ Image fImageDown;
+ Image* fCurImage;
+ int fCurButton;
+
+ Callback* fCallback;
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
+
+#endif // DGL_IMAGE_BUTTON_HPP_INCLUDED
diff --git a/dgl/ImageKnob.hpp b/dgl/ImageKnob.hpp
@@ -0,0 +1,89 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DGL_IMAGE_KNOB_HPP_INCLUDED
+#define DGL_IMAGE_KNOB_HPP_INCLUDED
+
+#include "Image.hpp"
+#include "Widget.hpp"
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+class ImageKnob : public Widget
+{
+public:
+ enum Orientation {
+ Horizontal,
+ Vertical
+ };
+
+ class Callback
+ {
+ public:
+ virtual ~Callback() {}
+ virtual void imageKnobDragStarted(ImageKnob* imageKnob) = 0;
+ virtual void imageKnobDragFinished(ImageKnob* imageKnob) = 0;
+ virtual void imageKnobValueChanged(ImageKnob* imageKnob, float value) = 0;
+ };
+
+ ImageKnob(Window& parent, const Image& image, Orientation orientation = Vertical);
+ ImageKnob(Widget* widget, const Image& image, Orientation orientation = Vertical);
+ ImageKnob(const ImageKnob& imageKnob);
+
+ float getValue() const;
+
+ void setOrientation(Orientation orientation);
+ void setRange(float min, float max);
+ void setValue(float value, bool sendCallback = false);
+ void setRotationAngle(int angle);
+
+ void setCallback(Callback* callback);
+
+protected:
+ void onDisplay() override;
+ bool onMouse(int button, bool press, int x, int y) override;
+ bool onMotion(int x, int y) override;
+ void onReshape(int width, int height) override;
+ void onClose() override;
+
+private:
+ Image fImage;
+ float fMinimum;
+ float fMaximum;
+ float fValue;
+ Orientation fOrientation;
+
+ int fRotationAngle;
+ bool fDragging;
+ int fLastX;
+ int fLastY;
+
+ Callback* fCallback;
+
+ bool fIsImgVertical;
+ int fImgLayerSize;
+ int fImgLayerCount;
+ Rectangle<int> fKnobArea;
+ GLuint fTextureId;
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
+
+#endif // DGL_IMAGE_KNOB_HPP_INCLUDED
diff --git a/dgl/ImageSlider.hpp b/dgl/ImageSlider.hpp
@@ -0,0 +1,85 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DGL_IMAGE_SLIDER_HPP_INCLUDED
+#define DGL_IMAGE_SLIDER_HPP_INCLUDED
+
+#include "Image.hpp"
+#include "Widget.hpp"
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+class ImageSlider : public Widget
+{
+public:
+ class Callback
+ {
+ public:
+ virtual ~Callback() {}
+ virtual void imageSliderDragStarted(ImageSlider* imageSlider) = 0;
+ virtual void imageSliderDragFinished(ImageSlider* imageSlider) = 0;
+ virtual void imageSliderValueChanged(ImageSlider* imageSlider, float value) = 0;
+ };
+
+ ImageSlider(Window& parent, const Image& image);
+ ImageSlider(Widget* widget, const Image& image);
+ ImageSlider(const ImageSlider& imageSlider);
+
+ float getValue() const;
+
+ void setStartPos(const Point<int>& startPos);
+ void setStartPos(int x, int y);
+ void setEndPos(const Point<int>& endPos);
+ void setEndPos(int x, int y);
+
+ void setRange(float min, float max);
+ void setValue(float value, bool sendCallback = false);
+ void setIsSwitch(bool yesNo);
+
+ void setCallback(Callback* callback);
+
+protected:
+ void onDisplay() override;
+ bool onMouse(int button, bool press, int x, int y) override;
+ bool onMotion(int x, int y) override;
+
+private:
+ Image fImage;
+ float fMinimum;
+ float fMaximum;
+ float fValue;
+
+ bool fIsSwitch;
+ bool fDragging;
+ int fStartedX;
+ int fStartedY;
+
+ Callback* fCallback;
+
+ Point<int> fStartPos;
+ Point<int> fEndPos;
+ Rectangle<int> fSliderArea;
+
+ void _recheckArea();
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
+
+#endif // DGL_IMAGE_SLIDER_HPP_INCLUDED
diff --git a/dgl/Makefile b/dgl/Makefile
@@ -0,0 +1,67 @@
+#!/usr/bin/make -f
+# Makefile for dgl #
+# ---------------- #
+# Created by falkTX
+#
+
+include Makefile.mk
+
+# --------------------------------------------------------------
+
+BUILD_C_FLAGS += $(DGL_FLAGS) -I.
+BUILD_CXX_FLAGS += $(DGL_FLAGS) -I.
+LINK_FLAGS += $(DGL_LIBS)
+
+# --------------------------------------------------------------
+
+OBJS = \
+ src/App.cpp.o \
+ src/Base.cpp.o \
+ src/Image.cpp.o \
+ src/ImageAboutWindow.cpp.o \
+ src/ImageButton.cpp.o \
+ src/ImageKnob.cpp.o \
+ src/ImageSlider.cpp.o \
+ src/Geometry.cpp.o \
+ src/Widget.cpp.o \
+ src/Window.cpp.o
+
+ifeq ($(MACOS),true)
+OBJS += src/pugl/pugl_osx_extended.m.o
+endif
+
+TARGET = ../libdgl.a
+
+# --------------------------------------------------------------
+
+all: $(TARGET)
+
+# --------------------------------------------------------------
+
+../libdgl.a: $(OBJS)
+ $(RM) $@
+ $(AR) crs $@ $^
+
+../libdgl.dll: $(OBJS)
+ $(CXX) $^ -shared $(LINK_FLAGS) -o $@
+
+../libdgl.dylib: $(OBJS)
+ $(CXX) $^ -dynamiclib $(LINK_FLAGS) -o $@
+
+../libdgl.so: $(OBJS)
+ $(CXX) $^ -shared $(LINK_FLAGS) -o $@
+
+# --------------------------------------------------------------
+
+%.cpp.o: %.cpp
+ $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@
+
+# --------------------------------------------------------------
+
+clean:
+ $(RM) src/*.o src/pugl/*.o ../libdgl.*
+
+debug:
+ $(MAKE) DEBUG=true
+
+# --------------------------------------------------------------
diff --git a/dgl/Makefile.mk b/dgl/Makefile.mk
@@ -0,0 +1,79 @@
+#!/usr/bin/make -f
+# Makefile for dgl #
+# ---------------- #
+# Created by falkTX
+#
+
+AR ?= ar
+RM ?= rm -f
+
+CC ?= gcc
+CXX ?= g++
+
+# --------------------------------------------------------------
+# Fallback to Linux if no other OS defined
+
+ifneq ($(MACOS),true)
+ifneq ($(WIN32),true)
+LINUX=true
+endif
+endif
+
+# --------------------------------------------------------------
+# Common build and link flags
+
+BASE_FLAGS = -Wall -Wextra -fPIC -DPIC -pipe -DREAL_BUILD
+BASE_OPTS = -O3 -ffast-math -mtune=generic -msse -msse2 -mfpmath=sse
+
+ifeq ($(RASPPI),true)
+# Raspberry-Pi optimization flags
+BASE_OPTS = -O3 -ffast-math -march=armv6 -mfpu=vfp -mfloat-abi=hard
+endif
+
+ifeq ($(DEBUG),true)
+BASE_FLAGS += -DDEBUG -O0 -g
+else
+BASE_FLAGS += -DNDEBUG $(BASE_OPTS) -fvisibility=hidden
+CXXFLAGS += -fvisibility-inlines-hidden
+LINK_OPTS += -Wl,--strip-all
+endif
+
+BUILD_C_FLAGS = $(BASE_FLAGS) -std=gnu99 $(CFLAGS)
+BUILD_CXX_FLAGS = $(BASE_FLAGS) -std=gnu++0x $(CXXFLAGS)
+LINK_FLAGS = $(LINK_OPTS) -Wl,--no-undefined $(LDFLAGS)
+
+ifeq ($(MACOS),true)
+# Get rid of most options for old gcc4.2
+BUILD_CXX_FLAGS = $(BASE_FLAGS) $(CXXFLAGS)
+LINK_FLAGS = $(LDFLAGS)
+endif
+
+# --------------------------------------------------------------
+# Check for required libs
+
+ifeq ($(LINUX),true)
+ifneq ($(shell pkg-config --exists gl && echo true),true)
+$(error OpenGL missing, cannot continue)
+endif
+ifneq ($(shell pkg-config --exists x11 && echo true),true)
+$(error X11 missing, cannot continue)
+endif
+endif
+
+# --------------------------------------------------------------
+# Set libs stuff
+
+ifeq ($(LINUX),true)
+DGL_FLAGS = $(shell pkg-config --cflags gl x11)
+DGL_LIBS = $(shell pkg-config --libs gl x11)
+endif
+
+ifeq ($(MACOS),true)
+DGL_LIBS = -framework OpenGL -framework Cocoa
+endif
+
+ifeq ($(WIN32),true)
+DGL_LIBS = -lopengl32 -lgdi32
+endif
+
+# --------------------------------------------------------------
diff --git a/dgl/StandaloneWindow.hpp b/dgl/StandaloneWindow.hpp
@@ -0,0 +1,79 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DGL_STANDALONE_WINDOW_HPP_INCLUDED
+#define DGL_STANDALONE_WINDOW_HPP_INCLUDED
+
+#include "App.hpp"
+#include "Window.hpp"
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+class StandaloneWindow
+{
+public:
+ StandaloneWindow()
+ : fApp(),
+ fWindow(fApp)
+ {
+ }
+
+ App& getApp() noexcept
+ {
+ return fApp;
+ }
+
+ Window& getWindow() noexcept
+ {
+ return fWindow;
+ }
+
+ void exec()
+ {
+ fWindow.show();
+ fApp.exec();
+ }
+
+ // -------------------------------------------------------------------
+ // helpers
+
+ void setResizable(bool yesNo)
+ {
+ fWindow.setResizable(yesNo);
+ }
+
+ void setSize(unsigned int width, unsigned int height)
+ {
+ fWindow.setSize(width, height);
+ }
+
+ void setTitle(const char* title)
+ {
+ fWindow.setTitle(title);
+ }
+
+private:
+ App fApp;
+ Window fWindow;
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
+
+#endif // DGL_STANDALONE_WINDOW_HPP_INCLUDED
diff --git a/dgl/Widget.hpp b/dgl/Widget.hpp
@@ -0,0 +1,100 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DGL_WIDGET_HPP_INCLUDED
+#define DGL_WIDGET_HPP_INCLUDED
+
+#include "Geometry.hpp"
+
+#ifdef PROPER_CPP11_SUPPORT
+# include <cstdint>
+#else
+# include <stdint.h>
+#endif
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+class App;
+class Window;
+
+class Widget
+{
+public:
+ Widget(Window& parent);
+ virtual ~Widget();
+
+ bool isVisible() const noexcept;
+ void setVisible(bool yesNo);
+
+ void show();
+ void hide();
+
+ int getX() const noexcept;
+ int getY() const noexcept;
+ const Point<int>& getPos() const noexcept;
+
+ void setX(int x);
+ void setY(int y);
+ void setPos(int x, int y);
+ void setPos(const Point<int>& pos);
+
+ void move(int x, int y);
+ void move(const Point<int>& pos);
+
+ int getWidth() const noexcept;
+ int getHeight() const noexcept;
+ const Size<int>& getSize() const noexcept;
+
+ void setWidth(int width);
+ void setHeight(int height);
+ void setSize(int width, int height);
+ void setSize(const Size<int>& size);
+
+ const Rectangle<int>& getArea() const noexcept;
+
+ uint32_t getEventTimestamp();
+ int getModifiers();
+
+ App& getParentApp() const noexcept;
+ Window& getParentWindow() const noexcept;
+
+ void repaint();
+
+protected:
+ virtual void onDisplay() = 0;
+ virtual bool onKeyboard(bool press, uint32_t key);
+ virtual bool onMouse(int button, bool press, int x, int y);
+ virtual bool onMotion(int x, int y);
+ virtual bool onScroll(float dx, float dy);
+ virtual bool onSpecial(bool press, Key key);
+ virtual void onReshape(int width, int height);
+ virtual void onClose();
+
+private:
+ Window& fParent;
+ bool fVisible;
+ Rectangle<int> fArea;
+
+ friend class Window;
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
+
+#endif // DGL_WIDGET_HPP_INCLUDED
diff --git a/dgl/Window.hpp b/dgl/Window.hpp
@@ -0,0 +1,85 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DGL_WINDOW_HPP_INCLUDED
+#define DGL_WINDOW_HPP_INCLUDED
+
+#include "Geometry.hpp"
+
+#ifdef PROPER_CPP11_SUPPORT
+# include <cstdint>
+#else
+# include <stdint.h>
+#endif
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+class App;
+class Widget;
+
+class Window
+{
+public:
+ Window(App& app);
+ Window(App& app, Window& parent);
+ Window(App& app, intptr_t parentId);
+ virtual ~Window();
+
+ void show();
+ void hide();
+ void close();
+ void exec(bool lockWait = false);
+
+ void focus();
+ void idle();
+ void repaint();
+
+ bool isVisible() const noexcept;
+ void setVisible(bool yesNo);
+
+ bool isResizable() const noexcept;
+ void setResizable(bool yesNo);
+
+#ifndef DGL_OS_MAC
+ int getWidth() const noexcept;
+ int getHeight() const noexcept;
+ Size<int> getSize() const noexcept;
+#endif
+ void setSize(unsigned int width, unsigned int height);
+
+ void setTitle(const char* title);
+
+ App& getApp() const noexcept;
+ uint32_t getEventTimestamp() const;
+ int getModifiers() const;
+ intptr_t getWindowId() const;
+
+private:
+ class PrivateData;
+ PrivateData* const pData;
+ friend class Widget;
+
+ void addWidget(Widget* const widget);
+ void removeWidget(Widget* const widget);
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
+
+#endif // DGL_WINDOW_HPP_INCLUDED
diff --git a/dgl/src/App.cpp b/dgl/src/App.cpp
@@ -0,0 +1,111 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "../App.hpp"
+#include "../Window.hpp"
+
+#include <list>
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+struct App::PrivateData {
+ bool doLoop;
+ unsigned visibleWindows;
+ std::list<Window*> windows;
+
+ PrivateData()
+ : doLoop(false),
+ visibleWindows(0) {}
+};
+
+// -----------------------------------------------------------------------
+
+App::App()
+ : pData(new PrivateData())
+{
+}
+
+App::~App()
+{
+ pData->windows.clear();
+ delete pData;
+}
+
+void App::idle()
+{
+ for (std::list<Window*>::iterator it = pData->windows.begin(); it != pData->windows.end(); ++it)
+ {
+ Window* const window(*it);
+ window->idle();
+ }
+}
+
+void App::exec()
+{
+ while (pData->doLoop)
+ {
+ idle();
+ msleep(10);
+ }
+}
+
+void App::quit()
+{
+ pData->doLoop = false;
+
+ for (std::list<Window*>::reverse_iterator rit = pData->windows.rbegin(); rit != pData->windows.rend(); ++rit)
+ {
+ Window* const window(*rit);
+ window->close();
+ }
+}
+
+bool App::isQuiting() const
+{
+ return !pData->doLoop;
+}
+
+// -----------------------------------------------------------------------
+
+void App::addWindow(Window* const window)
+{
+ if (window != nullptr)
+ pData->windows.push_back(window);
+}
+
+void App::removeWindow(Window* const window)
+{
+ if (window != nullptr)
+ pData->windows.remove(window);
+}
+
+void App::oneShown()
+{
+ if (++pData->visibleWindows == 1)
+ pData->doLoop = true;
+}
+
+void App::oneHidden()
+{
+ if (--pData->visibleWindows == 0)
+ pData->doLoop = false;
+}
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
diff --git a/dgl/src/Base.cpp b/dgl/src/Base.cpp
@@ -0,0 +1,49 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "../Base.hpp"
+
+#if DGL_OS_WINDOWS
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+void sleep(unsigned int secs)
+{
+#ifdef DGL_OS_WINDOWS
+ ::Sleep(secs * 1000);
+#else
+ ::sleep(secs);
+#endif
+}
+
+void msleep(unsigned int msecs)
+{
+#ifdef DGL_OS_WINDOWS
+ ::Sleep(msecs);
+#else
+ ::usleep(msecs * 1000);
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
diff --git a/dgl/src/Geometry.cpp b/dgl/src/Geometry.cpp
@@ -0,0 +1,416 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "../Geometry.hpp"
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+// Point
+
+template<typename T>
+Point<T>::Point() noexcept
+ : fX(0),
+ fY(0)
+{
+}
+
+template<typename T>
+Point<T>::Point(T x, T y) noexcept
+ : fX(x),
+ fY(y)
+{
+}
+
+template<typename T>
+Point<T>::Point(const Point& pos) noexcept
+ : fX(pos.fX),
+ fY(pos.fY)
+{
+}
+
+template<typename T>
+T Point<T>::getX() const noexcept
+{
+ return fX;
+}
+
+template<typename T>
+T Point<T>::getY() const noexcept
+{
+ return fY;
+}
+
+template<typename T>
+void Point<T>::setX(T x) noexcept
+{
+ fX = x;
+}
+
+template<typename T>
+void Point<T>::setY(T y) noexcept
+{
+ fY = y;
+}
+
+template<typename T>
+void Point<T>::move(T x, T y) noexcept
+{
+ fX += x;
+ fY += y;
+}
+
+template<typename T>
+void Point<T>::move(const Point& pos) noexcept
+{
+ fX += pos.fX;
+ fY += pos.fY;
+}
+
+template<typename T>
+Point<T>& Point<T>::operator=(const Point<T>& pos) noexcept
+{
+ fX = pos.fX;
+ fY = pos.fY;
+ return *this;
+}
+
+template<typename T>
+Point<T>& Point<T>::operator+=(const Point<T>& pos) noexcept
+{
+ fX += pos.fX;
+ fY += pos.fY;
+ return *this;
+}
+
+template<typename T>
+Point<T>& Point<T>::operator-=(const Point<T>& pos) noexcept
+{
+ fX -= pos.fX;
+ fY -= pos.fY;
+ return *this;
+}
+
+template<typename T>
+bool Point<T>::operator==(const Point<T>& pos) const noexcept
+{
+ return (fX == pos.fX && fY== pos.fY);
+}
+
+template<typename T>
+bool Point<T>::operator!=(const Point<T>& pos) const noexcept
+{
+ return !operator==(pos);
+}
+
+// -----------------------------------------------------------------------
+// Size
+
+template<typename T>
+Size<T>::Size() noexcept
+ : fWidth(0),
+ fHeight(0)
+{
+}
+
+template<typename T>
+Size<T>::Size(T width, T height) noexcept
+ : fWidth(width),
+ fHeight(height)
+{
+}
+
+template<typename T>
+Size<T>::Size(const Size<T>& size) noexcept
+ : fWidth(size.fWidth),
+ fHeight(size.fHeight)
+{
+}
+
+template<typename T>
+T Size<T>::getWidth() const noexcept
+{
+ return fWidth;
+}
+
+template<typename T>
+T Size<T>::getHeight() const noexcept
+{
+ return fHeight;
+}
+
+template<typename T>
+void Size<T>::setWidth(T width) noexcept
+{
+ fWidth = width;
+}
+
+template<typename T>
+void Size<T>::setHeight(T height) noexcept
+{
+ fHeight = height;
+}
+
+template<typename T>
+Size<T>& Size<T>::operator=(const Size<T>& size) noexcept
+{
+ fWidth = size.fWidth;
+ fHeight = size.fHeight;
+ return *this;
+}
+
+template<typename T>
+Size<T>& Size<T>::operator+=(const Size<T>& size) noexcept
+{
+ fWidth += size.fWidth;
+ fHeight += size.fHeight;
+ return *this;
+}
+
+template<typename T>
+Size<T>& Size<T>::operator-=(const Size<T>& size) noexcept
+{
+ fWidth -= size.fWidth;
+ fHeight -= size.fHeight;
+ return *this;
+}
+
+template<typename T>
+Size<T>& Size<T>::operator*=(T m) noexcept
+{
+ fWidth *= m;
+ fHeight *= m;
+ return *this;
+}
+
+template<typename T>
+Size<T>& Size<T>::operator/=(T d) noexcept
+{
+ fWidth /= d;
+ fHeight /= d;
+ return *this;
+}
+
+template<typename T>
+bool Size<T>::operator==(const Size<T>& size) const noexcept
+{
+ return (fWidth == size.fWidth && fHeight == size.fHeight);
+}
+
+template<typename T>
+bool Size<T>::operator!=(const Size<T>& size) const noexcept
+{
+ return !operator==(size);
+}
+
+// -----------------------------------------------------------------------
+// Rectangle
+
+template<typename T>
+Rectangle<T>::Rectangle() noexcept
+ : fPos(0, 0),
+ fSize(0, 0)
+{
+}
+
+template<typename T>
+Rectangle<T>::Rectangle(T x, T y, T width, T height) noexcept
+ : fPos(x, y),
+ fSize(width, height)
+{
+}
+
+template<typename T>
+Rectangle<T>::Rectangle(T x, T y, const Size<T>& size) noexcept
+ : fPos(x, y),
+ fSize(size)
+{
+}
+
+template<typename T>
+Rectangle<T>::Rectangle(const Point<T>& pos, T width, T height) noexcept
+ : fPos(pos),
+ fSize(width, height)
+{
+}
+
+template<typename T>
+Rectangle<T>::Rectangle(const Point<T>& pos, const Size<T>& size) noexcept
+ : fPos(pos),
+ fSize(size)
+{
+}
+
+template<typename T>
+Rectangle<T>::Rectangle(const Rectangle<T>& rect) noexcept
+ : fPos(rect.fPos),
+ fSize(rect.fSize)
+{
+}
+
+template<typename T>
+T Rectangle<T>::getX() const noexcept
+{
+ return fPos.fX;
+}
+
+template<typename T>
+T Rectangle<T>::getY() const noexcept
+{
+ return fPos.fY;
+}
+
+template<typename T>
+T Rectangle<T>::getWidth() const noexcept
+{
+ return fSize.fWidth;
+}
+
+template<typename T>
+T Rectangle<T>::getHeight() const noexcept
+{
+ return fSize.fHeight;
+}
+
+template<typename T>
+const Point<T>& Rectangle<T>::getPos() const noexcept
+{
+ return fPos;
+}
+
+template<typename T>
+const Size<T>& Rectangle<T>::getSize() const noexcept
+{
+ return fSize;
+}
+
+template<typename T>
+bool Rectangle<T>::contains(T x, T y) const noexcept
+{
+ return (x >= fPos.fX && y >= fPos.fY && x <= fPos.fX+fSize.fWidth && y <= fPos.fY+fSize.fHeight);
+}
+
+template<typename T>
+bool Rectangle<T>::contains(const Point<T>& pos) const noexcept
+{
+ return contains(pos.fX, pos.fY);
+}
+
+template<typename T>
+bool Rectangle<T>::containsX(T x) const noexcept
+{
+ return (x >= fPos.fX && x <= fPos.fX + fSize.fWidth);
+}
+
+template<typename T>
+bool Rectangle<T>::containsY(T y) const noexcept
+{
+ return (y >= fPos.fY && y <= fPos.fY + fSize.fHeight);
+}
+
+template<typename T>
+void Rectangle<T>::setX(T x) noexcept
+{
+ fPos.fX = x;
+}
+
+template<typename T>
+void Rectangle<T>::setY(T y) noexcept
+{
+ fPos.fY = y;
+}
+
+template<typename T>
+void Rectangle<T>::setPos(T x, T y) noexcept
+{
+ fPos.fX = x;
+ fPos.fY = y;
+}
+
+template<typename T>
+void Rectangle<T>::setPos(const Point<T>& pos) noexcept
+{
+ fPos = pos;
+}
+
+template<typename T>
+void Rectangle<T>::move(T x, T y) noexcept
+{
+ fPos.fX += x;
+ fPos.fY += y;
+}
+
+template<typename T>
+void Rectangle<T>::move(const Point<T>& pos) noexcept
+{
+ fPos += pos;
+}
+
+template<typename T>
+void Rectangle<T>::setWidth(T width) noexcept
+{
+ fSize.fWidth = width;
+}
+
+template<typename T>
+void Rectangle<T>::setHeight(T height) noexcept
+{
+ fSize.fHeight = height;
+}
+
+template<typename T>
+void Rectangle<T>::setSize(T width, T height) noexcept
+{
+ fSize.fWidth = width;
+ fSize.fHeight = height;
+}
+
+template<typename T>
+void Rectangle<T>::setSize(const Size<T>& size) noexcept
+{
+ fSize = size;
+}
+
+template<typename T>
+Rectangle<T>& Rectangle<T>::operator=(const Rectangle<T>& rect) noexcept
+{
+ fPos = rect.fPos;
+ fSize = rect.fSize;
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+// Possible template data types
+
+template class Point<int>;
+template class Point<long>;
+template class Point<float>;
+template class Point<double>;
+
+template class Size<int>;
+template class Size<long>;
+template class Size<float>;
+template class Size<double>;
+
+template class Rectangle<int>;
+template class Rectangle<long>;
+template class Rectangle<float>;
+template class Rectangle<double>;
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
+
diff --git a/dgl/src/Image.cpp b/dgl/src/Image.cpp
@@ -0,0 +1,145 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "../Image.hpp"
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+Image::Image() noexcept
+ : fRawData(nullptr),
+ fSize(0, 0),
+ fFormat(0),
+ fType(0)
+{
+}
+
+Image::Image(const char* rawData, int width, int height, GLenum format, GLenum type) noexcept
+ : fRawData(rawData),
+ fSize(width, height),
+ fFormat(format),
+ fType(type)
+{
+}
+
+Image::Image(const char* rawData, const Size<int>& size, GLenum format, GLenum type) noexcept
+ : fRawData(rawData),
+ fSize(size),
+ fFormat(format),
+ fType(type)
+{
+}
+
+Image::Image(const Image& image) noexcept
+ : fRawData(image.fRawData),
+ fSize(image.fSize),
+ fFormat(image.fFormat),
+ fType(image.fType)
+{
+}
+
+void Image::loadFromMemory(const char* rawData, int width, int height, GLenum format, GLenum type) noexcept
+{
+ loadFromMemory(rawData, Size<int>(width, height), format, type);
+}
+
+void Image::loadFromMemory(const char* rawData, const Size<int>& size, GLenum format, GLenum type) noexcept
+{
+ fRawData = rawData;
+ fSize = size;
+ fFormat = format;
+ fType = type;
+}
+
+bool Image::isValid() const noexcept
+{
+ return (fRawData != nullptr && getWidth() > 0 && getHeight() > 0);
+}
+
+int Image::getWidth() const noexcept
+{
+ return fSize.getWidth();
+}
+
+int Image::getHeight() const noexcept
+{
+ return fSize.getHeight();
+}
+
+const Size<int>& Image::getSize() const noexcept
+{
+ return fSize;
+}
+
+const char* Image::getRawData() const noexcept
+{
+ return fRawData;
+}
+
+GLenum Image::getFormat() const noexcept
+{
+ return fFormat;
+}
+
+GLenum Image::getType() const noexcept
+{
+ return fType;
+}
+
+void Image::draw() const
+{
+ draw(0, 0);
+}
+
+void Image::draw(int x, int y) const
+{
+ if (! isValid())
+ return;
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glRasterPos2i(x, fSize.getHeight()+y);
+ glDrawPixels(fSize.getWidth(), fSize.getHeight(), fFormat, fType, fRawData);
+}
+
+void Image::draw(const Point<int>& pos) const
+{
+ draw(pos.getX(), pos.getY());
+}
+
+Image& Image::operator=(const Image& image) noexcept
+{
+ fRawData = image.fRawData;
+ fSize = image.fSize;
+ fFormat = image.fFormat;
+ fType = image.fType;
+ return *this;
+}
+
+bool Image::operator==(const Image& image) const noexcept
+{
+ return (fRawData == image.fRawData);
+}
+
+bool Image::operator!=(const Image& image) const noexcept
+{
+ return (fRawData != image.fRawData);
+}
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
diff --git a/dgl/src/ImageAboutWindow.cpp b/dgl/src/ImageAboutWindow.cpp
@@ -0,0 +1,83 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "../ImageAboutWindow.hpp"
+
+// FIXME: 32bit hack
+#if ! (defined (__LP64__) || defined (_LP64) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__))
+# define PAD_SIZE +1
+#else
+# define PAD_SIZE
+#endif
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+ImageAboutWindow::ImageAboutWindow(App& app, Window& parent, const Image& image)
+ : Window(app, parent),
+ Widget((Window&)*this),
+ fImgBackground(image)
+{
+ Window::setSize(image.getWidth(), image.getHeight() PAD_SIZE);
+ Window::setTitle("About");
+}
+
+ImageAboutWindow::ImageAboutWindow(Widget* widget, const Image& image)
+ : Window(widget->getParentApp(), widget->getParentWindow()),
+ Widget((Window&)*this),
+ fImgBackground(image)
+{
+ Window::setSize(image.getWidth(), image.getHeight() PAD_SIZE);
+ Window::setTitle("About");
+}
+
+void ImageAboutWindow::setImage(const Image& image)
+{
+ fImgBackground = image;
+ Window::setSize(image.getWidth(), image.getHeight() PAD_SIZE);
+}
+
+void ImageAboutWindow::onDisplay()
+{
+ fImgBackground.draw();
+}
+
+bool ImageAboutWindow::onMouse(int, bool press, int, int)
+{
+ if (press)
+ {
+ Window::close();
+ return true;
+ }
+
+ return false;
+}
+
+bool ImageAboutWindow::onKeyboard(bool press, uint32_t key)
+{
+ if (press && key == CHAR_ESCAPE)
+ {
+ Window::close();
+ return true;
+ }
+
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
diff --git a/dgl/src/ImageButton.cpp b/dgl/src/ImageButton.cpp
@@ -0,0 +1,173 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "../ImageButton.hpp"
+
+#include <cassert>
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+ImageButton::ImageButton(Window& parent, const Image& image)
+ : Widget(parent),
+ fImageNormal(image),
+ fImageHover(image),
+ fImageDown(image),
+ fCurImage(&fImageNormal),
+ fCurButton(-1),
+ fCallback(nullptr)
+{
+}
+
+ImageButton::ImageButton(Widget* widget, const Image& image)
+ : Widget(widget->getParentWindow()),
+ fImageNormal(image),
+ fImageHover(image),
+ fImageDown(image),
+ fCurImage(&fImageNormal),
+ fCurButton(-1),
+ fCallback(nullptr)
+{
+}
+
+ImageButton::ImageButton(Window& parent, const Image& imageNormal, const Image& imageHover, const Image& imageDown)
+ : Widget(parent),
+ fImageNormal(imageNormal),
+ fImageHover(imageHover),
+ fImageDown(imageDown),
+ fCurImage(&fImageNormal),
+ fCurButton(-1),
+ fCallback(nullptr)
+{
+ assert(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize());
+
+ setSize(fCurImage->getSize());
+}
+
+ImageButton::ImageButton(Widget* widget, const Image& imageNormal, const Image& imageHover, const Image& imageDown)
+ : Widget(widget->getParentWindow()),
+ fImageNormal(imageNormal),
+ fImageHover(imageHover),
+ fImageDown(imageDown),
+ fCurImage(&fImageNormal),
+ fCurButton(-1),
+ fCallback(nullptr)
+{
+ assert(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize());
+
+ setSize(fCurImage->getSize());
+}
+
+ImageButton::ImageButton(const ImageButton& imageButton)
+ : Widget(imageButton.getParentWindow()),
+ fImageNormal(imageButton.fImageNormal),
+ fImageHover(imageButton.fImageHover),
+ fImageDown(imageButton.fImageDown),
+ fCurImage(&fImageNormal),
+ fCurButton(-1),
+ fCallback(imageButton.fCallback)
+{
+ assert(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize());
+
+ setSize(fCurImage->getSize());
+}
+
+void ImageButton::setCallback(Callback* callback)
+{
+ fCallback = callback;
+}
+
+void ImageButton::onDisplay()
+{
+ fCurImage->draw(getPos());
+}
+
+bool ImageButton::onMouse(int button, bool press, int x, int y)
+{
+ if (fCurButton != -1 && ! press)
+ {
+ if (fCurImage != &fImageNormal)
+ {
+ fCurImage = &fImageNormal;
+ repaint();
+ }
+
+ if (! getArea().contains(x, y))
+ {
+ fCurButton = -1;
+ return false;
+ }
+
+ if (fCallback != nullptr)
+ fCallback->imageButtonClicked(this, fCurButton);
+
+ //if (getArea().contains(x, y))
+ //{
+ // fCurImage = &fImageHover;
+ // repaint();
+ //}
+
+ fCurButton = -1;
+
+ return true;
+ }
+
+ if (press && getArea().contains(x, y))
+ {
+ if (fCurImage != &fImageDown)
+ {
+ fCurImage = &fImageDown;
+ repaint();
+ }
+
+ fCurButton = button;
+ return true;
+ }
+
+ return false;
+}
+
+bool ImageButton::onMotion(int x, int y)
+{
+ if (fCurButton != -1)
+ return true;
+
+ if (getArea().contains(x, y))
+ {
+ if (fCurImage != &fImageHover)
+ {
+ fCurImage = &fImageHover;
+ repaint();
+ }
+
+ return true;
+ }
+ else
+ {
+ if (fCurImage != &fImageNormal)
+ {
+ fCurImage = &fImageNormal;
+ repaint();
+ }
+
+ return false;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
diff --git a/dgl/src/ImageKnob.cpp b/dgl/src/ImageKnob.cpp
@@ -0,0 +1,340 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "../ImageKnob.hpp"
+
+#include <cassert>
+#include <cstdio>
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+ImageKnob::ImageKnob(Window& parent, const Image& image, Orientation orientation)
+ : Widget(parent),
+ fImage(image),
+ fMinimum(0.0f),
+ fMaximum(1.0f),
+ fValue(0.5f),
+ fOrientation(orientation),
+ fRotationAngle(0),
+ fDragging(false),
+ fLastX(0),
+ fLastY(0),
+ fCallback(nullptr),
+ fIsImgVertical(image.getHeight() > image.getWidth()),
+ fImgLayerSize(fIsImgVertical ? image.getWidth() : image.getHeight()),
+ fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerSize : image.getWidth()/fImgLayerSize),
+ fKnobArea(0, 0, fImgLayerSize, fImgLayerSize),
+ fTextureId(0)
+{
+ setSize(fImgLayerSize, fImgLayerSize);
+}
+
+ImageKnob::ImageKnob(Widget* widget, const Image& image, Orientation orientation)
+ : Widget(widget->getParentWindow()),
+ fImage(image),
+ fMinimum(0.0f),
+ fMaximum(1.0f),
+ fValue(0.5f),
+ fOrientation(orientation),
+ fRotationAngle(0),
+ fDragging(false),
+ fLastX(0),
+ fLastY(0),
+ fCallback(nullptr),
+ fIsImgVertical(image.getHeight() > image.getWidth()),
+ fImgLayerSize(fIsImgVertical ? image.getWidth() : image.getHeight()),
+ fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerSize : image.getWidth()/fImgLayerSize),
+ fKnobArea(0, 0, fImgLayerSize, fImgLayerSize),
+ fTextureId(0)
+{
+ setSize(fImgLayerSize, fImgLayerSize);
+}
+
+ImageKnob::ImageKnob(const ImageKnob& imageKnob)
+ : Widget(imageKnob.getParentWindow()),
+ fImage(imageKnob.fImage),
+ fMinimum(imageKnob.fMinimum),
+ fMaximum(imageKnob.fMaximum),
+ fValue(imageKnob.fValue),
+ fOrientation(imageKnob.fOrientation),
+ fRotationAngle(imageKnob.fRotationAngle),
+ fDragging(false),
+ fLastX(0),
+ fLastY(0),
+ fCallback(imageKnob.fCallback),
+ fIsImgVertical(imageKnob.fIsImgVertical),
+ fImgLayerSize(imageKnob.fImgLayerSize),
+ fImgLayerCount(imageKnob.fImgLayerCount),
+ fKnobArea(imageKnob.fKnobArea),
+ fTextureId(0)
+{
+ setSize(fImgLayerSize, fImgLayerSize);
+
+ if (fRotationAngle != 0)
+ {
+ // force new texture creation
+ fRotationAngle = 0;
+ setRotationAngle(imageKnob.fRotationAngle);
+ }
+}
+
+float ImageKnob::getValue() const
+{
+ return fValue;
+}
+
+void ImageKnob::setOrientation(Orientation orientation)
+{
+ if (fOrientation == orientation)
+ return;
+
+ fOrientation = orientation;
+}
+
+void ImageKnob::setRange(float min, float max)
+{
+ if (fValue < min)
+ {
+ fValue = min;
+ repaint();
+
+ if (fCallback != nullptr)
+ fCallback->imageKnobValueChanged(this, fValue);
+ }
+ else if (fValue > max)
+ {
+ fValue = max;
+ repaint();
+
+ if (fCallback != nullptr)
+ fCallback->imageKnobValueChanged(this, fValue);
+ }
+
+ fMinimum = min;
+ fMaximum = max;
+}
+
+void ImageKnob::setValue(float value, bool sendCallback)
+{
+ if (fValue == value)
+ return;
+
+ fValue = value;
+ repaint();
+
+ if (sendCallback && fCallback != nullptr)
+ fCallback->imageKnobValueChanged(this, fValue);
+}
+
+void ImageKnob::setRotationAngle(int angle)
+{
+ if (fRotationAngle == angle)
+ return;
+
+ if (fRotationAngle != 0)
+ {
+ // delete old texture
+ glDeleteTextures(1, &fTextureId);
+ fTextureId = 0;
+ }
+
+ fRotationAngle = angle;
+
+ if (angle != 0)
+ {
+ glEnable(GL_TEXTURE_2D);
+ glGenTextures(1, &fTextureId);
+ glBindTexture(GL_TEXTURE_2D, fTextureId);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWidth(), getHeight(), 0, fImage.getFormat(), fImage.getType(), fImage.getRawData());
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+
+ float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+ }
+}
+
+void ImageKnob::setCallback(Callback* callback)
+{
+ fCallback = callback;
+}
+
+void ImageKnob::onDisplay()
+{
+ const float normValue = (fValue - fMinimum) / (fMaximum - fMinimum);
+
+ if (fRotationAngle != 0)
+ {
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, fTextureId);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWidth(), getHeight(), 0, fImage.getFormat(), fImage.getType(), fImage.getRawData());
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+
+ float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
+
+ glPushMatrix();
+
+ const GLint w2 = getWidth()/2;
+ const GLint h2 = getHeight()/2;
+
+ glTranslatef(getX()+w2, getY()+h2, 0.0f);
+ glRotatef(normValue*fRotationAngle, 0.0f, 0.0f, 1.0f);
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0f, 1.0f);
+ glVertex2i(-w2, -h2);
+
+ glTexCoord2f(1.0f, 1.0f);
+ glVertex2i(getWidth()-w2, -h2);
+
+ glTexCoord2f(1.0f, 0.0f);
+ glVertex2i(getWidth()-w2, getHeight()-h2);
+
+ glTexCoord2f(0.0f, 0.0f);
+ glVertex2i(-w2, getHeight()-h2);
+ glEnd();
+
+ glPopMatrix();
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+ }
+ else
+ {
+ const int layerDataSize = fImgLayerSize * fImgLayerSize * ((fImage.getFormat() == GL_BGRA || fImage.getFormat() == GL_RGBA) ? 4 : 3);
+ const int imageDataSize = layerDataSize * fImgLayerCount;
+ const int imageDataOffset = imageDataSize - layerDataSize - (layerDataSize * int(normValue * float(fImgLayerCount-1)));
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glRasterPos2i(getX(), getY()+getHeight());
+ glDrawPixels(fImgLayerSize, fImgLayerSize, fImage.getFormat(), fImage.getType(), fImage.getRawData() + imageDataOffset);
+ }
+}
+
+bool ImageKnob::onMouse(int button, bool press, int x, int y)
+{
+ if (button != 1)
+ return false;
+
+ if (press)
+ {
+ if (! getArea().contains(x, y))
+ return false;
+
+ fDragging = true;
+ fLastX = x;
+ fLastY = y;
+
+ if (fCallback != nullptr)
+ fCallback->imageKnobDragStarted(this);
+
+ return true;
+ }
+ else if (fDragging)
+ {
+ if (fCallback != nullptr)
+ fCallback->imageKnobDragFinished(this);
+
+ fDragging = false;
+ return true;
+ }
+
+ return false;
+}
+
+bool ImageKnob::onMotion(int x, int y)
+{
+ if (! fDragging)
+ return false;
+
+ if (fOrientation == ImageKnob::Horizontal)
+ {
+ int movX = x - fLastX;
+
+ if (movX != 0)
+ {
+ float d = (getModifiers() & MODIFIER_SHIFT) ? 2000.0f : 200.0f;
+ float value = fValue + (float(fMaximum - fMinimum) / d * float(movX));
+
+ if (value < fMinimum)
+ value = fMinimum;
+ else if (value > fMaximum)
+ value = fMaximum;
+
+ setValue(value, true);
+ }
+ }
+ else if (fOrientation == ImageKnob::Vertical)
+ {
+ int movY = fLastY - y;
+
+ if (movY != 0)
+ {
+ float d = (getModifiers() & MODIFIER_SHIFT) ? 2000.0f : 200.0f;
+ float value = fValue + (float(fMaximum - fMinimum) / d * float(movY));
+
+ if (value < fMinimum)
+ value = fMinimum;
+ else if (value > fMaximum)
+ value = fMaximum;
+
+ setValue(value, true);
+ }
+ }
+
+ fLastX = x;
+ fLastY = y;
+
+ return true;
+}
+
+void ImageKnob::onReshape(int width, int height)
+{
+// if (fRotationAngle != 0)
+// glEnable(GL_TEXTURE_2D);
+
+ Widget::onReshape(width, height);
+}
+
+void ImageKnob::onClose()
+{
+ // delete old texture
+ setRotationAngle(0);
+}
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
diff --git a/dgl/src/ImageSlider.cpp b/dgl/src/ImageSlider.cpp
@@ -0,0 +1,316 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "../ImageSlider.hpp"
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+ImageSlider::ImageSlider(Window& parent, const Image& image)
+ : Widget(parent),
+ fImage(image),
+ fMinimum(0.0f),
+ fMaximum(1.0f),
+ fValue(0.5f),
+ fIsSwitch(false),
+ fDragging(false),
+ fStartedX(0),
+ fStartedY(0),
+ fCallback(nullptr)
+{
+ setSize(fImage.getSize());
+}
+
+ImageSlider::ImageSlider(Widget* widget, const Image& image)
+ : Widget(widget->getParentWindow()),
+ fImage(image),
+ fMinimum(0.0f),
+ fMaximum(1.0f),
+ fValue(0.5f),
+ fIsSwitch(false),
+ fDragging(false),
+ fStartedX(0),
+ fStartedY(0),
+ fCallback(nullptr)
+{
+ setSize(fImage.getSize());
+}
+
+ImageSlider::ImageSlider(const ImageSlider& imageSlider)
+ : Widget(imageSlider.getParentWindow()),
+ fImage(imageSlider.fImage),
+ fMinimum(imageSlider.fMinimum),
+ fMaximum(imageSlider.fMaximum),
+ fValue(imageSlider.fValue),
+ fIsSwitch(imageSlider.fIsSwitch),
+ fDragging(false),
+ fStartedX(0),
+ fStartedY(0),
+ fCallback(imageSlider.fCallback),
+ fStartPos(imageSlider.fStartPos),
+ fEndPos(imageSlider.fEndPos),
+ fSliderArea(imageSlider.fSliderArea)
+{
+ setSize(fImage.getSize());
+}
+
+float ImageSlider::getValue() const
+{
+ return fValue;
+}
+
+void ImageSlider::setStartPos(const Point<int>& startPos)
+{
+ fStartPos = startPos;
+ _recheckArea();
+}
+
+void ImageSlider::setStartPos(int x, int y)
+{
+ setStartPos(Point<int>(x, y));
+}
+
+void ImageSlider::setEndPos(const Point<int>& endPos)
+{
+ fEndPos = endPos;
+ _recheckArea();
+}
+
+void ImageSlider::setEndPos(int x, int y)
+{
+ setEndPos(Point<int>(x, y));
+}
+
+void ImageSlider::setRange(float min, float max)
+{
+ if (fValue < min)
+ {
+ fValue = min;
+ repaint();
+
+ if (fCallback != nullptr)
+ fCallback->imageSliderValueChanged(this, fValue);
+ }
+ else if (fValue > max)
+ {
+ fValue = max;
+ repaint();
+
+ if (fCallback != nullptr)
+ fCallback->imageSliderValueChanged(this, fValue);
+ }
+
+ fMinimum = min;
+ fMaximum = max;
+}
+
+void ImageSlider::setValue(float value, bool sendCallback)
+{
+ if (fValue == value)
+ return;
+
+ fValue = value;
+ repaint();
+
+ if (sendCallback && fCallback != nullptr)
+ fCallback->imageSliderValueChanged(this, fValue);
+}
+
+void ImageSlider::setIsSwitch(bool yesNo)
+{
+ if (fIsSwitch == yesNo)
+ return;
+
+ fIsSwitch = yesNo;
+ repaint();
+}
+
+void ImageSlider::setCallback(Callback* callback)
+{
+ fCallback = callback;
+}
+
+void ImageSlider::onDisplay()
+{
+#if 0 // DEBUG, paints slider area
+ glColor3f(0.4f, 0.5f, 0.1f);
+ glRecti(fSliderArea.getX(), fSliderArea.getY(), fSliderArea.getX()+fSliderArea.getWidth(), fSliderArea.getY()+fSliderArea.getHeight());
+#endif
+
+ float normValue = (fValue - fMinimum) / (fMaximum - fMinimum);
+
+ int x, y;
+
+ if (fStartPos.getX() == fEndPos.getX())
+ {
+ x = fStartPos.getX();
+ y = fEndPos.getY() - normValue*(fEndPos.getY()-fStartPos.getY());
+ }
+ else if (fStartPos.getY() == fEndPos.getY())
+ {
+ x = fEndPos.getX() - normValue*(fEndPos.getX()-fStartPos.getX());
+ y = fStartPos.getY();
+ }
+ else
+ return;
+
+ fImage.draw(x, y);
+}
+
+bool ImageSlider::onMouse(int button, bool press, int x, int y)
+{
+ if (button != 1)
+ return false;
+
+ if (press)
+ {
+ if (! fSliderArea.contains(x, y))
+ return false;
+
+ float vper;
+
+ if (fStartPos.getX() == fEndPos.getX())
+ {
+ // vertical
+ vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight());
+ }
+ else if (fStartPos.getY() == fEndPos.getY())
+ {
+ // horizontal
+ vper = float(x - fSliderArea.getX()) / float(fSliderArea.getWidth());
+ }
+ else
+ return false;
+
+ float value;
+
+ if (fIsSwitch)
+ {
+ if (vper < 0.5f)
+ value = fMaximum;
+ else
+ value = fMinimum;
+ }
+ else
+ {
+ value = fMaximum - vper * (fMaximum - fMinimum);
+
+ if (value < fMinimum)
+ value = fMinimum;
+ else if (value > fMaximum)
+ value = fMaximum;
+ }
+
+ fDragging = true;
+ fStartedX = x;
+ fStartedY = y;
+
+ if (fCallback != nullptr)
+ fCallback->imageSliderDragStarted(this);
+
+ setValue(value, true);
+
+ return true;
+ }
+ else if (fDragging)
+ {
+ if (fCallback != nullptr)
+ fCallback->imageSliderDragFinished(this);
+
+ fDragging = false;
+ return true;
+ }
+
+ return false;
+}
+
+bool ImageSlider::onMotion(int x, int y)
+{
+ if (! fDragging)
+ return false;
+
+ bool horizontal = fStartPos.getY() == fEndPos.getY();
+
+ if ((horizontal && fSliderArea.containsX(x)) || (fSliderArea.containsY(y) && ! horizontal))
+ {
+ float vper;
+
+ if (horizontal)
+ {
+ // horizontal
+ vper = float(x - fSliderArea.getX()) / float(fSliderArea.getWidth());
+ }
+ else
+ {
+ // vertical
+ vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight());
+ }
+
+ float value;
+
+ if (fIsSwitch)
+ {
+ if (vper < 0.5f)
+ value = fMaximum;
+ else
+ value = fMinimum;
+ }
+ else
+ {
+ value = fMaximum - vper * (fMaximum - fMinimum);
+
+ if (value < fMinimum)
+ value = fMinimum;
+ else if (value > fMaximum)
+ value = fMaximum;
+ }
+
+ setValue(value, true);
+ }
+ else if (y < fSliderArea.getY())
+ {
+ setValue(fMaximum, true);
+ }
+ else
+ {
+ setValue(fMinimum, true);
+ }
+
+ return true;
+}
+
+void ImageSlider::_recheckArea()
+{
+ if (fStartPos.getX() == fEndPos.getX())
+ {
+ fSliderArea = Rectangle<int>(fStartPos.getX(),
+ fStartPos.getY(),
+ fImage.getWidth(),
+ fEndPos.getY() + fImage.getHeight() - fStartPos.getY());
+ }
+ else if (fStartPos.getY() == fEndPos.getY())
+ {
+ fSliderArea = Rectangle<int>(fStartPos.getX(),
+ fStartPos.getY(),
+ fEndPos.getX() + fImage.getWidth() - fStartPos.getX(),
+ fImage.getHeight());
+ }
+}
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
diff --git a/dgl/src/Widget.cpp b/dgl/src/Widget.cpp
@@ -0,0 +1,243 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "../App.hpp"
+#include "../Widget.hpp"
+#include "../Window.hpp"
+
+#include <cassert>
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+// Widget
+
+Widget::Widget(Window& parent)
+ : fParent(parent),
+ fVisible(true)
+{
+ fParent.addWidget(this);
+}
+
+Widget::~Widget()
+{
+ fParent.removeWidget(this);
+}
+
+bool Widget::isVisible() const noexcept
+{
+ return fVisible;
+}
+
+void Widget::setVisible(bool yesNo)
+{
+ if (fVisible == yesNo)
+ return;
+
+ fVisible = yesNo;
+ fParent.repaint();
+}
+
+void Widget::show()
+{
+ setVisible(true);
+}
+
+void Widget::hide()
+{
+ setVisible(false);
+}
+
+int Widget::getX() const noexcept
+{
+ return fArea.getX();
+}
+
+int Widget::getY() const noexcept
+{
+ return fArea.getY();
+}
+
+const Point<int>& Widget::getPos() const noexcept
+{
+ return fArea.getPos();
+}
+
+void Widget::setX(int x)
+{
+ if (fArea.getX() == x)
+ return;
+
+ fArea.setX(x);
+ fParent.repaint();
+}
+
+void Widget::setY(int y)
+{
+ if (fArea.getY() == y)
+ return;
+
+ fArea.setY(y);
+ fParent.repaint();
+}
+
+void Widget::setPos(int x, int y)
+{
+ setPos(Point<int>(x, y));
+}
+
+void Widget::setPos(const Point<int>& pos)
+{
+ if (fArea.getPos() == pos)
+ return;
+
+ fArea.setPos(pos);
+ fParent.repaint();
+}
+
+void Widget::move(int x, int y)
+{
+ fArea.move(x, y);
+ fParent.repaint();
+}
+
+void Widget::move(const Point<int>& pos)
+{
+ fArea.move(pos);
+ fParent.repaint();
+}
+
+int Widget::getWidth() const noexcept
+{
+ return fArea.getWidth();
+}
+
+int Widget::getHeight() const noexcept
+{
+ return fArea.getHeight();
+}
+
+const Size<int>& Widget::getSize() const noexcept
+{
+ return fArea.getSize();
+}
+
+void Widget::setWidth(int width)
+{
+ if (fArea.getWidth() == width)
+ return;
+
+ fArea.setWidth(width);
+ fParent.repaint();
+}
+
+void Widget::setHeight(int height)
+{
+ if (fArea.getHeight() == height)
+ return;
+
+ fArea.setHeight(height);
+ fParent.repaint();
+}
+
+void Widget::setSize(int width, int height)
+{
+ setSize(Size<int>(width, height));
+}
+
+void Widget::setSize(const Size<int>& size)
+{
+ if (fArea.getSize() == size)
+ return;
+
+ fArea.setSize(size);
+ fParent.repaint();
+}
+
+const Rectangle<int>& Widget::getArea() const noexcept
+{
+ return fArea;
+}
+
+uint32_t Widget::getEventTimestamp()
+{
+ return fParent.getEventTimestamp();
+}
+
+int Widget::getModifiers()
+{
+ return fParent.getModifiers();
+}
+
+App& Widget::getParentApp() const noexcept
+{
+ return fParent.getApp();
+}
+
+Window& Widget::getParentWindow() const noexcept
+{
+ return fParent;
+}
+
+void Widget::repaint()
+{
+ fParent.repaint();
+}
+
+bool Widget::onKeyboard(bool, uint32_t)
+{
+ return false;
+}
+
+bool Widget::onMouse(int, bool, int, int)
+{
+ return false;
+}
+
+bool Widget::onMotion(int, int)
+{
+ return false;
+}
+
+bool Widget::onScroll(float, float)
+{
+ return false;
+}
+
+bool Widget::onSpecial(bool, Key)
+{
+ return false;
+}
+
+void Widget::onReshape(int width, int height)
+{
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, width, height, 0, 0.0f, 1.0f);
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+void Widget::onClose()
+{
+}
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
diff --git a/dgl/src/Window.cpp b/dgl/src/Window.cpp
@@ -0,0 +1,805 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "../App.hpp"
+#include "../Widget.hpp"
+#include "../Window.hpp"
+
+#include <cassert>
+#include <list>
+
+#include "pugl/pugl.h"
+
+#if DGL_OS_WINDOWS
+# include "pugl/pugl_win.cpp"
+#elif DGL_OS_MAC
+extern "C" {
+# include "pugl/pugl_osx_extended.h"
+}
+#elif DGL_OS_LINUX
+extern "C" {
+# include "pugl/pugl_x11.c"
+}
+#else
+# error Unsupported platform
+#endif
+
+#define FOR_EACH_WIDGET(it) \
+ for (std::list<Widget*>::iterator it = fWidgets.begin(); it != fWidgets.end(); ++it)
+
+#define FOR_EACH_WIDGET_INV(rit) \
+ for (std::list<Widget*>::reverse_iterator rit = fWidgets.rbegin(); rit != fWidgets.rend(); ++rit)
+
+START_NAMESPACE_DGL
+
+Window* dgl_lastUiParent = nullptr;
+
+// -----------------------------------------------------------------------
+// Window Private
+
+class Window::PrivateData
+{
+public:
+ PrivateData(App& app, Window* const self)
+ : fApp(app),
+ fSelf(self),
+ fView(puglCreate(0, "Window", 100, 100, true, false)),
+ fFirstInit(true),
+ fVisible(false),
+ fResizable(true),
+#if DGL_OS_WINDOWS
+ hwnd(0)
+#elif DGL_OS_LINUX
+ xDisplay(nullptr),
+ xWindow(0)
+#else
+ _dummy('\0')
+#endif
+ {
+ init();
+ }
+
+ PrivateData(App& app, Window* const self, Window& parent)
+ : fApp(app),
+ fSelf(self),
+ fView(puglCreate(0, "Window", 100, 100, true, false)),
+ fFirstInit(true),
+ fVisible(false),
+ fResizable(true),
+ fModal(parent.pData),
+#if DGL_OS_WINDOWS
+ hwnd(0)
+#elif DGL_OS_LINUX
+ xDisplay(nullptr),
+ xWindow(0)
+#else
+ _dummy('\0')
+#endif
+ {
+ init();
+
+#if DGL_OS_LINUX
+ PuglInternals* const parentImpl = parent.pData->fView->impl;
+
+ XSetTransientForHint(xDisplay, xWindow, parentImpl->win);
+#endif
+ }
+
+ PrivateData(App& app, Window* const self, const intptr_t parentId)
+ : fApp(app),
+ fSelf(self),
+ fView(puglCreate(parentId, "Window", 100, 100, true, true)),
+ fFirstInit(true),
+ fVisible(true),
+ fResizable(false),
+#if DGL_OS_WINDOWS
+ hwnd(0)
+#elif DGL_OS_LINUX
+ xDisplay(nullptr),
+ xWindow(0)
+#else
+ _dummy('\0')
+#endif
+ {
+ init();
+
+ // starts visible
+ fApp.oneShown();
+ fFirstInit = false;
+ }
+
+ void init()
+ {
+ if (fView == nullptr)
+ return;
+
+ dgl_lastUiParent = fSelf;
+
+ puglSetHandle(fView, this);
+ puglSetDisplayFunc(fView, onDisplayCallback);
+ puglSetKeyboardFunc(fView, onKeyboardCallback);
+ puglSetMotionFunc(fView, onMotionCallback);
+ puglSetMouseFunc(fView, onMouseCallback);
+ puglSetScrollFunc(fView, onScrollCallback);
+ puglSetSpecialFunc(fView, onSpecialCallback);
+ puglSetReshapeFunc(fView, onReshapeCallback);
+ puglSetCloseFunc(fView, onCloseCallback);
+
+#if DGL_OS_WINDOWS
+ PuglInternals* impl = fView->impl;
+ hwnd = impl->hwnd;
+#elif DGL_OS_LINUX
+ PuglInternals* impl = fView->impl;
+ xDisplay = impl->display;
+ xWindow = impl->win;
+#endif
+
+ fApp.addWindow(fSelf);
+ }
+
+ ~PrivateData()
+ {
+ //fOnModal = false;
+ fWidgets.clear();
+
+ if (fView != nullptr)
+ {
+ fApp.removeWindow(fSelf);
+ puglDestroy(fView);
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+ void close()
+ {
+ setVisible(false);
+
+ if (! fFirstInit)
+ {
+ fApp.oneHidden();
+ fFirstInit = true;
+ }
+ }
+
+ void exec(const bool lockWait)
+ {
+ exec_init();
+
+ if (lockWait)
+ {
+ while (fVisible && fModal.enabled)
+ {
+ // idle()
+ puglProcessEvents(fView);
+
+ if (fModal.parent != nullptr)
+ fModal.parent->idle();
+
+ msleep(10);
+ }
+
+ exec_fini();
+ }
+ else
+ {
+ idle();
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+ void focus()
+ {
+#if DGL_OS_WINDOWS
+ SetForegroundWindow(hwnd);
+ SetActiveWindow(hwnd);
+ SetFocus(hwnd);
+#elif DGL_OS_MAC
+ puglImplFocus(fView);
+#elif DGL_OS_LINUX
+ XRaiseWindow(xDisplay, xWindow);
+ XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime);
+#endif
+ }
+
+ void idle()
+ {
+ puglProcessEvents(fView);
+
+ if (fVisible && fModal.enabled && fModal.parent != nullptr)
+ fModal.parent->idle();
+ }
+
+ void repaint()
+ {
+ puglPostRedisplay(fView);
+ }
+
+ void flush()
+ {
+#if DGL_OS_WINDOWS
+ UpdateWindow(hwnd);
+#elif DGL_OS_MAC
+#elif DGL_OS_LINUX
+ XFlush(xDisplay);
+#endif
+ }
+
+ // -------------------------------------------------------------------
+
+ bool isVisible() const noexcept
+ {
+ return fVisible;
+ }
+
+ void setVisible(const bool yesNo)
+ {
+ if (fVisible == yesNo)
+ return;
+
+ fVisible = yesNo;
+
+#ifndef DGL_OS_MAC
+ if (yesNo && fFirstInit)
+ setSize(fView->width, fView->height, true);
+#endif
+
+#if DGL_OS_WINDOWS
+ if (yesNo)
+ {
+ ShowWindow(hwnd, WS_VISIBLE);
+
+ if (! fFirstInit)
+ ShowWindow(hwnd, SW_RESTORE);
+ }
+ else
+ {
+ ShowWindow(hwnd, SW_HIDE);
+ }
+#elif DGL_OS_MAC
+ puglImplSetVisible(fView, yesNo);
+#elif DGL_OS_LINUX
+ if (yesNo)
+ XMapRaised(xDisplay, xWindow);
+ else
+ XUnmapWindow(xDisplay, xWindow);
+#endif
+
+ if (yesNo)
+ {
+ if (fFirstInit)
+ {
+ fApp.oneShown();
+ fFirstInit = false;
+ }
+ }
+ else if (fModal.enabled)
+ exec_fini();
+ }
+
+ // -------------------------------------------------------------------
+
+ bool isResizable() const noexcept
+ {
+ return fResizable;
+ }
+
+ void setResizable(const bool yesNo)
+ {
+ if (fResizable == yesNo)
+ return;
+
+ fResizable = yesNo;
+
+#ifndef DGL_OS_MAC
+ setSize(fView->width, fView->height, true);
+#endif
+ }
+
+ // -------------------------------------------------------------------
+
+#ifndef DGL_OS_MAC
+ int getWidth() const noexcept
+ {
+ return fView->width;
+ }
+
+ int getHeight() const noexcept
+ {
+ return fView->height;
+ }
+
+ Size<int> getSize() const noexcept
+ {
+ return Size<int>(fView->width, fView->height);
+ }
+#endif
+
+ void setSize(unsigned int width, unsigned int height, const bool forced = false)
+ {
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+#ifndef DGL_OS_MAC
+ if (fView->width == (int)width && fView->height == (int)height && ! forced)
+ return;
+
+ fView->width = width;
+ fView->height = height;
+#endif
+
+#if DGL_OS_WINDOWS
+ int winFlags = WS_POPUPWINDOW | WS_CAPTION;
+
+ if (fResizable)
+ winFlags |= WS_SIZEBOX;
+
+ RECT wr = { 0, 0, (long)width, (long)height };
+ AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST);
+
+ SetWindowPos(hwnd, 0, 0, 0, wr.right-wr.left, wr.bottom-wr.top, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER);
+#elif DGL_OS_MAC
+ puglImplSetSize(fView, width, height);
+#elif DGL_OS_LINUX
+ XResizeWindow(xDisplay, xWindow, width, height);
+
+ if (! fResizable)
+ {
+ XSizeHints sizeHints;
+ memset(&sizeHints, 0, sizeof(sizeHints));
+
+ sizeHints.flags = PMinSize|PMaxSize;
+ sizeHints.min_width = width;
+ sizeHints.min_height = height;
+ sizeHints.max_width = width;
+ sizeHints.max_height = height;
+
+ XSetNormalHints(xDisplay, xWindow, &sizeHints);
+ }
+#endif
+
+ repaint();
+ }
+
+ // -------------------------------------------------------------------
+
+ void setTitle(const char* const title)
+ {
+#if DGL_OS_WINDOWS
+ SetWindowTextA(hwnd, title);
+#elif DGL_OS_MAC
+ puglImplSetTitle(fView, title);
+#elif DGL_OS_LINUX
+ XStoreName(xDisplay, xWindow, title);
+#endif
+ }
+
+ App& getApp() const noexcept
+ {
+ return fApp;
+ }
+
+ int getModifiers() const
+ {
+ return puglGetModifiers(fView);
+ }
+
+ uint32_t getEventTimestamp() const
+ {
+ return puglGetEventTimestamp(fView);
+ }
+
+ intptr_t getWindowId() const
+ {
+ return puglGetNativeWindow(fView);
+ }
+
+ // -------------------------------------------------------------------
+
+ void addWidget(Widget* const widget)
+ {
+ fWidgets.push_back(widget);
+ }
+
+ void removeWidget(Widget* const widget)
+ {
+ fWidgets.remove(widget);
+ }
+
+ // -------------------------------------------------------------------
+
+ void exec_init()
+ {
+ fModal.enabled = true;
+ assert(fModal.parent != nullptr);
+
+ if (fModal.parent == nullptr)
+ return setVisible(true);
+
+ fModal.parent->fModal.childFocus = this;
+
+#if DGL_OS_WINDOWS
+ // Center this window
+ PuglInternals* const parentImpl = fParent->fView->impl;
+
+ RECT curRect;
+ RECT parentRect;
+ GetWindowRect(hwnd, &curRect);
+ GetWindowRect(parentImpl->hwnd, &parentRect);
+
+ int x = parentRect.left+(parentRect.right-curRect.right)/2;
+ int y = parentRect.top +(parentRect.bottom-curRect.bottom)/2;
+
+ SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
+ UpdateWindow(hwnd);
+#endif
+
+ fModal.parent->setVisible(true);
+ setVisible(true);
+ }
+
+ void exec_fini()
+ {
+ fModal.enabled = false;
+
+ if (fModal.parent != nullptr)
+ fModal.parent->fModal.childFocus = nullptr;
+ }
+
+ // -------------------------------------------------------------------
+
+protected:
+ void onDisplay()
+ {
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ FOR_EACH_WIDGET(it)
+ {
+ Widget* const widget(*it);
+
+ if (widget->isVisible())
+ widget->onDisplay();
+ }
+ }
+
+ void onKeyboard(const bool press, const uint32_t key)
+ {
+ if (fModal.childFocus != nullptr)
+ return fModal.childFocus->focus();
+
+ FOR_EACH_WIDGET_INV(rit)
+ {
+ Widget* const widget(*rit);
+
+ if (widget->isVisible() && widget->onKeyboard(press, key))
+ break;
+ }
+ }
+
+ void onMouse(const int button, const bool press, const int x, const int y)
+ {
+ if (fModal.childFocus != nullptr)
+ return fModal.childFocus->focus();
+
+ FOR_EACH_WIDGET_INV(rit)
+ {
+ Widget* const widget(*rit);
+
+ if (widget->isVisible() && widget->onMouse(button, press, x, y))
+ break;
+ }
+ }
+
+ void onMotion(const int x, const int y)
+ {
+ if (fModal.childFocus != nullptr)
+ return;
+
+ FOR_EACH_WIDGET_INV(rit)
+ {
+ Widget* const widget(*rit);
+
+ if (widget->isVisible() && widget->onMotion(x, y))
+ break;
+ }
+ }
+
+ void onScroll(const float dx, const float dy)
+ {
+ if (fModal.childFocus != nullptr)
+ return;
+
+ FOR_EACH_WIDGET_INV(rit)
+ {
+ Widget* const widget(*rit);
+
+ if (widget->isVisible() && widget->onScroll(dx, dy))
+ break;
+ }
+ }
+
+ void onSpecial(const bool press, const Key key)
+ {
+ if (fModal.childFocus != nullptr)
+ return;
+
+ FOR_EACH_WIDGET_INV(rit)
+ {
+ Widget* const widget(*rit);
+
+ if (widget->isVisible() && widget->onSpecial(press, key))
+ break;
+ }
+ }
+
+ void onReshape(const int width, const int height)
+ {
+ printf("resized: %i:%i\n", width, height);
+ FOR_EACH_WIDGET(it)
+ {
+ Widget* const widget(*it);
+ widget->onReshape(width, height);
+ }
+ }
+
+ void onClose()
+ {
+ fModal.enabled = false;
+
+ if (fModal.childFocus != nullptr)
+ fModal.childFocus->onClose();
+
+ FOR_EACH_WIDGET(it)
+ {
+ Widget* const widget(*it);
+ widget->onClose();
+ }
+
+ close();
+ }
+
+ // -------------------------------------------------------------------
+
+private:
+ App& fApp;
+ Window* const fSelf;
+ PuglView* const fView;
+
+ bool fFirstInit;
+ bool fVisible;
+ bool fResizable;
+ std::list<Widget*> fWidgets;
+
+ struct Modal {
+ bool enabled;
+ PrivateData* parent;
+ PrivateData* childFocus;
+
+ Modal()
+ : enabled(false),
+ parent(nullptr),
+ childFocus(nullptr) {}
+
+ Modal(PrivateData* const p)
+ : enabled(false),
+ parent(p),
+ childFocus(nullptr) {}
+
+ ~Modal()
+ {
+ assert(! enabled);
+ assert(childFocus == nullptr);
+ }
+ } fModal;
+
+#if DGL_OS_WINDOWS
+ HWND hwnd;
+#elif DGL_OS_LINUX
+ Display* xDisplay;
+ ::Window xWindow;
+#else
+ char _dummy;
+#endif
+
+ // -------------------------------------------------------------------
+ // Callbacks
+
+ #define handlePtr ((PrivateData*)puglGetHandle(view))
+
+ static void onDisplayCallback(PuglView* view)
+ {
+ handlePtr->onDisplay();
+ }
+
+ static void onKeyboardCallback(PuglView* view, bool press, uint32_t key)
+ {
+ handlePtr->onKeyboard(press, key);
+ }
+
+ static void onMouseCallback(PuglView* view, int button, bool press, int x, int y)
+ {
+ handlePtr->onMouse(button, press, x, y);
+ }
+
+ static void onMotionCallback(PuglView* view, int x, int y)
+ {
+ handlePtr->onMotion(x, y);
+ }
+
+ static void onScrollCallback(PuglView* view, float dx, float dy)
+ {
+ handlePtr->onScroll(dx, dy);
+ }
+
+ static void onSpecialCallback(PuglView* view, bool press, PuglKey key)
+ {
+ handlePtr->onSpecial(press, static_cast<Key>(key));
+ }
+
+ static void onReshapeCallback(PuglView* view, int width, int height)
+ {
+ handlePtr->onReshape(width, height);
+ }
+
+ static void onCloseCallback(PuglView* view)
+ {
+ handlePtr->onClose();
+ }
+
+ #undef handlePtr
+};
+
+// -----------------------------------------------------------------------
+// Window
+
+Window::Window(App& app)
+ : pData(new PrivateData(app, this))
+{
+}
+
+Window::Window(App& app, Window& parent)
+ : pData(new PrivateData(app, this, parent))
+{
+}
+
+Window::Window(App& app, intptr_t parentId)
+ : pData(new PrivateData(app, this, parentId))
+{
+}
+
+Window::~Window()
+{
+ delete pData;
+}
+
+void Window::show()
+{
+ pData->setVisible(true);
+}
+
+void Window::hide()
+{
+ pData->setVisible(false);
+}
+
+void Window::close()
+{
+ pData->close();
+}
+
+void Window::exec(bool lockWait)
+{
+ pData->exec(lockWait);
+}
+
+void Window::focus()
+{
+ pData->focus();
+}
+
+void Window::idle()
+{
+ pData->idle();
+}
+
+void Window::repaint()
+{
+ pData->repaint();
+}
+
+bool Window::isVisible() const noexcept
+{
+ return pData->isVisible();
+}
+
+void Window::setVisible(bool yesNo)
+{
+ pData->setVisible(yesNo);
+}
+
+bool Window::isResizable() const noexcept
+{
+ return pData->isResizable();
+}
+
+void Window::setResizable(bool yesNo)
+{
+ pData->setResizable(yesNo);
+}
+
+#ifndef DGL_OS_MAC
+int Window::getWidth() const noexcept
+{
+ return pData->getWidth();
+}
+
+int Window::getHeight() const noexcept
+{
+ return pData->getHeight();
+}
+
+Size<int> Window::getSize() const noexcept
+{
+ return pData->getSize();
+}
+#endif
+
+void Window::setSize(unsigned int width, unsigned int height)
+{
+ pData->setSize(width, height);
+}
+
+void Window::setTitle(const char* title)
+{
+ pData->setTitle(title);
+}
+
+App& Window::getApp() const noexcept
+{
+ return pData->getApp();
+}
+
+int Window::getModifiers() const
+{
+ return pData->getModifiers();
+}
+
+uint32_t Window::getEventTimestamp() const
+{
+ return pData->getEventTimestamp();
+}
+
+intptr_t Window::getWindowId() const
+{
+ return pData->getWindowId();
+}
+
+void Window::addWidget(Widget* const widget)
+{
+ pData->addWidget(widget);
+}
+
+void Window::removeWidget(Widget* const widget)
+{
+ pData->removeWidget(widget);
+}
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DGL
diff --git a/dgl/src/pugl/pugl.h b/dgl/src/pugl/pugl.h
@@ -0,0 +1,353 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file pugl.h API for Pugl, a minimal portable API for OpenGL.
+*/
+
+#ifndef PUGL_H_INCLUDED
+#define PUGL_H_INCLUDED
+
+#include <stdint.h>
+
+/*
+ This API is pure portable C and contains no platform specific elements, or
+ even a GL dependency. However, unfortunately GL includes vary across
+ platforms so they are included here to allow for pure portable programs.
+*/
+#ifdef __APPLE__
+# include "OpenGL/gl.h"
+#else
+# ifdef _WIN32
+# include <windows.h> /* Broken Windows GL headers require this */
+# endif
+# include "GL/gl.h"
+#endif
+
+#ifdef PUGL_SHARED
+# ifdef _WIN32
+# define PUGL_LIB_IMPORT __declspec(dllimport)
+# define PUGL_LIB_EXPORT __declspec(dllexport)
+# else
+# define PUGL_LIB_IMPORT __attribute__((visibility("default")))
+# define PUGL_LIB_EXPORT __attribute__((visibility("default")))
+# endif
+# ifdef PUGL_INTERNAL
+# define PUGL_API PUGL_LIB_EXPORT
+# else
+# define PUGL_API PUGL_LIB_IMPORT
+# endif
+#else
+# define PUGL_API
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#else
+# include <stdbool.h>
+#endif
+
+/**
+ @defgroup pugl Pugl
+ A minimal portable API for OpenGL.
+ @{
+*/
+
+/**
+ An OpenGL view.
+*/
+typedef struct PuglViewImpl PuglView;
+
+/**
+ A native window handle.
+
+ On X11, this is a Window.
+ On OSX, this is an NSView*.
+ On Windows, this is a HWND.
+*/
+typedef intptr_t PuglNativeWindow;
+
+/**
+ Return status code.
+*/
+typedef enum {
+ PUGL_SUCCESS = 0
+} PuglStatus;
+
+/**
+ Convenience symbols for ASCII control characters.
+*/
+typedef enum {
+ PUGL_CHAR_BACKSPACE = 0x08,
+ PUGL_CHAR_ESCAPE = 0x1B,
+ PUGL_CHAR_DELETE = 0x7F
+} PuglChar;
+
+/**
+ Special (non-Unicode) keyboard keys.
+*/
+typedef enum {
+ PUGL_KEY_F1 = 1,
+ PUGL_KEY_F2,
+ PUGL_KEY_F3,
+ PUGL_KEY_F4,
+ PUGL_KEY_F5,
+ PUGL_KEY_F6,
+ PUGL_KEY_F7,
+ PUGL_KEY_F8,
+ PUGL_KEY_F9,
+ PUGL_KEY_F10,
+ PUGL_KEY_F11,
+ PUGL_KEY_F12,
+ PUGL_KEY_LEFT,
+ PUGL_KEY_UP,
+ PUGL_KEY_RIGHT,
+ PUGL_KEY_DOWN,
+ PUGL_KEY_PAGE_UP,
+ PUGL_KEY_PAGE_DOWN,
+ PUGL_KEY_HOME,
+ PUGL_KEY_END,
+ PUGL_KEY_INSERT,
+ PUGL_KEY_SHIFT,
+ PUGL_KEY_CTRL,
+ PUGL_KEY_ALT,
+ PUGL_KEY_SUPER
+} PuglKey;
+
+/**
+ Keyboard modifier flags.
+*/
+typedef enum {
+ PUGL_MOD_SHIFT = 1, /**< Shift key */
+ PUGL_MOD_CTRL = 1 << 1, /**< Control key */
+ PUGL_MOD_ALT = 1 << 2, /**< Alt/Option key */
+ PUGL_MOD_SUPER = 1 << 3 /**< Mod4/Command/Windows key */
+} PuglMod;
+
+/**
+ Handle for opaque user data.
+*/
+typedef void* PuglHandle;
+
+/**
+ A function called when the window is closed.
+*/
+typedef void (*PuglCloseFunc)(PuglView* view);
+
+/**
+ A function called to draw the view contents with OpenGL.
+*/
+typedef void (*PuglDisplayFunc)(PuglView* view);
+
+/**
+ A function called when a key is pressed or released.
+ @param view The view the event occured in.
+ @param press True if the key was pressed, false if released.
+ @param key Unicode point of the key pressed.
+*/
+typedef void (*PuglKeyboardFunc)(PuglView* view, bool press, uint32_t key);
+
+/**
+ A function called when the pointer moves.
+ @param view The view the event occured in.
+ @param x The window-relative x coordinate of the pointer.
+ @param y The window-relative y coordinate of the pointer.
+*/
+typedef void (*PuglMotionFunc)(PuglView* view, int x, int y);
+
+/**
+ A function called when a mouse button is pressed or released.
+ @param view The view the event occured in.
+ @param button The button number (1 = left, 2 = middle, 3 = right).
+ @param press True if the key was pressed, false if released.
+ @param x The window-relative x coordinate of the pointer.
+ @param y The window-relative y coordinate of the pointer.
+*/
+typedef void (*PuglMouseFunc)(
+ PuglView* view, int button, bool press, int x, int y);
+
+/**
+ A function called when the view is resized.
+ @param view The view being resized.
+ @param width The new view width.
+ @param height The new view height.
+*/
+typedef void (*PuglReshapeFunc)(PuglView* view, int width, int height);
+
+/**
+ A function called on scrolling (e.g. mouse wheel or track pad).
+
+ The distances used here are in "lines", a single tick of a clicking mouse
+ wheel. For example, @p dy = 1.0 scrolls 1 line up. Some systems and
+ devices support finer resolution and/or higher values for fast scrolls,
+ so programs should handle any value gracefully.
+
+ @param view The view being scrolled.
+ @param dx The scroll x distance.
+ @param dx The scroll y distance.
+*/
+typedef void (*PuglScrollFunc)(PuglView* view, float dx, float dy);
+
+/**
+ A function called when a special key is pressed or released.
+
+ This callback allows the use of keys that do not have unicode points. Note
+ that some non-printable keys
+ @param view The view the event occured in.
+ @param press True if the key was pressed, false if released.
+ @param key The key pressed.
+*/
+typedef void (*PuglSpecialFunc)(PuglView* view, bool press, PuglKey key);
+
+/**
+ Create a new GL window.
+ @param parent Parent window, or 0 for top level.
+ @param title Window title, or NULL.
+ @param width Window width in pixels.
+ @param height Window height in pixels.
+ @param resizable Whether window should be user resizable.
+ @param visible Whether window should be initially visible.
+*/
+PUGL_API PuglView*
+puglCreate(PuglNativeWindow parent,
+ const char* title,
+ int width,
+ int height,
+ bool resizable,
+ bool visible);
+
+/**
+ Set the handle to be passed to all callbacks.
+
+ This is generally a pointer to a struct which contains all necessary state.
+ Everything needed in callbacks should be here, not in static variables.
+
+ Note the lack of this facility makes GLUT unsuitable for plugins or
+ non-trivial programs; this mistake is largely why Pugl exists.
+*/
+PUGL_API void
+puglSetHandle(PuglView* view, PuglHandle handle);
+
+/**
+ Get the handle to be passed to all callbacks.
+*/
+PUGL_API PuglHandle
+puglGetHandle(PuglView* view);
+
+/**
+ Return the timestamp (if any) of the currently-processing event.
+*/
+PUGL_API uint32_t
+puglGetEventTimestamp(PuglView* view);
+
+/**
+ Get the currently active modifiers (PuglMod flags).
+
+ This should only be called from an event handler.
+*/
+PUGL_API int
+puglGetModifiers(PuglView* view);
+
+/**
+ Ignore synthetic repeated key events.
+*/
+PUGL_API void
+puglIgnoreKeyRepeat(PuglView* view, bool ignore);
+
+/**
+ Set the function to call when the window is closed.
+*/
+PUGL_API void
+puglSetCloseFunc(PuglView* view, PuglCloseFunc closeFunc);
+
+/**
+ Set the display function which should draw the UI using GL.
+*/
+PUGL_API void
+puglSetDisplayFunc(PuglView* view, PuglDisplayFunc displayFunc);
+
+/**
+ Set the function to call on keyboard events.
+*/
+PUGL_API void
+puglSetKeyboardFunc(PuglView* view, PuglKeyboardFunc keyboardFunc);
+
+/**
+ Set the function to call on mouse motion.
+*/
+PUGL_API void
+puglSetMotionFunc(PuglView* view, PuglMotionFunc motionFunc);
+
+/**
+ Set the function to call on mouse button events.
+*/
+PUGL_API void
+puglSetMouseFunc(PuglView* view, PuglMouseFunc mouseFunc);
+
+/**
+ Set the function to call on scroll events.
+*/
+PUGL_API void
+puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc);
+
+/**
+ Set the function to call on special events.
+*/
+PUGL_API void
+puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc);
+
+/**
+ Set the function to call when the window size changes.
+*/
+PUGL_API void
+puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc);
+
+/**
+ Return the native window handle.
+*/
+PUGL_API PuglNativeWindow
+puglGetNativeWindow(PuglView* view);
+
+/**
+ Process all pending window events.
+
+ This handles input events as well as rendering, so it should be called
+ regularly and rapidly enough to keep the UI responsive.
+*/
+PUGL_API PuglStatus
+puglProcessEvents(PuglView* view);
+
+/**
+ Request a redisplay on the next call to puglProcessEvents().
+*/
+PUGL_API void
+puglPostRedisplay(PuglView* view);
+
+/**
+ Destroy a GL window.
+*/
+PUGL_API void
+puglDestroy(PuglView* view);
+
+/**
+ @}
+*/
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PUGL_H_INCLUDED */
diff --git a/dgl/src/pugl/pugl_internal.h b/dgl/src/pugl/pugl_internal.h
@@ -0,0 +1,143 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file pugl_internal.h Private platform-independent definitions.
+
+ Note this file contains function definitions, so it must be compiled into
+ the final binary exactly once. Each platform specific implementation file
+ including it once should achieve this.
+*/
+
+#include "pugl.h"
+
+typedef struct PuglInternalsImpl PuglInternals;
+
+struct PuglViewImpl {
+ PuglHandle handle;
+ PuglCloseFunc closeFunc;
+ PuglDisplayFunc displayFunc;
+ PuglKeyboardFunc keyboardFunc;
+ PuglMotionFunc motionFunc;
+ PuglMouseFunc mouseFunc;
+ PuglReshapeFunc reshapeFunc;
+ PuglScrollFunc scrollFunc;
+ PuglSpecialFunc specialFunc;
+
+ PuglInternals* impl;
+
+ int width;
+ int height;
+ int mods;
+ bool mouse_in_view;
+ bool ignoreKeyRepeat;
+ bool redisplay;
+ uint32_t event_timestamp_ms;
+};
+
+void
+puglSetHandle(PuglView* view, PuglHandle handle)
+{
+ view->handle = handle;
+}
+
+PuglHandle
+puglGetHandle(PuglView* view)
+{
+ return view->handle;
+}
+
+uint32_t
+puglGetEventTimestamp(PuglView* view)
+{
+ return view->event_timestamp_ms;
+}
+
+int
+puglGetModifiers(PuglView* view)
+{
+ return view->mods;
+}
+
+void
+puglDefaultReshape(PuglView* view, int width, int height)
+{
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, width, height, 0, 0, 1);
+ glViewport(0, 0, width, height);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ return;
+
+ // unused
+ (void)view;
+}
+
+void
+puglIgnoreKeyRepeat(PuglView* view, bool ignore)
+{
+ view->ignoreKeyRepeat = ignore;
+}
+
+void
+puglSetCloseFunc(PuglView* view, PuglCloseFunc closeFunc)
+{
+ view->closeFunc = closeFunc;
+}
+
+void
+puglSetDisplayFunc(PuglView* view, PuglDisplayFunc displayFunc)
+{
+ view->displayFunc = displayFunc;
+}
+
+void
+puglSetKeyboardFunc(PuglView* view, PuglKeyboardFunc keyboardFunc)
+{
+ view->keyboardFunc = keyboardFunc;
+}
+
+void
+puglSetMotionFunc(PuglView* view, PuglMotionFunc motionFunc)
+{
+ view->motionFunc = motionFunc;
+}
+
+void
+puglSetMouseFunc(PuglView* view, PuglMouseFunc mouseFunc)
+{
+ view->mouseFunc = mouseFunc;
+}
+
+void
+puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc)
+{
+ view->reshapeFunc = reshapeFunc;
+}
+
+void
+puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc)
+{
+ view->scrollFunc = scrollFunc;
+}
+
+void
+puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc)
+{
+ view->specialFunc = specialFunc;
+}
diff --git a/dgl/src/pugl/pugl_osx.m b/dgl/src/pugl/pugl_osx.m
@@ -0,0 +1,418 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file pugl_osx.m OSX/Cocoa Pugl Implementation.
+*/
+
+#include <stdlib.h>
+
+#import <Cocoa/Cocoa.h>
+
+#include "pugl_internal.h"
+
+@interface PuglWindow : NSWindow
+{
+@public
+ PuglView* puglview;
+}
+
+- (id) initWithContentRect:(NSRect)contentRect
+ styleMask:(unsigned int)aStyle
+ backing:(NSBackingStoreType)bufferingType
+ defer:(BOOL)flag;
+- (void) setPuglview:(PuglView*)view;
+- (BOOL) windowShouldClose:(id)sender;
+@end
+
+@implementation PuglWindow
+
+- (id)initWithContentRect:(NSRect)contentRect
+ styleMask:(unsigned int)aStyle
+ backing:(NSBackingStoreType)bufferingType
+ defer:(BOOL)flag
+{
+ NSWindow* result = [super initWithContentRect:contentRect
+ styleMask:(NSClosableWindowMask |
+ NSTitledWindowMask |
+ NSResizableWindowMask)
+ backing:NSBackingStoreBuffered defer:NO];
+
+ [result setAcceptsMouseMovedEvents:YES];
+ [result setLevel: CGShieldingWindowLevel() + 1];
+
+ return result;
+}
+
+- (void)setPuglview:(PuglView*)view
+{
+ puglview = view;
+ [self setContentSize:NSMakeSize(view->width, view->height) ];
+}
+
+- (BOOL)windowShouldClose:(id)sender
+{
+ if (puglview->closeFunc)
+ puglview->closeFunc(puglview);
+ return YES;
+}
+
+@end
+
+void
+puglDisplay(PuglView* view)
+{
+ if (view->displayFunc) {
+ view->displayFunc(view);
+ }
+}
+
+@interface PuglOpenGLView : NSOpenGLView
+{
+ int colorBits;
+ int depthBits;
+@public
+ PuglView* puglview;
+
+ NSTrackingArea* trackingArea;
+}
+
+- (id) initWithFrame:(NSRect)frame
+ colorBits:(int)numColorBits
+ depthBits:(int)numDepthBits;
+- (void) reshape;
+- (void) drawRect:(NSRect)rect;
+- (void) mouseMoved:(NSEvent*)event;
+- (void) mouseDragged:(NSEvent*)event;
+- (void) mouseDown:(NSEvent*)event;
+- (void) mouseUp:(NSEvent*)event;
+- (void) rightMouseDown:(NSEvent*)event;
+- (void) rightMouseUp:(NSEvent*)event;
+- (void) keyDown:(NSEvent*)event;
+- (void) keyUp:(NSEvent*)event;
+- (void) flagsChanged:(NSEvent*)event;
+
+@end
+
+@implementation PuglOpenGLView
+
+- (id) initWithFrame:(NSRect)frame
+ colorBits:(int)numColorBits
+ depthBits:(int)numDepthBits
+{
+ colorBits = numColorBits;
+ depthBits = numDepthBits;
+
+ NSOpenGLPixelFormatAttribute pixelAttribs[16] = {
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFAColorSize,
+ colorBits,
+ NSOpenGLPFADepthSize,
+ depthBits,
+ 0
+ };
+
+ NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc]
+ initWithAttributes:pixelAttribs];
+
+ if (pixelFormat) {
+ self = [super initWithFrame:frame pixelFormat:pixelFormat];
+ [pixelFormat release];
+ if (self) {
+ [[self openGLContext] makeCurrentContext];
+ [self reshape];
+ }
+ } else {
+ self = nil;
+ }
+
+ return self;
+}
+
+- (void) reshape
+{
+ [[self openGLContext] update];
+
+ NSRect bounds = [self bounds];
+ int width = bounds.size.width;
+ int height = bounds.size.height;
+
+ if (puglview) {
+ /* NOTE: Apparently reshape gets called when the GC gets around to
+ deleting the view (?), so we must have reset puglview to NULL when
+ this comes around.
+ */
+ if (puglview->reshapeFunc) {
+ puglview->reshapeFunc(puglview, width, height);
+ } else {
+ puglDefaultReshape(puglview, width, height);
+ }
+
+ puglview->width = width;
+ puglview->height = height;
+ }
+}
+
+- (void) drawRect:(NSRect)rect
+{
+ puglDisplay(puglview);
+ glFlush();
+ glSwapAPPLE();
+}
+
+static unsigned
+getModifiers(PuglView* view, NSEvent* ev)
+{
+ const unsigned modifierFlags = [ev modifierFlags];
+
+ view->event_timestamp_ms = fmod([ev timestamp] * 1000.0, UINT32_MAX);
+
+ unsigned mods = 0;
+ mods |= (modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0;
+ mods |= (modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0;
+ mods |= (modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0;
+ mods |= (modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0;
+ return mods;
+}
+
+-(void)updateTrackingAreas
+{
+ if (trackingArea != nil) {
+ [self removeTrackingArea:trackingArea];
+ [trackingArea release];
+ }
+
+ const int opts = (NSTrackingMouseEnteredAndExited |
+ NSTrackingMouseMoved |
+ NSTrackingActiveAlways);
+ trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
+ options:opts
+ owner:self
+ userInfo:nil];
+ [self addTrackingArea:trackingArea];
+}
+
+- (void)mouseEntered:(NSEvent*)theEvent
+{
+ [self updateTrackingAreas];
+}
+
+- (void)mouseExited:(NSEvent*)theEvent
+{
+}
+
+- (void) mouseMoved:(NSEvent*)event
+{
+ if (puglview->motionFunc) {
+ NSPoint loc = [event locationInWindow];
+ puglview->mods = getModifiers(puglview, event);
+ puglview->motionFunc(puglview, loc.x, puglview->height - loc.y);
+ }
+}
+
+- (void) mouseDragged:(NSEvent*)event
+{
+ if (puglview->motionFunc) {
+ NSPoint loc = [event locationInWindow];
+ puglview->mods = getModifiers(puglview, event);
+ puglview->motionFunc(puglview, loc.x, puglview->height - loc.y);
+ }
+}
+
+- (void) mouseDown:(NSEvent*)event
+{
+ if (puglview->mouseFunc) {
+ NSPoint loc = [event locationInWindow];
+ puglview->mods = getModifiers(puglview, event);
+ puglview->mouseFunc(puglview, 1, true, loc.x, puglview->height - loc.y);
+ }
+}
+
+- (void) mouseUp:(NSEvent*)event
+{
+ if (puglview->mouseFunc) {
+ NSPoint loc = [event locationInWindow];
+ puglview->mods = getModifiers(puglview, event);
+ puglview->mouseFunc(puglview, 1, false, loc.x, puglview->height - loc.y);
+ }
+ [self updateTrackingAreas];
+}
+
+- (void) rightMouseDown:(NSEvent*)event
+{
+ if (puglview->mouseFunc) {
+ NSPoint loc = [event locationInWindow];
+ puglview->mods = getModifiers(puglview, event);
+ puglview->mouseFunc(puglview, 3, true, loc.x, puglview->height - loc.y);
+ }
+}
+
+- (void) rightMouseUp:(NSEvent*)event
+{
+ if (puglview->mouseFunc) {
+ NSPoint loc = [event locationInWindow];
+ puglview->mods = getModifiers(puglview, event);
+ puglview->mouseFunc(puglview, 3, false, loc.x, puglview->height - loc.y);
+ }
+}
+
+- (void) scrollWheel:(NSEvent*)event
+{
+ if (puglview->scrollFunc) {
+ puglview->mods = getModifiers(puglview, event);
+ puglview->scrollFunc(puglview, [event deltaX], [event deltaY]);
+ }
+ [self updateTrackingAreas];
+}
+
+- (void) keyDown:(NSEvent*)event
+{
+ if (puglview->keyboardFunc && !(puglview->ignoreKeyRepeat && [event isARepeat])) {
+ NSString* chars = [event characters];
+ puglview->mods = getModifiers(puglview, event);
+ puglview->keyboardFunc(puglview, true, [chars characterAtIndex:0]);
+ }
+}
+
+- (void) keyUp:(NSEvent*)event
+{
+ if (puglview->keyboardFunc) {
+ NSString* chars = [event characters];
+ puglview->mods = getModifiers(puglview, event);
+ puglview->keyboardFunc(puglview, false, [chars characterAtIndex:0]);
+ }
+}
+
+- (void) flagsChanged:(NSEvent*)event
+{
+ if (puglview->specialFunc) {
+ const unsigned mods = getModifiers(puglview, event);
+ if ((mods & PUGL_MOD_SHIFT) != (puglview->mods & PUGL_MOD_SHIFT)) {
+ puglview->specialFunc(puglview, mods & PUGL_MOD_SHIFT, PUGL_KEY_SHIFT);
+ } else if ((mods & PUGL_MOD_CTRL) != (puglview->mods & PUGL_MOD_CTRL)) {
+ puglview->specialFunc(puglview, mods & PUGL_MOD_CTRL, PUGL_KEY_CTRL);
+ } else if ((mods & PUGL_MOD_ALT) != (puglview->mods & PUGL_MOD_ALT)) {
+ puglview->specialFunc(puglview, mods & PUGL_MOD_ALT, PUGL_KEY_ALT);
+ } else if ((mods & PUGL_MOD_SUPER) != (puglview->mods & PUGL_MOD_SUPER)) {
+ puglview->specialFunc(puglview, mods & PUGL_MOD_SUPER, PUGL_KEY_SUPER);
+ }
+ puglview->mods = mods;
+ }
+}
+
+@end
+
+struct PuglInternalsImpl {
+ PuglOpenGLView* glview;
+ id window;
+};
+
+PuglView*
+puglCreate(PuglNativeWindow parent,
+ const char* title,
+ int width,
+ int height,
+ bool resizable,
+ bool visible)
+{
+ PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
+ PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
+ if (!view || !impl) {
+ return NULL;
+ }
+
+ view->impl = impl;
+ view->width = width;
+ view->height = height;
+
+ [NSAutoreleasePool new];
+ [NSApplication sharedApplication];
+
+ NSString* titleString = [[NSString alloc]
+ initWithBytes:title
+ length:strlen(title)
+ encoding:NSUTF8StringEncoding];
+
+ id window = [[PuglWindow new]retain];
+
+ [window setPuglview:view];
+ [window setTitle:titleString];
+
+ impl->glview = [PuglOpenGLView new];
+ impl->window = window;
+ impl->glview->puglview = view;
+
+ [window setContentView:impl->glview];
+ [NSApp activateIgnoringOtherApps:YES];
+ [window makeFirstResponder:impl->glview];
+ [window makeKeyAndOrderFront:window];
+
+ if (! visible) {
+ [window setIsVisible:NO];
+ }
+
+ return view;
+}
+
+void
+puglDestroy(PuglView* view)
+{
+ view->impl->glview->puglview = NULL;
+ [view->impl->window close];
+ [view->impl->glview release];
+ [view->impl->window release];
+ free(view->impl);
+ free(view);
+}
+
+PuglStatus
+puglProcessEvents(PuglView* view)
+{
+ [view->impl->glview setNeedsDisplay: YES];
+
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ NSEvent* event;
+
+ for (;;) {
+ event = [view->impl->window
+ nextEventMatchingMask:NSAnyEventMask
+ untilDate:[NSDate distantPast]
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+
+ if (event == nil)
+ break;
+
+ [view->impl->window sendEvent: event];
+ }
+
+ [pool release];
+
+ return PUGL_SUCCESS;
+}
+
+void
+puglPostRedisplay(PuglView* view)
+{
+ view->redisplay = true;
+}
+
+PuglNativeWindow
+puglGetNativeWindow(PuglView* view)
+{
+ return (PuglNativeWindow)view->impl->glview;
+}
diff --git a/dgl/src/pugl/pugl_osx_extended.h b/dgl/src/pugl/pugl_osx_extended.h
@@ -0,0 +1,29 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+ Copyright 2013 Filipe Coelho <falktx@falktx.com>
+
+ 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.
+*/
+
+/**
+ @file pugl_osx_extended.h Extended OSX/Cocoa Pugl Implementation.
+*/
+
+#include <stdbool.h>
+
+#include "pugl.h"
+
+void puglImplFocus(PuglView* view);
+void puglImplSetSize(PuglView* view, unsigned int width, unsigned int height);
+void puglImplSetTitle(PuglView* view, const char* title);
+void puglImplSetVisible(PuglView* view, bool yesNo);
diff --git a/dgl/src/pugl/pugl_osx_extended.m b/dgl/src/pugl/pugl_osx_extended.m
@@ -0,0 +1,64 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+ Copyright 2013 Filipe Coelho <falktx@falktx.com>
+
+ 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.
+*/
+
+/**
+ @file pugl_osx_extended.m Extended OSX/Cocoa Pugl Implementation.
+*/
+
+#import "pugl_osx.m"
+
+#include "pugl_osx_extended.h"
+
+void puglImplFocus(PuglView* view)
+{
+ // TODO
+}
+
+void puglImplSetSize(PuglView* view, unsigned int width, unsigned int height)
+{
+ //id window = view->impl->window;
+
+ // TODO
+ //NSRect frame = [window frame];
+ //frame.size.width = width;
+ //frame.size.height = height;
+
+ // display:NO ?
+ //[window setFrame:frame display:YES animate:NO];
+}
+
+void puglImplSetTitle(PuglView* view, const char* title)
+{
+ id window = view->impl->window;
+
+ NSString* titleString = [[NSString alloc]
+ initWithBytes:title
+ length:strlen(title)
+ encoding:NSUTF8StringEncoding];
+
+ [window setTitle:titleString];
+}
+
+void puglImplSetVisible(PuglView* view, bool yesNo)
+{
+ id window = view->impl->window;
+
+ if (yesNo)
+ [window setIsVisible:YES];
+ else
+ [window setIsVisible:NO];
+}
diff --git a/dgl/src/pugl/pugl_win.cpp b/dgl/src/pugl/pugl_win.cpp
@@ -0,0 +1,374 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file pugl_win.cpp Windows/WGL Pugl Implementation.
+*/
+
+#include <windows.h>
+#include <windowsx.h>
+#include <GL/gl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "pugl_internal.h"
+
+#ifndef WM_MOUSEWHEEL
+# define WM_MOUSEWHEEL 0x020A
+#endif
+#ifndef WM_MOUSEHWHEEL
+# define WM_MOUSEHWHEEL 0x020E
+#endif
+#ifndef WHEEL_DELTA
+# define WHEEL_DELTA 120
+#endif
+
+const int LOCAL_CLOSE_MSG = WM_USER + 50;
+
+struct PuglInternalsImpl {
+ HWND hwnd;
+ HDC hdc;
+ HGLRC hglrc;
+ WNDCLASS wc;
+};
+
+LRESULT CALLBACK
+wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+PuglView*
+puglCreate(PuglNativeWindow parent,
+ const char* title,
+ int width,
+ int height,
+ bool resizable,
+ bool visible)
+{
+ PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
+ PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
+ if (!view || !impl) {
+ return NULL;
+ }
+
+ view->impl = impl;
+ view->width = width;
+ view->height = height;
+
+ // FIXME: This is nasty, and pugl should not have static anything.
+ // Should class be a parameter? Does this make sense on other platforms?
+ static int wc_count = 0;
+ char classNameBuf[256];
+ _snprintf(classNameBuf, sizeof(classNameBuf), "%s_%d\n", title, wc_count++);
+
+ impl->wc.style = CS_OWNDC;
+ impl->wc.lpfnWndProc = wndProc;
+ impl->wc.cbClsExtra = 0;
+ impl->wc.cbWndExtra = 0;
+ impl->wc.hInstance = 0;
+ impl->wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ impl->wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ impl->wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
+ impl->wc.lpszMenuName = NULL;
+ impl->wc.lpszClassName = classNameBuf;
+ RegisterClass(&impl->wc);
+
+ int winFlags = WS_POPUPWINDOW | WS_CAPTION;
+ if (resizable) {
+ winFlags |= WS_SIZEBOX;
+ }
+
+ // Adjust the overall window size to accomodate our requested client size
+ RECT wr = { 0, 0, width, height };
+ AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST);
+
+ impl->hwnd = CreateWindowEx(
+ WS_EX_TOPMOST,
+ classNameBuf, title,
+ (visible ? WS_VISIBLE : 0) | (parent ? WS_CHILD : winFlags),
+ 0, 0, wr.right-wr.left, wr.bottom-wr.top,
+ (HWND)parent, NULL, NULL, NULL);
+
+ if (!impl->hwnd) {
+ free(impl);
+ free(view);
+ return NULL;
+ }
+
+ SetWindowLongPtr(impl->hwnd, GWL_USERDATA, (LONG)view);
+
+ impl->hdc = GetDC(impl->hwnd);
+
+ PIXELFORMATDESCRIPTOR pfd;
+ ZeroMemory(&pfd, sizeof(pfd));
+ pfd.nSize = sizeof(pfd);
+ pfd.nVersion = 1;
+ pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+ pfd.iPixelType = PFD_TYPE_RGBA;
+ pfd.cColorBits = 24;
+ pfd.cDepthBits = 16;
+ pfd.iLayerType = PFD_MAIN_PLANE;
+
+ int format = ChoosePixelFormat(impl->hdc, &pfd);
+ SetPixelFormat(impl->hdc, format, &pfd);
+
+ impl->hglrc = wglCreateContext(impl->hdc);
+ wglMakeCurrent(impl->hdc, impl->hglrc);
+
+ view->width = width;
+ view->height = height;
+
+ return view;
+}
+
+void
+puglDestroy(PuglView* view)
+{
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(view->impl->hglrc);
+ ReleaseDC(view->impl->hwnd, view->impl->hdc);
+ DestroyWindow(view->impl->hwnd);
+ UnregisterClass(view->impl->wc.lpszClassName, NULL);
+ free(view->impl);
+ free(view);
+}
+
+static void
+puglReshape(PuglView* view, int width, int height)
+{
+ wglMakeCurrent(view->impl->hdc, view->impl->hglrc);
+
+ if (view->reshapeFunc) {
+ view->reshapeFunc(view, width, height);
+ } else {
+ puglDefaultReshape(view, width, height);
+ }
+
+ view->width = width;
+ view->height = height;
+}
+
+void
+puglDisplay(PuglView* view)
+{
+ wglMakeCurrent(view->impl->hdc, view->impl->hglrc);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glLoadIdentity();
+
+ if (view->displayFunc) {
+ view->displayFunc(view);
+ }
+
+ glFlush();
+ SwapBuffers(view->impl->hdc);
+ view->redisplay = false;
+}
+
+static PuglKey
+keySymToSpecial(int sym)
+{
+ switch (sym) {
+ case VK_F1: return PUGL_KEY_F1;
+ case VK_F2: return PUGL_KEY_F2;
+ case VK_F3: return PUGL_KEY_F3;
+ case VK_F4: return PUGL_KEY_F4;
+ case VK_F5: return PUGL_KEY_F5;
+ case VK_F6: return PUGL_KEY_F6;
+ case VK_F7: return PUGL_KEY_F7;
+ case VK_F8: return PUGL_KEY_F8;
+ case VK_F9: return PUGL_KEY_F9;
+ case VK_F10: return PUGL_KEY_F10;
+ case VK_F11: return PUGL_KEY_F11;
+ case VK_F12: return PUGL_KEY_F12;
+ case VK_LEFT: return PUGL_KEY_LEFT;
+ case VK_UP: return PUGL_KEY_UP;
+ case VK_RIGHT: return PUGL_KEY_RIGHT;
+ case VK_DOWN: return PUGL_KEY_DOWN;
+ case VK_PRIOR: return PUGL_KEY_PAGE_UP;
+ case VK_NEXT: return PUGL_KEY_PAGE_DOWN;
+ case VK_HOME: return PUGL_KEY_HOME;
+ case VK_END: return PUGL_KEY_END;
+ case VK_INSERT: return PUGL_KEY_INSERT;
+ case VK_SHIFT: return PUGL_KEY_SHIFT;
+ case VK_CONTROL: return PUGL_KEY_CTRL;
+ case VK_MENU: return PUGL_KEY_ALT;
+ case VK_LWIN: return PUGL_KEY_SUPER;
+ case VK_RWIN: return PUGL_KEY_SUPER;
+ }
+ return (PuglKey)0;
+}
+
+static void
+processMouseEvent(PuglView* view, int button, bool press, LPARAM lParam)
+{
+ view->event_timestamp_ms = GetMessageTime();
+ if (press) {
+ SetCapture(view->impl->hwnd);
+ } else {
+ ReleaseCapture();
+ }
+
+ if (view->mouseFunc) {
+ view->mouseFunc(view, button, press,
+ GET_X_LPARAM(lParam),
+ GET_Y_LPARAM(lParam));
+ }
+}
+
+static void
+setModifiers(PuglView* view)
+{
+ view->mods = 0;
+ view->mods |= (GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0;
+ view->mods |= (GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0;
+ view->mods |= (GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0;
+ view->mods |= (GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0;
+ view->mods |= (GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0;
+}
+
+static LRESULT
+handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ PAINTSTRUCT ps;
+ PuglKey key;
+
+ setModifiers(view);
+ switch (message) {
+ case WM_CREATE:
+ case WM_SHOWWINDOW:
+ case WM_SIZE:
+ RECT rect;
+ GetClientRect(view->impl->hwnd, &rect);
+ puglReshape(view, rect.right, rect.bottom);
+ view->width = rect.right;
+ view->height = rect.bottom;
+ break;
+ case WM_PAINT:
+ BeginPaint(view->impl->hwnd, &ps);
+ puglDisplay(view);
+ EndPaint(view->impl->hwnd, &ps);
+ break;
+ case WM_MOUSEMOVE:
+ if (view->motionFunc) {
+ view->motionFunc(view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+ }
+ break;
+ case WM_LBUTTONDOWN:
+ processMouseEvent(view, 1, true, lParam);
+ break;
+ case WM_MBUTTONDOWN:
+ processMouseEvent(view, 2, true, lParam);
+ break;
+ case WM_RBUTTONDOWN:
+ processMouseEvent(view, 3, true, lParam);
+ break;
+ case WM_LBUTTONUP:
+ processMouseEvent(view, 1, false, lParam);
+ break;
+ case WM_MBUTTONUP:
+ processMouseEvent(view, 2, false, lParam);
+ break;
+ case WM_RBUTTONUP:
+ processMouseEvent(view, 3, false, lParam);
+ break;
+ case WM_MOUSEWHEEL:
+ if (view->scrollFunc) {
+ view->scrollFunc(
+ view, 0, (int16_t)HIWORD(wParam) / (float)WHEEL_DELTA);
+ }
+ break;
+ case WM_MOUSEHWHEEL:
+ if (view->scrollFunc) {
+ view->scrollFunc(
+ view, (int16_t)HIWORD(wParam) / float(WHEEL_DELTA), 0);
+ }
+ break;
+ case WM_KEYDOWN:
+ view->event_timestamp_ms = (GetMessageTime());
+ if (view->ignoreKeyRepeat && (lParam & (1 << 30))) {
+ break;
+ } // else nobreak
+ case WM_KEYUP:
+ if ((key = keySymToSpecial(wParam))) {
+ if (view->specialFunc) {
+ view->specialFunc(view, message == WM_KEYDOWN, key);
+ }
+ } else if (view->keyboardFunc) {
+ view->keyboardFunc(view, message == WM_KEYDOWN, wParam);
+ }
+ break;
+ case WM_QUIT:
+ case LOCAL_CLOSE_MSG:
+ if (view->closeFunc) {
+ view->closeFunc(view);
+ }
+ break;
+ default:
+ return DefWindowProc(
+ view->impl->hwnd, message, wParam, lParam);
+ }
+
+ return 0;
+}
+
+PuglStatus
+puglProcessEvents(PuglView* view)
+{
+ MSG msg;
+ while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) {
+ handleMessage(view, msg.message, msg.wParam, msg.lParam);
+ }
+
+
+ if (view->redisplay) {
+ InvalidateRect(view->impl->hwnd, NULL, FALSE);
+ }
+
+ return PUGL_SUCCESS;
+}
+
+LRESULT CALLBACK
+wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWL_USERDATA);
+ switch (message) {
+ case WM_CREATE:
+ PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0);
+ return 0;
+ case WM_CLOSE:
+ PostMessage(hwnd, LOCAL_CLOSE_MSG, wParam, lParam);
+ return 0;
+ case WM_DESTROY:
+ return 0;
+ default:
+ if (view) {
+ return handleMessage(view, message, wParam, lParam);
+ } else {
+ return DefWindowProc(hwnd, message, wParam, lParam);
+ }
+ }
+}
+
+void
+puglPostRedisplay(PuglView* view)
+{
+ view->redisplay = true;
+}
+
+PuglNativeWindow
+puglGetNativeWindow(PuglView* view)
+{
+ return (PuglNativeWindow)view->impl->hwnd;
+}
diff --git a/dgl/src/pugl/pugl_x11.c b/dgl/src/pugl/pugl_x11.c
@@ -0,0 +1,414 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+ Copyright 2011-2012 Ben Loftis, Harrison Consoles
+ Copyright 2013 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.
+*/
+
+/**
+ @file pugl_x11.c X11 Pugl Implementation.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+
+#include "pugl_internal.h"
+
+/* work around buggy re-parent & focus issues on some systems
+ * where no keyboard events are passed through even if the
+ * app has mouse-focus and all other events are working.
+ */
+//#define XKEYFOCUSGRAB
+
+/* show messages during initalization
+ */
+//#define VERBOSE_PUGL
+
+struct PuglInternalsImpl {
+ Display* display;
+ int screen;
+ Window win;
+ GLXContext ctx;
+ Bool doubleBuffered;
+};
+
+/**
+ Attributes for single-buffered RGBA with at least
+ 4 bits per color and a 16 bit depth buffer.
+*/
+static int attrListSgl[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 4,
+ GLX_GREEN_SIZE, 4,
+ GLX_BLUE_SIZE, 4,
+ GLX_DEPTH_SIZE, 16,
+ None
+};
+
+/**
+ Attributes for double-buffered RGBA with at least
+ 4 bits per color and a 16 bit depth buffer.
+*/
+static int attrListDbl[] = {
+ GLX_RGBA, GLX_DOUBLEBUFFER,
+ GLX_RED_SIZE, 4,
+ GLX_GREEN_SIZE, 4,
+ GLX_BLUE_SIZE, 4,
+ GLX_DEPTH_SIZE, 16,
+ None
+};
+
+PuglView*
+puglCreate(PuglNativeWindow parent,
+ const char* title,
+ int width,
+ int height,
+ bool resizable,
+ bool visible)
+{
+ PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
+ PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
+ if (!view || !impl) {
+ return NULL;
+ }
+
+ view->impl = impl;
+ view->width = width;
+ view->height = height;
+
+ impl->display = XOpenDisplay(0);
+ impl->screen = DefaultScreen(impl->display);
+
+ XVisualInfo* vi = glXChooseVisual(impl->display, impl->screen, attrListDbl);
+ if (!vi) {
+ vi = glXChooseVisual(impl->display, impl->screen, attrListSgl);
+ impl->doubleBuffered = False;
+#ifdef VERBOSE_PUGL
+ printf("puGL: singlebuffered rendering will be used, no doublebuffering available\n");
+#endif
+ } else {
+ impl->doubleBuffered = True;
+#ifdef VERBOSE_PUGL
+ printf("puGL: doublebuffered rendering available\n");
+#endif
+ }
+
+ int glxMajor, glxMinor;
+ glXQueryVersion(impl->display, &glxMajor, &glxMinor);
+#ifdef VERBOSE_PUGL
+ printf("puGL: GLX-Version : %d.%d\n", glxMajor, glxMinor);
+#endif
+
+ impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE);
+
+ Window xParent = parent
+ ? (Window)parent
+ : RootWindow(impl->display, impl->screen);
+
+ Colormap cmap = XCreateColormap(
+ impl->display, xParent, vi->visual, AllocNone);
+
+ XSetWindowAttributes attr;
+ memset(&attr, 0, sizeof(XSetWindowAttributes));
+ attr.colormap = cmap;
+ attr.border_pixel = 0;
+
+ attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask
+ | ButtonPressMask | ButtonReleaseMask
+#ifdef XKEYFOCUSGRAB
+ | EnterWindowMask
+#endif
+ | PointerMotionMask | StructureNotifyMask;
+
+ impl->win = XCreateWindow(
+ impl->display, xParent,
+ 0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual,
+ CWBorderPixel | CWColormap | CWEventMask, &attr);
+
+ XSizeHints sizeHints;
+ memset(&sizeHints, 0, sizeof(sizeHints));
+ if (!resizable) {
+ sizeHints.flags = PMinSize|PMaxSize;
+ sizeHints.min_width = width;
+ sizeHints.min_height = height;
+ sizeHints.max_width = width;
+ sizeHints.max_height = height;
+ XSetNormalHints(impl->display, impl->win, &sizeHints);
+ }
+
+ if (title) {
+ XStoreName(impl->display, impl->win, title);
+ }
+
+ if (!parent) {
+ Atom wmDelete = XInternAtom(impl->display, "WM_DELETE_WINDOW", True);
+ XSetWMProtocols(impl->display, impl->win, &wmDelete, 1);
+ }
+
+ if (visible) {
+ XMapRaised(impl->display, impl->win);
+ }
+
+ if (glXIsDirect(impl->display, impl->ctx)) {
+#ifdef VERBOSE_PUGL
+ printf("puGL: DRI enabled\n");
+#endif
+ } else {
+#ifdef VERBOSE_PUGL
+ printf("puGL: No DRI available\n");
+#endif
+ }
+
+ XFree(vi);
+
+ return view;
+}
+
+void
+puglDestroy(PuglView* view)
+{
+ if (!view) {
+ return;
+ }
+
+ glXDestroyContext(view->impl->display, view->impl->ctx);
+ XDestroyWindow(view->impl->display, view->impl->win);
+ XCloseDisplay(view->impl->display);
+ free(view->impl);
+ free(view);
+}
+
+static void
+puglReshape(PuglView* view, int width, int height)
+{
+ glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx);
+
+ if (view->reshapeFunc) {
+ view->reshapeFunc(view, width, height);
+ } else {
+ puglDefaultReshape(view, width, height);
+ }
+
+ view->width = width;
+ view->height = height;
+}
+
+static void
+puglDisplay(PuglView* view)
+{
+ glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glLoadIdentity();
+
+ if (view->displayFunc) {
+ view->displayFunc(view);
+ }
+
+ glFlush();
+ if (view->impl->doubleBuffered) {
+ glXSwapBuffers(view->impl->display, view->impl->win);
+ }
+
+ view->redisplay = false;
+}
+
+static PuglKey
+keySymToSpecial(KeySym sym)
+{
+ switch (sym) {
+ case XK_F1: return PUGL_KEY_F1;
+ case XK_F2: return PUGL_KEY_F2;
+ case XK_F3: return PUGL_KEY_F3;
+ case XK_F4: return PUGL_KEY_F4;
+ case XK_F5: return PUGL_KEY_F5;
+ case XK_F6: return PUGL_KEY_F6;
+ case XK_F7: return PUGL_KEY_F7;
+ case XK_F8: return PUGL_KEY_F8;
+ case XK_F9: return PUGL_KEY_F9;
+ case XK_F10: return PUGL_KEY_F10;
+ case XK_F11: return PUGL_KEY_F11;
+ case XK_F12: return PUGL_KEY_F12;
+ case XK_Left: return PUGL_KEY_LEFT;
+ case XK_Up: return PUGL_KEY_UP;
+ case XK_Right: return PUGL_KEY_RIGHT;
+ case XK_Down: return PUGL_KEY_DOWN;
+ case XK_Page_Up: return PUGL_KEY_PAGE_UP;
+ case XK_Page_Down: return PUGL_KEY_PAGE_DOWN;
+ case XK_Home: return PUGL_KEY_HOME;
+ case XK_End: return PUGL_KEY_END;
+ case XK_Insert: return PUGL_KEY_INSERT;
+ case XK_Shift_L: return PUGL_KEY_SHIFT;
+ case XK_Shift_R: return PUGL_KEY_SHIFT;
+ case XK_Control_L: return PUGL_KEY_CTRL;
+ case XK_Control_R: return PUGL_KEY_CTRL;
+ case XK_Alt_L: return PUGL_KEY_ALT;
+ case XK_Alt_R: return PUGL_KEY_ALT;
+ case XK_Super_L: return PUGL_KEY_SUPER;
+ case XK_Super_R: return PUGL_KEY_SUPER;
+ }
+ return (PuglKey)0;
+}
+
+static void
+setModifiers(PuglView* view, unsigned xstate, unsigned xtime)
+{
+ view->event_timestamp_ms = xtime;
+
+ view->mods = 0;
+ view->mods |= (xstate & ShiftMask) ? PUGL_MOD_SHIFT : 0;
+ view->mods |= (xstate & ControlMask) ? PUGL_MOD_CTRL : 0;
+ view->mods |= (xstate & Mod1Mask) ? PUGL_MOD_ALT : 0;
+ view->mods |= (xstate & Mod4Mask) ? PUGL_MOD_SUPER : 0;
+}
+
+PuglStatus
+puglProcessEvents(PuglView* view)
+{
+ XEvent event;
+ while (XPending(view->impl->display) > 0) {
+ XNextEvent(view->impl->display, &event);
+ switch (event.type) {
+ case MapNotify:
+ puglReshape(view, view->width, view->height);
+ break;
+ case ConfigureNotify:
+ if ((event.xconfigure.width != view->width) ||
+ (event.xconfigure.height != view->height)) {
+ puglReshape(view,
+ event.xconfigure.width,
+ event.xconfigure.height);
+ }
+ break;
+ case Expose:
+ if (event.xexpose.count != 0) {
+ break;
+ }
+ puglDisplay(view);
+ break;
+ case MotionNotify:
+ setModifiers(view, event.xmotion.state, event.xmotion.time);
+ if (view->motionFunc) {
+ view->motionFunc(view, event.xmotion.x, event.xmotion.y);
+ }
+ break;
+ case ButtonPress:
+ setModifiers(view, event.xbutton.state, event.xbutton.time);
+ if (event.xbutton.button >= 4 && event.xbutton.button <= 7) {
+ if (view->scrollFunc) {
+ float dx = 0, dy = 0;
+ switch (event.xbutton.button) {
+ case 4: dy = 1.0f; break;
+ case 5: dy = -1.0f; break;
+ case 6: dx = -1.0f; break;
+ case 7: dx = 1.0f; break;
+ }
+ view->scrollFunc(view, dx, dy);
+ }
+ break;
+ }
+ // nobreak
+ case ButtonRelease:
+ setModifiers(view, event.xbutton.state, event.xbutton.time);
+ if (view->mouseFunc &&
+ (event.xbutton.button < 4 || event.xbutton.button > 7)) {
+ view->mouseFunc(view,
+ event.xbutton.button, event.type == ButtonPress,
+ event.xbutton.x, event.xbutton.y);
+ }
+ break;
+ case KeyPress: {
+ setModifiers(view, event.xkey.state, event.xkey.time);
+ KeySym sym;
+ char str[5];
+ int n = XLookupString(&event.xkey, str, 4, &sym, NULL);
+ PuglKey key = keySymToSpecial(sym);
+ if (!key && view->keyboardFunc) {
+ if (n == 1) {
+ view->keyboardFunc(view, true, str[0]);
+ } else {
+ fprintf(stderr, "warning: Unknown key %X\n", (int)sym);
+ }
+ } else if (view->specialFunc) {
+ view->specialFunc(view, true, key);
+ }
+ } break;
+ case KeyRelease: {
+ setModifiers(view, event.xkey.state, event.xkey.time);
+ bool repeated = false;
+ if (view->ignoreKeyRepeat &&
+ XEventsQueued(view->impl->display, QueuedAfterReading)) {
+ XEvent next;
+ XPeekEvent(view->impl->display, &next);
+ if (next.type == KeyPress &&
+ next.xkey.time == event.xkey.time &&
+ next.xkey.keycode == event.xkey.keycode) {
+ XNextEvent(view->impl->display, &event);
+ repeated = true;
+ }
+ }
+
+ if (!repeated && view->keyboardFunc) {
+ KeySym sym = XLookupKeysym(&event.xkey, 0);
+ PuglKey special = keySymToSpecial(sym);
+ if (!special) {
+ view->keyboardFunc(view, false, sym);
+ } else if (view->specialFunc) {
+ view->specialFunc(view, false, special);
+ }
+ }
+ } break;
+ case ClientMessage:
+ if (!strcmp(XGetAtomName(view->impl->display,
+ event.xclient.message_type),
+ "WM_PROTOCOLS")) {
+ if (view->closeFunc) {
+ view->closeFunc(view);
+ }
+ }
+ break;
+#ifdef XKEYFOCUSGRAB
+ case EnterNotify:
+ XSetInputFocus(view->impl->display, view->impl->win, RevertToPointerRoot, CurrentTime);
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+
+ if (view->redisplay) {
+ puglDisplay(view);
+ }
+
+ return PUGL_SUCCESS;
+}
+
+void
+puglPostRedisplay(PuglView* view)
+{
+ view->redisplay = true;
+}
+
+PuglNativeWindow
+puglGetNativeWindow(PuglView* view)
+{
+ return view->impl->win;
+}
diff --git a/distrho/DistrhoPlugin.hpp b/distrho/DistrhoPlugin.hpp
@@ -0,0 +1,239 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DISTRHO_PLUGIN_HPP_INCLUDED
+#define DISTRHO_PLUGIN_HPP_INCLUDED
+
+#include "DistrhoUtils.hpp"
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+// Parameter Hints
+
+const uint32_t PARAMETER_IS_AUTOMABLE = 1 << 0;
+const uint32_t PARAMETER_IS_BOOLEAN = 1 << 1;
+const uint32_t PARAMETER_IS_INTEGER = 1 << 2;
+const uint32_t PARAMETER_IS_LOGARITHMIC = 1 << 3;
+const uint32_t PARAMETER_IS_OUTPUT = 1 << 4;
+
+// -----------------------------------------------------------------------
+// Parameter Ranges
+
+struct ParameterRanges {
+ float def;
+ float min;
+ float max;
+
+ ParameterRanges() noexcept
+ : def(0.0f),
+ min(0.0f),
+ max(1.0f) {}
+
+ ParameterRanges(float def, float min, float max) noexcept
+ {
+ this->def = def;
+ this->min = min;
+ this->max = max;
+ }
+
+ void clear() noexcept
+ {
+ def = 0.0f;
+ min = 0.0f;
+ max = 1.0f;
+ }
+
+ void fixValue(float& value) const noexcept
+ {
+ if (value < min)
+ value = min;
+ else if (value > max)
+ value = max;
+ }
+
+ float getFixedValue(const float& value) const noexcept
+ {
+ if (value < min)
+ return min;
+ else if (value > max)
+ return max;
+ return value;
+ }
+
+ float getNormalizedValue(const float& value) const noexcept
+ {
+ const float newValue((value - min) / (max - min));
+
+ if (newValue <= 0.0f)
+ return 0.0f;
+ if (newValue >= 1.0f)
+ return 1.0f;
+ return newValue;
+ }
+
+ float getUnnormalizedValue(const float& value) const noexcept
+ {
+ return value * (max - min) + min;
+ }
+};
+
+// -----------------------------------------------------------------------
+// Parameter
+
+struct Parameter {
+ uint32_t hints;
+ d_string name;
+ d_string symbol;
+ d_string unit;
+ ParameterRanges ranges;
+
+ Parameter()
+ : hints(0x0) {}
+
+ void clear() noexcept
+ {
+ hints = 0x0;
+ name = "";
+ symbol = "";
+ unit = "";
+ ranges.clear();
+ }
+};
+
+// -----------------------------------------------------------------------
+// MidiEvent
+
+struct MidiEvent {
+ uint32_t frame;
+ uint8_t size;
+ uint8_t buf[4];
+
+ void clear() noexcept
+ {
+ frame = 0;
+ size = 0;
+ buf[0] = 0;
+ buf[1] = 0;
+ buf[2] = 0;
+ buf[3] = 0;
+ }
+};
+
+// -----------------------------------------------------------------------
+// TimePos
+
+struct TimePos {
+ bool playing;
+ uint64_t frame;
+ double bpm;
+
+ TimePos() noexcept
+ : playing(false),
+ frame(0),
+ bpm(120.0) {}
+};
+
+// -----------------------------------------------------------------------
+// Plugin
+
+class Plugin
+{
+public:
+ Plugin(uint32_t parameterCount, uint32_t programCount, uint32_t stateCount);
+ virtual ~Plugin();
+
+ // -------------------------------------------------------------------
+ // Host state
+
+ uint32_t d_getBufferSize() const noexcept;
+ double d_getSampleRate() const noexcept;
+#if DISTRHO_PLUGIN_WANT_TIMEPOS
+ const TimePos& d_getTimePos() const noexcept;
+#endif
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ void d_setLatency(uint32_t frames) noexcept;
+#endif
+
+protected:
+ // -------------------------------------------------------------------
+ // Information
+
+ virtual const char* d_getName() const noexcept { return DISTRHO_PLUGIN_NAME; }
+ virtual const char* d_getLabel() const noexcept = 0;
+ virtual const char* d_getMaker() const noexcept = 0;
+ virtual const char* d_getLicense() const noexcept = 0;
+ virtual uint32_t d_getVersion() const noexcept = 0;
+ virtual long d_getUniqueId() const noexcept = 0;
+
+ // -------------------------------------------------------------------
+ // Init
+
+ virtual void d_initParameter(uint32_t index, Parameter& parameter) = 0;
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ virtual void d_initProgramName(uint32_t index, d_string& programName) = 0;
+#endif
+#if DISTRHO_PLUGIN_WANT_STATE
+ virtual void d_initStateKey(uint32_t index, d_string& stateKey) = 0;
+#endif
+
+ // -------------------------------------------------------------------
+ // Internal data
+
+ virtual float d_getParameterValue(uint32_t index) const = 0;
+ virtual void d_setParameterValue(uint32_t index, float value) = 0;
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ virtual void d_setProgram(uint32_t index) = 0;
+#endif
+#if DISTRHO_PLUGIN_WANT_STATE
+ virtual void d_setState(const char* key, const char* value) = 0;
+#endif
+
+ // -------------------------------------------------------------------
+ // Process
+
+ virtual void d_activate() {}
+ virtual void d_deactivate() {}
+#if DISTRHO_PLUGIN_IS_SYNTH
+ virtual void d_run(float** inputs, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) = 0;
+#else
+ virtual void d_run(float** inputs, float** outputs, uint32_t frames) = 0;
+#endif
+
+ // -------------------------------------------------------------------
+ // Callbacks (optional)
+
+ virtual void d_bufferSizeChanged(uint32_t newBufferSize);
+ virtual void d_sampleRateChanged(double newSampleRate);
+
+ // -------------------------------------------------------------------
+
+private:
+ struct PrivateData;
+ PrivateData* const pData;
+ friend class PluginExporter;
+};
+
+// -----------------------------------------------------------------------
+// Create plugin, entry point
+
+extern Plugin* createPlugin();
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
+
+#endif // DISTRHO_PLUGIN_HPP_INCLUDED
diff --git a/distrho/DistrhoPluginMain.cpp b/distrho/DistrhoPluginMain.cpp
@@ -0,0 +1,26 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "src/DistrhoPlugin.cpp"
+
+#if (defined(DISTRHO_PLUGIN_TARGET_LADSPA) || defined(DISTRHO_PLUGIN_TARGET_DSSI))
+# include "src/DistrhoPluginLADSPA+DSSI.cpp"
+#elif defined(DISTRHO_PLUGIN_TARGET_LV2)
+# include "src/DistrhoPluginLV2.cpp"
+# include "src/DistrhoPluginLV2export.cpp"
+#elif defined(DISTRHO_PLUGIN_TARGET_VST)
+# include "src/DistrhoPluginVST.cpp"
+#endif
diff --git a/distrho/DistrhoUI.hpp b/distrho/DistrhoUI.hpp
@@ -0,0 +1,94 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DISTRHO_UI_HPP_INCLUDED
+#define DISTRHO_UI_HPP_INCLUDED
+
+#include "DistrhoUtils.hpp"
+
+#include "../dgl/Widget.hpp"
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+// UI
+
+class UI : public DGL::Widget
+{
+public:
+ UI();
+ virtual ~UI();
+
+ // -------------------------------------------------------------------
+ // Host DSP State
+
+ double d_getSampleRate() const noexcept;
+ void d_editParameter(uint32_t index, bool started);
+ void d_setParameterValue(uint32_t index, float value);
+#if DISTRHO_PLUGIN_WANT_STATE
+ void d_setState(const char* key, const char* value);
+#endif
+#if DISTRHO_PLUGIN_IS_SYNTH
+ void d_sendNote(uint8_t channel, uint8_t note, uint8_t velocity);
+#endif
+
+ // -------------------------------------------------------------------
+ // Host UI State
+
+ void d_uiResize(unsigned int width, unsigned int height);
+
+protected:
+ // -------------------------------------------------------------------
+ // Basic Information
+
+ virtual const char* d_getName() const noexcept { return DISTRHO_PLUGIN_NAME; }
+ virtual unsigned int d_getWidth() const noexcept = 0;
+ virtual unsigned int d_getHeight() const noexcept = 0;
+
+ // -------------------------------------------------------------------
+ // DSP Callbacks
+
+ virtual void d_parameterChanged(uint32_t index, float value) = 0;
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ virtual void d_programChanged(uint32_t index) = 0;
+#endif
+#if DISTRHO_PLUGIN_WANT_STATE
+ virtual void d_stateChanged(const char* key, const char* value) = 0;
+#endif
+
+ // -------------------------------------------------------------------
+ // UI Callbacks (optional)
+
+ virtual void d_uiIdle() {}
+
+ // -------------------------------------------------------------------
+
+private:
+ struct PrivateData;
+ PrivateData* const pData;
+ friend class UIExporter;
+};
+
+// -----------------------------------------------------------------------
+// Create UI, entry point
+
+extern UI* createUI();
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
+
+#endif // DISTRHO_UI_HPP_INCLUDED
diff --git a/distrho/DistrhoUIMain.cpp b/distrho/DistrhoUIMain.cpp
@@ -0,0 +1,25 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "src/DistrhoUI.cpp"
+
+#if defined(DISTRHO_PLUGIN_TARGET_DSSI)
+# include "src/DistrhoUIDSSI.cpp"
+#elif defined(DISTRHO_PLUGIN_TARGET_LV2)
+# include "src/DistrhoUILV2.cpp"
+#elif defined(DISTRHO_PLUGIN_TARGET_VST)
+// nothing
+#endif
diff --git a/distrho/DistrhoUtils.hpp b/distrho/DistrhoUtils.hpp
@@ -0,0 +1,684 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DISTRHO_UTILS_HPP_INCLUDED
+#define DISTRHO_UTILS_HPP_INCLUDED
+
+#include "src/DistrhoDefines.h"
+
+#include <cassert>
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#ifdef PROPER_CPP11_SUPPORT
+# include <cstdint>
+#else
+# include <stdint.h>
+#endif
+
+#ifdef DISTRHO_OS_WINDOWS
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+#if defined(DISTRHO_OS_MAC) && ! defined(CARLA_OS_MAC)
+namespace std {
+inline float
+ fmin(float __x, float __y)
+ { return __builtin_fminf(__x, __y); }
+inline float
+ fmax(float __x, float __y)
+ { return __builtin_fmaxf(__x, __y); }
+inline float
+ rint(float __x)
+ { return __builtin_rintf(__x); }
+}
+#endif
+
+// -----------------------------------------------------------------------
+// misc functions
+
+static inline
+long d_cconst(int a, int b, int c, int d) noexcept
+{
+ return (a << 24) | (b << 16) | (c << 8) | (d << 0);
+}
+
+// -----------------------------------------------------------------------
+// string print functions
+
+#ifndef DEBUG
+# define d_debug(...)
+#else
+static inline
+void d_debug(const char* const fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ std::fprintf(stdout, "\x1b[30;1m");
+ std::vfprintf(stdout, fmt, args);
+ std::fprintf(stdout, "\x1b[0m\n");
+ va_end(args);
+}
+#endif
+
+static inline
+void d_stdout(const char* const fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ std::vfprintf(stdout, fmt, args);
+ std::fprintf(stdout, "\n");
+ va_end(args);
+}
+
+static inline
+void d_stderr(const char* const fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ std::vfprintf(stderr, fmt, args);
+ std::fprintf(stderr, "\n");
+ va_end(args);
+}
+
+static inline
+void d_stderr2(const char* const fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ std::fprintf(stderr, "\x1b[31m");
+ std::vfprintf(stderr, fmt, args);
+ std::fprintf(stderr, "\x1b[0m\n");
+ va_end(args);
+}
+
+// -----------------------------------------------------------------------
+// d_*sleep
+
+static inline
+void d_sleep(unsigned int secs)
+{
+#ifdef DISTRHO_OS_WINDOWS
+ Sleep(secs * 1000);
+#else
+ sleep(secs);
+#endif
+}
+
+static inline
+void d_msleep(unsigned int msecs)
+{
+#ifdef DISTRHO_OS_WINDOWS
+ Sleep(msecs);
+#else
+ usleep(msecs * 1000);
+#endif
+}
+
+// -----------------------------------------------------------------------
+// d_string class
+
+class d_string
+{
+public:
+ // -------------------------------------------------------------------
+ // constructors (no explicit conversions allowed)
+
+ /*
+ * Empty string.
+ */
+ explicit d_string()
+ {
+ _init();
+ _dup(nullptr);
+ }
+
+ /*
+ * Simple character.
+ */
+ explicit d_string(const char c)
+ {
+ char ch[2];
+ ch[0] = c;
+ ch[1] = '\0';
+
+ _init();
+ _dup(ch);
+ }
+
+ /*
+ * Simple char string.
+ */
+ explicit d_string(char* const strBuf)
+ {
+ _init();
+ _dup(strBuf);
+ }
+
+ /*
+ * Simple const char string.
+ */
+ explicit d_string(const char* const strBuf)
+ {
+ _init();
+ _dup(strBuf);
+ }
+
+ /*
+ * Integer.
+ */
+ explicit d_string(const int value)
+ {
+ char strBuf[0xff+1];
+ std::memset(strBuf, 0, (0xff+1)*sizeof(char));
+ std::snprintf(strBuf, 0xff, "%d", value);
+
+ _init();
+ _dup(strBuf);
+ }
+
+ /*
+ * Unsigned integer, possibly in hexadecimal.
+ */
+ explicit d_string(const unsigned int value, const bool hexadecimal = false)
+ {
+ char strBuf[0xff+1];
+ std::memset(strBuf, 0, (0xff+1)*sizeof(char));
+ std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value);
+
+ _init();
+ _dup(strBuf);
+ }
+
+ /*
+ * Long integer.
+ */
+ explicit d_string(const long int value)
+ {
+ char strBuf[0xff+1];
+ std::memset(strBuf, 0, (0xff+1)*sizeof(char));
+ std::snprintf(strBuf, 0xff, "%ld", value);
+
+ _init();
+ _dup(strBuf);
+ }
+
+ /*
+ * Long unsigned integer, possibly hexadecimal.
+ */
+ explicit d_string(const unsigned long int value, const bool hexadecimal = false)
+ {
+ char strBuf[0xff+1];
+ std::memset(strBuf, 0, (0xff+1)*sizeof(char));
+ std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value);
+
+ _init();
+ _dup(strBuf);
+ }
+
+ /*
+ * Single-precision floating point number.
+ */
+ explicit d_string(const float value)
+ {
+ char strBuf[0xff+1];
+ std::memset(strBuf, 0, (0xff+1)*sizeof(char));
+ std::snprintf(strBuf, 0xff, "%f", value);
+
+ _init();
+ _dup(strBuf);
+ }
+
+ /*
+ * Double-precision floating point number.
+ */
+ explicit d_string(const double value)
+ {
+ char strBuf[0xff+1];
+ std::memset(strBuf, 0, (0xff+1)*sizeof(char));
+ std::snprintf(strBuf, 0xff, "%g", value);
+
+ _init();
+ _dup(strBuf);
+ }
+
+ // -------------------------------------------------------------------
+ // non-explicit constructor
+
+ /*
+ * Create string from another string.
+ */
+ d_string(const d_string& str)
+ {
+ _init();
+ _dup(str.fBuffer);
+ }
+
+ // -------------------------------------------------------------------
+ // destructor
+
+ /*
+ * Destructor.
+ */
+ ~d_string()
+ {
+ assert(fBuffer != nullptr);
+
+ delete[] fBuffer;
+ fBuffer = nullptr;
+ }
+
+ // -------------------------------------------------------------------
+ // public methods
+
+ /*
+ * Get length of the string.
+ */
+ size_t length() const noexcept
+ {
+ return fBufferLen;
+ }
+
+ /*
+ * Check if the string is empty.
+ */
+ bool isEmpty() const noexcept
+ {
+ return (fBufferLen == 0);
+ }
+
+ /*
+ * Check if the string is not empty.
+ */
+ bool isNotEmpty() const noexcept
+ {
+ return (fBufferLen != 0);
+ }
+
+ /*
+ * Check if the string contains another string, optionally ignoring case.
+ */
+ bool contains(const char* const strBuf, const bool ignoreCase = false) const
+ {
+ if (strBuf == nullptr)
+ return false;
+
+ if (ignoreCase)
+ {
+#ifdef __USE_GNU
+ return (strcasestr(fBuffer, strBuf) != nullptr);
+#else
+ d_string tmp1(fBuffer), tmp2(strBuf);
+ tmp1.toLower();
+ tmp2.toLower();
+ return (std::strstr((const char*)tmp1, (const char*)tmp2) != nullptr);
+#endif
+ }
+
+ return (std::strstr(fBuffer, strBuf) != nullptr);
+ }
+
+ /*
+ * Overloaded function.
+ */
+ bool contains(const d_string& str, const bool ignoreCase = false) const
+ {
+ return contains(str.fBuffer, ignoreCase);
+ }
+
+ /*
+ * Check if character at 'pos' is a digit.
+ */
+ bool isDigit(const size_t pos) const noexcept
+ {
+ if (pos >= fBufferLen)
+ return false;
+
+ return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9');
+ }
+
+ /*
+ * Check if the string starts with the character 'c'.
+ */
+ bool startsWith(const char c) const
+ {
+ if (c == '\0')
+ return false;
+
+ return (fBufferLen > 0 && fBuffer[0] == c);
+ }
+
+ /*
+ * Check if the string starts with the string 'prefix'.
+ */
+ bool startsWith(const char* const prefix) const
+ {
+ if (prefix == nullptr)
+ return false;
+
+ const size_t prefixLen(std::strlen(prefix));
+
+ if (fBufferLen < prefixLen)
+ return false;
+
+ return (std::strncmp(fBuffer + (fBufferLen-prefixLen), prefix, prefixLen) == 0);
+ }
+
+ /*
+ * Check if the string ends with the character 'c'.
+ */
+ bool endsWith(const char c) const
+ {
+ if (c == '\0')
+ return false;
+
+ return (fBufferLen > 0 && fBuffer[fBufferLen] == c);
+ }
+
+ /*
+ * Check if the string ends with the string 'suffix'.
+ */
+ bool endsWith(const char* const suffix) const
+ {
+ if (suffix == nullptr)
+ return false;
+
+ const size_t suffixLen(std::strlen(suffix));
+
+ if (fBufferLen < suffixLen)
+ return false;
+
+ return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
+ }
+
+ /*
+ * Clear the string.
+ */
+ void clear() noexcept
+ {
+ truncate(0);
+ }
+
+ /*
+ * Replace all occurrences of character 'before' with character 'after'.
+ */
+ void replace(const char before, const char after) noexcept
+ {
+ if (before == '\0' || after == '\0')
+ return;
+
+ for (size_t i=0; i < fBufferLen; ++i)
+ {
+ if (fBuffer[i] == before)
+ fBuffer[i] = after;
+ else if (fBuffer[i] == '\0')
+ break;
+ }
+ }
+
+ /*
+ * Truncate the string to size 'n'.
+ */
+ void truncate(const size_t n) noexcept
+ {
+ if (n >= fBufferLen)
+ return;
+
+ for (size_t i=n; i < fBufferLen; ++i)
+ fBuffer[i] = '\0';
+
+ fBufferLen = n;
+ }
+
+ /*
+ * Convert all non-basic characters to '_'.
+ */
+ void toBasic() noexcept
+ {
+ for (size_t i=0; i < fBufferLen; ++i)
+ {
+ if (fBuffer[i] >= '0' && fBuffer[i] <= '9')
+ continue;
+ if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
+ continue;
+ if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
+ continue;
+ if (fBuffer[i] == '_')
+ continue;
+
+ fBuffer[i] = '_';
+ }
+ }
+
+ /*
+ * Convert to all ascii characters to lowercase.
+ */
+ void toLower() noexcept
+ {
+ static const char kCharDiff('a' - 'A');
+
+ for (size_t i=0; i < fBufferLen; ++i)
+ {
+ if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
+ fBuffer[i] += kCharDiff;
+ }
+ }
+
+ /*
+ * Convert to all ascii characters to uppercase.
+ */
+ void toUpper() noexcept
+ {
+ static const char kCharDiff('a' - 'A');
+
+ for (size_t i=0; i < fBufferLen; ++i)
+ {
+ if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
+ fBuffer[i] -= kCharDiff;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ // public operators
+
+ operator const char*() const noexcept
+ {
+ return fBuffer;
+ }
+
+ char& operator[](const size_t pos) const noexcept
+ {
+ return fBuffer[pos];
+ }
+
+ bool operator==(const char* const strBuf) const
+ {
+ return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0);
+ }
+
+ bool operator==(const d_string& str) const
+ {
+ return operator==(str.fBuffer);
+ }
+
+ bool operator!=(const char* const strBuf) const
+ {
+ return !operator==(strBuf);
+ }
+
+ bool operator!=(const d_string& str) const
+ {
+ return !operator==(str.fBuffer);
+ }
+
+ d_string& operator=(const char* const strBuf)
+ {
+ _dup(strBuf);
+
+ return *this;
+ }
+
+ d_string& operator=(const d_string& str)
+ {
+ return operator=(str.fBuffer);
+ }
+
+ d_string& operator+=(const char* const strBuf)
+ {
+ if (strBuf == nullptr)
+ return *this;
+
+ const size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1;
+ char newBuf[newBufSize];
+
+ std::strcpy(newBuf, fBuffer);
+ std::strcat(newBuf, strBuf);
+
+ _dup(newBuf, newBufSize-1);
+
+ return *this;
+ }
+
+ d_string& operator+=(const d_string& str)
+ {
+ return operator+=(str.fBuffer);
+ }
+
+ d_string operator+(const char* const strBuf)
+ {
+ const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
+ char newBuf[newBufSize];
+
+ std::strcpy(newBuf, fBuffer);
+
+ if (strBuf != nullptr)
+ std::strcat(newBuf, strBuf);
+
+ return d_string(newBuf);
+ }
+
+ d_string operator+(const d_string& str)
+ {
+ return operator+(str.fBuffer);
+ }
+
+ // -------------------------------------------------------------------
+
+private:
+ char* fBuffer; // the actual string buffer
+ size_t fBufferLen; // string length
+ bool fFirstInit; // true when first initiated
+
+ /*
+ * Shared init function.
+ * Called on all constructors.
+ */
+ void _init() noexcept
+ {
+ fBuffer = nullptr;
+ fBufferLen = 0;
+ fFirstInit = true;
+ }
+
+ /*
+ * Helper function.
+ * Called whenever the string needs to be allocated.
+ *
+ * Notes:
+ * - Allocates string only if first initiated, or if 'strBuf' is not null and new string contents are different
+ * - If 'strBuf' is null 'size' must be 0
+ */
+ void _dup(const char* const strBuf, const size_t size = 0)
+ {
+ if (strBuf != nullptr)
+ {
+ // don't recreate string if contents match
+ if (fFirstInit || std::strcmp(fBuffer, strBuf) != 0)
+ {
+ if (! fFirstInit)
+ {
+ assert(fBuffer != nullptr);
+ delete[] fBuffer;
+ }
+
+ fBufferLen = (size > 0) ? size : std::strlen(strBuf);
+ fBuffer = new char[fBufferLen+1];
+
+ std::strcpy(fBuffer, strBuf);
+
+ fBuffer[fBufferLen] = '\0';
+
+ fFirstInit = false;
+ }
+ }
+ else
+ {
+ assert(size == 0);
+
+ // don't recreate null string
+ if (fFirstInit || fBufferLen != 0)
+ {
+ if (! fFirstInit)
+ {
+ assert(fBuffer != nullptr);
+ delete[] fBuffer;
+ }
+
+ fBufferLen = 0;
+ fBuffer = new char[1];
+ fBuffer[0] = '\0';
+
+ fFirstInit = false;
+ }
+ }
+ }
+};
+
+// -----------------------------------------------------------------------
+
+static inline
+d_string operator+(const d_string& strBefore, const char* const strBufAfter)
+{
+ const char* const strBufBefore = (const char*)strBefore;
+ const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
+ char newBuf[newBufSize];
+
+ std::strcpy(newBuf, strBufBefore);
+ std::strcat(newBuf, strBufAfter);
+
+ return d_string(newBuf);
+}
+
+static inline
+d_string operator+(const char* const strBufBefore, const d_string& strAfter)
+{
+ const char* const strBufAfter = (const char*)strAfter;
+ const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
+ char newBuf[newBufSize];
+
+ std::strcpy(newBuf, strBufBefore);
+ std::strcat(newBuf, strBufAfter);
+
+ return d_string(newBuf);
+}
+
+// -----------------------------------------------------------------------
+
+#endif // DISTRHO_UTILS_HPP_INCLUDED
diff --git a/distrho/src/DistrhoDefines.h b/distrho/src/DistrhoDefines.h
@@ -0,0 +1,114 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DISTRHO_DEFINES_H_INCLUDED
+#define DISTRHO_DEFINES_H_INCLUDED
+
+#include "DistrhoPluginInfo.h"
+
+#ifndef DISTRHO_PLUGIN_NAME
+# error DISTRHO_PLUGIN_NAME undefined!
+#endif
+
+#ifndef DISTRHO_PLUGIN_HAS_UI
+# error DISTRHO_PLUGIN_HAS_UI undefined!
+#endif
+
+#ifndef DISTRHO_PLUGIN_IS_SYNTH
+# error DISTRHO_PLUGIN_IS_SYNTH undefined!
+#endif
+
+#ifndef DISTRHO_PLUGIN_NUM_INPUTS
+# error DISTRHO_PLUGIN_NUM_INPUTS undefined!
+#endif
+
+#ifndef DISTRHO_PLUGIN_NUM_OUTPUTS
+# error DISTRHO_PLUGIN_NUM_OUTPUTS undefined!
+#endif
+
+#ifndef DISTRHO_PLUGIN_WANT_LATENCY
+# error DISTRHO_PLUGIN_WANT_LATENCY undefined!
+#endif
+
+#ifndef DISTRHO_PLUGIN_WANT_PROGRAMS
+# error DISTRHO_PLUGIN_WANT_PROGRAMS undefined!
+#endif
+
+#ifndef DISTRHO_PLUGIN_WANT_STATE
+# error DISTRHO_PLUGIN_WANT_STATE undefined!
+#endif
+
+#ifndef DISTRHO_PLUGIN_WANT_TIMEPOS
+# error DISTRHO_PLUGIN_WANT_TIMEPOS undefined!
+#endif
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+# define DISTRHO_PLUGIN_EXPORT extern "C" __declspec (dllexport)
+# define DISTRHO_OS_WINDOWS 1
+# define DISTRHO_DLL_EXTENSION "dll"
+#else
+# define DISTRHO_PLUGIN_EXPORT extern "C" __attribute__ ((visibility("default")))
+# if defined(__APPLE__)
+# define DISTRHO_OS_MAC 1
+# define DISTRHO_DLL_EXTENSION "dylib"
+# elif defined(__HAIKU__)
+# define DISTRHO_OS_HAIKU 1
+# define DISTRHO_DLL_EXTENSION "so"
+# elif defined(__linux__)
+# define DISTRHO_OS_LINUX 1
+# define DISTRHO_DLL_EXTENSION "so"
+# endif
+#endif
+
+#ifndef DISTRHO_DLL_EXTENSION
+# define DISTRHO_DLL_EXTENSION "so"
+#endif
+
+#if defined(HAVE_CPP11_SUPPORT)
+# define PROPER_CPP11_SUPPORT
+#elif defined(__GNUC__) && (__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__))
+# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
+# define PROPER_CPP11_SUPPORT
+# if (__GNUC__ * 100 + __GNUC_MINOR__) < 407
+# define override // gcc4.7+ only
+# endif
+# endif
+#endif
+
+#ifndef PROPER_CPP11_SUPPORT
+# ifndef __clang__
+# define noexcept throw()
+# endif
+# define override
+# define nullptr (0)
+#endif
+
+#ifndef DISTRHO_NO_NAMESPACE
+# ifndef DISTRHO_NAMESPACE
+# define DISTRHO_NAMESPACE DISTRHO
+# endif
+# define START_NAMESPACE_DISTRHO namespace DISTRHO_NAMESPACE {
+# define END_NAMESPACE_DISTRHO }
+# define USE_NAMESPACE_DISTRHO using namespace DISTRHO_NAMESPACE;
+#else
+# define START_NAMESPACE_DISTRHO
+# define END_NAMESPACE_DISTRHO
+# define USE_NAMESPACE_DISTRHO
+#endif
+
+#define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI"
+
+#endif // DISTRHO_DEFINES_H_INCLUDED
diff --git a/distrho/src/DistrhoPlugin.cpp b/distrho/src/DistrhoPlugin.cpp
@@ -0,0 +1,107 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "DistrhoPluginInternal.hpp"
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+// Static data, see DistrhoPluginInternal.hpp
+
+uint32_t d_lastBufferSize = 0;
+double d_lastSampleRate = 0.0;
+
+// -----------------------------------------------------------------------
+// Static fallback data, see DistrhoPluginInternal.hpp
+
+const d_string PluginExporter::sFallbackString;
+const ParameterRanges PluginExporter::sFallbackRanges;
+
+// -----------------------------------------------------------------------
+// Plugin
+
+Plugin::Plugin(uint32_t parameterCount, uint32_t programCount, uint32_t stateCount)
+ : pData(new PrivateData())
+{
+ if (parameterCount > 0)
+ {
+ pData->parameterCount = parameterCount;
+ pData->parameters = new Parameter[parameterCount];
+ }
+
+ if (programCount > 0)
+ {
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ pData->programCount = programCount;
+ pData->programNames = new d_string[programCount];
+#endif
+ }
+
+ if (stateCount > 0)
+ {
+#if DISTRHO_PLUGIN_WANT_STATE
+ pData->stateCount = stateCount;
+ pData->stateKeys = new d_string[stateCount];
+#endif
+ }
+}
+
+Plugin::~Plugin()
+{
+ delete pData;
+}
+
+// -----------------------------------------------------------------------
+// Host state
+
+uint32_t Plugin::d_getBufferSize() const noexcept
+{
+ return pData->bufferSize;
+}
+
+double Plugin::d_getSampleRate() const noexcept
+{
+ return pData->sampleRate;
+}
+
+#if DISTRHO_PLUGIN_WANT_TIMEPOS
+const TimePos& Plugin::d_getTimePos() const noexcept
+{
+ return pData->timePos;
+}
+#endif
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+void Plugin::d_setLatency(uint32_t frames) noexcept
+{
+ pData->latency = frames;
+}
+#endif
+
+// -----------------------------------------------------------------------
+// Callbacks (optional)
+
+void Plugin::d_bufferSizeChanged(uint32_t)
+{
+}
+
+void Plugin::d_sampleRateChanged(double)
+{
+}
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
diff --git a/distrho/src/DistrhoPluginInternal.hpp b/distrho/src/DistrhoPluginInternal.hpp
@@ -0,0 +1,380 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED
+#define DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED
+
+#include "../DistrhoPlugin.hpp"
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+// Maxmimum values
+
+static const uint32_t kMaxMidiEvents = 512;
+
+// -----------------------------------------------------------------------
+// Static data, see DistrhoPlugin.cpp
+
+extern uint32_t d_lastBufferSize;
+extern double d_lastSampleRate;
+
+// -----------------------------------------------------------------------
+// Plugin private data
+
+struct Plugin::PrivateData {
+ uint32_t parameterCount;
+ Parameter* parameters;
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ uint32_t programCount;
+ d_string* programNames;
+#endif
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ uint32_t stateCount;
+ d_string* stateKeys;
+#endif
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ uint32_t latency;
+#endif
+
+#if DISTRHO_PLUGIN_WANT_TIMEPOS
+ TimePos timePos;
+#endif
+
+ uint32_t bufferSize;
+ double sampleRate;
+
+ PrivateData() noexcept
+ : parameterCount(0),
+ parameters(nullptr),
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ programCount(0),
+ programNames(nullptr),
+#endif
+#if DISTRHO_PLUGIN_WANT_STATE
+ stateCount(0),
+ stateKeys(nullptr),
+#endif
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ latency(0),
+#endif
+ bufferSize(d_lastBufferSize),
+ sampleRate(d_lastSampleRate)
+ {
+ assert(bufferSize != 0);
+ assert(sampleRate != 0.0);
+ }
+
+ ~PrivateData()
+ {
+ if (parameters != nullptr)
+ {
+ delete[] parameters;
+ parameters = nullptr;
+ }
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ if (programNames != nullptr)
+ {
+ delete[] programNames;
+ programNames = nullptr;
+ }
+#endif
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ if (stateKeys != nullptr)
+ {
+ delete[] stateKeys;
+ stateKeys = nullptr;
+ }
+#endif
+ }
+};
+
+// -----------------------------------------------------------------------
+// Plugin exporter class
+
+class PluginExporter
+{
+public:
+ PluginExporter()
+ : fPlugin(createPlugin()),
+ fData((fPlugin != nullptr) ? fPlugin->pData : nullptr)
+ {
+ assert(fPlugin != nullptr);
+
+ if (fPlugin == nullptr)
+ return;
+
+ for (uint32_t i=0, count=fData->parameterCount; i < count; ++i)
+ fPlugin->d_initParameter(i, fData->parameters[i]);
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ for (uint32_t i=0, count=fData->programCount; i < count; ++i)
+ fPlugin->d_initProgramName(i, fData->programNames[i]);
+#endif
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ for (uint32_t i=0, count=fData->stateCount; i < count; ++i)
+ fPlugin->d_initStateKey(i, fData->stateKeys[i]);
+#endif
+ }
+
+ ~PluginExporter()
+ {
+ delete fPlugin;
+ }
+
+ // -------------------------------------------------------------------
+
+ const char* getName() const noexcept
+ {
+ return (fPlugin != nullptr) ? fPlugin->d_getName() : "";
+ }
+
+ const char* getLabel() const noexcept
+ {
+ return (fPlugin != nullptr) ? fPlugin->d_getLabel() : "";
+ }
+
+ const char* getMaker() const noexcept
+ {
+ return (fPlugin != nullptr) ? fPlugin->d_getMaker() : "";
+ }
+
+ const char* getLicense() const noexcept
+ {
+ return (fPlugin != nullptr) ? fPlugin->d_getLicense() : "";
+ }
+
+ uint32_t getVersion() const noexcept
+ {
+ return (fPlugin != nullptr) ? fPlugin->d_getVersion() : 1000;
+ }
+
+ long getUniqueId() const noexcept
+ {
+ return (fPlugin != nullptr) ? fPlugin->d_getUniqueId() : 0;
+ }
+
+ // -------------------------------------------------------------------
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ uint32_t getLatency() const noexcept
+ {
+ return (fData != nullptr) ? fData->latency : 0;
+ }
+#endif
+
+ uint32_t getParameterCount() const noexcept
+ {
+ return (fData != nullptr) ? fData->parameterCount : 0;
+ }
+
+ uint32_t getParameterHints(const uint32_t index) const noexcept
+ {
+ assert(index < fData->parameterCount);
+ return (fData != nullptr && index < fData->parameterCount) ? fData->parameters[index].hints : 0x0;
+ }
+
+ bool isParameterOutput(const uint32_t index) const noexcept
+ {
+ return (getParameterHints(index) & PARAMETER_IS_OUTPUT);
+ }
+
+ const d_string& getParameterName(const uint32_t index) const noexcept
+ {
+ assert(index < fData->parameterCount);
+ return (fData != nullptr && index < fData->parameterCount) ? fData->parameters[index].name : sFallbackString;
+ }
+
+ const d_string& getParameterSymbol(const uint32_t index) const noexcept
+ {
+ assert(index < fData->parameterCount);
+ return (fData != nullptr && index < fData->parameterCount) ? fData->parameters[index].symbol : sFallbackString;
+ }
+
+ const d_string& getParameterUnit(const uint32_t index) const noexcept
+ {
+ assert(index < fData->parameterCount);
+ return (fData != nullptr && index < fData->parameterCount) ? fData->parameters[index].unit : sFallbackString;
+ }
+
+ const ParameterRanges& getParameterRanges(const uint32_t index) const noexcept
+ {
+ assert(index < fData->parameterCount);
+ return (fData != nullptr && index < fData->parameterCount) ? fData->parameters[index].ranges : sFallbackRanges;
+ }
+
+ float getParameterValue(const uint32_t index) const noexcept
+ {
+ assert(index < fData->parameterCount);
+ return (fPlugin != nullptr && index < fData->parameterCount) ? fPlugin->d_getParameterValue(index) : 0.0f;
+ }
+
+ void setParameterValue(const uint32_t index, const float value)
+ {
+ assert(index < fData->parameterCount);
+
+ if (fPlugin != nullptr && index < fData->parameterCount)
+ fPlugin->d_setParameterValue(index, value);
+ }
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ uint32_t getProgramCount() const noexcept
+ {
+ return (fData != nullptr) ? fData->programCount : 0;
+ }
+
+ const d_string& getProgramName(const uint32_t index) const noexcept
+ {
+ assert(index < fData->programCount);
+ return (fData != nullptr && index < fData->programCount) ? fData->programNames[index] : sFallbackString;
+ }
+
+ void setProgram(const uint32_t index)
+ {
+ assert(index < fData->programCount);
+
+ if (fPlugin != nullptr && index < fData->programCount)
+ fPlugin->d_setProgram(index);
+ }
+#endif
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ uint32_t getStateCount() const noexcept
+ {
+ return fData != nullptr ? fData->stateCount : 0;
+ }
+
+ const d_string& getStateKey(const uint32_t index) const noexcept
+ {
+ assert(index < fData->stateCount);
+ return (fData != nullptr && index < fData->stateCount) ? fData->stateKeys[index] : sFallbackString;
+ }
+
+ void setState(const char* const key, const char* const value)
+ {
+ assert(key != nullptr && value != nullptr);
+
+ if (fPlugin != nullptr && key != nullptr && value != nullptr)
+ fPlugin->d_setState(key, value);
+ }
+#endif
+
+#if DISTRHO_PLUGIN_WANT_TIMEPOS
+ void setTimePos(const bool playing, const uint64_t frame, const double bpm)
+ {
+ if (fData != nullptr)
+ {
+ fData->timePos.playing = playing;
+ fData->timePos.frame = frame;
+ fData->timePos.bpm = bpm;
+ }
+ }
+#endif
+
+ // -------------------------------------------------------------------
+
+ void activate()
+ {
+ if (fPlugin != nullptr)
+ fPlugin->d_activate();
+ }
+
+ void deactivate()
+ {
+ if (fPlugin != nullptr)
+ fPlugin->d_deactivate();
+ }
+
+#if DISTRHO_PLUGIN_IS_SYNTH
+ void run(float** const inputs, float** const outputs, const uint32_t frames, const MidiEvent* const midiEvents, const uint32_t midiEventCount)
+ {
+ if (fPlugin != nullptr)
+ fPlugin->d_run(inputs, outputs, frames, midiEvents, midiEventCount);
+ }
+#else
+ void run(float** const inputs, float** const outputs, const uint32_t frames)
+ {
+ if (fPlugin != nullptr)
+ fPlugin->d_run(inputs, outputs, frames);
+ }
+#endif
+ // -------------------------------------------------------------------
+
+ void setBufferSize(const uint32_t bufferSize, bool doCallback = false)
+ {
+ assert(bufferSize >= 2);
+
+ if (fData != nullptr)
+ {
+ if (doCallback && fData->bufferSize == bufferSize)
+ doCallback = false;
+
+ fData->bufferSize = bufferSize;
+ }
+
+ if (fPlugin != nullptr && doCallback)
+ {
+ fPlugin->d_deactivate();
+ fPlugin->d_bufferSizeChanged(bufferSize);
+ fPlugin->d_activate();
+ }
+ }
+
+ void setSampleRate(const double sampleRate, bool doCallback = false)
+ {
+ assert(sampleRate > 0.0);
+
+ if (fData != nullptr)
+ {
+ if (doCallback && fData->sampleRate == sampleRate)
+ doCallback = false;
+
+ fData->sampleRate = sampleRate;
+ }
+
+ if (fPlugin != nullptr && doCallback)
+ {
+ fPlugin->d_deactivate();
+ fPlugin->d_sampleRateChanged(sampleRate);
+ fPlugin->d_activate();
+ }
+ }
+
+private:
+ // -------------------------------------------------------------------
+ // private members accessed by DistrhoPlugin class
+
+ Plugin* const fPlugin;
+ Plugin::PrivateData* const fData;
+
+ // -------------------------------------------------------------------
+ // Static fallback data, see DistrhoPlugin.cpp
+
+ static const d_string sFallbackString;
+ static const ParameterRanges sFallbackRanges;
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
+
+#endif // DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED
diff --git a/distrho/src/DistrhoPluginLADSPA+DSSI.cpp b/distrho/src/DistrhoPluginLADSPA+DSSI.cpp
@@ -0,0 +1,702 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "DistrhoPluginInternal.hpp"
+
+#ifdef DISTRHO_PLUGIN_TARGET_DSSI
+# include "dssi/dssi.h"
+#else
+# include "ladspa/ladspa.h"
+# if DISTRHO_PLUGIN_IS_SYNTH
+# error Cannot build synth plugin with LADSPA
+# endif
+# if DISTRHO_PLUGIN_WANT_STATE
+# warning LADSPA cannot handle states
+# endif
+#endif
+
+#if DISTRHO_PLUGIN_WANT_TIMEPOS
+# warning LADSPA/DSSI does not support TimePos
+#endif
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+
+class PluginLadspaDssi
+{
+public:
+ PluginLadspaDssi()
+ : fPortControls(nullptr),
+ fLastControlValues(nullptr)
+ {
+#if DISTRHO_PLUGIN_NUM_INPUTS > 0
+ for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
+ fPortAudioIns[i] = nullptr;
+#else
+ fPortAudioIns = nullptr;
+#endif
+
+#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
+ fPortAudioOuts[i] = nullptr;
+#else
+ fPortAudioOuts = nullptr;
+#endif
+
+ {
+ const uint32_t count(fPlugin.getParameterCount());
+
+ fPortControls = new LADSPA_Data*[count];
+ fLastControlValues = new LADSPA_Data[count];
+
+ for (uint32_t i=0; i < count; ++i)
+ {
+ fPortControls[i] = nullptr;
+ fLastControlValues[i] = fPlugin.getParameterValue(i);
+ }
+ }
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ fPortLatency = nullptr;
+#endif
+ }
+
+ ~PluginLadspaDssi()
+ {
+ if (fPortControls != nullptr)
+ {
+ delete[] fPortControls;
+ fPortControls = nullptr;
+ }
+
+ if (fLastControlValues)
+ {
+ delete[] fLastControlValues;
+ fLastControlValues = nullptr;
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+ void ladspa_activate()
+ {
+ fPlugin.activate();
+ }
+
+ void ladspa_deactivate()
+ {
+ fPlugin.deactivate();
+ }
+
+ // -------------------------------------------------------------------
+
+ void ladspa_connect_port(const unsigned long port, LADSPA_Data* const dataLocation)
+ {
+ unsigned long index = 0;
+
+#if DISTRHO_PLUGIN_NUM_INPUTS > 0
+ for (unsigned long i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
+ {
+ if (port == index++)
+ {
+ fPortAudioIns[i] = dataLocation;
+ return;
+ }
+ }
+#endif
+
+#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ for (unsigned long i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
+ {
+ if (port == index++)
+ {
+ fPortAudioOuts[i] = dataLocation;
+ return;
+ }
+ }
+#endif
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ if (port == index++)
+ {
+ fPortLatency = dataLocation;
+ return;
+ }
+#endif
+
+ for (unsigned long i=0, count=fPlugin.getParameterCount(); i < count; ++i)
+ {
+ if (port == index++)
+ {
+ fPortControls[i] = dataLocation;
+ return;
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+#ifdef DISTRHO_PLUGIN_TARGET_DSSI
+ void ladspa_run(const unsigned long sampleCount)
+ {
+ dssi_run_synth(sampleCount, nullptr, 0);
+ }
+
+ void dssi_run_synth(const unsigned long sampleCount, snd_seq_event_t* const events, const unsigned long eventCount)
+#else
+ void ladspa_run(const unsigned long sampleCount)
+#endif
+ {
+ // pre-roll
+ if (sampleCount == 0)
+ return updateParameterOutputs();
+
+ // Check for updated parameters
+ float curValue;
+
+ for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
+ {
+ if (fPortControls[i] == nullptr)
+ continue;
+
+ curValue = *fPortControls[i];
+
+ if (fLastControlValues[i] != curValue && ! fPlugin.isParameterOutput(i))
+ {
+ fLastControlValues[i] = curValue;
+ fPlugin.setParameterValue(i, curValue);
+ }
+ }
+
+#if DISTRHO_PLUGIN_IS_SYNTH
+ // Get MIDI Events
+ uint32_t midiEventCount = 0;
+ MidiEvent midiEvents[eventCount];
+
+ for (uint32_t i=0, j; i < eventCount; ++i)
+ {
+ const snd_seq_event_t& seqEvent(events[i]);
+
+ if (seqEvent.data.note.channel > 0xF || seqEvent.data.control.channel > 0xF)
+ continue;
+
+ switch (seqEvent.type)
+ {
+ case SND_SEQ_EVENT_NOTEOFF:
+ j = midiEventCount++;
+ midiEvents[j].frame = seqEvent.time.tick;
+ midiEvents[j].size = 3;
+ midiEvents[j].buf[0] = 0x80 + seqEvent.data.note.channel;
+ midiEvents[j].buf[1] = seqEvent.data.note.note;
+ midiEvents[j].buf[2] = 0;
+ midiEvents[j].buf[3] = 0;
+ break;
+ case SND_SEQ_EVENT_NOTEON:
+ j = midiEventCount++;
+ midiEvents[j].frame = seqEvent.time.tick;
+ midiEvents[j].size = 3;
+ midiEvents[j].buf[0] = 0x90 + seqEvent.data.note.channel;
+ midiEvents[j].buf[1] = seqEvent.data.note.note;
+ midiEvents[j].buf[2] = seqEvent.data.note.velocity;
+ midiEvents[j].buf[3] = 0;
+ break;
+ case SND_SEQ_EVENT_KEYPRESS:
+ j = midiEventCount++;
+ midiEvents[j].frame = seqEvent.time.tick;
+ midiEvents[j].size = 3;
+ midiEvents[j].buf[0] = 0xA0 + seqEvent.data.note.channel;
+ midiEvents[j].buf[1] = seqEvent.data.note.note;
+ midiEvents[j].buf[2] = seqEvent.data.note.velocity;
+ midiEvents[j].buf[3] = 0;
+ break;
+ case SND_SEQ_EVENT_CONTROLLER:
+ j = midiEventCount++;
+ midiEvents[j].frame = seqEvent.time.tick;
+ midiEvents[j].size = 3;
+ midiEvents[j].buf[0] = 0xB0 + seqEvent.data.control.channel;
+ midiEvents[j].buf[1] = seqEvent.data.control.param;
+ midiEvents[j].buf[2] = seqEvent.data.control.value;
+ midiEvents[j].buf[3] = 0;
+ break;
+ case SND_SEQ_EVENT_CHANPRESS:
+ j = midiEventCount++;
+ midiEvents[j].frame = seqEvent.time.tick;
+ midiEvents[j].size = 2;
+ midiEvents[j].buf[0] = 0xD0 + seqEvent.data.control.channel;
+ midiEvents[j].buf[1] = seqEvent.data.control.value;
+ midiEvents[j].buf[2] = 0;
+ midiEvents[j].buf[3] = 0;
+ break;
+#if 0 // TODO
+ case SND_SEQ_EVENT_PITCHBEND:
+ j = midiEventCount++;
+ midiEvents[j].frame = seqEvent.time.tick;
+ midiEvents[j].size = 3;
+ midiEvents[j].buf[0] = 0xE0 + seqEvent.data.control.channel;
+ midiEvents[j].buf[1] = 0;
+ midiEvents[j].buf[2] = 0;
+ midiEvents[j].buf[3] = 0;
+ break;
+#endif
+ }
+ }
+
+ fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount, midiEvents, midiEventCount);
+#else
+ fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount);
+#endif
+
+ updateParameterOutputs();
+
+#if defined(DISTRHO_PLUGIN_TARGET_DSSI) && ! DISTRHO_PLUGIN_IS_SYNTH
+ return; // unused
+ (void)events;
+ (void)eventCount;
+#endif
+ }
+
+ // -------------------------------------------------------------------
+
+#ifdef DISTRHO_PLUGIN_TARGET_DSSI
+# if DISTRHO_PLUGIN_WANT_STATE
+ char* dssi_configure(const char* const key, const char* const value)
+ {
+ if (std::strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX, std::strlen(DSSI_RESERVED_CONFIGURE_PREFIX) == 0))
+ return nullptr;
+ if (std::strncmp(key, DSSI_GLOBAL_CONFIGURE_PREFIX, std::strlen(DSSI_GLOBAL_CONFIGURE_PREFIX) == 0))
+ return nullptr;
+
+ fPlugin.setState(key, value);
+ return nullptr;
+ }
+# endif
+
+# if DISTRHO_PLUGIN_WANT_PROGRAMS
+ const DSSI_Program_Descriptor* dssi_get_program(const unsigned long index)
+ {
+ if (index >= fPlugin.getProgramCount())
+ return nullptr;
+
+ static DSSI_Program_Descriptor desc;
+
+ desc.Bank = index / 128;
+ desc.Program = index % 128;
+ desc.Name = fPlugin.getProgramName(index);
+
+ return &desc;
+ }
+
+ void dssi_select_program(const unsigned long bank, const unsigned long program)
+ {
+ const unsigned long realProgram(bank * 128 + program);
+
+ if (realProgram >= fPlugin.getProgramCount())
+ return;
+
+ fPlugin.setProgram(realProgram);
+
+ // Update control inputs
+ for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
+ {
+ if (fPlugin.isParameterOutput(i))
+ continue;
+
+ fLastControlValues[i] = fPlugin.getParameterValue(i);
+
+ if (fPortControls[i] != nullptr)
+ *fPortControls[i] = fLastControlValues[i];
+ }
+ }
+# endif
+#endif
+
+ // -------------------------------------------------------------------
+
+private:
+ PluginExporter fPlugin;
+
+ // LADSPA ports
+#if DISTRHO_PLUGIN_NUM_INPUTS > 0
+ LADSPA_Data* fPortAudioIns[DISTRHO_PLUGIN_NUM_INPUTS];
+#else
+ LADSPA_Data** fPortAudioIns;
+#endif
+#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ LADSPA_Data* fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS];
+#else
+ LADSPA_Data** fPortAudioOuts;
+#endif
+ LADSPA_Data** fPortControls;
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ LADSPA_Data* fPortLatency;
+#endif
+
+ // Temporary data
+ LADSPA_Data* fLastControlValues;
+
+ // -------------------------------------------------------------------
+
+ void updateParameterOutputs()
+ {
+ for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
+ {
+ if (! fPlugin.isParameterOutput(i))
+ continue;
+
+ fLastControlValues[i] = fPlugin.getParameterValue(i);
+
+ if (fPortControls[i] != nullptr)
+ *fPortControls[i] = fLastControlValues[i];
+ }
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ if (fPortLatency != nullptr)
+ *fPortLatency = fPlugin.getLatency();
+#endif
+ }
+};
+
+// -----------------------------------------------------------------------
+
+static LADSPA_Handle ladspa_instantiate(const LADSPA_Descriptor*, unsigned long sampleRate)
+{
+ if (d_lastBufferSize == 0)
+ d_lastBufferSize = 2048;
+ d_lastSampleRate = sampleRate;
+
+ return new PluginLadspaDssi();
+}
+
+#define instancePtr ((PluginLadspaDssi*)instance)
+
+static void ladspa_connect_port(LADSPA_Handle instance, unsigned long port, LADSPA_Data* dataLocation)
+{
+ instancePtr->ladspa_connect_port(port, dataLocation);
+}
+
+static void ladspa_activate(LADSPA_Handle instance)
+{
+ instancePtr->ladspa_activate();
+}
+
+static void ladspa_run(LADSPA_Handle instance, unsigned long sampleCount)
+{
+ instancePtr->ladspa_run(sampleCount);
+}
+
+static void ladspa_deactivate(LADSPA_Handle instance)
+{
+ instancePtr->ladspa_deactivate();
+}
+
+static void ladspa_cleanup(LADSPA_Handle instance)
+{
+ delete instancePtr;
+}
+
+#ifdef DISTRHO_PLUGIN_TARGET_DSSI
+# if DISTRHO_PLUGIN_WANT_STATE
+static char* dssi_configure(LADSPA_Handle instance, const char* key, const char* value)
+{
+ return instancePtr->dssi_configure(key, value);
+}
+# endif
+
+# if DISTRHO_PLUGIN_WANT_PROGRAMS
+static const DSSI_Program_Descriptor* dssi_get_program(LADSPA_Handle instance, unsigned long index)
+{
+ return instancePtr->dssi_get_program(index);
+}
+
+static void dssi_select_program(LADSPA_Handle instance, unsigned long bank, unsigned long program)
+{
+ instancePtr->dssi_select_program(bank, program);
+}
+# endif
+
+# if DISTRHO_PLUGIN_IS_SYNTH
+static void dssi_run_synth(LADSPA_Handle instance, unsigned long sampleCount, snd_seq_event_t* events, unsigned long eventCount)
+{
+ instancePtr->dssi_run_synth(sampleCount, events, eventCount);
+}
+# endif
+#endif
+
+#undef instancePtr
+
+// -----------------------------------------------------------------------
+
+static LADSPA_Descriptor sLadspaDescriptor = {
+ /* UniqueID */ 0,
+ /* Label */ nullptr,
+ /* Properties */ LADSPA_PROPERTY_REALTIME | LADSPA_PROPERTY_HARD_RT_CAPABLE,
+ /* Name */ nullptr,
+ /* Maker */ nullptr,
+ /* Copyright */ nullptr,
+ /* PortCount */ 0,
+ /* PortDescriptors */ nullptr,
+ /* PortNames */ nullptr,
+ /* PortRangeHints */ nullptr,
+ /* ImplementationData */ nullptr,
+ ladspa_instantiate,
+ ladspa_connect_port,
+ ladspa_activate,
+ ladspa_run,
+ /* run_adding */ nullptr,
+ /* set_run_adding_gain */ nullptr,
+ ladspa_deactivate,
+ ladspa_cleanup
+};
+
+#ifdef DISTRHO_PLUGIN_TARGET_DSSI
+static DSSI_Descriptor sDssiDescriptor = {
+ 1,
+ &sLadspaDescriptor,
+# if DISTRHO_PLUGIN_WANT_STATE
+ dssi_configure,
+# else
+ /* configure */ nullptr,
+# endif
+# if DISTRHO_PLUGIN_WANT_PROGRAMS
+ dssi_get_program,
+ dssi_select_program,
+# else
+ /* get_program */ nullptr,
+ /* select_program */ nullptr,
+# endif
+ /* get_midi_controller_for_port */ nullptr,
+# if DISTRHO_PLUGIN_IS_SYNTH
+ dssi_run_synth,
+# else
+ /* run_synth */ nullptr,
+# endif
+ /* run_synth_adding */ nullptr,
+ /* run_multiple_synths */ nullptr,
+ /* run_multiple_synths_adding */ nullptr,
+ nullptr, nullptr
+};
+#endif
+
+// -----------------------------------------------------------------------
+
+class DescriptorInitializer
+{
+public:
+ DescriptorInitializer()
+ {
+ // Create dummy plugin to get data from
+ d_lastBufferSize = 512;
+ d_lastSampleRate = 44100.0;
+ PluginExporter plugin;
+ d_lastBufferSize = 0;
+ d_lastSampleRate = 0.0;
+
+ // Get port count, init
+ unsigned long port = 0;
+ unsigned long portCount = DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS + plugin.getParameterCount();
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ portCount += 1;
+#endif
+ const char** const portNames = new const char*[portCount];
+ LADSPA_PortDescriptor* portDescriptors = new LADSPA_PortDescriptor[portCount];
+ LADSPA_PortRangeHint* portRangeHints = new LADSPA_PortRangeHint [portCount];
+
+ // Set ports
+#if DISTRHO_PLUGIN_NUM_INPUTS > 0
+ for (unsigned long i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++port)
+ {
+ char portName[24] = { '\0' };
+ std::sprintf(portName, "Audio Input %lu", i+1);
+
+ portNames[port] = strdup(portName);
+ portDescriptors[port] = LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT;
+
+ portRangeHints[port].HintDescriptor = 0x0;
+ portRangeHints[port].LowerBound = 0.0f;
+ portRangeHints[port].UpperBound = 1.0f;
+ }
+#endif
+
+#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ for (unsigned long i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++port)
+ {
+ char portName[24] = { '\0' };
+ std::sprintf(portName, "Audio Output %lu", i+1);
+
+ portNames[port] = strdup(portName);
+ portDescriptors[port] = LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT;
+
+ portRangeHints[port].HintDescriptor = 0x0;
+ portRangeHints[port].LowerBound = 0.0f;
+ portRangeHints[port].UpperBound = 1.0f;
+ }
+#endif
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ // Set latency port
+ portNames[port] = strdup("_latency");
+ portDescriptors[port] = LADSPA_PORT_CONTROL | LADSPA_PORT_OUTPUT;
+ portRangeHints[port].HintDescriptor = LADSPA_HINT_SAMPLE_RATE;
+ portRangeHints[port].LowerBound = 0.0f;
+ portRangeHints[port].UpperBound = 1.0f;
+ ++port;
+#endif
+
+ for (unsigned long i=0, count=plugin.getParameterCount(); i < count; ++i, ++port)
+ {
+ portNames[port] = strdup((const char*)plugin.getParameterName(i));
+ portDescriptors[port] = LADSPA_PORT_CONTROL;
+
+ if (plugin.isParameterOutput(i))
+ portDescriptors[port] |= LADSPA_PORT_OUTPUT;
+ else
+ portDescriptors[port] |= LADSPA_PORT_INPUT;
+
+ {
+ const ParameterRanges& ranges(plugin.getParameterRanges(i));
+ const float defValue(ranges.def);
+
+ portRangeHints[port].HintDescriptor = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
+ portRangeHints[port].LowerBound = ranges.min;
+ portRangeHints[port].UpperBound = ranges.max;
+
+ if (defValue == 0.0f)
+ portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_0;
+ else if (defValue == 1.0f)
+ portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_1;
+ else if (defValue == 100.0f)
+ portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_100;
+ else if (defValue == 440.0f)
+ portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_440;
+ else if (ranges.min == defValue)
+ portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_MINIMUM;
+ else if (ranges.max == defValue)
+ portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_MAXIMUM;
+ else
+ {
+ const float middleValue = ranges.min/2.0f + ranges.max/2.0f;
+ const float middleLow = (ranges.min/2.0f + middleValue/2.0f)/2.0f + middleValue/2.0f;
+ const float middleHigh = (ranges.max/2.0f + middleValue/2.0f)/2.0f + middleValue/2.0f;
+
+ if (defValue < middleLow)
+ portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_LOW;
+ else if (defValue > middleHigh)
+ portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_HIGH;
+ else
+ portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_MIDDLE;
+ }
+ }
+
+ {
+ const uint32_t hints(plugin.getParameterHints(i));
+
+ if (hints & PARAMETER_IS_BOOLEAN)
+ portRangeHints[port].HintDescriptor |= LADSPA_HINT_TOGGLED;
+ if (hints & PARAMETER_IS_INTEGER)
+ portRangeHints[port].HintDescriptor |= LADSPA_HINT_INTEGER;
+ if (hints & PARAMETER_IS_LOGARITHMIC)
+ portRangeHints[port].HintDescriptor |= LADSPA_HINT_LOGARITHMIC;
+ }
+ }
+
+ // Set data
+ sLadspaDescriptor.UniqueID = plugin.getUniqueId();
+ sLadspaDescriptor.Label = strdup(plugin.getLabel());
+ sLadspaDescriptor.Name = strdup(plugin.getName());
+ sLadspaDescriptor.Maker = strdup(plugin.getMaker());
+ sLadspaDescriptor.Copyright = strdup(plugin.getLicense());
+ sLadspaDescriptor.PortCount = portCount;
+ sLadspaDescriptor.PortNames = portNames;
+ sLadspaDescriptor.PortDescriptors = portDescriptors;
+ sLadspaDescriptor.PortRangeHints = portRangeHints;
+ }
+
+ ~DescriptorInitializer()
+ {
+ if (sLadspaDescriptor.Label != nullptr)
+ {
+ std::free((void*)sLadspaDescriptor.Label);
+ sLadspaDescriptor.Label = nullptr;
+ }
+
+ if (sLadspaDescriptor.Name != nullptr)
+ {
+ std::free((void*)sLadspaDescriptor.Name);
+ sLadspaDescriptor.Name = nullptr;
+ }
+
+ if (sLadspaDescriptor.Maker != nullptr)
+ {
+ std::free((void*)sLadspaDescriptor.Maker);
+ sLadspaDescriptor.Maker = nullptr;
+ }
+
+ if (sLadspaDescriptor.Copyright != nullptr)
+ {
+ std::free((void*)sLadspaDescriptor.Copyright);
+ sLadspaDescriptor.Copyright = nullptr;
+ }
+
+ if (sLadspaDescriptor.PortDescriptors != nullptr)
+ {
+ delete[] sLadspaDescriptor.PortDescriptors;
+ sLadspaDescriptor.PortDescriptors = nullptr;
+ }
+
+ if (sLadspaDescriptor.PortRangeHints != nullptr)
+ {
+ delete[] sLadspaDescriptor.PortRangeHints;
+ sLadspaDescriptor.PortRangeHints = nullptr;
+ }
+
+ if (sLadspaDescriptor.PortNames != nullptr)
+ {
+ for (unsigned long i=0; i < sLadspaDescriptor.PortCount; ++i)
+ {
+ if (sLadspaDescriptor.PortNames[i] != nullptr)
+ std::free((void*)sLadspaDescriptor.PortNames[i]);
+ }
+
+ delete[] sLadspaDescriptor.PortNames;
+ sLadspaDescriptor.PortNames = nullptr;
+ }
+ }
+};
+
+static DescriptorInitializer sDescInit;
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
+
+DISTRHO_PLUGIN_EXPORT
+const LADSPA_Descriptor* ladspa_descriptor(unsigned long index)
+{
+ USE_NAMESPACE_DISTRHO
+ return (index == 0) ? &sLadspaDescriptor : nullptr;
+}
+
+#ifdef DISTRHO_PLUGIN_TARGET_DSSI
+DISTRHO_PLUGIN_EXPORT
+const DSSI_Descriptor* dssi_descriptor(unsigned long index)
+{
+ USE_NAMESPACE_DISTRHO
+ return (index == 0) ? &sDssiDescriptor : nullptr;
+}
+#endif
+
+// -----------------------------------------------------------------------
diff --git a/distrho/src/DistrhoPluginLV2.cpp b/distrho/src/DistrhoPluginLV2.cpp
@@ -0,0 +1,714 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "DistrhoPluginInternal.hpp"
+
+#include "lv2/atom.h"
+#include "lv2/atom-util.h"
+#include "lv2/buf-size.h"
+#include "lv2/midi.h"
+#include "lv2/options.h"
+#include "lv2/state.h"
+#include "lv2/time.h"
+#include "lv2/urid.h"
+#include "lv2/worker.h"
+#include "lv2/lv2_programs.h"
+
+#ifdef noexcept
+# undef noexcept
+#endif
+
+#include <map>
+
+#ifndef DISTRHO_PLUGIN_URI
+# error DISTRHO_PLUGIN_URI undefined!
+#endif
+
+#if DISTRHO_PLUGIN_WANT_STATE
+# warning LV2 State still TODO
+#endif
+#if DISTRHO_PLUGIN_WANT_TIMEPOS
+# warning LV2 TimePos still TODO
+#endif
+
+#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI))
+#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)
+
+typedef std::map<d_string,d_string> StringMap;
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+
+class PluginLv2
+{
+public:
+ PluginLv2(const LV2_URID_Map* const uridMap, const LV2_Worker_Schedule* const worker)
+ : fPortControls(nullptr),
+ fLastControlValues(nullptr),
+#if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT
+ fURIDs(uridMap),
+#endif
+ fUridMap(uridMap),
+ fWorker(worker)
+ {
+#if DISTRHO_PLUGIN_NUM_INPUTS > 0
+ for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
+ fPortAudioIns[i] = nullptr;
+#else
+ fPortAudioIns = nullptr;
+#endif
+
+#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
+ fPortAudioOuts[i] = nullptr;
+#else
+ fPortAudioOuts = nullptr;
+#endif
+
+ {
+ const uint32_t count(fPlugin.getParameterCount());
+
+ fPortControls = new float*[count];
+ fLastControlValues = new float[count];
+
+ for (uint32_t i=0; i < count; ++i)
+ {
+ fPortControls[i] = nullptr;
+ fLastControlValues[i] = fPlugin.getParameterValue(i);
+ }
+ }
+
+#if DISTRHO_LV2_USE_EVENTS_IN
+ fPortEventsIn = nullptr;
+#endif
+#if DISTRHO_LV2_USE_EVENTS_OUT
+ fPortEventsOut = nullptr;
+#endif
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ fPortLatency = nullptr;
+#endif
+ }
+
+ ~PluginLv2()
+ {
+ if (fPortControls != nullptr)
+ {
+ delete[] fPortControls;
+ fPortControls = nullptr;
+ }
+
+ if (fLastControlValues)
+ {
+ delete[] fLastControlValues;
+ fLastControlValues = nullptr;
+ }
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ fStateMap.clear();
+#endif
+ }
+
+ // -------------------------------------------------------------------
+
+ void lv2_activate()
+ {
+ fPlugin.activate();
+ }
+
+ void lv2_deactivate()
+ {
+ fPlugin.deactivate();
+ }
+
+ // -------------------------------------------------------------------
+
+ void lv2_connect_port(const uint32_t port, void* const dataLocation)
+ {
+ uint32_t index = 0;
+
+#if DISTRHO_PLUGIN_NUM_INPUTS > 0
+ for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
+ {
+ if (port == index++)
+ {
+ fPortAudioIns[i] = (float*)dataLocation;
+ return;
+ }
+ }
+#endif
+
+#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
+ {
+ if (port == index++)
+ {
+ fPortAudioOuts[i] = (float*)dataLocation;
+ return;
+ }
+ }
+#endif
+
+#if DISTRHO_LV2_USE_EVENTS_IN
+ if (port == index++)
+ {
+ fPortEventsIn = (LV2_Atom_Sequence*)dataLocation;
+ return;
+ }
+#endif
+
+#if DISTRHO_LV2_USE_EVENTS_OUT
+ if (port == index++)
+ {
+ fPortEventsOut = (LV2_Atom_Sequence*)dataLocation;
+ return;
+ }
+#endif
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ if (port == index++)
+ {
+ fPortLatency = (float*)dataLocation;
+ return;
+ }
+#endif
+
+ for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
+ {
+ if (port == index++)
+ {
+ fPortControls[i] = (float*)dataLocation;
+ return;
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+ void lv2_run(const uint32_t sampleCount)
+ {
+ // pre-roll
+ if (sampleCount == 0)
+ return updateParameterOutputs();
+
+ // Check for updated parameters
+ float curValue;
+
+ for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
+ {
+ if (fPortControls[i] == nullptr)
+ continue;
+
+ curValue = *fPortControls[i];
+
+ if (fLastControlValues[i] != curValue && ! fPlugin.isParameterOutput(i))
+ {
+ fLastControlValues[i] = curValue;
+ fPlugin.setParameterValue(i, curValue);
+ }
+ }
+
+#if DISTRHO_LV2_USE_EVENTS_IN
+# if DISTRHO_PLUGIN_IS_SYNTH
+ uint32_t midiEventCount = 0;
+# endif
+ LV2_ATOM_SEQUENCE_FOREACH(fPortEventsIn, event)
+ {
+ if (event == nullptr)
+ break;
+
+# if DISTRHO_PLUGIN_IS_SYNTH
+ if (event->body.type == fURIDs.midiEvent)
+ {
+ if (event->body.size > 4 || midiEventCount >= kMaxMidiEvents)
+ continue;
+
+ const uint8_t* const data((const uint8_t*)(event + 1));
+
+ MidiEvent& midiEvent(fMidiEvents[midiEventCount]);
+
+ midiEvent.frame = event->time.frames;
+ midiEvent.size = event->body.size;
+
+ uint8_t i;
+ for (i=0; i < midiEvent.size; ++i)
+ midiEvent.buf[i] = data[i];
+ for (; i < 4; ++i)
+ midiEvent.buf[i] = 0;
+
+ ++midiEventCount;
+ continue;
+ }
+# endif
+# if DISTRHO_PLUGIN_WANT_TIMEPOS
+ if (event->body.type == fURIDs.timePosition)
+ {
+ // TODO
+ }
+# endif
+# if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)
+ if (event->body.type == fURIDs.distrhoState && fWorker != nullptr)
+ {
+ const void* const data((const void*)(event + 1));
+ fWorker->schedule_work(fWorker->handle, event->body.size, data);
+ }
+# endif
+ }
+#endif
+
+#if DISTRHO_PLUGIN_IS_SYNTH
+ fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount, fMidiEvents, midiEventCount);
+#else
+ fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount);
+#endif
+
+#if DISTRHO_LV2_USE_EVENTS_OUT
+#endif
+
+ updateParameterOutputs();
+ }
+
+ // -------------------------------------------------------------------
+
+ uint32_t lv2_get_options(LV2_Options_Option* const /*options*/)
+ {
+ // currently unused
+ return LV2_OPTIONS_ERR_UNKNOWN;
+ }
+
+ uint32_t lv2_set_options(const LV2_Options_Option* const options)
+ {
+ for (int i=0; options[i].key != 0; ++i)
+ {
+ if (options[i].key == fUridMap->map(fUridMap->handle, LV2_BUF_SIZE__maxBlockLength))
+ {
+ if (options[i].type == fUridMap->map(fUridMap->handle, LV2_ATOM__Int))
+ {
+ const int bufferSize(*(const int*)options[i].value);
+ fPlugin.setBufferSize(bufferSize);
+ return LV2_OPTIONS_SUCCESS;
+ }
+ else
+ {
+ d_stderr("Host changed maxBlockLength but with wrong value type");
+ return LV2_OPTIONS_ERR_BAD_VALUE;
+ }
+ }
+ else if (options[i].key == fUridMap->map(fUridMap->handle, LV2_CORE__sampleRate))
+ {
+ if (options[i].type == fUridMap->map(fUridMap->handle, LV2_ATOM__Double))
+ {
+ const double sampleRate(*(const double*)options[i].value);
+ fPlugin.setSampleRate(sampleRate);
+ return LV2_OPTIONS_SUCCESS;
+ }
+ else
+ {
+ d_stderr("Host changed sampleRate but with wrong value type");
+ return LV2_OPTIONS_ERR_BAD_VALUE;
+ }
+ }
+ }
+
+ return LV2_OPTIONS_ERR_BAD_KEY;
+ }
+
+ // -------------------------------------------------------------------
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ const LV2_Program_Descriptor* lv2_get_program(const uint32_t index)
+ {
+ if (index >= fPlugin.getProgramCount())
+ return nullptr;
+
+ static LV2_Program_Descriptor desc;
+
+ desc.bank = index / 128;
+ desc.program = index % 128;
+ desc.name = fPlugin.getProgramName(index);
+
+ return &desc;
+ }
+
+ void lv2_select_program(const uint32_t bank, const uint32_t program)
+ {
+ const uint32_t realProgram(bank * 128 + program);
+
+ if (realProgram >= fPlugin.getProgramCount())
+ return;
+
+ fPlugin.setProgram(realProgram);
+
+ // Update control inputs
+ for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
+ {
+ if (fPlugin.isParameterOutput(i))
+ continue;
+
+ fLastControlValues[i] = fPlugin.getParameterValue(i);
+
+ if (fPortControls[i] != nullptr)
+ *fPortControls[i] = fLastControlValues[i];
+ }
+ }
+#endif
+
+ // -------------------------------------------------------------------
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ LV2_State_Status lv2_save(const LV2_State_Store_Function store, const LV2_State_Handle handle, const uint32_t flags)
+ {
+ //flags = LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE;
+
+ for (auto it = fStateMap.begin(), end = fStateMap.end(); it != end; ++it)
+ {
+ const d_string& key = it->first;
+ const d_string& value = it->second;
+
+ store(handle, fUridMap->map(fUridMap->handle, (const char*)key), (const char*)value, value.length()+1, fURIDs.atomString, flags);
+ }
+
+ return LV2_STATE_SUCCESS;
+ }
+
+ LV2_State_Status lv2_restore(const LV2_State_Retrieve_Function retrieve, const LV2_State_Handle handle)
+ {
+ size_t size = 0;
+ uint32_t type = 0;
+ uint32_t flags = LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE;
+
+ for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i)
+ {
+ const d_string& key = fPlugin.getStateKey(i);
+
+ const void* data = retrieve(handle, fUridMap->map(fUridMap->handle, (const char*)key), &size, &type, &flags);
+
+ if (size == 0)
+ continue;
+ if (data == nullptr)
+ continue;
+ if (type != fURIDs.atomString)
+ continue;
+
+ const char* const value((const char*)data);
+
+ if (std::strlen(value) != size)
+ continue;
+
+ setState(key, value);
+ }
+
+ return LV2_STATE_SUCCESS;
+ }
+
+ // -------------------------------------------------------------------
+
+ LV2_Worker_Status lv2_work(const void* const data)
+ {
+ const char* const stateKey((const char*)data);
+ const char* const stateValue(stateKey+std::strlen(stateKey)+1);
+
+ setState(stateKey, stateValue);
+
+ return LV2_WORKER_SUCCESS;
+ }
+#endif
+
+ // -------------------------------------------------------------------
+
+private:
+ PluginExporter fPlugin;
+
+ // LV2 ports
+#if DISTRHO_PLUGIN_NUM_INPUTS > 0
+ float* fPortAudioIns[DISTRHO_PLUGIN_NUM_INPUTS];
+#else
+ float** fPortAudioIns;
+#endif
+#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ float* fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS];
+#else
+ float** fPortAudioOuts;
+#endif
+ float** fPortControls;
+#if DISTRHO_LV2_USE_EVENTS_IN
+ LV2_Atom_Sequence* fPortEventsIn;
+#endif
+#if DISTRHO_LV2_USE_EVENTS_OUT
+ LV2_Atom_Sequence* fPortEventsOut;
+#endif
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ float* fPortLatency;
+#endif
+
+ // Temporary data
+ float* fLastControlValues;
+#if DISTRHO_PLUGIN_IS_SYNTH
+ MidiEvent fMidiEvents[kMaxMidiEvents];
+#endif
+
+ // LV2 URIDs
+#if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT
+ struct URIDs {
+ LV2_URID atomString;
+ LV2_URID distrhoState;
+ LV2_URID midiEvent;
+ LV2_URID timePosition;
+
+ URIDs(const LV2_URID_Map* const uridMap)
+ : atomString(uridMap->map(uridMap->handle, LV2_ATOM__String)),
+ distrhoState(uridMap->map(uridMap->handle, "urn:distrho:keyValueState")),
+ midiEvent(uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent)),
+ timePosition(uridMap->map(uridMap->handle, LV2_TIME__Position)) {}
+ } fURIDs;
+#endif
+
+ // LV2 features
+ const LV2_URID_Map* const fUridMap;
+ const LV2_Worker_Schedule* const fWorker;
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ StringMap fStateMap;
+
+ void setState(const char* const key, const char* const newValue)
+ {
+ fPlugin.setState(key, newValue);
+
+ // check if key already exists
+ for (auto it = fStateMap.begin(), end = fStateMap.end(); it != end; ++it)
+ {
+ const d_string& d_key = it->first;
+
+ if (d_key == key)
+ {
+ it->second = newValue;
+ return;
+ }
+ }
+
+ // add a new one then
+ d_string d_key(key);
+ fStateMap[d_key] = newValue;
+ }
+#endif
+
+ void updateParameterOutputs()
+ {
+ for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
+ {
+ if (! fPlugin.isParameterOutput(i))
+ continue;
+
+ fLastControlValues[i] = fPlugin.getParameterValue(i);
+
+ if (fPortControls[i] != nullptr)
+ *fPortControls[i] = fLastControlValues[i];
+ }
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ if (fPortLatency != nullptr)
+ *fPortLatency = fPlugin.getLatency();
+#endif
+ }
+};
+
+// -----------------------------------------------------------------------
+
+static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, const char*, const LV2_Feature* const* features)
+{
+ const LV2_Options_Option* options = nullptr;
+ const LV2_URID_Map* uridMap = nullptr;
+ const LV2_Worker_Schedule* worker = nullptr;
+
+ for (int i=0; features[i] != nullptr; ++i)
+ {
+ if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0)
+ options = (const LV2_Options_Option*)features[i]->data;
+ else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0)
+ uridMap = (const LV2_URID_Map*)features[i]->data;
+ else if (std::strcmp(features[i]->URI, LV2_WORKER__schedule) == 0)
+ worker = (const LV2_Worker_Schedule*)features[i]->data;
+ }
+
+ if (options == nullptr)
+ {
+ d_stderr("Options feature missing, cannot continue!");
+ return nullptr;
+ }
+
+ if (uridMap == nullptr)
+ {
+ d_stderr("URID Map feature missing, cannot continue!");
+ return nullptr;
+ }
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ if (worker == nullptr)
+ {
+ d_stderr("Worker feature missing, cannot continue!");
+ return nullptr;
+ }
+#endif
+
+ for (int i=0; options[i].key != 0; ++i)
+ {
+ if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength))
+ {
+ if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int))
+ d_lastBufferSize = *(const int*)options[i].value;
+ else
+ d_stderr("Host provides maxBlockLength but has wrong value type");
+
+ break;
+ }
+ }
+
+ if (d_lastBufferSize == 0)
+ d_lastBufferSize = 2048;
+
+ d_lastSampleRate = sampleRate;
+
+ return new PluginLv2(uridMap, worker);
+}
+
+#define instancePtr ((PluginLv2*)instance)
+
+static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation)
+{
+ instancePtr->lv2_connect_port(port, dataLocation);
+}
+
+static void lv2_activate(LV2_Handle instance)
+{
+ instancePtr->lv2_activate();
+}
+
+static void lv2_run(LV2_Handle instance, uint32_t sampleCount)
+{
+ instancePtr->lv2_run(sampleCount);
+}
+
+static void lv2_deactivate(LV2_Handle instance)
+{
+ instancePtr->lv2_deactivate();
+}
+
+static void lv2_cleanup(LV2_Handle instance)
+{
+ delete instancePtr;
+}
+
+// -----------------------------------------------------------------------
+
+static uint32_t lv2_get_options(LV2_Handle instance, LV2_Options_Option* options)
+{
+ return instancePtr->lv2_get_options(options);
+}
+
+static uint32_t lv2_set_options(LV2_Handle instance, const LV2_Options_Option* options)
+{
+ return instancePtr->lv2_set_options(options);
+}
+
+// -----------------------------------------------------------------------
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+static const LV2_Program_Descriptor* lv2_get_program(LV2_Handle instance, uint32_t index)
+{
+ return instancePtr->lv2_get_program(index);
+}
+
+static void lv2_select_program(LV2_Handle instance, uint32_t bank, uint32_t program)
+{
+ instancePtr->lv2_select_program(bank, program);
+}
+#endif
+
+// -----------------------------------------------------------------------
+
+#if DISTRHO_PLUGIN_WANT_STATE
+static LV2_State_Status lv2_save(LV2_Handle instance, LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const*)
+{
+ return instancePtr->lv2_save(store, handle, flags);
+}
+
+static LV2_State_Status lv2_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t, const LV2_Feature* const*)
+{
+ return instancePtr->lv2_restore(retrieve, handle);
+}
+
+LV2_Worker_Status lv2_work(LV2_Handle instance, LV2_Worker_Respond_Function, LV2_Worker_Respond_Handle, uint32_t, const void* data)
+{
+ return instancePtr->lv2_work(data);
+}
+#endif
+
+// -----------------------------------------------------------------------
+
+static const void* lv2_extension_data(const char* uri)
+{
+ static const LV2_Options_Interface options = { lv2_get_options, lv2_set_options };
+
+ if (std::strcmp(uri, LV2_OPTIONS__interface) == 0)
+ return &options;
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ static const LV2_Programs_Interface programs = { lv2_get_program, lv2_select_program };
+
+ if (std::strcmp(uri, LV2_PROGRAMS__Interface) == 0)
+ return &programs;
+#endif
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ static const LV2_State_Interface state = { lv2_save, lv2_restore };
+ static const LV2_Worker_Interface worker = { lv2_work, nullptr, nullptr };
+
+ if (std::strcmp(uri, LV2_STATE__interface) == 0)
+ return &state;
+ if (std::strcmp(uri, LV2_WORKER__interface) == 0)
+ return &worker;
+#endif
+
+ return nullptr;
+}
+
+#undef instancePtr
+
+// -----------------------------------------------------------------------
+
+static const LV2_Descriptor sLv2Descriptor = {
+ DISTRHO_PLUGIN_URI,
+ lv2_instantiate,
+ lv2_connect_port,
+ lv2_activate,
+ lv2_run,
+ lv2_deactivate,
+ lv2_cleanup,
+ lv2_extension_data
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
+
+DISTRHO_PLUGIN_EXPORT
+const LV2_Descriptor* lv2_descriptor(uint32_t index)
+{
+ USE_NAMESPACE_DISTRHO
+ return (index == 0) ? &sLv2Descriptor : nullptr;
+}
+
+// -----------------------------------------------------------------------
diff --git a/distrho/src/DistrhoPluginLV2export.cpp b/distrho/src/DistrhoPluginLV2export.cpp
@@ -0,0 +1,367 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "DistrhoPluginInternal.hpp"
+
+#include "lv2/atom.h"
+#include "lv2/buf-size.h"
+#include "lv2/midi.h"
+#include "lv2/options.h"
+#include "lv2/state.h"
+#include "lv2/time.h"
+#include "lv2/ui.h"
+#include "lv2/units.h"
+#include "lv2/urid.h"
+#include "lv2/worker.h"
+#include "lv2/lv2_programs.h"
+
+#include <fstream>
+#include <iostream>
+
+#ifndef DISTRHO_PLUGIN_URI
+# error DISTRHO_PLUGIN_URI undefined!
+#endif
+
+#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI))
+#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)
+
+// -----------------------------------------------------------------------
+
+DISTRHO_PLUGIN_EXPORT
+void lv2_generate_ttl(const char* const basename)
+{
+ USE_NAMESPACE_DISTRHO
+
+ // Dummy plugin to get data from
+ d_lastBufferSize = 512;
+ d_lastSampleRate = 44100.0;
+ PluginExporter plugin;
+ d_lastBufferSize = 0;
+ d_lastSampleRate = 0.0;
+
+ d_string pluginLabel(basename);
+ d_string pluginTTL(pluginLabel + ".ttl");
+
+ // ---------------------------------------------
+
+ {
+ std::cout << "Writing manifest.ttl..."; std::cout.flush();
+ std::fstream manifestFile("manifest.ttl", std::ios::out);
+
+ d_string manifestString;
+ manifestString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n";
+ manifestString += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
+#if DISTRHO_PLUGIN_HAS_UI
+ manifestString += "@prefix ui: <" LV2_UI_PREFIX "> .\n";
+#endif
+ manifestString += "\n";
+
+ manifestString += "<" DISTRHO_PLUGIN_URI ">\n";
+ manifestString += " a lv2:Plugin ;\n";
+ manifestString += " lv2:binary <" + pluginLabel + "." DISTRHO_DLL_EXTENSION "> ;\n";
+ manifestString += " rdfs:seeAlso <" + pluginTTL + "> .\n";
+ manifestString += "\n";
+
+#if DISTRHO_PLUGIN_HAS_UI
+ manifestString += "<" DISTRHO_UI_URI ">\n";
+# if DISTRHO_OS_HAIKU
+ manifestString += " a ui:BeUI ;\n";
+# elif DISTRHO_OS_MACOS
+ manifestString += " a ui:CocoaUI ;\n";
+# elif DISTRHO_OS_WINDOWS
+ manifestString += " a ui:WindowsUI ;\n";
+# else
+ manifestString += " a ui:X11UI ;\n";
+# endif
+ manifestString += " ui:binary <" + pluginLabel + "_ui." DISTRHO_DLL_EXTENSION "> ;\n";
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ manifestString += " lv2:extensionData ui:idleInterface ,\n";
+ manifestString += " <" LV2_PROGRAMS__Interface "> ;\n";
+#else
+ manifestString += " lv2:extensionData ui:idleInterface ;\n";
+#endif
+ manifestString += " lv2:optionalFeature ui:noUserResize ,\n";
+ manifestString += " ui:touch ;\n";
+ manifestString += " lv2:requiredFeature ui:resize ,\n";
+ manifestString += " <" LV2_OPTIONS__options "> ,\n";
+ manifestString += " <" LV2_URID__map "> .\n";
+#endif
+
+ manifestFile << manifestString << std::endl;
+ manifestFile.close();
+ std::cout << " done!" << std::endl;
+ }
+
+ // ---------------------------------------------
+
+ {
+ std::cout << "Writing " << pluginTTL << "..."; std::cout.flush();
+ std::fstream pluginFile(pluginTTL, std::ios::out);
+
+ d_string pluginString;
+
+ // header
+#if DISTRHO_LV2_USE_EVENTS_IN
+ pluginString += "@prefix atom: <" LV2_ATOM_PREFIX "> .\n";
+#endif
+ pluginString += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n";
+ pluginString += "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n";
+ pluginString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n";
+#if DISTRHO_PLUGIN_HAS_UI
+ pluginString += "@prefix ui: <" LV2_UI_PREFIX "> .\n";
+#endif
+ pluginString += "@prefix unit: <" LV2_UNITS_PREFIX "> .\n";
+ pluginString += "\n";
+
+ // plugin
+ pluginString += "<" DISTRHO_PLUGIN_URI ">\n";
+#if DISTRHO_PLUGIN_IS_SYNTH
+ pluginString += " a lv2:InstrumentPlugin, lv2:Plugin ;\n";
+#else
+ pluginString += " a lv2:Plugin ;\n";
+#endif
+ pluginString += "\n";
+
+ // extensionData
+ pluginString += " lv2:extensionData <" LV2_STATE__interface "> ";
+#if DISTRHO_PLUGIN_WANT_STATE
+ pluginString += ",\n <" LV2_OPTIONS__interface "> ";
+ pluginString += ",\n <" LV2_WORKER__interface "> ";
+#endif
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ pluginString += ",\n <" LV2_PROGRAMS__Interface "> ";
+#endif
+ pluginString += ";\n\n";
+
+ // optionalFeatures
+ pluginString += " lv2:optionalFeature <" LV2_CORE__hardRTCapable "> ,\n";
+ pluginString += " <" LV2_BUF_SIZE__boundedBlockLength "> ;\n";
+ pluginString += "\n";
+
+ // requiredFeatures
+ pluginString += " lv2:requiredFeature <" LV2_OPTIONS__options "> ";
+ pluginString += ",\n <" LV2_URID__map "> ";
+#if DISTRHO_PLUGIN_WANT_STATE
+ pluginString += ",\n <" LV2_WORKER__schedule "> ";
+#endif
+ pluginString += ";\n\n";
+
+ // UI
+#if DISTRHO_PLUGIN_HAS_UI
+ pluginString += " ui:ui <" DISTRHO_UI_URI "> ;\n";
+ pluginString += "\n";
+#endif
+
+ {
+ uint32_t portIndex = 0;
+
+#if DISTRHO_PLUGIN_NUM_INPUTS > 0
+ for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++portIndex)
+ {
+ if (i == 0)
+ pluginString += " lv2:port [\n";
+ else
+ pluginString += " [\n";
+
+ pluginString += " a lv2:InputPort, lv2:AudioPort ;\n";
+ pluginString += " lv2:index " + d_string(portIndex) + " ;\n";
+ pluginString += " lv2:symbol \"lv2_audio_in_" + d_string(i+1) + "\" ;\n";
+ pluginString += " lv2:name \"Audio Input " + d_string(i+1) + "\" ;\n";
+
+ if (i+1 == DISTRHO_PLUGIN_NUM_INPUTS)
+ pluginString += " ] ;\n\n";
+ else
+ pluginString += " ] ,\n";
+ }
+ pluginString += "\n";
+#endif
+
+#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++portIndex)
+ {
+ if (i == 0)
+ pluginString += " lv2:port [\n";
+ else
+ pluginString += " [\n";
+
+ pluginString += " a lv2:OutputPort, lv2:AudioPort ;\n";
+ pluginString += " lv2:index " + d_string(portIndex) + " ;\n";
+ pluginString += " lv2:symbol \"lv2_audio_out_" + d_string(i+1) + "\" ;\n";
+ pluginString += " lv2:name \"Audio Output " + d_string(i+1) + "\" ;\n";
+
+ if (i+1 == DISTRHO_PLUGIN_NUM_OUTPUTS)
+ pluginString += " ] ;\n\n";
+ else
+ pluginString += " ] ,\n";
+ }
+ pluginString += "\n";
+#endif
+
+#if DISTRHO_LV2_USE_EVENTS_IN
+ pluginString += " lv2:port [\n";
+ pluginString += " a lv2:InputPort, atom:AtomPort ;\n";
+ pluginString += " lv2:index " + d_string(portIndex) + " ;\n";
+ pluginString += " lv2:name \"Events Input\" ;\n";
+ pluginString += " lv2:symbol \"lv2_events_in\" ;\n";
+ pluginString += " atom:bufferType atom:Sequence ;\n";
+# if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)
+ pluginString += " atom:supports <" LV2_ATOM__String "> ;\n";
+# endif
+# if DISTRHO_PLUGIN_WANT_TIMEPOS
+ pluginString += " atom:supports <" LV2_TIME__Position "> ;\n";
+# endif
+# if DISTRHO_PLUGIN_IS_SYNTH
+ pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n";
+# endif
+
+ pluginString += " ] ;\n\n";
+ ++portIndex;
+#endif
+
+#if DISTRHO_LV2_USE_EVENTS_OUT
+ pluginString += " lv2:port [\n";
+ pluginString += " a lv2:OutputPort, atom:AtomPort ;\n";
+ pluginString += " lv2:index " + d_string(portIndex) + " ;\n";
+ pluginString += " lv2:name \"Events Output\" ;\n";
+ pluginString += " lv2:symbol \"lv2_events_out\" ;\n";
+ pluginString += " atom:bufferType atom:Sequence ;\n";
+ pluginString += " atom:supports <" LV2_ATOM__String "> ;\n";
+ pluginString += " ] ;\n\n";
+ ++portIndex;
+#endif
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ pluginString += " lv2:port [\n";
+ pluginString += " a lv2:OutputPort, lv2:ControlPort ;\n";
+ pluginString += " lv2:index " + d_string(portIndex) + " ;\n";
+ pluginString += " lv2:name \"Latency\" ;\n";
+ pluginString += " lv2:symbol \"lv2_latency\" ;\n";
+ pluginString += " lv2:designation lv2:latency ;\n";
+ pluginString += " lv2:portProperty lv2:reportsLatency ;\n";
+ pluginString += " ] ;\n\n";
+ ++portIndex;
+#endif
+
+ for (uint32_t i=0, count=plugin.getParameterCount(); i < count; ++i, ++portIndex)
+ {
+ if (i == 0)
+ pluginString += " lv2:port [\n";
+ else
+ pluginString += " [\n";
+
+ if (plugin.isParameterOutput(i))
+ pluginString += " a lv2:OutputPort, lv2:ControlPort ;\n";
+ else
+ pluginString += " a lv2:InputPort, lv2:ControlPort ;\n";
+
+ pluginString += " lv2:index " + d_string(portIndex) + " ;\n";
+ pluginString += " lv2:name \"" + plugin.getParameterName(i) + "\" ;\n";
+
+ // symbol
+ {
+ d_string symbol(plugin.getParameterSymbol(i));
+
+ if (symbol.isEmpty())
+ symbol = "lv2_port_" + d_string(portIndex-1);
+
+ pluginString += " lv2:symbol \"" + symbol + "\" ;\n";
+ }
+
+ // ranges
+ {
+ const ParameterRanges& ranges(plugin.getParameterRanges(i));
+
+ if (plugin.getParameterHints(i) & PARAMETER_IS_INTEGER)
+ {
+ pluginString += " lv2:default " + d_string(int(plugin.getParameterValue(i))) + " ;\n";
+ pluginString += " lv2:minimum " + d_string(int(ranges.min)) + " ;\n";
+ pluginString += " lv2:maximum " + d_string(int(ranges.max)) + " ;\n";
+ }
+ else
+ {
+ pluginString += " lv2:default " + d_string(plugin.getParameterValue(i)) + " ;\n";
+ pluginString += " lv2:minimum " + d_string(ranges.min) + " ;\n";
+ pluginString += " lv2:maximum " + d_string(ranges.max) + " ;\n";
+ }
+ }
+
+ // unit
+ {
+ const d_string& unit(plugin.getParameterUnit(i));
+
+ if (! unit.isEmpty())
+ {
+ if (unit == "db" || unit == "dB")
+ {
+ pluginString += " unit:unit unit:db ;\n";
+ }
+ else if (unit == "hz" || unit == "Hz")
+ {
+ pluginString += " unit:unit unit:hz ;\n";
+ }
+ else if (unit == "khz" || unit == "kHz")
+ {
+ pluginString += " unit:unit unit:khz ;\n";
+ }
+ else if (unit == "mhz" || unit == "mHz")
+ {
+ pluginString += " unit:unit unit:mhz ;\n";
+ }
+ else if (unit == "%")
+ {
+ pluginString += " unit:unit unit:pc ;\n";
+ }
+ else
+ {
+ pluginString += " unit:unit [\n";
+ pluginString += " a unit:Unit ;\n";
+ pluginString += " unit:name \"" + unit + "\" ;\n";
+ pluginString += " unit:symbol \"" + unit + "\" ;\n";
+ pluginString += " unit:render \"%f " + unit + "\" ;\n";
+ pluginString += " ] ;\n";
+ }
+ }
+ }
+
+ // hints
+ {
+ const uint32_t hints(plugin.getParameterHints(i));
+
+ if (hints & PARAMETER_IS_BOOLEAN)
+ pluginString += " lv2:portProperty lv2:toggled ;\n";
+ if (hints & PARAMETER_IS_INTEGER)
+ pluginString += " lv2:portProperty lv2:integer ;\n";
+ if (hints & PARAMETER_IS_LOGARITHMIC)
+ pluginString += " lv2:portProperty <http://lv2plug.in/ns/ext/port-props#logarithmic> ;\n";
+ if ((hints & PARAMETER_IS_AUTOMABLE) == 0 && ! plugin.isParameterOutput(i))
+ pluginString += " lv2:portProperty <http://lv2plug.in/ns/ext/port-props#expensive> ;\n";
+ }
+
+ if (i+1 == count)
+ pluginString += " ] ;\n\n";
+ else
+ pluginString += " ] ,\n";
+ }
+ }
+
+ pluginString += " doap:name \"" + d_string(plugin.getName()) + "\" ;\n";
+ pluginString += " doap:maintainer [ foaf:name \"" + d_string(plugin.getMaker()) + "\" ] .\n";
+
+ pluginFile << pluginString << std::endl;
+ pluginFile.close();
+ std::cout << " done!" << std::endl;
+ }
+}
diff --git a/distrho/src/DistrhoPluginVST.cpp b/distrho/src/DistrhoPluginVST.cpp
@@ -0,0 +1,963 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "DistrhoPluginInternal.hpp"
+
+#if DISTRHO_PLUGIN_HAS_UI
+# include "DistrhoUIInternal.hpp"
+#endif
+
+#ifndef __cdecl
+# define __cdecl
+#endif
+
+// has some conflicts
+#ifdef noexcept
+# undef noexcept
+#endif
+
+#define VESTIGE_HEADER
+#define VST_FORCE_DEPRECATED 0
+
+#include <map>
+#include <string>
+
+#ifdef VESTIGE_HEADER
+# include "vestige/aeffectx.h"
+#define effFlagsProgramChunks (1 << 5)
+#define effGetParamLabel 6
+#define effGetParamDisplay 7
+#define effGetChunk 23
+#define effSetChunk 24
+#define effCanBeAutomated 26
+#define effGetProgramNameIndexed 29
+#define effGetPlugCategory 35
+#define kPlugCategEffect 1
+#define kPlugCategSynth 2
+#define kVstVersion 2400
+struct ERect {
+ int16_t top, left, bottom, right;
+};
+#else
+# include "vst/aeffectx.h"
+#endif
+
+typedef std::map<d_string,d_string> StringMap;
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+
+void strncpy(char* const dst, const char* const src, const size_t size)
+{
+ std::strncpy(dst, src, size);
+ dst[size] = '\0';
+}
+
+// -----------------------------------------------------------------------
+
+#if DISTRHO_PLUGIN_WANT_STATE
+class StateHelper
+{
+public:
+ virtual ~StateHelper() {}
+ virtual void setSharedState(const char* const newKey, const char* const newValue) = 0;
+};
+#else
+typedef void StateHelper;
+#endif
+
+// -----------------------------------------------------------------------
+
+#if DISTRHO_PLUGIN_HAS_UI
+class UIVst
+{
+public:
+ UIVst(const audioMasterCallback audioMaster, AEffect* const effect, PluginExporter* const plugin, StateHelper* const stateHelper, const intptr_t winId)
+ : fAudioMaster(audioMaster),
+ fEffect(effect),
+ fPlugin(plugin),
+ fStateHelper(stateHelper),
+ fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, uiResizeCallback),
+ fParameterChecks(nullptr),
+ fParameterValues(nullptr)
+ {
+ const uint32_t paramCount(plugin->getParameterCount());
+
+ if (paramCount > 0)
+ {
+ fParameterChecks = new bool[paramCount];
+ fParameterValues = new float[paramCount];
+
+ for (uint32_t i=0; i < paramCount; ++i)
+ {
+ fParameterChecks[i] = false;
+ fParameterValues[i] = 0.0f;
+ }
+ }
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ fNextProgram = -1;
+#endif
+ }
+
+ ~UIVst()
+ {
+ if (fParameterChecks != nullptr)
+ {
+ delete[] fParameterChecks;
+ fParameterChecks = nullptr;
+ }
+
+ if (fParameterValues != nullptr)
+ {
+ delete[] fParameterValues;
+ fParameterValues = nullptr;
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+ void idle()
+ {
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ if (fNextProgram != -1)
+ {
+ fUI.programChanged(fNextProgram);
+ fNextProgram = -1;
+ }
+#endif
+
+ for (uint32_t i=0, count = fPlugin->getParameterCount(); i < count; ++i)
+ {
+ if (fParameterChecks[i])
+ {
+ fParameterChecks[i] = false;
+ fUI.parameterChanged(i, fParameterValues[i]);
+ }
+ }
+
+ fUI.idle();
+ }
+
+ int16_t getWidth() const
+ {
+ return fUI.getWidth();
+ }
+
+ int16_t getHeight() const
+ {
+ return fUI.getHeight();
+ }
+
+ // -------------------------------------------------------------------
+ // functions called from the plugin side, RT no block
+
+ void setParameterValueFromPlugin(const uint32_t index, const float perValue)
+ {
+ fParameterChecks[index] = true;
+ fParameterValues[index] = perValue;
+ }
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ void setProgramFromPlugin(const uint32_t index)
+ {
+ fNextProgram = index;
+
+ // set previous parameters invalid
+ for (uint32_t i=0, count = fPlugin->getParameterCount(); i < count; ++i)
+ fParameterChecks[i] = false;
+ }
+#endif
+
+ // -------------------------------------------------------------------
+ // functions called from the plugin side, block
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ void setStateFromPlugin(const char* const key, const char* const value)
+ {
+ fUI.stateChanged(key, value);
+ }
+#endif
+
+ // -------------------------------------------------------------------
+
+protected:
+ intptr_t hostCallback(const int32_t opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
+ {
+ return fAudioMaster(fEffect, opcode, index, value, ptr, opt);
+ }
+
+ void editParameter(const uint32_t index, const bool started)
+ {
+ if (started)
+ hostCallback(audioMasterBeginEdit, index, 0, nullptr, 0.0f);
+ else
+ hostCallback(audioMasterEndEdit, index, 0, nullptr, 0.0f);
+ }
+
+ void setParameterValue(const uint32_t index, const float realValue)
+ {
+ const ParameterRanges& ranges(fPlugin->getParameterRanges(index));
+ const float perValue(ranges.getNormalizedValue(realValue));
+
+ fPlugin->setParameterValue(index, realValue);
+ hostCallback(audioMasterAutomate, index, 0, nullptr, perValue);
+ }
+
+ void setState(const char* const key, const char* const value)
+ {
+#if DISTRHO_PLUGIN_WANT_STATE
+ fStateHelper->setSharedState(key, value);
+#else
+ return; // unused
+ (void)key;
+ (void)value;
+#endif
+ }
+
+ void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity)
+ {
+#if 0 //DISTRHO_PLUGIN_IS_SYNTH
+ // TODO
+#else
+ return; // unused
+ (void)channel;
+ (void)note;
+ (void)velocity;
+#endif
+ }
+
+ void uiResize(const unsigned int width, const unsigned int height)
+ {
+ fUI.setSize(width, height);
+ hostCallback(audioMasterSizeWindow, width, height, nullptr, 0.0f);
+ }
+
+private:
+ // Vst stuff
+ const audioMasterCallback fAudioMaster;
+ AEffect* const fEffect;
+ PluginExporter* const fPlugin;
+ StateHelper* const fStateHelper;
+
+ // Plugin UI
+ UIExporter fUI;
+
+ // Temporary data
+ bool* fParameterChecks;
+ float* fParameterValues;
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ int32_t fNextProgram;
+#endif
+
+ // -------------------------------------------------------------------
+ // Callbacks
+
+ #define handlePtr ((UIVst*)ptr)
+
+ static void editParameterCallback(void* ptr, uint32_t index, bool started)
+ {
+ handlePtr->editParameter(index, started);
+ }
+
+ static void setParameterCallback(void* ptr, uint32_t rindex, float value)
+ {
+ handlePtr->setParameterValue(rindex, value);
+ }
+
+ static void setStateCallback(void* ptr, const char* key, const char* value)
+ {
+ handlePtr->setState(key, value);
+ }
+
+ static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
+ {
+ handlePtr->sendNote(channel, note, velocity);
+ }
+
+ static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height)
+ {
+ handlePtr->uiResize(width, height);
+ }
+
+ #undef handlePtr
+};
+#endif
+
+// -----------------------------------------------------------------------
+
+#if DISTRHO_PLUGIN_WANT_STATE
+class PluginVst : public StateHelper
+#else
+class PluginVst
+#endif
+{
+public:
+ PluginVst(const audioMasterCallback audioMaster, AEffect* const effect)
+ : fAudioMaster(audioMaster),
+ fEffect(effect)
+ {
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ fCurProgram = -1;
+#endif
+
+#if DISTRHO_PLUGIN_IS_SYNTH
+ fMidiEventCount = 0;
+#endif
+
+#if DISTRHO_PLUGIN_HAS_UI
+ fVstUi = nullptr;
+ fVstRect.top = 0;
+ fVstRect.left = 0;
+ fVstRect.bottom = 0;
+ fVstRect.right = 0;
+#endif
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ fStateChunk = nullptr;
+#endif
+ }
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ ~PluginVst()
+ {
+ if (fStateChunk != nullptr)
+ {
+ delete[] fStateChunk;
+ fStateChunk = nullptr;
+ }
+
+ fStateMap.clear();
+ }
+#endif
+
+ intptr_t vst_dispatcher(const int32_t opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
+ {
+ int32_t ret = 0;
+
+ switch (opcode)
+ {
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ case effSetProgram:
+ if (value >= 0 && value < static_cast<intptr_t>(fPlugin.getProgramCount()))
+ {
+ fCurProgram = value;
+ fPlugin.setProgram(fCurProgram);
+
+#if DISTRHO_PLUGIN_HAS_UI
+ if (fVstUi != nullptr)
+ fVstUi->setProgramFromPlugin(fCurProgram);
+#endif
+
+ ret = 1;
+ }
+ break;
+
+ case effGetProgram:
+ ret = fCurProgram;
+ break;
+
+ //case effSetProgramName:
+ // unsupported
+ // break;
+
+ case effGetProgramName:
+ if (ptr != nullptr && fCurProgram >= 0 && fCurProgram < static_cast<int32_t>(fPlugin.getProgramCount()))
+ {
+ DISTRHO::strncpy((char*)ptr, fPlugin.getProgramName(fCurProgram), 24);
+ ret = 1;
+ }
+ break;
+#endif
+
+ case effGetParamDisplay:
+ if (ptr != nullptr && index < static_cast<int32_t>(fPlugin.getParameterCount()))
+ {
+ char* buf = (char*)ptr;
+ std::snprintf((char*)ptr, 8, "%f", fPlugin.getParameterValue(index));
+ buf[8] = '\0';
+ ret = 1;
+ }
+ break;
+
+ case effSetSampleRate:
+ fPlugin.setSampleRate(opt, true);
+ break;
+
+ case effSetBlockSize:
+ fPlugin.setBufferSize(value, true);
+ break;
+
+ case effMainsChanged:
+ if (value != 0)
+ {
+ fPlugin.activate();
+#if DISTRHO_PLUGIN_IS_SYNTH
+ fMidiEventCount = 0;
+#endif
+ }
+ else
+ {
+ fPlugin.deactivate();
+ }
+ break;
+
+#if DISTRHO_PLUGIN_HAS_UI
+ case effEditGetRect:
+ if (fVstUi != nullptr)
+ {
+ fVstRect.right = fVstUi->getWidth();
+ fVstRect.bottom = fVstUi->getHeight();
+ }
+ else
+ {
+ d_lastUiSampleRate = fAudioMaster(fEffect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f);
+ UIExporter tmpUI(nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr);
+ fVstRect.right = tmpUI.getWidth();
+ fVstRect.bottom = tmpUI.getHeight();
+ }
+ *(ERect**)ptr = &fVstRect;
+ ret = 1;
+ break;
+
+ case effEditOpen:
+ if (fVstUi == nullptr)
+ {
+ d_lastUiSampleRate = fAudioMaster(fEffect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f);
+
+ fVstUi = new UIVst(fAudioMaster, fEffect, &fPlugin, this, (intptr_t)ptr);
+
+# if DISTRHO_PLUGIN_WANT_PROGRAMS
+ if (fCurProgram >= 0)
+ fVstUi->setProgramFromPlugin(fCurProgram);
+# endif
+ for (uint32_t i=0, count = fPlugin.getParameterCount(); i < count; ++i)
+ fVstUi->setParameterValueFromPlugin(i, fPlugin.getParameterValue(i));
+
+ fVstUi->idle();
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ if (fStateMap.size() > 0)
+ {
+ for (auto it = fStateMap.begin(), end = fStateMap.end(); it != end; ++it)
+ {
+ const d_string& key = it->first;
+ const d_string& value = it->second;
+
+ fVstUi->setStateFromPlugin((const char*)key, (const char*)value);
+ }
+
+ fVstUi->idle();
+ }
+#endif
+ ret = 1;
+ }
+ break;
+
+ case effEditClose:
+ if (fVstUi != nullptr)
+ {
+ delete fVstUi;
+ fVstUi = nullptr;
+ ret = 1;
+ }
+ break;
+
+ case effEditIdle:
+ if (fVstUi != nullptr)
+ fVstUi->idle();
+ break;
+#endif
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ case effGetChunk:
+ if (ptr == nullptr)
+ return 0;
+
+ if (fStateChunk != nullptr)
+ delete[] fStateChunk;
+
+ if (fStateMap.size() == 0)
+ {
+ fStateChunk = new char[1];
+ fStateChunk[0] = '\0';
+ ret = 1;
+ }
+ else
+ {
+ std::string tmpStr;
+
+ for (auto it = fStateMap.begin(), end = fStateMap.end(); it != end; ++it)
+ {
+ const d_string& key = it->first;
+ const d_string& value = it->second;
+
+ tmpStr += (const char*)key;
+ tmpStr += "\xff";
+ tmpStr += (const char*)value;
+ tmpStr += "\xff";
+ }
+
+ const size_t size(tmpStr.size());
+ fStateChunk = new char[size];
+ std::memcpy(fStateChunk, tmpStr.c_str(), size*sizeof(char));
+
+ for (size_t i=0; i < size; ++i)
+ {
+ if (fStateChunk[i] == '\xff')
+ fStateChunk[i] = '\0';
+ }
+
+ ret = size;
+ }
+
+ *(void**)ptr = fStateChunk;
+ break;
+
+ case effSetChunk:
+ if (value <= 0)
+ return 0;
+ if (value == 1)
+ return 1;
+
+ if (const char* const state = (const char*)ptr)
+ {
+ const size_t stateSize = value;
+ const char* stateKey = state;
+ const char* stateValue = nullptr;
+
+ for (size_t i=0; i < stateSize; ++i)
+ {
+ // find next null char
+ if (state[i] != '\0')
+ continue;
+
+ // found, set value
+ stateValue = &state[i+1];
+ setSharedState(stateKey, stateValue);
+
+ if (fVstUi != nullptr)
+ fVstUi->setStateFromPlugin(stateKey, stateValue);
+
+ // increment text position
+ i += std::strlen(stateValue) + 2;
+
+ // check if end of data
+ if (i >= stateSize)
+ break;
+
+ // get next key
+ stateKey = &state[i];
+ }
+
+ ret = 1;
+ }
+
+ break;
+#endif
+
+#if DISTRHO_PLUGIN_IS_SYNTH
+ case effProcessEvents:
+ if (const VstEvents* const events = (const VstEvents*)ptr)
+ {
+ if (events->numEvents == 0)
+ break;
+
+ for (int i=0, count=events->numEvents; i < count; ++i)
+ {
+ const VstMidiEvent* const vstMidiEvent((const VstMidiEvent*)events->events[i]);
+
+ if (vstMidiEvent == nullptr)
+ break;
+ if (vstMidiEvent->type != kVstMidiType)
+ continue;
+ if (fMidiEventCount >= kMaxMidiEvents)
+ break;
+
+ MidiEvent& midiEvent(fMidiEvents[fMidiEventCount++]);
+ midiEvent.frame = vstMidiEvent->deltaFrames;
+ midiEvent.size = 3;
+ std::memcpy(midiEvent.buf, vstMidiEvent->midiData, 3*sizeof(uint8_t));
+ }
+ }
+ break;
+#endif
+
+ case effCanBeAutomated:
+ if (index < static_cast<int32_t>(fPlugin.getParameterCount()))
+ {
+ const uint32_t hints(fPlugin.getParameterHints(index));
+
+ // must be automable, and not output
+ if ((hints & PARAMETER_IS_AUTOMABLE) != 0 && (hints & PARAMETER_IS_OUTPUT) == 0)
+ ret = 1;
+ }
+ break;
+
+#if (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS)
+ case effCanDo:
+ if (const char* const canDo = (const char*)ptr)
+ {
+# if DISTRHO_PLUGIN_IS_SYNTH
+ if (std::strcmp(canDo, "receiveVstEvents") == 0)
+ return 1;
+ if (std::strcmp(canDo, "receiveVstMidiEvent") == 0)
+ return 1;
+# endif
+# if DISTRHO_PLUGIN_WANT_TIMEPOS
+ if (std::strcmp(canDo, "receiveVstTimeInfo") == 0)
+ return 1;
+# endif
+ }
+ break;
+#endif
+
+ //case effStartProcess:
+ //case effStopProcess:
+ // unused
+ // break;
+ }
+
+ return ret;
+ }
+
+ float vst_getParameter(const int32_t index)
+ {
+ const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
+ return ranges.getNormalizedValue(fPlugin.getParameterValue(index));
+ }
+
+ void vst_setParameter(const int32_t index, const float value)
+ {
+ const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
+ const float realValue(ranges.getUnnormalizedValue(value));
+ fPlugin.setParameterValue(index, realValue);
+
+#if DISTRHO_PLUGIN_HAS_UI
+ if (fVstUi != nullptr)
+ fVstUi->setParameterValueFromPlugin(index, realValue);
+#endif
+ }
+
+ void vst_processReplacing(float** const inputs, float** const outputs, const int32_t sampleFrames)
+ {
+#if DISTRHO_PLUGIN_WANT_TIMEPOS
+ if (const VstTimeInfo* const timeInfo = (const VstTimeInfo*)fEffect->dispatcher(fEffect, audioMasterGetTime, 0, kVstTempoValid, nullptr, 0.0f))
+ fPlugin.setTimePos((timeInfo->flags & kVstTransportPlaying) != 0, timeInfo->samplePos, timeInfo->tempo);
+#endif
+
+#if DISTRHO_PLUGIN_IS_SYNTH
+ fPlugin.run(inputs, outputs, sampleFrames, fMidiEvents, fMidiEventCount);
+ fMidiEventCount = 0;
+#else
+ fPlugin.run(inputs, outputs, sampleFrames);
+#endif
+ }
+
+ // -------------------------------------------------------------------
+
+ friend class UIVst;
+
+private:
+ // VST stuff
+ const audioMasterCallback fAudioMaster;
+ AEffect* const fEffect;
+
+ // Plugin
+ PluginExporter fPlugin;
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ int32_t fCurProgram;
+#endif
+
+#if DISTRHO_PLUGIN_IS_SYNTH
+ uint32_t fMidiEventCount;
+ MidiEvent fMidiEvents[kMaxMidiEvents];
+#endif
+
+#if DISTRHO_PLUGIN_HAS_UI
+ UIVst* fVstUi;
+ ERect fVstRect;
+#endif
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ char* fStateChunk;
+ StringMap fStateMap;
+
+ void setSharedState(const char* const newKey, const char* const newValue) override
+ {
+ fPlugin.setState(newKey, newValue);
+
+ // check if key already exists
+ for (auto it = fStateMap.begin(), end = fStateMap.end(); it != end; ++it)
+ {
+ const d_string& key = it->first;
+
+ if (key == newKey)
+ {
+ it->second = newValue;
+ return;
+ }
+ }
+
+ // add a new one then
+ d_string d_key(newKey);
+ fStateMap[d_key] = newValue;
+ }
+#endif
+};
+
+// -----------------------------------------------------------------------
+
+#ifdef VESTIGE_HEADER
+# define handlePtr ((PluginVst*)effect->ptr2)
+# define validEffect effect != nullptr && effect->ptr2 != nullptr
+#else
+# define handlePtr ((PluginVst*)effect->resvd2)
+# define validEffect effect != nullptr && effect->resvd2 != 0
+#endif
+
+static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt)
+{
+ // first internal init
+ bool doInternalInit = (opcode == -1729 && index == 0xdead && value == 0xf00d);
+
+ if (doInternalInit)
+ {
+ // set valid but dummy values
+ d_lastBufferSize = 512;
+ d_lastSampleRate = 44100.0;
+ }
+
+ // Create dummy plugin to get data from
+ static PluginExporter plugin;
+
+ if (doInternalInit)
+ {
+ // unset
+ d_lastBufferSize = 0;
+ d_lastSampleRate = 0.0;
+
+ *(PluginExporter**)ptr = &plugin;
+ return 0;
+ }
+
+ // handle base opcodes
+ switch (opcode)
+ {
+ case effOpen:
+#ifdef VESTIGE_HEADER
+ if (effect != nullptr && effect->ptr3 != nullptr)
+ {
+ audioMasterCallback audioMaster = (audioMasterCallback)effect->ptr3;
+#else
+ if (effect != nullptr && effect->object != nullptr)
+ {
+ audioMasterCallback audioMaster = (audioMasterCallback)effect->object;
+#endif
+ d_lastBufferSize = audioMaster(effect, audioMasterGetBlockSize, 0, 0, nullptr, 0.0f);
+ d_lastSampleRate = audioMaster(effect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f);
+ PluginVst* const plugin(new PluginVst(audioMaster, effect));
+#ifdef VESTIGE_HEADER
+ effect->ptr2 = plugin;
+#else
+ effect->resvd2 = (intptr_t)plugin;
+#endif
+ return 1;
+ }
+ return 0;
+
+ case effClose:
+ if (validEffect)
+ {
+#ifdef VESTIGE_HEADER
+ delete (PluginVst*)effect->ptr2;
+ effect->ptr2 = nullptr;
+ effect->ptr3 = nullptr;
+#else
+ delete (PluginVst*)effect->resvd2;
+ effect->resvd2 = 0;
+ effect->object = nullptr;
+#endif
+ delete effect;
+ return 1;
+ }
+ return 0;
+
+ case effGetParamLabel:
+ if (ptr != nullptr && index < static_cast<int32_t>(plugin.getParameterCount()))
+ {
+ DISTRHO::strncpy((char*)ptr, plugin.getParameterUnit(index), 8);
+ return 1;
+ }
+ return 0;
+
+ case effGetParamName:
+ if (ptr != nullptr && index < static_cast<int32_t>(plugin.getParameterCount()))
+ {
+ DISTRHO::strncpy((char*)ptr, plugin.getParameterName(index), 8);
+ return 1;
+ }
+ return 0;
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ case effGetProgramNameIndexed:
+ if (ptr != nullptr && index < static_cast<int32_t>(plugin.getProgramCount()))
+ {
+ DISTRHO::strncpy((char*)ptr, plugin.getProgramName(index), 24);
+ return 1;
+ }
+ return 0;
+#endif
+
+ case effGetPlugCategory:
+#if DISTRHO_PLUGIN_IS_SYNTH
+ return kPlugCategSynth;
+#else
+ return kPlugCategEffect;
+#endif
+
+ case effGetEffectName:
+ if (ptr != nullptr)
+ {
+ DISTRHO::strncpy((char*)ptr, plugin.getName(), 64);
+ return 1;
+ }
+ return 0;
+
+ case effGetVendorString:
+ if (ptr != nullptr)
+ {
+ DISTRHO::strncpy((char*)ptr, plugin.getMaker(), 64);
+ return 1;
+ }
+ return 0;
+
+ case effGetProductString:
+ if (ptr != nullptr)
+ {
+ DISTRHO::strncpy((char*)ptr, plugin.getLabel(), 32);
+ return 1;
+ }
+ return 0;
+
+ case effGetVendorVersion:
+ return plugin.getVersion();
+
+ case effGetVstVersion:
+ return kVstVersion;
+ };
+
+ // handle advanced opcodes
+ if (validEffect)
+ return handlePtr->vst_dispatcher(opcode, index, value, ptr, opt);
+
+ return 0;
+}
+
+static float vst_getParameterCallback(AEffect* effect, int32_t index)
+{
+ if (validEffect)
+ return handlePtr->vst_getParameter(index);
+ return 0.0f;
+}
+
+static void vst_setParameterCallback(AEffect* effect, int32_t index, float value)
+{
+ if (validEffect)
+ handlePtr->vst_setParameter(index, value);
+}
+
+static void vst_processCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
+{
+ if (validEffect)
+ handlePtr->vst_processReplacing(inputs, outputs, sampleFrames);
+}
+
+static void vst_processReplacingCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
+{
+ if (validEffect)
+ handlePtr->vst_processReplacing(inputs, outputs, sampleFrames);
+}
+
+#undef handlePtr
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
+
+DISTRHO_PLUGIN_EXPORT
+const AEffect* VSTPluginMain(audioMasterCallback audioMaster)
+{
+ USE_NAMESPACE_DISTRHO
+
+ // old version
+ if (audioMaster(nullptr, audioMasterVersion, 0, 0, nullptr, 0.0f) == 0)
+ return nullptr;
+
+ // first internal init
+ PluginExporter* plugin = nullptr;
+ vst_dispatcherCallback(nullptr, -1729, 0xdead, 0xf00d, &plugin, 0.0f);
+
+ AEffect* const effect(new AEffect);
+ std::memset(effect, 0, sizeof(AEffect));
+
+ // vst fields
+ effect->magic = kEffectMagic;
+ effect->uniqueID = plugin->getUniqueId();
+#ifdef VESTIGE_HEADER
+ *(int32_t*)&effect->unknown1 = plugin->getVersion();
+#else
+ effect->version = plugin->getVersion();
+#endif
+
+ // plugin fields
+ effect->numParams = plugin->getParameterCount();
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ effect->numPrograms = plugin->getProgramCount();
+#endif
+ effect->numInputs = DISTRHO_PLUGIN_NUM_INPUTS;
+ effect->numOutputs = DISTRHO_PLUGIN_NUM_OUTPUTS;
+
+ // plugin flags
+ effect->flags |= effFlagsCanReplacing;
+#if DISTRHO_PLUGIN_IS_SYNTH
+ effect->flags |= effFlagsIsSynth;
+#endif
+#if DISTRHO_PLUGIN_HAS_UI
+ effect->flags |= effFlagsHasEditor;
+#endif
+#if DISTRHO_PLUGIN_WANT_STATE
+ effect->flags |= effFlagsProgramChunks;
+#endif
+
+ // static calls
+ effect->dispatcher = vst_dispatcherCallback;
+ effect->process = vst_processCallback;
+ effect->getParameter = vst_getParameterCallback;
+ effect->setParameter = vst_setParameterCallback;
+ effect->processReplacing = vst_processReplacingCallback;
+
+ // pointers
+#ifdef VESTIGE_HEADER
+ effect->ptr3 = (void*)audioMaster;
+#else
+ effect->object = (void*)audioMaster;
+#endif
+
+ return effect;
+}
diff --git a/distrho/src/DistrhoUI.cpp b/distrho/src/DistrhoUI.cpp
@@ -0,0 +1,89 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "DistrhoUIInternal.hpp"
+
+START_NAMESPACE_DGL
+extern Window* dgl_lastUiParent;
+END_NAMESPACE_DGL
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+// Static data
+
+double d_lastUiSampleRate = 0.0;
+
+// -----------------------------------------------------------------------
+// UI
+
+UI::UI()
+ : DGL::Widget(*DGL::dgl_lastUiParent),
+ pData(new PrivateData())
+{
+ assert(DGL::dgl_lastUiParent != nullptr);
+
+ DGL::dgl_lastUiParent = nullptr;
+}
+
+UI::~UI()
+{
+ delete pData;
+}
+
+// -----------------------------------------------------------------------
+// Host DSP State
+
+double UI::d_getSampleRate() const noexcept
+{
+ return pData->sampleRate;
+}
+
+void UI::d_editParameter(uint32_t index, bool started)
+{
+ pData->editParamCallback(index + pData->parameterOffset, started);
+}
+
+void UI::d_setParameterValue(uint32_t index, float value)
+{
+ pData->setParamCallback(index + pData->parameterOffset, value);
+}
+
+#if DISTRHO_PLUGIN_WANT_STATE
+void UI::d_setState(const char* key, const char* value)
+{
+ pData->setStateCallback(key, value);
+}
+#endif
+
+#if DISTRHO_PLUGIN_IS_SYNTH
+void UI::d_sendNote(uint8_t channel, uint8_t note, uint8_t velocity)
+{
+ pData->sendNoteCallback(channel, note, velocity);
+}
+#endif
+
+// -----------------------------------------------------------------------
+// Host UI State
+
+void UI::d_uiResize(unsigned int width, unsigned int height)
+{
+ pData->uiResizeCallback(width, height);
+}
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
diff --git a/distrho/src/DistrhoUIDSSI.cpp b/distrho/src/DistrhoUIDSSI.cpp
@@ -0,0 +1,489 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "DistrhoUIInternal.hpp"
+
+#include <lo/lo.h>
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+
+struct OscData {
+ lo_address addr;
+ const char* path;
+ lo_server server;
+
+ OscData()
+ : addr(nullptr),
+ path(nullptr),
+ server(nullptr) {}
+
+ void idle() const
+ {
+ if (server == nullptr)
+ return;
+
+ while (lo_server_recv_noblock(server, 0) != 0) {}
+ }
+
+ void send_configure(const char* const key, const char* const value) const
+ {
+ char targetPath[std::strlen(path)+11];
+ std::strcpy(targetPath, path);
+ std::strcat(targetPath, "/configure");
+ lo_send(addr, targetPath, "ss", key, value);
+ }
+
+ void send_control(const int32_t index, const float value) const
+ {
+ char targetPath[std::strlen(path)+9];
+ std::strcpy(targetPath, path);
+ std::strcat(targetPath, "/control");
+ lo_send(addr, targetPath, "if", index, value);
+ }
+
+ void send_midi(unsigned char data[4]) const
+ {
+ char targetPath[std::strlen(path)+6];
+ std::strcpy(targetPath, path);
+ std::strcat(targetPath, "/midi");
+ lo_send(addr, targetPath, "m", data);
+ }
+
+ void send_update(const char* const url) const
+ {
+ char targetPath[std::strlen(path)+8];
+ std::strcpy(targetPath, path);
+ std::strcat(targetPath, "/update");
+ lo_send(addr, targetPath, "s", url);
+ }
+
+ void send_exiting() const
+ {
+ char targetPath[std::strlen(path)+9];
+ std::strcpy(targetPath, path);
+ std::strcat(targetPath, "/exiting");
+ lo_send(addr, targetPath, "");
+ }
+};
+
+// -----------------------------------------------------------------------
+
+class UIDssi
+{
+public:
+ UIDssi(const OscData& oscData, const char* const uiTitle)
+ : fUI(this, 0, nullptr, setParameterCallback, setStateCallback, sendNoteCallback, uiResizeCallback),
+ fHostClosed(false),
+ fOscData(oscData)
+ {
+ fUI.setTitle(uiTitle);
+ }
+
+ ~UIDssi()
+ {
+ if (fOscData.server != nullptr && ! fHostClosed)
+ fOscData.send_exiting();
+ }
+
+ void exec()
+ {
+ for (;;)
+ {
+ fOscData.idle();
+
+ if (! fUI.idle())
+ break;
+
+ d_msleep(50);
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ void dssiui_configure(const char* key, const char* value)
+ {
+ fUI.stateChanged(key, value);
+ }
+#endif
+
+ void dssiui_control(unsigned long index, float value)
+ {
+ fUI.parameterChanged(index, value);
+ }
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ void dssiui_program(unsigned long bank, unsigned long program)
+ {
+ fUI.programChanged(bank * 128 + program);
+ }
+#endif
+
+ void dssiui_show()
+ {
+ fUI.setVisible(true);
+ }
+
+ void dssiui_hide()
+ {
+ fUI.setVisible(false);
+ }
+
+ void dssiui_quit()
+ {
+ fHostClosed = true;
+ fUI.quit();
+ }
+
+ // -------------------------------------------------------------------
+
+protected:
+ void setParameterValue(const uint32_t rindex, const float value)
+ {
+ if (fOscData.server == nullptr)
+ return;
+
+ fOscData.send_control(rindex, value);
+ }
+
+ void setState(const char* const key, const char* const value)
+ {
+ if (fOscData.server == nullptr)
+ return;
+
+ fOscData.send_configure(key, value);
+ }
+
+ void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity)
+ {
+ if (fOscData.server == nullptr)
+ return;
+ if (channel > 0xF)
+ return;
+
+ uint8_t mdata[4] = { 0, channel, note, velocity };
+ mdata[1] += (velocity != 0) ? 0x90 : 0x80;
+
+ fOscData.send_midi(mdata);
+ }
+
+ void uiResize(const unsigned int width, const unsigned int height)
+ {
+ fUI.setSize(width, height);
+ }
+
+private:
+ UIExporter fUI;
+ bool fHostClosed;
+
+ const OscData& fOscData;
+
+ // -------------------------------------------------------------------
+ // Callbacks
+
+ #define uiPtr ((UIDssi*)ptr)
+
+ static void setParameterCallback(void* ptr, uint32_t rindex, float value)
+ {
+ uiPtr->setParameterValue(rindex, value);
+ }
+
+ static void setStateCallback(void* ptr, const char* key, const char* value)
+ {
+ uiPtr->setState(key, value);
+ }
+
+ static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
+ {
+ uiPtr->sendNote(channel, note, velocity);
+ }
+
+ static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height)
+ {
+ uiPtr->uiResize(width, height);
+ }
+
+ #undef uiPtr
+};
+
+// -----------------------------------------------------------------------
+
+static OscData gOscData;
+static const char* gUiTitle = nullptr;
+static UIDssi* globalUI = nullptr;
+
+static void initUiIfNeeded()
+{
+ if (globalUI != nullptr)
+ return;
+
+ if (d_lastUiSampleRate == 0.0)
+ d_lastUiSampleRate = 44100.0;
+
+ globalUI = new UIDssi(gOscData, gUiTitle);
+}
+
+// -----------------------------------------------------------------------
+
+int osc_debug_handler(const char* path, const char*, lo_arg**, int, lo_message, void*)
+{
+ d_debug("osc_debug_handler(\"%s\")", path);
+ return 0;
+}
+
+void osc_error_handler(int num, const char* msg, const char* path)
+{
+ d_stderr("osc_error_handler(%i, \"%s\", \"%s\")", num, msg, path);
+}
+
+#if DISTRHO_PLUGIN_WANT_STATE
+int osc_configure_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*)
+{
+ const char* const key = &argv[0]->s;
+ const char* const value = &argv[1]->s;
+ d_debug("osc_configure_handler(\"%s\", \"%s\")", key, value);
+
+ initUiIfNeeded();
+
+ globalUI->dssiui_configure(key, value);
+
+ return 0;
+}
+#endif
+
+int osc_control_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*)
+{
+ const int32_t rindex = argv[0]->i;
+ const float value = argv[1]->f;
+ d_debug("osc_control_handler(%i, %f)", rindex, value);
+
+ int32_t index = rindex - DISTRHO_PLUGIN_NUM_INPUTS - DISTRHO_PLUGIN_NUM_OUTPUTS;
+
+ // latency
+#if DISTRHO_PLUGIN_WANT_LATENCY
+ index -= 1;
+#endif
+
+ if (index < 0)
+ return 0;
+
+ initUiIfNeeded();
+
+ globalUI->dssiui_control(index, value);
+
+ return 0;
+}
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+int osc_program_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*)
+{
+ const int32_t bank = argv[0]->i;
+ const int32_t program = argv[1]->f;
+ d_debug("osc_program_handler(%i, %i)", bank, program);
+
+ initUiIfNeeded();
+
+ globalUI->dssiui_program(bank, program);
+
+ return 0;
+}
+#endif
+
+int osc_sample_rate_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*)
+{
+ const int32_t sampleRate = argv[0]->i;
+ d_debug("osc_sample_rate_handler(%i)", sampleRate);
+
+ d_lastUiSampleRate = sampleRate;
+
+ return 0;
+}
+
+int osc_show_handler(const char*, const char*, lo_arg**, int, lo_message, void*)
+{
+ d_debug("osc_show_handler()");
+
+ initUiIfNeeded();
+
+ globalUI->dssiui_show();
+
+ return 0;
+}
+
+int osc_hide_handler(const char*, const char*, lo_arg**, int, lo_message, void*)
+{
+ d_debug("osc_hide_handler()");
+
+ if (globalUI != nullptr)
+ globalUI->dssiui_hide();
+
+ return 0;
+}
+
+int osc_quit_handler(const char*, const char*, lo_arg**, int, lo_message, void*)
+{
+ d_debug("osc_quit_handler()");
+
+ if (globalUI != nullptr)
+ globalUI->dssiui_quit();
+
+ return 0;
+}
+
+END_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+
+int main(int argc, char* argv[])
+{
+ USE_NAMESPACE_DISTRHO
+
+ // dummy test mode
+ if (argc == 1)
+ {
+ gUiTitle = "DSSI UI Test";
+
+ initUiIfNeeded();
+ globalUI->dssiui_show();
+ globalUI->exec();
+
+ return 0;
+ }
+
+ if (argc != 5)
+ {
+ fprintf(stderr, "Usage: %s <osc-url> <plugin-dll> <plugin-label> <instance-name>\n", argv[0]);
+ return 1;
+ }
+
+ const char* oscUrl = argv[1];
+ const char* uiTitle = argv[4];
+
+ char* const oscHost = lo_url_get_hostname(oscUrl);
+ char* const oscPort = lo_url_get_port(oscUrl);
+ char* const oscPath = lo_url_get_path(oscUrl);
+ size_t oscPathSize = strlen(oscPath);
+ lo_address oscAddr = lo_address_new(oscHost, oscPort);
+ lo_server oscServer = lo_server_new_with_proto(nullptr, LO_UDP, osc_error_handler);
+
+ char* const oscServerPath = lo_server_get_url(oscServer);
+
+ char pluginPath[strlen(oscServerPath)+oscPathSize];
+ strcpy(pluginPath, oscServerPath);
+ strcat(pluginPath, oscPath+1);
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ char oscPathConfigure[oscPathSize+11];
+ strcpy(oscPathConfigure, oscPath);
+ strcat(oscPathConfigure, "/configure");
+ lo_server_add_method(oscServer, oscPathConfigure, "ss", osc_configure_handler, nullptr);
+#endif
+
+ char oscPathControl[oscPathSize+9];
+ strcpy(oscPathControl, oscPath);
+ strcat(oscPathControl, "/control");
+ lo_server_add_method(oscServer, oscPathControl, "if", osc_control_handler, nullptr);
+
+ d_stdout("oscServerPath: \"%s\"", oscServerPath);
+ d_stdout("pluginPath: \"%s\"", pluginPath);
+ d_stdout("oscPathControl: \"%s\"", oscPathControl);
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ char oscPathProgram[oscPathSize+9];
+ strcpy(oscPathProgram, oscPath);
+ strcat(oscPathProgram, "/program");
+ lo_server_add_method(oscServer, oscPathProgram, "ii", osc_program_handler, nullptr);
+#endif
+
+ char oscPathSampleRate[oscPathSize+13];
+ strcpy(oscPathSampleRate, oscPath);
+ strcat(oscPathSampleRate, "/sample-rate");
+ lo_server_add_method(oscServer, oscPathSampleRate, "i", osc_sample_rate_handler, nullptr);
+
+ char oscPathShow[oscPathSize+6];
+ strcpy(oscPathShow, oscPath);
+ strcat(oscPathShow, "/show");
+ lo_server_add_method(oscServer, oscPathShow, "", osc_show_handler, nullptr);
+
+ char oscPathHide[oscPathSize+6];
+ strcpy(oscPathHide, oscPath);
+ strcat(oscPathHide, "/hide");
+ lo_server_add_method(oscServer, oscPathHide, "", osc_hide_handler, nullptr);
+
+ char oscPathQuit[oscPathSize+6];
+ strcpy(oscPathQuit, oscPath);
+ strcat(oscPathQuit, "/quit");
+ lo_server_add_method(oscServer, oscPathQuit, "", osc_quit_handler, nullptr);
+
+ lo_server_add_method(oscServer, nullptr, nullptr, osc_debug_handler, nullptr);
+
+ gUiTitle = uiTitle;
+
+ gOscData.addr = oscAddr;
+ gOscData.path = oscPath;
+ gOscData.server = oscServer;
+ gOscData.send_update(pluginPath);
+
+ // wait for init
+ for (int i=0; i < 100; ++i)
+ {
+ lo_server_recv(oscServer);
+
+ if (d_lastUiSampleRate != 0.0 || globalUI != nullptr)
+ break;
+
+ d_msleep(50);
+ }
+
+ int ret = 1;
+
+ if (d_lastUiSampleRate != 0.0 || globalUI != nullptr)
+ {
+ initUiIfNeeded();
+
+ globalUI->exec();
+
+ delete globalUI;
+ globalUI = nullptr;
+
+ ret = 0;
+ }
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ lo_server_del_method(oscServer, oscPathConfigure, "ss");
+#endif
+ lo_server_del_method(oscServer, oscPathControl, "if");
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ lo_server_del_method(oscServer, oscPathProgram, "ii");
+#endif
+ lo_server_del_method(oscServer, oscPathSampleRate, "i");
+ lo_server_del_method(oscServer, oscPathShow, "");
+ lo_server_del_method(oscServer, oscPathHide, "");
+ lo_server_del_method(oscServer, oscPathQuit, "");
+ lo_server_del_method(oscServer, nullptr, nullptr);
+
+ std::free(oscServerPath);
+ std::free(oscHost);
+ std::free(oscPort);
+ std::free(oscPath);
+
+ lo_address_free(oscAddr);
+ lo_server_free(oscServer);
+
+ return ret;
+}
diff --git a/distrho/src/DistrhoUIInternal.hpp b/distrho/src/DistrhoUIInternal.hpp
@@ -0,0 +1,249 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#ifndef DISTRHO_UI_INTERNAL_HPP_INCLUDED
+#define DISTRHO_UI_INTERNAL_HPP_INCLUDED
+
+#include "../DistrhoUI.hpp"
+
+#include "../../dgl/App.hpp"
+#include "../../dgl/Window.hpp"
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+// Static data, see DistrhoUI.cpp
+
+extern double d_lastUiSampleRate;
+
+// -----------------------------------------------------------------------
+// UI callbacks
+
+typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started);
+typedef void (*setParamFunc) (void* ptr, uint32_t rindex, float value);
+typedef void (*setStateFunc) (void* ptr, const char* key, const char* value);
+typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8_t velo);
+typedef void (*uiResizeFunc) (void* ptr, unsigned int width, unsigned int height);
+
+// -----------------------------------------------------------------------
+// UI private data
+
+struct UI::PrivateData {
+ // DSP
+ double sampleRate;
+ uint32_t parameterOffset;
+
+ // Callbacks
+ editParamFunc editParamCallbackFunc;
+ setParamFunc setParamCallbackFunc;
+ setStateFunc setStateCallbackFunc;
+ sendNoteFunc sendNoteCallbackFunc;
+ uiResizeFunc uiResizeCallbackFunc;
+ void* ptr;
+
+ PrivateData() noexcept
+ : sampleRate(d_lastUiSampleRate),
+ parameterOffset(0),
+ editParamCallbackFunc(nullptr),
+ setParamCallbackFunc(nullptr),
+ setStateCallbackFunc(nullptr),
+ sendNoteCallbackFunc(nullptr),
+ uiResizeCallbackFunc(nullptr),
+ ptr(nullptr)
+ {
+ assert(sampleRate != 0.0);
+
+#if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2)
+ parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
+# if DISTRHO_PLUGIN_WANT_LATENCY
+ parameterOffset += 1;
+# endif
+#endif
+#ifdef DISTRHO_PLUGIN_TARGET_LV2
+# if (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE)
+ parameterOffset += 1;
+# if DISTRHO_PLUGIN_WANT_STATE
+ parameterOffset += 1;
+# endif
+# endif
+#endif
+ }
+
+ void editParamCallback(const uint32_t rindex, const bool started)
+ {
+ if (editParamCallbackFunc != nullptr)
+ editParamCallbackFunc(ptr, rindex, started);
+ }
+
+ void setParamCallback(const uint32_t rindex, const float value)
+ {
+ if (setParamCallbackFunc != nullptr)
+ setParamCallbackFunc(ptr, rindex, value);
+ }
+
+ void setStateCallback(const char* const key, const char* const value)
+ {
+ if (setStateCallbackFunc != nullptr)
+ setStateCallbackFunc(ptr, key, value);
+ }
+
+ void sendNoteCallback(const uint8_t channel, const uint8_t note, const uint8_t velocity)
+ {
+ if (sendNoteCallbackFunc != nullptr)
+ sendNoteCallbackFunc(ptr, channel, note, velocity);
+ }
+
+ void uiResizeCallback(const unsigned int width, const unsigned int height)
+ {
+ if (uiResizeCallbackFunc != nullptr)
+ uiResizeCallbackFunc(ptr, width, height);
+ }
+};
+
+// -----------------------------------------------------------------------
+// UI exporter class
+
+class UIExporter
+{
+public:
+ UIExporter(void* const ptr, const intptr_t winId,
+ const editParamFunc editParamCall, const setParamFunc setParamCall, const setStateFunc setStateCall, const sendNoteFunc sendNoteCall, const uiResizeFunc uiResizeCall)
+ : glApp(),
+ glWindow(glApp, winId),
+ fUi(createUI()),
+ fData((fUi != nullptr) ? fUi->pData : nullptr)
+ {
+ assert(fUi != nullptr);
+
+ if (fUi == nullptr)
+ return;
+
+ fData->ptr = ptr;
+ fData->editParamCallbackFunc = editParamCall;
+ fData->setParamCallbackFunc = setParamCall;
+ fData->setStateCallbackFunc = setStateCall;
+ fData->sendNoteCallbackFunc = sendNoteCall;
+ fData->uiResizeCallbackFunc = uiResizeCall;
+
+ glWindow.setSize(fUi->d_getWidth(), fUi->d_getHeight());
+ glWindow.setResizable(false);
+ }
+
+ ~UIExporter()
+ {
+ delete fUi;
+ }
+
+ // -------------------------------------------------------------------
+
+ const char* getName() const noexcept
+ {
+ return (fUi != nullptr) ? fUi->d_getName() : "";
+ }
+
+ unsigned int getWidth() const noexcept
+ {
+ return (fUi != nullptr) ? fUi->d_getWidth() : 0;
+ }
+
+ unsigned int getHeight() const noexcept
+ {
+ return (fUi != nullptr) ? fUi->d_getHeight() : 0;
+ }
+
+ // -------------------------------------------------------------------
+
+ uint32_t getParameterOffset() const noexcept
+ {
+ return (fData != nullptr) ? fData->parameterOffset : 0;
+ }
+
+ // -------------------------------------------------------------------
+
+ void parameterChanged(const uint32_t index, const float value)
+ {
+ if (fUi != nullptr)
+ fUi->d_parameterChanged(index, value);
+ }
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ void programChanged(const uint32_t index)
+ {
+ if (fUi != nullptr)
+ fUi->d_programChanged(index);
+ }
+#endif
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ void stateChanged(const char* const key, const char* const value)
+ {
+ if (fUi != nullptr)
+ fUi->d_stateChanged(key, value);
+ }
+#endif
+
+ // -------------------------------------------------------------------
+
+ bool idle()
+ {
+ if (fUi != nullptr)
+ fUi->d_uiIdle();
+
+ glApp.idle();
+
+ return ! glApp.isQuiting();
+ }
+
+ void quit()
+ {
+ glWindow.close();
+ glApp.quit();
+ }
+
+ void setSize(const unsigned int width, const unsigned int height)
+ {
+ glWindow.setSize(width, height);
+ }
+
+ void setTitle(const char* const uiTitle)
+ {
+ glWindow.setTitle(uiTitle);
+ }
+
+ void setVisible(const bool yesNo)
+ {
+ glWindow.setVisible(yesNo);
+ }
+
+private:
+ // -------------------------------------------------------------------
+ // DGL Application and Window for this plugin
+
+ DGL::App glApp;
+ DGL::Window glWindow;
+
+ // -------------------------------------------------------------------
+ // private members accessed by DistrhoPlugin class
+
+ UI* const fUi;
+ UI::PrivateData* const fData;
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
+
+#endif // DISTRHO_UI_INTERNAL_HPP_INCLUDED
diff --git a/distrho/src/DistrhoUILV2.cpp b/distrho/src/DistrhoUILV2.cpp
@@ -0,0 +1,333 @@
+/*
+ * DISTRHO Plugin Toolkit (DPT)
+ * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
+ *
+ * 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.
+ *
+ * THE 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.
+ */
+
+#include "DistrhoUIInternal.hpp"
+
+#include "lv2/atom.h"
+#include "lv2/atom-util.h"
+#include "lv2/options.h"
+#include "lv2/ui.h"
+#include "lv2/urid.h"
+#include "lv2/lv2_programs.h"
+
+#include <string>
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+
+class UiLv2
+{
+public:
+ UiLv2(const intptr_t winId, const LV2_URID_Map* const uridMap, const LV2UI_Resize* const uiResz, const LV2UI_Touch* uiTouch, const LV2UI_Controller controller, const LV2UI_Write_Function writeFunc)
+ : fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, uiResizeCallback),
+ fUridMap(uridMap),
+ fUiResize(uiResz),
+ fUiTouch(uiTouch),
+ fController(controller),
+ fWriteFunction(writeFunc)
+ {
+ fUiResize->ui_resize(fUiResize->handle, fUI.getWidth(), fUI.getHeight());
+ }
+
+ // -------------------------------------------------------------------
+
+ void lv2ui_port_event(const uint32_t rindex, const uint32_t bufferSize, const uint32_t format, const void* const buffer)
+ {
+ if (format == 0)
+ {
+ const uint32_t parameterOffset(fUI.getParameterOffset());
+
+ if (rindex < parameterOffset)
+ return;
+ if (bufferSize != sizeof(float))
+ return;
+
+ const float value(*(const float*)buffer);
+ fUI.parameterChanged(rindex-parameterOffset, value);
+ }
+ else
+ {
+ //fUI.stateChanged(key, value);
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+ int lv2ui_idle()
+ {
+ fUI.idle();
+ return 0;
+ }
+
+ // -------------------------------------------------------------------
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ void lv2ui_select_program(const uint32_t bank, const uint32_t program)
+ {
+ const uint32_t realProgram(bank * 128 + program);
+
+ fUI.programChanged(realProgram);
+ }
+#endif
+
+ // -------------------------------------------------------------------
+
+protected:
+ void editParameterValue(const uint32_t rindex, const bool started)
+ {
+ if (fUiTouch != nullptr && fUiTouch->touch != nullptr)
+ fUiTouch->touch(fUiTouch->handle, rindex, started);
+ }
+
+ void setParameterValue(const uint32_t rindex, const float value)
+ {
+ if (fWriteFunction != nullptr)
+ fWriteFunction(fController, rindex, sizeof(float), 0, &value);
+ }
+
+ void setState(const char* const key, const char* const value)
+ {
+ if (fWriteFunction == nullptr)
+ return;
+
+ const uint32_t eventInPortIndex(DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS);
+
+ // join key and value
+ std::string tmpStr;
+ tmpStr += std::string(key);
+ tmpStr += std::string("\0", 1);
+ tmpStr += std::string(value);
+
+ // get msg size
+ const size_t msgSize(tmpStr.size()+1);
+
+ // reserve atom space
+ const size_t atomSize(lv2_atom_pad_size(sizeof(LV2_Atom) + msgSize));
+ char atomBuf[atomSize];
+ std::memset(atomBuf, 0, atomSize);
+
+ // set atom info
+ LV2_Atom* const atom((LV2_Atom*)atomBuf);
+ atom->size = msgSize;
+ atom->type = fUridMap->map(fUridMap->handle, "urn:distrho:keyValueState");
+
+ // set atom data
+ std::memcpy(atomBuf + sizeof(LV2_Atom), tmpStr.data(), msgSize-1);
+
+ // send to DSP side
+ fWriteFunction(fController, eventInPortIndex, atomSize, fUridMap->map(fUridMap->handle, LV2_ATOM__eventTransfer), atom);
+ }
+
+ void sendNote(const uint8_t /*channel*/, const uint8_t /*note*/, const uint8_t /*velocity*/)
+ {
+ }
+
+ void uiResize(const unsigned int width, const unsigned int height)
+ {
+ fUI.setSize(width, height);
+ fUiResize->ui_resize(fUiResize->handle, width, height);
+ }
+
+private:
+ UIExporter fUI;
+
+ // LV2 features
+ const LV2_URID_Map* const fUridMap;
+ const LV2UI_Resize* const fUiResize;
+ const LV2UI_Touch* const fUiTouch;
+
+ // LV2 UI stuff
+ const LV2UI_Controller fController;
+ const LV2UI_Write_Function fWriteFunction;
+
+ // -------------------------------------------------------------------
+ // Callbacks
+
+ #define uiPtr ((UiLv2*)ptr)
+
+ static void editParameterCallback(void* ptr, uint32_t rindex, bool started)
+ {
+ uiPtr->editParameterValue(rindex, started);
+ }
+
+ static void setParameterCallback(void* ptr, uint32_t rindex, float value)
+ {
+ uiPtr->setParameterValue(rindex, value);
+ }
+
+ static void setStateCallback(void* ptr, const char* key, const char* value)
+ {
+ uiPtr->setState(key, value);
+ }
+
+ static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
+ {
+ uiPtr->sendNote(channel, note, velocity);
+ }
+
+ static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height)
+ {
+ uiPtr->uiResize(width, height);
+ }
+
+ #undef uiPtr
+};
+
+// -----------------------------------------------------------------------
+
+static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const char* uri, const char*, LV2UI_Write_Function writeFunction, LV2UI_Controller controller, LV2UI_Widget* widget, const LV2_Feature* const* features)
+{
+ if (uri == nullptr || std::strcmp(uri, DISTRHO_PLUGIN_URI) != 0)
+ {
+ d_stderr("Invalid plugin URI");
+ return nullptr;
+ }
+
+ const LV2_Options_Option* options = nullptr;
+ const LV2_URID_Map* uridMap = nullptr;
+ const LV2UI_Resize* uiResize = nullptr;
+ const LV2UI_Touch* uiTouch = nullptr;
+ void* parentId = nullptr;
+
+ for (int i=0; features[i] != nullptr; ++i)
+ {
+ if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0)
+ options = (const LV2_Options_Option*)features[i]->data;
+ else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0)
+ uridMap = (const LV2_URID_Map*)features[i]->data;
+ else if (std::strcmp(features[i]->URI, LV2_UI__resize) == 0)
+ uiResize = (const LV2UI_Resize*)features[i]->data;
+ else if (std::strcmp(features[i]->URI, LV2_UI__parent) == 0)
+ parentId = features[i]->data;
+ }
+
+ if (options == nullptr)
+ {
+ d_stderr("Options feature missing, cannot continue!");
+ return nullptr;
+ }
+
+ if (uridMap == nullptr)
+ {
+ d_stderr("URID Map feature missing, cannot continue!");
+ return nullptr;
+ }
+
+ if (uiResize == nullptr)
+ {
+ d_stderr("UI Resize feature missing, cannot continue!");
+ return nullptr;
+ }
+
+ if (parentId == nullptr)
+ {
+ d_stderr("Parent Window Id missing, cannot continue!");
+ return nullptr;
+ }
+
+ *widget = parentId;
+
+ const intptr_t winId(*((intptr_t*)&parentId));
+
+ for (int i=0; options[i].key != 0; ++i)
+ {
+ if (options[i].key == uridMap->map(uridMap->handle, LV2_CORE__sampleRate))
+ {
+ if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Double))
+ d_lastUiSampleRate = *(const double*)options[i].value;
+ else
+ d_stderr("Host provides sampleRate but has wrong value type");
+
+ break;
+ }
+ }
+
+ if (d_lastUiSampleRate == 0.0)
+ d_lastUiSampleRate = 44100.0;
+
+ return new UiLv2(winId, uridMap, uiResize, uiTouch, controller, writeFunction);
+}
+
+#define uiPtr ((UiLv2*)ui)
+
+static void lv2ui_cleanup(LV2UI_Handle ui)
+{
+ delete uiPtr;
+}
+
+static void lv2ui_port_event(LV2UI_Handle ui, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer)
+{
+ uiPtr->lv2ui_port_event(portIndex, bufferSize, format, buffer);
+}
+
+// -----------------------------------------------------------------------
+
+static int lv2ui_idle(LV2UI_Handle ui)
+{
+ return uiPtr->lv2ui_idle();
+}
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+static void lv2ui_select_program(LV2UI_Handle ui, uint32_t bank, uint32_t program)
+{
+ uiPtr->lv2ui_select_program(bank, program);
+}
+#endif
+
+// -----------------------------------------------------------------------
+
+static const void* lv2ui_extension_data(const char* uri)
+{
+ static const LV2UI_Idle_Interface uiIdle = { lv2ui_idle };
+
+ if (std::strcmp(uri, LV2_UI__idleInterface) == 0)
+ return &uiIdle;
+
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ static const LV2_Programs_UI_Interface uiPrograms = { lv2ui_select_program };
+
+ if (std::strcmp(uri, LV2_PROGRAMS__UIInterface) == 0)
+ return &uiPrograms;
+#endif
+
+ return nullptr;
+}
+
+#undef instancePtr
+
+// -----------------------------------------------------------------------
+
+static const LV2UI_Descriptor sLv2UiDescriptor = {
+ DISTRHO_UI_URI,
+ lv2ui_instantiate,
+ lv2ui_cleanup,
+ lv2ui_port_event,
+ lv2ui_extension_data
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
+
+DISTRHO_PLUGIN_EXPORT
+const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
+{
+ USE_NAMESPACE_DISTRHO
+ return (index == 0) ? &sLv2UiDescriptor : nullptr;
+}
+
+// -----------------------------------------------------------------------
diff --git a/distrho/src/dssi/dssi.h b/distrho/src/dssi/dssi.h
@@ -0,0 +1,441 @@
+/* -*- c-basic-offset: 4 -*- */
+
+/* dssi.h
+
+ DSSI version 1.0
+ Copyright (c) 2004, 2009 Chris Cannam, Steve Harris and Sean Bolton
+
+ This library 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 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#ifndef DSSI_INCLUDED
+#define DSSI_INCLUDED
+
+#include "../ladspa/ladspa.h"
+#include "seq_event-compat.h"
+
+#define DSSI_VERSION "1.0"
+#define DSSI_VERSION_MAJOR 1
+#define DSSI_VERSION_MINOR 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ There is a need for an API that supports hosted MIDI soft synths
+ with GUIs in Linux audio applications. In time the GMPI initiative
+ should comprehensively address this need, but the requirement for
+ Linux applications to be able to support simple hosted synths is
+ here now, and GMPI is not. This proposal (the "DSSI Soft Synth
+ Interface" or DSSI, pronounced "dizzy") aims to provide a simple
+ solution in a way that we hope will prove complete and compelling
+ enough to support now, yet not so compelling as to supplant GMPI or
+ any other comprehensive future proposal.
+
+ For simplicity and familiarity, this API is based as far as
+ possible on existing work -- the LADSPA plugin API for control
+ values and audio processing, and the ALSA sequencer event types for
+ MIDI event communication. The GUI part of the proposal is quite
+ new, but may also be applicable retroactively to LADSPA plugins
+ that do not otherwise support this synth interface.
+*/
+
+typedef struct _DSSI_Program_Descriptor {
+
+ /** Bank number for this program. Note that DSSI does not support
+ MIDI-style separation of bank LSB and MSB values. There is no
+ restriction on the set of available banks: the numbers do not
+ need to be contiguous, there does not need to be a bank 0, etc. */
+ unsigned long Bank;
+
+ /** Program number (unique within its bank) for this program.
+ There is no restriction on the set of available programs: the
+ numbers do not need to be contiguous, there does not need to
+ be a program 0, etc. */
+ unsigned long Program;
+
+ /** Name of the program. */
+ const char * Name;
+
+} DSSI_Program_Descriptor;
+
+
+typedef struct _DSSI_Descriptor {
+
+ /**
+ * DSSI_API_Version
+ *
+ * This member indicates the DSSI API level used by this plugin.
+ * If we're lucky, this will never be needed. For now all plugins
+ * must set it to 1.
+ */
+ int DSSI_API_Version;
+
+ /**
+ * LADSPA_Plugin
+ *
+ * A DSSI synth plugin consists of a LADSPA plugin plus an
+ * additional framework for controlling program settings and
+ * transmitting MIDI events. A plugin must fully implement the
+ * LADSPA descriptor fields as well as the required LADSPA
+ * functions including instantiate() and (de)activate(). It
+ * should also implement run(), with the same behaviour as if
+ * run_synth() (below) were called with no synth events.
+ *
+ * In order to instantiate a synth the host calls the LADSPA
+ * instantiate function, passing in this LADSPA_Descriptor
+ * pointer. The returned LADSPA_Handle is used as the argument
+ * for the DSSI functions below as well as for the LADSPA ones.
+ */
+ const LADSPA_Descriptor *LADSPA_Plugin;
+
+ /**
+ * configure()
+ *
+ * This member is a function pointer that sends a piece of
+ * configuration data to the plugin. The key argument specifies
+ * some aspect of the synth's configuration that is to be changed,
+ * and the value argument specifies a new value for it. A plugin
+ * that does not require this facility at all may set this member
+ * to NULL.
+ *
+ * This call is intended to set some session-scoped aspect of a
+ * plugin's behaviour, for example to tell the plugin to load
+ * sample data from a particular file. The plugin should act
+ * immediately on the request. The call should return NULL on
+ * success, or an error string that may be shown to the user. The
+ * host will free the returned value after use if it is non-NULL.
+ *
+ * Calls to configure() are not automated as timed events.
+ * Instead, a host should remember the last value associated with
+ * each key passed to configure() during a given session for a
+ * given plugin instance, and should call configure() with the
+ * correct value for each key the next time it instantiates the
+ * "same" plugin instance, for example on reloading a project in
+ * which the plugin was used before. Plugins should note that a
+ * host may typically instantiate a plugin multiple times with the
+ * same configuration values, and should share data between
+ * instances where practical.
+ *
+ * Calling configure() completely invalidates the program and bank
+ * information last obtained from the plugin.
+ *
+ * Reserved and special key prefixes
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * The DSSI: prefix
+ * ----------------
+ * Configure keys starting with DSSI: are reserved for particular
+ * purposes documented in the DSSI specification. At the moment,
+ * there is one such key: DSSI:PROJECT_DIRECTORY. A host may call
+ * configure() passing this key and a directory path value. This
+ * indicates to the plugin and its UI that a directory at that
+ * path exists and may be used for project-local data. Plugins
+ * may wish to use the project directory as a fallback location
+ * when looking for other file data, or as a base for relative
+ * paths in other configuration values.
+ *
+ * The GLOBAL: prefix
+ * ------------------
+ * Configure keys starting with GLOBAL: may be used by the plugin
+ * and its UI for any purpose, but are treated specially by the
+ * host. When one of these keys is used in a configure OSC call
+ * from the plugin UI, the host makes the corresponding configure
+ * call (preserving the GLOBAL: prefix) not only to the target
+ * plugin but also to all other plugins in the same instance
+ * group, as well as their UIs. Note that if any instance
+ * returns non-NULL from configure to indicate error, the host
+ * may stop there (and the set of plugins on which configure has
+ * been called will thus depend on the host implementation).
+ * See also the configure OSC call documentation in RFC.txt.
+ */
+ char *(*configure)(LADSPA_Handle Instance,
+ const char *Key,
+ const char *Value);
+
+ #define DSSI_RESERVED_CONFIGURE_PREFIX "DSSI:"
+ #define DSSI_GLOBAL_CONFIGURE_PREFIX "GLOBAL:"
+ #define DSSI_PROJECT_DIRECTORY_KEY \
+ DSSI_RESERVED_CONFIGURE_PREFIX "PROJECT_DIRECTORY"
+
+ /**
+ * get_program()
+ *
+ * This member is a function pointer that provides a description
+ * of a program (named preset sound) available on this synth. A
+ * plugin that does not support programs at all should set this
+ * member to NULL.
+ *
+ * The Index argument is an index into the plugin's list of
+ * programs, not a program number as represented by the Program
+ * field of the DSSI_Program_Descriptor. (This distinction is
+ * needed to support synths that use non-contiguous program or
+ * bank numbers.)
+ *
+ * This function returns a DSSI_Program_Descriptor pointer that is
+ * guaranteed to be valid only until the next call to get_program,
+ * deactivate, or configure, on the same plugin instance. This
+ * function must return NULL if passed an Index argument out of
+ * range, so that the host can use it to query the number of
+ * programs as well as their properties.
+ */
+ const DSSI_Program_Descriptor *(*get_program)(LADSPA_Handle Instance,
+ unsigned long Index);
+
+ /**
+ * select_program()
+ *
+ * This member is a function pointer that selects a new program
+ * for this synth. The program change should take effect
+ * immediately at the start of the next run_synth() call. (This
+ * means that a host providing the capability of changing programs
+ * between any two notes on a track must vary the block size so as
+ * to place the program change at the right place. A host that
+ * wanted to avoid this would probably just instantiate a plugin
+ * for each program.)
+ *
+ * A plugin that does not support programs at all should set this
+ * member NULL. Plugins should ignore a select_program() call
+ * with an invalid bank or program.
+ *
+ * A plugin is not required to select any particular default
+ * program on activate(): it's the host's duty to set a program
+ * explicitly. The current program is invalidated by any call to
+ * configure().
+ *
+ * A plugin is permitted to re-write the values of its input
+ * control ports when select_program is called. The host should
+ * re-read the input control port values and update its own
+ * records appropriately. (This is the only circumstance in
+ * which a DSSI plugin is allowed to modify its own input ports.)
+ */
+ void (*select_program)(LADSPA_Handle Instance,
+ unsigned long Bank,
+ unsigned long Program);
+
+ /**
+ * get_midi_controller_for_port()
+ *
+ * This member is a function pointer that returns the MIDI
+ * controller number or NRPN that should be mapped to the given
+ * input control port. If the given port should not have any MIDI
+ * controller mapped to it, the function should return DSSI_NONE.
+ * The behaviour of this function is undefined if the given port
+ * number does not correspond to an input control port. A plugin
+ * that does not want MIDI controllers mapped to ports at all may
+ * set this member NULL.
+ *
+ * Correct values can be got using the macros DSSI_CC(num) and
+ * DSSI_NRPN(num) as appropriate, and values can be combined using
+ * bitwise OR: e.g. DSSI_CC(23) | DSSI_NRPN(1069) means the port
+ * should respond to CC #23 and NRPN #1069.
+ *
+ * The host is responsible for doing proper scaling from MIDI
+ * controller and NRPN value ranges to port ranges according to
+ * the plugin's LADSPA port hints. Hosts should not deliver
+ * through run_synth any MIDI controller events that have already
+ * been mapped to control port values.
+ *
+ * A plugin should not attempt to request mappings from
+ * controllers 0 or 32 (MIDI Bank Select MSB and LSB).
+ */
+ int (*get_midi_controller_for_port)(LADSPA_Handle Instance,
+ unsigned long Port);
+
+ /**
+ * run_synth()
+ *
+ * This member is a function pointer that runs a synth for a
+ * block. This is identical in function to the LADSPA run()
+ * function, except that it also supplies events to the synth.
+ *
+ * A plugin may provide this function, run_multiple_synths() (see
+ * below), both, or neither (if it is not in fact a synth). A
+ * plugin that does not provide this function must set this member
+ * to NULL. Authors of synth plugins are encouraged to provide
+ * this function if at all possible.
+ *
+ * The Events pointer points to a block of EventCount ALSA
+ * sequencer events, which is used to communicate MIDI and related
+ * events to the synth. Each event is timestamped relative to the
+ * start of the block, (mis)using the ALSA "tick time" field as a
+ * frame count. The host is responsible for ensuring that events
+ * with differing timestamps are already ordered by time.
+ *
+ * See also the notes on activation, port connection etc in
+ * ladpsa.h, in the context of the LADSPA run() function.
+ *
+ * Note Events
+ * ~~~~~~~~~~~
+ * There are two minor requirements aimed at making the plugin
+ * writer's life as simple as possible:
+ *
+ * 1. A host must never send events of type SND_SEQ_EVENT_NOTE.
+ * Notes should always be sent as separate SND_SEQ_EVENT_NOTE_ON
+ * and NOTE_OFF events. A plugin should discard any one-point
+ * NOTE events it sees.
+ *
+ * 2. A host must not attempt to switch notes off by sending
+ * zero-velocity NOTE_ON events. It should always send true
+ * NOTE_OFFs. It is the host's responsibility to remap events in
+ * cases where an external MIDI source has sent it zero-velocity
+ * NOTE_ONs.
+ *
+ * Bank and Program Events
+ * ~~~~~~~~~~~~~~~~~~~~~~~
+ * Hosts must map MIDI Bank Select MSB and LSB (0 and 32)
+ * controllers and MIDI Program Change events onto the banks and
+ * programs specified by the plugin, using the DSSI select_program
+ * call. No host should ever deliver a program change or bank
+ * select controller to a plugin via run_synth.
+ */
+ void (*run_synth)(LADSPA_Handle Instance,
+ unsigned long SampleCount,
+ snd_seq_event_t *Events,
+ unsigned long EventCount);
+
+ /**
+ * run_synth_adding()
+ *
+ * This member is a function pointer that runs an instance of a
+ * synth for a block, adding its outputs to the values already
+ * present at the output ports. This is provided for symmetry
+ * with LADSPA run_adding(), and is equally optional. A plugin
+ * that does not provide it must set this member to NULL.
+ */
+ void (*run_synth_adding)(LADSPA_Handle Instance,
+ unsigned long SampleCount,
+ snd_seq_event_t *Events,
+ unsigned long EventCount);
+
+ /**
+ * run_multiple_synths()
+ *
+ * This member is a function pointer that runs multiple synth
+ * instances for a block. This is very similar to run_synth(),
+ * except that Instances, Events, and EventCounts each point to
+ * arrays that hold the LADSPA handles, event buffers, and
+ * event counts for each of InstanceCount instances. That is,
+ * Instances points to an array of InstanceCount pointers to
+ * DSSI plugin instantiations, Events points to an array of
+ * pointers to each instantiation's respective event list, and
+ * EventCounts points to an array containing each instantiation's
+ * respective event count.
+ *
+ * A host using this function must guarantee that ALL active
+ * instances of the plugin are represented in each call to the
+ * function -- that is, a host may not call run_multiple_synths()
+ * for some instances of a given plugin and then call run_synth()
+ * as well for others. 'All .. instances of the plugin' means
+ * every instance sharing the same LADSPA label and shared object
+ * (*.so) file (rather than every instance sharing the same *.so).
+ * 'Active' means any instance for which activate() has been called
+ * but deactivate() has not.
+ *
+ * A plugin may provide this function, run_synths() (see above),
+ * both, or neither (if it not in fact a synth). A plugin that
+ * does not provide this function must set this member to NULL.
+ * Plugin authors implementing run_multiple_synths are strongly
+ * encouraged to implement run_synth as well if at all possible,
+ * to aid simplistic hosts, even where it would be less efficient
+ * to use it.
+ */
+ void (*run_multiple_synths)(unsigned long InstanceCount,
+ LADSPA_Handle *Instances,
+ unsigned long SampleCount,
+ snd_seq_event_t **Events,
+ unsigned long *EventCounts);
+
+ /**
+ * run_multiple_synths_adding()
+ *
+ * This member is a function pointer that runs multiple synth
+ * instances for a block, adding each synth's outputs to the
+ * values already present at the output ports. This is provided
+ * for symmetry with both the DSSI run_multiple_synths() and LADSPA
+ * run_adding() functions, and is equally optional. A plugin
+ * that does not provide it must set this member to NULL.
+ */
+ void (*run_multiple_synths_adding)(unsigned long InstanceCount,
+ LADSPA_Handle *Instances,
+ unsigned long SampleCount,
+ snd_seq_event_t **Events,
+ unsigned long *EventCounts);
+
+ /**
+ * set_custom_data()
+ */
+ int (*set_custom_data)(LADSPA_Handle Instance,
+ void *Data,
+ unsigned long DataLength);
+
+ /**
+ * get_custom_data()
+ */
+ int (*get_custom_data)(LADSPA_Handle Instance,
+ void **Data,
+ unsigned long *DataLength);
+
+} DSSI_Descriptor;
+
+/**
+ * DSSI supports a plugin discovery method similar to that of LADSPA:
+ *
+ * - DSSI hosts may wish to locate DSSI plugin shared object files by
+ * searching the paths contained in the DSSI_PATH and LADSPA_PATH
+ * environment variables, if they are present. Both are expected
+ * to be colon-separated lists of directories to be searched (in
+ * order), and DSSI_PATH should be searched first if both variables
+ * are set.
+ *
+ * - Each shared object file containing DSSI plugins must include a
+ * function dssi_descriptor(), with the following function prototype
+ * and C-style linkage. Hosts may enumerate the plugin types
+ * available in the shared object file by repeatedly calling
+ * this function with successive Index values (beginning from 0),
+ * until a return value of NULL indicates no more plugin types are
+ * available. Each non-NULL return is the DSSI_Descriptor
+ * of a distinct plugin type.
+ */
+
+const DSSI_Descriptor *dssi_descriptor(unsigned long Index);
+
+typedef const DSSI_Descriptor *(*DSSI_Descriptor_Function)(unsigned long Index);
+
+/*
+ * Macros to specify particular MIDI controllers in return values from
+ * get_midi_controller_for_port()
+ */
+
+#define DSSI_CC_BITS 0x20000000
+#define DSSI_NRPN_BITS 0x40000000
+
+#define DSSI_NONE -1
+#define DSSI_CONTROLLER_IS_SET(n) (DSSI_NONE != (n))
+
+#define DSSI_CC(n) (DSSI_CC_BITS | (n))
+#define DSSI_IS_CC(n) (DSSI_CC_BITS & (n))
+#define DSSI_CC_NUMBER(n) ((n) & 0x7f)
+
+#define DSSI_NRPN(n) (DSSI_NRPN_BITS | ((n) << 7))
+#define DSSI_IS_NRPN(n) (DSSI_NRPN_BITS & (n))
+#define DSSI_NRPN_NUMBER(n) (((n) >> 7) & 0x3fff)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DSSI_INCLUDED */
diff --git a/distrho/src/dssi/seq_event-compat.h b/distrho/src/dssi/seq_event-compat.h
@@ -0,0 +1,272 @@
+/*
+ * This library 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 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __ALSA_SEQ_EVENT_COMPAT_H
+#define __ALSA_SEQ_EVENT_COMPAT_H
+
+/**
+ * Sequencer event data type
+ */
+typedef unsigned char snd_seq_event_type_t;
+
+/** Sequencer event type */
+enum snd_seq_event_type {
+ /** system status; event data type = #snd_seq_result_t */
+ SND_SEQ_EVENT_SYSTEM = 0,
+ /** returned result status; event data type = #snd_seq_result_t */
+ SND_SEQ_EVENT_RESULT,
+
+ /** note on and off with duration; event data type = #snd_seq_ev_note_t */
+ SND_SEQ_EVENT_NOTE = 5,
+ /** note on; event data type = #snd_seq_ev_note_t */
+ SND_SEQ_EVENT_NOTEON,
+ /** note off; event data type = #snd_seq_ev_note_t */
+ SND_SEQ_EVENT_NOTEOFF,
+ /** key pressure change (aftertouch); event data type = #snd_seq_ev_note_t */
+ SND_SEQ_EVENT_KEYPRESS,
+
+ /** controller; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_CONTROLLER = 10,
+ /** program change; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_PGMCHANGE,
+ /** channel pressure; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_CHANPRESS,
+ /** pitchwheel; event data type = #snd_seq_ev_ctrl_t; data is from -8192 to 8191) */
+ SND_SEQ_EVENT_PITCHBEND,
+ /** 14 bit controller value; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_CONTROL14,
+ /** 14 bit NRPN; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_NONREGPARAM,
+ /** 14 bit RPN; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_REGPARAM,
+
+ /** SPP with LSB and MSB values; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_SONGPOS = 20,
+ /** Song Select with song ID number; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_SONGSEL,
+ /** midi time code quarter frame; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_QFRAME,
+ /** SMF Time Signature event; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_TIMESIGN,
+ /** SMF Key Signature event; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_KEYSIGN,
+
+ /** MIDI Real Time Start message; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_START = 30,
+ /** MIDI Real Time Continue message; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_CONTINUE,
+ /** MIDI Real Time Stop message; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_STOP,
+ /** Set tick queue position; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_SETPOS_TICK,
+ /** Set real-time queue position; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_SETPOS_TIME,
+ /** (SMF) Tempo event; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_TEMPO,
+ /** MIDI Real Time Clock message; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_CLOCK,
+ /** MIDI Real Time Tick message; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_TICK,
+ /** Queue timer skew; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_QUEUE_SKEW,
+ /** Sync position changed; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_SYNC_POS,
+
+ /** Tune request; event data type = none */
+ SND_SEQ_EVENT_TUNE_REQUEST = 40,
+ /** Reset to power-on state; event data type = none */
+ SND_SEQ_EVENT_RESET,
+ /** Active sensing event; event data type = none */
+ SND_SEQ_EVENT_SENSING,
+
+ /** Echo-back event; event data type = any type */
+ SND_SEQ_EVENT_ECHO = 50,
+ /** OSS emulation raw event; event data type = any type */
+ SND_SEQ_EVENT_OSS,
+
+ /** New client has connected; event data type = #snd_seq_addr_t */
+ SND_SEQ_EVENT_CLIENT_START = 60,
+ /** Client has left the system; event data type = #snd_seq_addr_t */
+ SND_SEQ_EVENT_CLIENT_EXIT,
+ /** Client status/info has changed; event data type = #snd_seq_addr_t */
+ SND_SEQ_EVENT_CLIENT_CHANGE,
+ /** New port was created; event data type = #snd_seq_addr_t */
+ SND_SEQ_EVENT_PORT_START,
+ /** Port was deleted from system; event data type = #snd_seq_addr_t */
+ SND_SEQ_EVENT_PORT_EXIT,
+ /** Port status/info has changed; event data type = #snd_seq_addr_t */
+ SND_SEQ_EVENT_PORT_CHANGE,
+
+ /** Ports connected; event data type = #snd_seq_connect_t */
+ SND_SEQ_EVENT_PORT_SUBSCRIBED,
+ /** Ports disconnected; event data type = #snd_seq_connect_t */
+ SND_SEQ_EVENT_PORT_UNSUBSCRIBED,
+
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR0 = 90,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR1,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR2,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR3,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR4,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR5,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR6,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR7,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR8,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR9,
+
+ /** system exclusive data (variable length); event data type = #snd_seq_ev_ext_t */
+ SND_SEQ_EVENT_SYSEX = 130,
+ /** error event; event data type = #snd_seq_ev_ext_t */
+ SND_SEQ_EVENT_BOUNCE,
+ /** reserved for user apps; event data type = #snd_seq_ev_ext_t */
+ SND_SEQ_EVENT_USR_VAR0 = 135,
+ /** reserved for user apps; event data type = #snd_seq_ev_ext_t */
+ SND_SEQ_EVENT_USR_VAR1,
+ /** reserved for user apps; event data type = #snd_seq_ev_ext_t */
+ SND_SEQ_EVENT_USR_VAR2,
+ /** reserved for user apps; event data type = #snd_seq_ev_ext_t */
+ SND_SEQ_EVENT_USR_VAR3,
+ /** reserved for user apps; event data type = #snd_seq_ev_ext_t */
+ SND_SEQ_EVENT_USR_VAR4,
+
+ /** NOP; ignored in any case */
+ SND_SEQ_EVENT_NONE = 255
+};
+
+/** Sequencer event address */
+typedef struct snd_seq_addr {
+ unsigned char client; /**< Client id */
+ unsigned char port; /**< Port id */
+} snd_seq_addr_t;
+
+/** Connection (subscription) between ports */
+typedef struct snd_seq_connect {
+ snd_seq_addr_t sender; /**< sender address */
+ snd_seq_addr_t dest; /**< destination address */
+} snd_seq_connect_t;
+
+/** Real-time data record */
+typedef struct snd_seq_real_time {
+ unsigned int tv_sec; /**< seconds */
+ unsigned int tv_nsec; /**< nanoseconds */
+} snd_seq_real_time_t;
+
+/** (MIDI) Tick-time data record */
+typedef unsigned int snd_seq_tick_time_t;
+
+/** unioned time stamp */
+typedef union snd_seq_timestamp {
+ snd_seq_tick_time_t tick; /**< tick-time */
+ struct snd_seq_real_time time; /**< real-time */
+} snd_seq_timestamp_t;
+
+/** Note event */
+typedef struct snd_seq_ev_note {
+ unsigned char channel; /**< channel number */
+ unsigned char note; /**< note */
+ unsigned char velocity; /**< velocity */
+ unsigned char off_velocity; /**< note-off velocity; only for #SND_SEQ_EVENT_NOTE */
+ unsigned int duration; /**< duration until note-off; only for #SND_SEQ_EVENT_NOTE */
+} snd_seq_ev_note_t;
+
+/** Controller event */
+typedef struct snd_seq_ev_ctrl {
+ unsigned char channel; /**< channel number */
+ unsigned char unused[3]; /**< reserved */
+ unsigned int param; /**< control parameter */
+ signed int value; /**< control value */
+} snd_seq_ev_ctrl_t;
+
+/** generic set of bytes (12x8 bit) */
+typedef struct snd_seq_ev_raw8 {
+ unsigned char d[12]; /**< 8 bit value */
+} snd_seq_ev_raw8_t;
+
+/** generic set of integers (3x32 bit) */
+typedef struct snd_seq_ev_raw32 {
+ unsigned int d[3]; /**< 32 bit value */
+} snd_seq_ev_raw32_t;
+
+/** external stored data */
+typedef struct snd_seq_ev_ext {
+ unsigned int len; /**< length of data */
+ void *ptr; /**< pointer to data (note: can be 64-bit) */
+} __attribute__((packed)) snd_seq_ev_ext_t;
+
+/** Result events */
+typedef struct snd_seq_result {
+ int event; /**< processed event type */
+ int result; /**< status */
+} snd_seq_result_t;
+
+/** Queue skew values */
+typedef struct snd_seq_queue_skew {
+ unsigned int value; /**< skew value */
+ unsigned int base; /**< skew base */
+} snd_seq_queue_skew_t;
+
+/** queue timer control */
+typedef struct snd_seq_ev_queue_control {
+ unsigned char queue; /**< affected queue */
+ unsigned char unused[3]; /**< reserved */
+ union {
+ signed int value; /**< affected value (e.g. tempo) */
+ snd_seq_timestamp_t time; /**< time */
+ unsigned int position; /**< sync position */
+ snd_seq_queue_skew_t skew; /**< queue skew */
+ unsigned int d32[2]; /**< any data */
+ unsigned char d8[8]; /**< any data */
+ } param; /**< data value union */
+} snd_seq_ev_queue_control_t;
+
+/** Sequencer event */
+typedef struct snd_seq_event {
+ snd_seq_event_type_t type; /**< event type */
+ unsigned char flags; /**< event flags */
+ unsigned char tag; /**< tag */
+
+ unsigned char queue; /**< schedule queue */
+ snd_seq_timestamp_t time; /**< schedule time */
+
+ snd_seq_addr_t source; /**< source address */
+ snd_seq_addr_t dest; /**< destination address */
+
+ union {
+ snd_seq_ev_note_t note; /**< note information */
+ snd_seq_ev_ctrl_t control; /**< MIDI control information */
+ snd_seq_ev_raw8_t raw8; /**< raw8 data */
+ snd_seq_ev_raw32_t raw32; /**< raw32 data */
+ snd_seq_ev_ext_t ext; /**< external data */
+ snd_seq_ev_queue_control_t queue; /**< queue control */
+ snd_seq_timestamp_t time; /**< timestamp */
+ snd_seq_addr_t addr; /**< address */
+ snd_seq_connect_t connect; /**< connect information */
+ snd_seq_result_t result; /**< operation result code */
+ } data; /**< event data... */
+} snd_seq_event_t;
+
+#endif /* __ALSA_SEQ_EVENT_COMPAT_H */
+
diff --git a/distrho/src/ladspa/ladspa.h b/distrho/src/ladspa/ladspa.h
@@ -0,0 +1,603 @@
+/* ladspa.h
+
+ Linux Audio Developer's Simple Plugin API Version 1.1[LGPL].
+ Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis,
+ Stefan Westerfeld.
+
+ This library 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 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA. */
+
+#ifndef LADSPA_INCLUDED
+#define LADSPA_INCLUDED
+
+#define LADSPA_VERSION "1.1"
+#define LADSPA_VERSION_MAJOR 1
+#define LADSPA_VERSION_MINOR 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+/* Overview:
+
+ There is a large number of synthesis packages in use or development
+ on the Linux platform at this time. This API (`The Linux Audio
+ Developer's Simple Plugin API') attempts to give programmers the
+ ability to write simple `plugin' audio processors in C/C++ and link
+ them dynamically (`plug') into a range of these packages (`hosts').
+ It should be possible for any host and any plugin to communicate
+ completely through this interface.
+
+ This API is deliberately short and simple. To achieve compatibility
+ with a range of promising Linux sound synthesis packages it
+ attempts to find the `greatest common divisor' in their logical
+ behaviour. Having said this, certain limiting decisions are
+ implicit, notably the use of a fixed type (LADSPA_Data) for all
+ data transfer and absence of a parameterised `initialisation'
+ phase. See below for the LADSPA_Data typedef.
+
+ Plugins are expected to distinguish between control and audio
+ data. Plugins have `ports' that are inputs or outputs for audio or
+ control data and each plugin is `run' for a `block' corresponding
+ to a short time interval measured in samples. Audio data is
+ communicated using arrays of LADSPA_Data, allowing a block of audio
+ to be processed by the plugin in a single pass. Control data is
+ communicated using single LADSPA_Data values. Control data has a
+ single value at the start of a call to the `run()' or `run_adding()'
+ function, and may be considered to remain this value for its
+ duration. The plugin may assume that all its input and output ports
+ have been connected to the relevant data location (see the
+ `connect_port()' function below) before it is asked to run.
+
+ Plugins will reside in shared object files suitable for dynamic
+ linking by dlopen() and family. The file will provide a number of
+ `plugin types' that can be used to instantiate actual plugins
+ (sometimes known as `plugin instances') that can be connected
+ together to perform tasks.
+
+ This API contains very limited error-handling. */
+
+/*****************************************************************************/
+
+/* Fundamental data type passed in and out of plugin. This data type
+ is used to communicate audio samples and control values. It is
+ assumed that the plugin will work sensibly given any numeric input
+ value although it may have a preferred range (see hints below).
+
+ For audio it is generally assumed that 1.0f is the `0dB' reference
+ amplitude and is a `normal' signal level. */
+
+typedef float LADSPA_Data;
+
+/*****************************************************************************/
+
+/* Special Plugin Properties:
+
+ Optional features of the plugin type are encapsulated in the
+ LADSPA_Properties type. This is assembled by ORing individual
+ properties together. */
+
+typedef int LADSPA_Properties;
+
+/* Property LADSPA_PROPERTY_REALTIME indicates that the plugin has a
+ real-time dependency (e.g. listens to a MIDI device) and so its
+ output must not be cached or subject to significant latency. */
+#define LADSPA_PROPERTY_REALTIME 0x1
+
+/* Property LADSPA_PROPERTY_INPLACE_BROKEN indicates that the plugin
+ may cease to work correctly if the host elects to use the same data
+ location for both input and output (see connect_port()). This
+ should be avoided as enabling this flag makes it impossible for
+ hosts to use the plugin to process audio `in-place.' */
+#define LADSPA_PROPERTY_INPLACE_BROKEN 0x2
+
+/* Property LADSPA_PROPERTY_HARD_RT_CAPABLE indicates that the plugin
+ is capable of running not only in a conventional host but also in a
+ `hard real-time' environment. To qualify for this the plugin must
+ satisfy all of the following:
+
+ (1) The plugin must not use malloc(), free() or other heap memory
+ management within its run() or run_adding() functions. All new
+ memory used in run() must be managed via the stack. These
+ restrictions only apply to the run() function.
+
+ (2) The plugin will not attempt to make use of any library
+ functions with the exceptions of functions in the ANSI standard C
+ and C maths libraries, which the host is expected to provide.
+
+ (3) The plugin will not access files, devices, pipes, sockets, IPC
+ or any other mechanism that might result in process or thread
+ blocking.
+
+ (4) The plugin will take an amount of time to execute a run() or
+ run_adding() call approximately of form (A+B*SampleCount) where A
+ and B depend on the machine and host in use. This amount of time
+ may not depend on input signals or plugin state. The host is left
+ the responsibility to perform timings to estimate upper bounds for
+ A and B. */
+#define LADSPA_PROPERTY_HARD_RT_CAPABLE 0x4
+
+#define LADSPA_IS_REALTIME(x) ((x) & LADSPA_PROPERTY_REALTIME)
+#define LADSPA_IS_INPLACE_BROKEN(x) ((x) & LADSPA_PROPERTY_INPLACE_BROKEN)
+#define LADSPA_IS_HARD_RT_CAPABLE(x) ((x) & LADSPA_PROPERTY_HARD_RT_CAPABLE)
+
+/*****************************************************************************/
+
+/* Plugin Ports:
+
+ Plugins have `ports' that are inputs or outputs for audio or
+ data. Ports can communicate arrays of LADSPA_Data (for audio
+ inputs/outputs) or single LADSPA_Data values (for control
+ input/outputs). This information is encapsulated in the
+ LADSPA_PortDescriptor type which is assembled by ORing individual
+ properties together.
+
+ Note that a port must be an input or an output port but not both
+ and that a port must be a control or audio port but not both. */
+
+typedef int LADSPA_PortDescriptor;
+
+/* Property LADSPA_PORT_INPUT indicates that the port is an input. */
+#define LADSPA_PORT_INPUT 0x1
+
+/* Property LADSPA_PORT_OUTPUT indicates that the port is an output. */
+#define LADSPA_PORT_OUTPUT 0x2
+
+/* Property LADSPA_PORT_CONTROL indicates that the port is a control
+ port. */
+#define LADSPA_PORT_CONTROL 0x4
+
+/* Property LADSPA_PORT_AUDIO indicates that the port is a audio
+ port. */
+#define LADSPA_PORT_AUDIO 0x8
+
+#define LADSPA_IS_PORT_INPUT(x) ((x) & LADSPA_PORT_INPUT)
+#define LADSPA_IS_PORT_OUTPUT(x) ((x) & LADSPA_PORT_OUTPUT)
+#define LADSPA_IS_PORT_CONTROL(x) ((x) & LADSPA_PORT_CONTROL)
+#define LADSPA_IS_PORT_AUDIO(x) ((x) & LADSPA_PORT_AUDIO)
+
+/*****************************************************************************/
+
+/* Plugin Port Range Hints:
+
+ The host may wish to provide a representation of data entering or
+ leaving a plugin (e.g. to generate a GUI automatically). To make
+ this more meaningful, the plugin should provide `hints' to the host
+ describing the usual values taken by the data.
+
+ Note that these are only hints. The host may ignore them and the
+ plugin must not assume that data supplied to it is meaningful. If
+ the plugin receives invalid input data it is expected to continue
+ to run without failure and, where possible, produce a sensible
+ output (e.g. a high-pass filter given a negative cutoff frequency
+ might switch to an all-pass mode).
+
+ Hints are meaningful for all input and output ports but hints for
+ input control ports are expected to be particularly useful.
+
+ More hint information is encapsulated in the
+ LADSPA_PortRangeHintDescriptor type which is assembled by ORing
+ individual hint types together. Hints may require further
+ LowerBound and UpperBound information.
+
+ All the hint information for a particular port is aggregated in the
+ LADSPA_PortRangeHint structure. */
+
+typedef int LADSPA_PortRangeHintDescriptor;
+
+/* Hint LADSPA_HINT_BOUNDED_BELOW indicates that the LowerBound field
+ of the LADSPA_PortRangeHint should be considered meaningful. The
+ value in this field should be considered the (inclusive) lower
+ bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also
+ specified then the value of LowerBound should be multiplied by the
+ sample rate. */
+#define LADSPA_HINT_BOUNDED_BELOW 0x1
+
+/* Hint LADSPA_HINT_BOUNDED_ABOVE indicates that the UpperBound field
+ of the LADSPA_PortRangeHint should be considered meaningful. The
+ value in this field should be considered the (inclusive) upper
+ bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also
+ specified then the value of UpperBound should be multiplied by the
+ sample rate. */
+#define LADSPA_HINT_BOUNDED_ABOVE 0x2
+
+/* Hint LADSPA_HINT_TOGGLED indicates that the data item should be
+ considered a Boolean toggle. Data less than or equal to zero should
+ be considered `off' or `false,' and data above zero should be
+ considered `on' or `true.' LADSPA_HINT_TOGGLED may not be used in
+ conjunction with any other hint except LADSPA_HINT_DEFAULT_0 or
+ LADSPA_HINT_DEFAULT_1. */
+#define LADSPA_HINT_TOGGLED 0x4
+
+/* Hint LADSPA_HINT_SAMPLE_RATE indicates that any bounds specified
+ should be interpreted as multiples of the sample rate. For
+ instance, a frequency range from 0Hz to the Nyquist frequency (half
+ the sample rate) could be requested by this hint in conjunction
+ with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds
+ at all must support this hint to retain meaning. */
+#define LADSPA_HINT_SAMPLE_RATE 0x8
+
+/* Hint LADSPA_HINT_LOGARITHMIC indicates that it is likely that the
+ user will find it more intuitive to view values using a logarithmic
+ scale. This is particularly useful for frequencies and gains. */
+#define LADSPA_HINT_LOGARITHMIC 0x10
+
+/* Hint LADSPA_HINT_INTEGER indicates that a user interface would
+ probably wish to provide a stepped control taking only integer
+ values. Any bounds set should be slightly wider than the actual
+ integer range required to avoid floating point rounding errors. For
+ instance, the integer set {0,1,2,3} might be described as [-0.1,
+ 3.1]. */
+#define LADSPA_HINT_INTEGER 0x20
+
+/* The various LADSPA_HINT_HAS_DEFAULT_* hints indicate a `normal'
+ value for the port that is sensible as a default. For instance,
+ this value is suitable for use as an initial value in a user
+ interface or as a value the host might assign to a control port
+ when the user has not provided one. Defaults are encoded using a
+ mask so only one default may be specified for a port. Some of the
+ hints make use of lower and upper bounds, in which case the
+ relevant bound or bounds must be available and
+ LADSPA_HINT_SAMPLE_RATE must be applied as usual. The resulting
+ default must be rounded if LADSPA_HINT_INTEGER is present. Default
+ values were introduced in LADSPA v1.1. */
+#define LADSPA_HINT_DEFAULT_MASK 0x3C0
+
+/* This default values indicates that no default is provided. */
+#define LADSPA_HINT_DEFAULT_NONE 0x0
+
+/* This default hint indicates that the suggested lower bound for the
+ port should be used. */
+#define LADSPA_HINT_DEFAULT_MINIMUM 0x40
+
+/* This default hint indicates that a low value between the suggested
+ lower and upper bounds should be chosen. For ports with
+ LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.75 +
+ log(upper) * 0.25). Otherwise, this should be (lower * 0.75 + upper
+ * 0.25). */
+#define LADSPA_HINT_DEFAULT_LOW 0x80
+
+/* This default hint indicates that a middle value between the
+ suggested lower and upper bounds should be chosen. For ports with
+ LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.5 +
+ log(upper) * 0.5). Otherwise, this should be (lower * 0.5 + upper *
+ 0.5). */
+#define LADSPA_HINT_DEFAULT_MIDDLE 0xC0
+
+/* This default hint indicates that a high value between the suggested
+ lower and upper bounds should be chosen. For ports with
+ LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.25 +
+ log(upper) * 0.75). Otherwise, this should be (lower * 0.25 + upper
+ * 0.75). */
+#define LADSPA_HINT_DEFAULT_HIGH 0x100
+
+/* This default hint indicates that the suggested upper bound for the
+ port should be used. */
+#define LADSPA_HINT_DEFAULT_MAXIMUM 0x140
+
+/* This default hint indicates that the number 0 should be used. Note
+ that this default may be used in conjunction with
+ LADSPA_HINT_TOGGLED. */
+#define LADSPA_HINT_DEFAULT_0 0x200
+
+/* This default hint indicates that the number 1 should be used. Note
+ that this default may be used in conjunction with
+ LADSPA_HINT_TOGGLED. */
+#define LADSPA_HINT_DEFAULT_1 0x240
+
+/* This default hint indicates that the number 100 should be used. */
+#define LADSPA_HINT_DEFAULT_100 0x280
+
+/* This default hint indicates that the Hz frequency of `concert A'
+ should be used. This will be 440 unless the host uses an unusual
+ tuning convention, in which case it may be within a few Hz. */
+#define LADSPA_HINT_DEFAULT_440 0x2C0
+
+#define LADSPA_IS_HINT_BOUNDED_BELOW(x) ((x) & LADSPA_HINT_BOUNDED_BELOW)
+#define LADSPA_IS_HINT_BOUNDED_ABOVE(x) ((x) & LADSPA_HINT_BOUNDED_ABOVE)
+#define LADSPA_IS_HINT_TOGGLED(x) ((x) & LADSPA_HINT_TOGGLED)
+#define LADSPA_IS_HINT_SAMPLE_RATE(x) ((x) & LADSPA_HINT_SAMPLE_RATE)
+#define LADSPA_IS_HINT_LOGARITHMIC(x) ((x) & LADSPA_HINT_LOGARITHMIC)
+#define LADSPA_IS_HINT_INTEGER(x) ((x) & LADSPA_HINT_INTEGER)
+
+#define LADSPA_IS_HINT_HAS_DEFAULT(x) ((x) & LADSPA_HINT_DEFAULT_MASK)
+#define LADSPA_IS_HINT_DEFAULT_MINIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_MINIMUM)
+#define LADSPA_IS_HINT_DEFAULT_LOW(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_LOW)
+#define LADSPA_IS_HINT_DEFAULT_MIDDLE(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_MIDDLE)
+#define LADSPA_IS_HINT_DEFAULT_HIGH(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_HIGH)
+#define LADSPA_IS_HINT_DEFAULT_MAXIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_MAXIMUM)
+#define LADSPA_IS_HINT_DEFAULT_0(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_0)
+#define LADSPA_IS_HINT_DEFAULT_1(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_1)
+#define LADSPA_IS_HINT_DEFAULT_100(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_100)
+#define LADSPA_IS_HINT_DEFAULT_440(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_440)
+
+typedef struct _LADSPA_PortRangeHint {
+
+ /* Hints about the port. */
+ LADSPA_PortRangeHintDescriptor HintDescriptor;
+
+ /* Meaningful when hint LADSPA_HINT_BOUNDED_BELOW is active. When
+ LADSPA_HINT_SAMPLE_RATE is also active then this value should be
+ multiplied by the relevant sample rate. */
+ LADSPA_Data LowerBound;
+
+ /* Meaningful when hint LADSPA_HINT_BOUNDED_ABOVE is active. When
+ LADSPA_HINT_SAMPLE_RATE is also active then this value should be
+ multiplied by the relevant sample rate. */
+ LADSPA_Data UpperBound;
+
+} LADSPA_PortRangeHint;
+
+/*****************************************************************************/
+
+/* Plugin Handles:
+
+ This plugin handle indicates a particular instance of the plugin
+ concerned. It is valid to compare this to NULL (0 for C++) but
+ otherwise the host should not attempt to interpret it. The plugin
+ may use it to reference internal instance data. */
+
+typedef void * LADSPA_Handle;
+
+/*****************************************************************************/
+
+/* Descriptor for a Type of Plugin:
+
+ This structure is used to describe a plugin type. It provides a
+ number of functions to examine the type, instantiate it, link it to
+ buffers and workspaces and to run it. */
+
+typedef struct _LADSPA_Descriptor {
+
+ /* This numeric identifier indicates the plugin type
+ uniquely. Plugin programmers may reserve ranges of IDs from a
+ central body to avoid clashes. Hosts may assume that IDs are
+ below 0x1000000. */
+ unsigned long UniqueID;
+
+ /* This identifier can be used as a unique, case-sensitive
+ identifier for the plugin type within the plugin file. Plugin
+ types should be identified by file and label rather than by index
+ or plugin name, which may be changed in new plugin
+ versions. Labels must not contain white-space characters. */
+ const char * Label;
+
+ /* This indicates a number of properties of the plugin. */
+ LADSPA_Properties Properties;
+
+ /* This member points to the null-terminated name of the plugin
+ (e.g. "Sine Oscillator"). */
+ const char * Name;
+
+ /* This member points to the null-terminated string indicating the
+ maker of the plugin. This can be an empty string but not NULL. */
+ const char * Maker;
+
+ /* This member points to the null-terminated string indicating any
+ copyright applying to the plugin. If no Copyright applies the
+ string "None" should be used. */
+ const char * Copyright;
+
+ /* This indicates the number of ports (input AND output) present on
+ the plugin. */
+ unsigned long PortCount;
+
+ /* This member indicates an array of port descriptors. Valid indices
+ vary from 0 to PortCount-1. */
+ const LADSPA_PortDescriptor * PortDescriptors;
+
+ /* This member indicates an array of null-terminated strings
+ describing ports (e.g. "Frequency (Hz)"). Valid indices vary from
+ 0 to PortCount-1. */
+ const char * const * PortNames;
+
+ /* This member indicates an array of range hints for each port (see
+ above). Valid indices vary from 0 to PortCount-1. */
+ const LADSPA_PortRangeHint * PortRangeHints;
+
+ /* This may be used by the plugin developer to pass any custom
+ implementation data into an instantiate call. It must not be used
+ or interpreted by the host. It is expected that most plugin
+ writers will not use this facility as LADSPA_Handle should be
+ used to hold instance data. */
+ void * ImplementationData;
+
+ /* This member is a function pointer that instantiates a plugin. A
+ handle is returned indicating the new plugin instance. The
+ instantiation function accepts a sample rate as a parameter. The
+ plugin descriptor from which this instantiate function was found
+ must also be passed. This function must return NULL if
+ instantiation fails.
+
+ Note that instance initialisation should generally occur in
+ activate() rather than here. */
+ LADSPA_Handle (*instantiate)(const struct _LADSPA_Descriptor * Descriptor,
+ unsigned long SampleRate);
+
+ /* This member is a function pointer that connects a port on an
+ instantiated plugin to a memory location at which a block of data
+ for the port will be read/written. The data location is expected
+ to be an array of LADSPA_Data for audio ports or a single
+ LADSPA_Data value for control ports. Memory issues will be
+ managed by the host. The plugin must read/write the data at these
+ locations every time run() or run_adding() is called and the data
+ present at the time of this connection call should not be
+ considered meaningful.
+
+ connect_port() may be called more than once for a plugin instance
+ to allow the host to change the buffers that the plugin is
+ reading or writing. These calls may be made before or after
+ activate() or deactivate() calls.
+
+ connect_port() must be called at least once for each port before
+ run() or run_adding() is called. When working with blocks of
+ LADSPA_Data the plugin should pay careful attention to the block
+ size passed to the run function as the block allocated may only
+ just be large enough to contain the block of samples.
+
+ Plugin writers should be aware that the host may elect to use the
+ same buffer for more than one port and even use the same buffer
+ for both input and output (see LADSPA_PROPERTY_INPLACE_BROKEN).
+ However, overlapped buffers or use of a single buffer for both
+ audio and control data may result in unexpected behaviour. */
+ void (*connect_port)(LADSPA_Handle Instance,
+ unsigned long Port,
+ LADSPA_Data * DataLocation);
+
+ /* This member is a function pointer that initialises a plugin
+ instance and activates it for use. This is separated from
+ instantiate() to aid real-time support and so that hosts can
+ reinitialise a plugin instance by calling deactivate() and then
+ activate(). In this case the plugin instance must reset all state
+ information dependent on the history of the plugin instance
+ except for any data locations provided by connect_port() and any
+ gain set by set_run_adding_gain(). If there is nothing for
+ activate() to do then the plugin writer may provide a NULL rather
+ than an empty function.
+
+ When present, hosts must call this function once before run() (or
+ run_adding()) is called for the first time. This call should be
+ made as close to the run() call as possible and indicates to
+ real-time plugins that they are now live. Plugins should not rely
+ on a prompt call to run() after activate(). activate() may not be
+ called again unless deactivate() is called first. Note that
+ connect_port() may be called before or after a call to
+ activate(). */
+ void (*activate)(LADSPA_Handle Instance);
+
+ /* This method is a function pointer that runs an instance of a
+ plugin for a block. Two parameters are required: the first is a
+ handle to the particular instance to be run and the second
+ indicates the block size (in samples) for which the plugin
+ instance may run.
+
+ Note that if an activate() function exists then it must be called
+ before run() or run_adding(). If deactivate() is called for a
+ plugin instance then the plugin instance may not be reused until
+ activate() has been called again.
+
+ If the plugin has the property LADSPA_PROPERTY_HARD_RT_CAPABLE
+ then there are various things that the plugin should not do
+ within the run() or run_adding() functions (see above). */
+ void (*run)(LADSPA_Handle Instance,
+ unsigned long SampleCount);
+
+ /* This method is a function pointer that runs an instance of a
+ plugin for a block. This has identical behaviour to run() except
+ in the way data is output from the plugin. When run() is used,
+ values are written directly to the memory areas associated with
+ the output ports. However when run_adding() is called, values
+ must be added to the values already present in the memory
+ areas. Furthermore, output values written must be scaled by the
+ current gain set by set_run_adding_gain() (see below) before
+ addition.
+
+ run_adding() is optional. When it is not provided by a plugin,
+ this function pointer must be set to NULL. When it is provided,
+ the function set_run_adding_gain() must be provided also. */
+ void (*run_adding)(LADSPA_Handle Instance,
+ unsigned long SampleCount);
+
+ /* This method is a function pointer that sets the output gain for
+ use when run_adding() is called (see above). If this function is
+ never called the gain is assumed to default to 1. Gain
+ information should be retained when activate() or deactivate()
+ are called.
+
+ This function should be provided by the plugin if and only if the
+ run_adding() function is provided. When it is absent this
+ function pointer must be set to NULL. */
+ void (*set_run_adding_gain)(LADSPA_Handle Instance,
+ LADSPA_Data Gain);
+
+ /* This is the counterpart to activate() (see above). If there is
+ nothing for deactivate() to do then the plugin writer may provide
+ a NULL rather than an empty function.
+
+ Hosts must deactivate all activated units after they have been
+ run() (or run_adding()) for the last time. This call should be
+ made as close to the last run() call as possible and indicates to
+ real-time plugins that they are no longer live. Plugins should
+ not rely on prompt deactivation. Note that connect_port() may be
+ called before or after a call to deactivate().
+
+ Deactivation is not similar to pausing as the plugin instance
+ will be reinitialised when activate() is called to reuse it. */
+ void (*deactivate)(LADSPA_Handle Instance);
+
+ /* Once an instance of a plugin has been finished with it can be
+ deleted using the following function. The instance handle passed
+ ceases to be valid after this call.
+
+ If activate() was called for a plugin instance then a
+ corresponding call to deactivate() must be made before cleanup()
+ is called. */
+ void (*cleanup)(LADSPA_Handle Instance);
+
+} LADSPA_Descriptor;
+
+/**********************************************************************/
+
+/* Accessing a Plugin: */
+
+/* The exact mechanism by which plugins are loaded is host-dependent,
+ however all most hosts will need to know is the name of shared
+ object file containing the plugin types. To allow multiple hosts to
+ share plugin types, hosts may wish to check for environment
+ variable LADSPA_PATH. If present, this should contain a
+ colon-separated path indicating directories that should be searched
+ (in order) when loading plugin types.
+
+ A plugin programmer must include a function called
+ "ladspa_descriptor" with the following function prototype within
+ the shared object file. This function will have C-style linkage (if
+ you are using C++ this is taken care of by the `extern "C"' clause
+ at the top of the file).
+
+ A host will find the plugin shared object file by one means or
+ another, find the ladspa_descriptor() function, call it, and
+ proceed from there.
+
+ Plugin types are accessed by index (not ID) using values from 0
+ upwards. Out of range indexes must result in this function
+ returning NULL, so the plugin count can be determined by checking
+ for the least index that results in NULL being returned. */
+
+const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index);
+
+/* Datatype corresponding to the ladspa_descriptor() function. */
+typedef const LADSPA_Descriptor *
+(*LADSPA_Descriptor_Function)(unsigned long Index);
+
+/**********************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LADSPA_INCLUDED */
+
+/* EOF */
diff --git a/distrho/src/lv2/atom-forge.h b/distrho/src/lv2/atom-forge.h
@@ -0,0 +1,619 @@
+/*
+ Copyright 2008-2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file forge.h An API for constructing LV2 atoms.
+
+ This file provides an API for constructing Atoms which makes it relatively
+ simple to build nested atoms of arbitrary complexity without requiring
+ dynamic memory allocation.
+
+ The API is based on successively appending the appropriate pieces to build a
+ complete Atom. The size of containers is automatically updated. Functions
+ that begin a container return (via their frame argument) a stack frame which
+ must be popped when the container is finished.
+
+ All output is written to a user-provided buffer or sink function. This
+ makes it popssible to create create atoms on the stack, on the heap, in LV2
+ port buffers, in a ringbuffer, or elsewhere, all using the same API.
+
+ This entire API is realtime safe if used with a buffer or a realtime safe
+ sink, except lv2_atom_forge_init() which is only realtime safe if the URI
+ map function is.
+
+ Note these functions are all static inline, do not take their address.
+
+ This header is non-normative, it is provided for convenience.
+*/
+
+#ifndef LV2_ATOM_FORGE_H
+#define LV2_ATOM_FORGE_H
+
+#include <assert.h>
+
+#include "atom.h"
+#include "atom-util.h"
+#include "urid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#else
+# include <stdbool.h>
+#endif
+
+/** Handle for LV2_Atom_Forge_Sink. */
+typedef void* LV2_Atom_Forge_Sink_Handle;
+
+/** A reference to a chunk of written output. */
+typedef intptr_t LV2_Atom_Forge_Ref;
+
+/** Sink function for writing output. See lv2_atom_forge_set_sink(). */
+typedef LV2_Atom_Forge_Ref
+(*LV2_Atom_Forge_Sink)(LV2_Atom_Forge_Sink_Handle handle,
+ const void* buf,
+ uint32_t size);
+
+/** Function for resolving a reference. See lv2_atom_forge_set_sink(). */
+typedef LV2_Atom*
+(*LV2_Atom_Forge_Deref_Func)(LV2_Atom_Forge_Sink_Handle handle,
+ LV2_Atom_Forge_Ref ref);
+
+/** A stack frame used for keeping track of nested Atom containers. */
+typedef struct _LV2_Atom_Forge_Frame {
+ struct _LV2_Atom_Forge_Frame* parent;
+ LV2_Atom_Forge_Ref ref;
+} LV2_Atom_Forge_Frame;
+
+/** A "forge" for creating atoms by appending to a buffer. */
+typedef struct {
+ uint8_t* buf;
+ uint32_t offset;
+ uint32_t size;
+
+ LV2_Atom_Forge_Sink sink;
+ LV2_Atom_Forge_Deref_Func deref;
+ LV2_Atom_Forge_Sink_Handle handle;
+
+ LV2_Atom_Forge_Frame* stack;
+
+ LV2_URID Blank;
+ LV2_URID Bool;
+ LV2_URID Chunk;
+ LV2_URID Double;
+ LV2_URID Float;
+ LV2_URID Int;
+ LV2_URID Long;
+ LV2_URID Literal;
+ LV2_URID Path;
+ LV2_URID Property;
+ LV2_URID Resource;
+ LV2_URID Sequence;
+ LV2_URID String;
+ LV2_URID Tuple;
+ LV2_URID URI;
+ LV2_URID URID;
+ LV2_URID Vector;
+} LV2_Atom_Forge;
+
+static inline void
+lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size);
+
+/**
+ Initialise @p forge.
+
+ URIs will be mapped using @p map and stored, a reference to @p map itself is
+ not held.
+*/
+static inline void
+lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map)
+{
+ lv2_atom_forge_set_buffer(forge, NULL, 0);
+ forge->Blank = map->map(map->handle, LV2_ATOM__Blank);
+ forge->Bool = map->map(map->handle, LV2_ATOM__Bool);
+ forge->Chunk = map->map(map->handle, LV2_ATOM__Chunk);
+ forge->Double = map->map(map->handle, LV2_ATOM__Double);
+ forge->Float = map->map(map->handle, LV2_ATOM__Float);
+ forge->Int = map->map(map->handle, LV2_ATOM__Int);
+ forge->Long = map->map(map->handle, LV2_ATOM__Long);
+ forge->Literal = map->map(map->handle, LV2_ATOM__Literal);
+ forge->Path = map->map(map->handle, LV2_ATOM__Path);
+ forge->Property = map->map(map->handle, LV2_ATOM__Property);
+ forge->Resource = map->map(map->handle, LV2_ATOM__Resource);
+ forge->Sequence = map->map(map->handle, LV2_ATOM__Sequence);
+ forge->String = map->map(map->handle, LV2_ATOM__String);
+ forge->Tuple = map->map(map->handle, LV2_ATOM__Tuple);
+ forge->URI = map->map(map->handle, LV2_ATOM__URI);
+ forge->URID = map->map(map->handle, LV2_ATOM__URID);
+ forge->Vector = map->map(map->handle, LV2_ATOM__Vector);
+}
+
+static inline LV2_Atom*
+lv2_atom_forge_deref(LV2_Atom_Forge* forge, LV2_Atom_Forge_Ref ref)
+{
+ if (forge->buf) {
+ return (LV2_Atom*)ref;
+ } else {
+ return forge->deref(forge->handle, ref);
+ }
+}
+
+/**
+ @name Object Stack
+ @{
+*/
+
+/**
+ Push a stack frame.
+ This is done automatically by container functions (which take a stack frame
+ pointer), but may be called by the user to push the top level container when
+ writing to an existing Atom.
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_push(LV2_Atom_Forge* forge,
+ LV2_Atom_Forge_Frame* frame,
+ LV2_Atom_Forge_Ref ref)
+{
+ frame->parent = forge->stack;
+ frame->ref = ref;
+ forge->stack = frame;
+ return ref;
+}
+
+/** Pop a stack frame. This must be called when a container is finished. */
+static inline void
+lv2_atom_forge_pop(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
+{
+ assert(frame == forge->stack);
+ forge->stack = frame->parent;
+}
+
+/** Return true iff the top of the stack has the given type. */
+static inline bool
+lv2_atom_forge_top_is(LV2_Atom_Forge* forge, uint32_t type)
+{
+ return forge->stack &&
+ lv2_atom_forge_deref(forge, forge->stack->ref)->type == type;
+}
+
+/**
+ @}
+ @name Output Configuration
+ @{
+*/
+
+/** Set the output buffer where @p forge will write atoms. */
+static inline void
+lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size)
+{
+ forge->buf = buf;
+ forge->size = size;
+ forge->offset = 0;
+ forge->deref = NULL;
+ forge->sink = NULL;
+ forge->handle = NULL;
+ forge->stack = NULL;
+}
+
+/**
+ Set the sink function where @p forge will write output.
+
+ The return value of forge functions is an LV2_Atom_Forge_Ref which is an
+ integer type safe to use as a pointer but is otherwise opaque. The sink
+ function must return a ref that can be dereferenced to access as least
+ sizeof(LV2_Atom) bytes of the written data, so sizes can be updated. For
+ ringbuffers, this should be possible as long as the size of the buffer is a
+ multiple of sizeof(LV2_Atom), since atoms are always aligned.
+
+ Note that 0 is an invalid reference, so if you are using a buffer offset be
+ sure to offset it such that 0 is never a valid reference. You will get
+ confusing errors otherwise.
+*/
+static inline void
+lv2_atom_forge_set_sink(LV2_Atom_Forge* forge,
+ LV2_Atom_Forge_Sink sink,
+ LV2_Atom_Forge_Deref_Func deref,
+ LV2_Atom_Forge_Sink_Handle handle)
+{
+ forge->buf = NULL;
+ forge->size = forge->offset = 0;
+ forge->deref = deref;
+ forge->sink = sink;
+ forge->handle = handle;
+ forge->stack = NULL;
+}
+
+/**
+ @}
+ @name Low Level Output
+ @{
+*/
+
+/**
+ Write raw output. This is used internally, but is also useful for writing
+ atom types not explicitly supported by the forge API. Note the caller is
+ responsible for ensuring the output is approriately padded.
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_raw(LV2_Atom_Forge* forge, const void* data, uint32_t size)
+{
+ LV2_Atom_Forge_Ref out = 0;
+ if (forge->sink) {
+ out = forge->sink(forge->handle, data, size);
+ } else {
+ out = (LV2_Atom_Forge_Ref)forge->buf + forge->offset;
+ uint8_t* mem = forge->buf + forge->offset;
+ if (forge->offset + size > forge->size) {
+ return 0;
+ }
+ forge->offset += size;
+ memcpy(mem, data, size);
+ }
+ for (LV2_Atom_Forge_Frame* f = forge->stack; f; f = f->parent) {
+ lv2_atom_forge_deref(forge, f->ref)->size += size;
+ }
+ return out;
+}
+
+/** Pad output accordingly so next write is 64-bit aligned. */
+static inline void
+lv2_atom_forge_pad(LV2_Atom_Forge* forge, uint32_t written)
+{
+ const uint64_t pad = 0;
+ const uint32_t pad_size = lv2_atom_pad_size(written) - written;
+ lv2_atom_forge_raw(forge, &pad, pad_size);
+}
+
+/** Write raw output, padding to 64-bits as necessary. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_write(LV2_Atom_Forge* forge, const void* data, uint32_t size)
+{
+ LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, data, size);
+ if (out) {
+ lv2_atom_forge_pad(forge, size);
+ }
+ return out;
+}
+
+/** Write a null-terminated string body. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_string_body(LV2_Atom_Forge* forge,
+ const char* str,
+ uint32_t len)
+{
+ LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, str, len);
+ if (out && (out = lv2_atom_forge_raw(forge, "", 1))) {
+ lv2_atom_forge_pad(forge, len + 1);
+ }
+ return out;
+}
+
+/**
+ @}
+ @name Atom Output
+ @{
+*/
+
+/** Write an atom:Atom header. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_atom(LV2_Atom_Forge* forge, uint32_t size, uint32_t type)
+{
+ const LV2_Atom a = { size, type };
+ return lv2_atom_forge_raw(forge, &a, sizeof(a));
+}
+
+/** Write a primitive (fixed-size) atom. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_primitive(LV2_Atom_Forge* forge, const LV2_Atom* a)
+{
+ if (lv2_atom_forge_top_is(forge, forge->Vector)) {
+ return lv2_atom_forge_raw(forge, LV2_ATOM_BODY_CONST(a), a->size);
+ } else {
+ return lv2_atom_forge_write(forge, a, sizeof(LV2_Atom) + a->size);
+ }
+}
+
+/** Write an atom:Int. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_int(LV2_Atom_Forge* forge, int32_t val)
+{
+ const LV2_Atom_Int a = { { sizeof(val), forge->Int }, val };
+ return lv2_atom_forge_primitive(forge, &a.atom);
+}
+
+/** Write an atom:Long. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_long(LV2_Atom_Forge* forge, int64_t val)
+{
+ const LV2_Atom_Long a = { { sizeof(val), forge->Long }, val };
+ return lv2_atom_forge_primitive(forge, &a.atom);
+}
+
+/** Write an atom:Float. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_float(LV2_Atom_Forge* forge, float val)
+{
+ const LV2_Atom_Float a = { { sizeof(val), forge->Float }, val };
+ return lv2_atom_forge_primitive(forge, &a.atom);
+}
+
+/** Write an atom:Double. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_double(LV2_Atom_Forge* forge, double val)
+{
+ const LV2_Atom_Double a = { { sizeof(val), forge->Double }, val };
+ return lv2_atom_forge_primitive(forge, &a.atom);
+}
+
+/** Write an atom:Bool. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_bool(LV2_Atom_Forge* forge, bool val)
+{
+ const LV2_Atom_Bool a = { { sizeof(int32_t), forge->Bool }, val ? 1 : 0 };
+ return lv2_atom_forge_primitive(forge, &a.atom);
+}
+
+/** Write an atom:URID. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_URID id)
+{
+ const LV2_Atom_URID a = { { sizeof(id), forge->URID }, id };
+ return lv2_atom_forge_primitive(forge, &a.atom);
+}
+
+/** Write an atom compatible with atom:String. Used internally. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_typed_string(LV2_Atom_Forge* forge,
+ uint32_t type,
+ const char* str,
+ uint32_t len)
+{
+ const LV2_Atom_String a = { { len + 1, type } };
+ LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a));
+ if (out) {
+ if (!lv2_atom_forge_string_body(forge, str, len)) {
+ LV2_Atom* atom = lv2_atom_forge_deref(forge, out);
+ atom->size = atom->type = 0;
+ out = 0;
+ }
+ }
+ return out;
+}
+
+/** Write an atom:String. Note that @p str need not be NULL terminated. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_string(LV2_Atom_Forge* forge, const char* str, uint32_t len)
+{
+ return lv2_atom_forge_typed_string(forge, forge->String, str, len);
+}
+
+/**
+ Write an atom:URI. Note that @p uri need not be NULL terminated.
+ This does not map the URI, but writes the complete URI string. To write
+ a mapped URI, use lv2_atom_forge_urid().
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_uri(LV2_Atom_Forge* forge, const char* uri, uint32_t len)
+{
+ return lv2_atom_forge_typed_string(forge, forge->URI, uri, len);
+}
+
+/** Write an atom:Path. Note that @p path need not be NULL terminated. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_path(LV2_Atom_Forge* forge, const char* path, uint32_t len)
+{
+ return lv2_atom_forge_typed_string(forge, forge->Path, path, len);
+}
+
+/** Write an atom:Literal. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_literal(LV2_Atom_Forge* forge,
+ const char* str,
+ uint32_t len,
+ uint32_t datatype,
+ uint32_t lang)
+{
+ const LV2_Atom_Literal a = {
+ { (uint32_t)(sizeof(LV2_Atom_Literal) - sizeof(LV2_Atom) + len + 1),
+ forge->Literal },
+ { datatype,
+ lang }
+ };
+ LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a));
+ if (out) {
+ if (!lv2_atom_forge_string_body(forge, str, len)) {
+ LV2_Atom* atom = lv2_atom_forge_deref(forge, out);
+ atom->size = atom->type = 0;
+ out = 0;
+ }
+ }
+ return out;
+}
+
+/** Start an atom:Vector. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_vector_head(LV2_Atom_Forge* forge,
+ LV2_Atom_Forge_Frame* frame,
+ uint32_t child_size,
+ uint32_t child_type)
+{
+ const LV2_Atom_Vector a = {
+ { sizeof(LV2_Atom_Vector_Body), forge->Vector },
+ { child_size, child_type }
+ };
+ return lv2_atom_forge_push(
+ forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
+}
+
+/** Write a complete atom:Vector. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_vector(LV2_Atom_Forge* forge,
+ uint32_t child_size,
+ uint32_t child_type,
+ uint32_t n_elems,
+ const void* elems)
+{
+ const LV2_Atom_Vector a = {
+ { (uint32_t)(sizeof(LV2_Atom_Vector_Body) + n_elems * child_size),
+ forge->Vector },
+ { child_size, child_type }
+ };
+ LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a));
+ if (out) {
+ lv2_atom_forge_write(forge, elems, child_size * n_elems);
+ }
+ return out;
+}
+
+/**
+ Write the header of an atom:Tuple.
+
+ The passed frame will be initialised to represent this tuple. To complete
+ the tuple, write a sequence of atoms, then pop the frame with
+ lv2_atom_forge_pop().
+
+ For example:
+ @code
+ // Write tuple (1, 2.0)
+ LV2_Atom_Forge_Frame frame;
+ LV2_Atom* tup = (LV2_Atom*)lv2_atom_forge_tuple(forge, &frame);
+ lv2_atom_forge_int32(forge, 1);
+ lv2_atom_forge_float(forge, 2.0);
+ lv2_atom_forge_pop(forge, &frame);
+ @endcode
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_tuple(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
+{
+ const LV2_Atom_Tuple a = { { 0, forge->Tuple } };
+ return lv2_atom_forge_push(
+ forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
+}
+
+/**
+ Write the header of an atom:Resource.
+
+ The passed frame will be initialised to represent this object. To complete
+ the object, write a sequence of properties, then pop the frame with
+ lv2_atom_forge_pop().
+
+ For example:
+ @code
+ LV2_URID eg_Cat = map("http://example.org/Cat");
+ LV2_URID eg_name = map("http://example.org/name");
+
+ // Write object header
+ LV2_Atom_Forge_Frame frame;
+ lv2_atom_forge_resource(forge, &frame, 1, eg_Cat);
+
+ // Write property: eg:name = "Hobbes"
+ lv2_atom_forge_property_head(forge, eg_name, 0);
+ lv2_atom_forge_string(forge, "Hobbes", strlen("Hobbes"));
+
+ // Finish object
+ lv2_atom_forge_pop(forge, &frame);
+ @endcode
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_resource(LV2_Atom_Forge* forge,
+ LV2_Atom_Forge_Frame* frame,
+ LV2_URID id,
+ LV2_URID otype)
+{
+ const LV2_Atom_Object a = {
+ { sizeof(LV2_Atom_Object) - sizeof(LV2_Atom), forge->Resource },
+ { id, otype }
+ };
+ LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a));
+ return lv2_atom_forge_push(forge, frame, out);
+}
+
+/**
+ The same as lv2_atom_forge_resource(), but for object:Blank.
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_blank(LV2_Atom_Forge* forge,
+ LV2_Atom_Forge_Frame* frame,
+ uint32_t id,
+ LV2_URID otype)
+{
+ const LV2_Atom_Object a = {
+ { sizeof(LV2_Atom_Object) - sizeof(LV2_Atom), forge->Blank },
+ { id, otype }
+ };
+ LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a));
+ return lv2_atom_forge_push(forge, frame, out);
+}
+
+/**
+ Write the header for a property body (likely in an Object).
+ See lv2_atom_forge_resource() documentation for an example.
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_property_head(LV2_Atom_Forge* forge,
+ LV2_URID key,
+ LV2_URID context)
+{
+ const LV2_Atom_Property_Body a = { key, context, { 0, 0 } };
+ return lv2_atom_forge_write(forge, &a, 2 * sizeof(uint32_t));
+}
+
+/**
+ Write the header for a Sequence.
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge,
+ LV2_Atom_Forge_Frame* frame,
+ uint32_t unit)
+{
+ const LV2_Atom_Sequence a = {
+ { sizeof(LV2_Atom_Sequence) - sizeof(LV2_Atom), forge->Sequence },
+ { unit, 0 }
+ };
+ LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a));
+ return lv2_atom_forge_push(forge, frame, out);
+}
+
+/**
+ Write the time stamp header of an Event (in a Sequence) in audio frames.
+ After this, call the appropriate forge method(s) to write the body. Note
+ the returned reference is to an LV2_Event which is NOT an Atom.
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_frame_time(LV2_Atom_Forge* forge, int64_t frames)
+{
+ return lv2_atom_forge_write(forge, &frames, sizeof(frames));
+}
+
+/**
+ Write the time stamp header of an Event (in a Sequence) in beats. After
+ this, call the appropriate forge method(s) to write the body. Note the
+ returned reference is to an LV2_Event which is NOT an Atom.
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_beat_time(LV2_Atom_Forge* forge, double beats)
+{
+ return lv2_atom_forge_write(forge, &beats, sizeof(beats));
+}
+
+/**
+ @}
+*/
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_ATOM_FORGE_H */
diff --git a/distrho/src/lv2/atom-helpers.h b/distrho/src/lv2/atom-helpers.h
@@ -0,0 +1,255 @@
+// lv2_atom_helpers.h
+//
+/****************************************************************************
+ Copyright (C) 2005-2012, rncbc aka Rui Nuno Capela. All rights reserved.
+
+ This program 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 program 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*****************************************************************************/
+
+/* Helper functions for LV2 atom:Sequence event buffer.
+ *
+ * tentatively adapted from:
+ *
+ * - lv2_evbuf.h,c - An abstract/opaque LV2 event buffer implementation.
+ *
+ * - event-helpers.h - Helper functions for the LV2 Event extension.
+ * <http://lv2plug.in/ns/ext/event>
+ *
+ * Copyright 2008-2012 David Robillard <http://drobilla.net>
+ */
+
+#ifndef LV2_ATOM_HELPERS_H
+#define LV2_ATOM_HELPERS_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "atom.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// An abstract/opaque LV2 atom:Sequence buffer.
+//
+typedef
+struct _LV2_Atom_Buffer
+{
+ uint32_t capacity;
+ uint32_t chunk_type;
+ uint32_t sequence_type;
+ LV2_Atom_Sequence atoms;
+
+} LV2_Atom_Buffer;
+
+
+// Pad a size to 64 bits (for LV2 atom:Sequence event sizes).
+//
+static inline
+uint32_t lv2_atom_buffer_pad_size ( uint32_t size )
+{
+ return (size + 7) & (~7);
+}
+
+
+// Clear and initialize an existing LV2 atom:Sequenece buffer.
+//
+static inline
+void lv2_atom_buffer_reset ( LV2_Atom_Buffer *buf, bool input )
+{
+ if (input)
+ buf->atoms.atom.size = sizeof(LV2_Atom_Sequence_Body);
+ else
+ buf->atoms.atom.size = buf->capacity;
+
+ buf->atoms.atom.type = buf->sequence_type;
+ buf->atoms.body.unit = 0;
+ buf->atoms.body.pad = 0;
+}
+
+
+// Allocate a new, empty LV2 atom:Sequence buffer.
+//
+static inline
+LV2_Atom_Buffer *lv2_atom_buffer_new (
+ uint32_t capacity, uint32_t sequence_type, bool input )
+{
+ LV2_Atom_Buffer *buf = (LV2_Atom_Buffer *)
+ malloc(sizeof(LV2_Atom_Buffer) + sizeof(LV2_Atom_Sequence) + capacity);
+
+ buf->capacity = capacity;
+ buf->sequence_type = sequence_type;
+
+ lv2_atom_buffer_reset(buf, input);
+
+ return buf;
+}
+
+
+// Free an LV2 atom:Sequenece buffer allocated with lv2_atome_buffer_new.
+//
+static inline
+void lv2_atom_buffer_free ( LV2_Atom_Buffer *buf )
+{
+ free(buf);
+}
+
+
+// Return the total padded size of events stored in a LV2 atom:Sequence buffer.
+//
+static inline
+uint32_t lv2_atom_buffer_get_size ( LV2_Atom_Buffer *buf )
+{
+ return buf->atoms.atom.size - sizeof(LV2_Atom_Sequence_Body);
+}
+
+
+// Return the actual LV2 atom:Sequence implementation.
+//
+static inline
+LV2_Atom_Sequence *lv2_atom_buffer_get_sequence ( LV2_Atom_Buffer *buf )
+{
+ return &buf->atoms;
+}
+
+
+// An iterator over an atom:Sequence buffer.
+//
+typedef
+struct _LV2_Atom_Buffer_Iterator
+{
+ LV2_Atom_Buffer *buf;
+ uint32_t offset;
+
+} LV2_Atom_Buffer_Iterator;
+
+
+// Reset an iterator to point to the start of an LV2 atom:Sequence buffer.
+//
+static inline
+bool lv2_atom_buffer_begin (
+ LV2_Atom_Buffer_Iterator *iter, LV2_Atom_Buffer *buf )
+{
+ iter->buf = buf;
+ iter->offset = 0;
+
+ return (buf->atoms.atom.size > 0);
+}
+
+
+// Reset an iterator to point to the end of an LV2 atom:Sequence buffer.
+//
+static inline
+bool lv2_atom_buffer_end (
+ LV2_Atom_Buffer_Iterator *iter, LV2_Atom_Buffer *buf )
+{
+ iter->buf = buf;
+ iter->offset = lv2_atom_buffer_pad_size(lv2_atom_buffer_get_size(buf));
+
+ return (iter->offset < buf->capacity - sizeof(LV2_Atom_Event));
+}
+
+
+// Check if a LV2 atom:Sequenece buffer iterator is valid.
+//
+static inline
+bool lv2_atom_buffer_is_valid ( LV2_Atom_Buffer_Iterator *iter )
+{
+ return iter->offset < lv2_atom_buffer_get_size(iter->buf);
+}
+
+
+// Advance a LV2 atom:Sequenece buffer iterator forward one event.
+//
+static inline
+bool lv2_atom_buffer_increment ( LV2_Atom_Buffer_Iterator *iter )
+{
+ if (!lv2_atom_buffer_is_valid(iter))
+ return false;
+
+ LV2_Atom_Buffer *buf = iter->buf;
+ LV2_Atom_Sequence *atoms = &buf->atoms;
+ uint32_t size = ((LV2_Atom_Event *) ((char *)
+ LV2_ATOM_CONTENTS(LV2_Atom_Sequence, atoms) + iter->offset))->body.size;
+ iter->offset += lv2_atom_buffer_pad_size(sizeof(LV2_Atom_Event) + size);
+
+ return true;
+}
+
+
+// Get the event currently pointed at a LV2 atom:Sequence buffer iterator.
+//
+static inline
+LV2_Atom_Event *lv2_atom_buffer_get (
+ LV2_Atom_Buffer_Iterator *iter, uint8_t **data )
+{
+ if (!lv2_atom_buffer_is_valid(iter))
+ return NULL;
+
+ LV2_Atom_Buffer *buf = iter->buf;
+ LV2_Atom_Sequence *atoms = &buf->atoms;
+ LV2_Atom_Event *ev = (LV2_Atom_Event *) ((char *)
+ LV2_ATOM_CONTENTS(LV2_Atom_Sequence, atoms) + iter->offset);
+
+ *data = (uint8_t *) LV2_ATOM_BODY(&ev->body);
+
+ return ev;
+}
+
+
+// Write an event at a LV2 atom:Sequence buffer iterator.
+
+static inline
+bool lv2_atom_buffer_write (
+ LV2_Atom_Buffer_Iterator *iter,
+ uint32_t frames,
+ uint32_t /*subframes*/,
+ uint32_t type,
+ uint32_t size,
+ const uint8_t *data )
+{
+ LV2_Atom_Buffer *buf = iter->buf;
+ LV2_Atom_Sequence *atoms = &buf->atoms;
+ if (buf->capacity - sizeof(LV2_Atom) - atoms->atom.size
+ < sizeof(LV2_Atom_Event) + size)
+ return false;
+
+ LV2_Atom_Event *ev = (LV2_Atom_Event*) ((char *)
+ LV2_ATOM_CONTENTS(LV2_Atom_Sequence, atoms) + iter->offset);
+
+ ev->time.frames = frames;
+ ev->body.type = type;
+ ev->body.size = size;
+
+ memcpy(LV2_ATOM_BODY(&ev->body), data, size);
+
+ size = lv2_atom_buffer_pad_size(sizeof(LV2_Atom_Event) + size);
+ atoms->atom.size += size;
+ iter->offset += size;
+
+ return true;
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif // LV2_ATOM_HELPERS_H
+
+// end of lv2_atom_helpers.h
diff --git a/distrho/src/lv2/atom-util.h b/distrho/src/lv2/atom-util.h
@@ -0,0 +1,401 @@
+/*
+ Copyright 2008-2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file util.h Helper functions for the LV2 Atom extension.
+
+ Note these functions are all static inline, do not take their address.
+
+ This header is non-normative, it is provided for convenience.
+*/
+
+#ifndef LV2_ATOM_UTIL_H
+#define LV2_ATOM_UTIL_H
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "atom.h"
+
+#ifdef __cplusplus
+extern "C" {
+#else
+# include <stdbool.h>
+#endif
+
+/** Pad a size to 64 bits. */
+static inline uint32_t
+lv2_atom_pad_size(uint32_t size)
+{
+ return (size + 7) & (~7);
+}
+
+/** Return the total size of @p atom, including the header. */
+static inline uint32_t
+lv2_atom_total_size(const LV2_Atom* atom)
+{
+ return sizeof(LV2_Atom) + atom->size;
+}
+
+/** Return true iff @p atom is null. */
+static inline bool
+lv2_atom_is_null(const LV2_Atom* atom)
+{
+ return !atom || (atom->type == 0 && atom->size == 0);
+}
+
+/** Return true iff @p a is equal to @p b. */
+static inline bool
+lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b)
+{
+ return (a == b) || ((a->type == b->type) &&
+ (a->size == b->size) &&
+ !memcmp(a + 1, b + 1, a->size));
+}
+
+/**
+ @name Sequence Iterator
+ @{
+*/
+
+/** Get an iterator pointing to the first event in a Sequence body. */
+static inline const LV2_Atom_Event*
+lv2_atom_sequence_begin(const LV2_Atom_Sequence_Body* body)
+{
+ return (const LV2_Atom_Event*)(body + 1);
+}
+
+/** Get an iterator pointing to the end of a Sequence body. */
+static inline const LV2_Atom_Event*
+lv2_atom_sequence_end(const LV2_Atom_Sequence_Body* body, uint32_t size)
+{
+ return (const LV2_Atom_Event*)((const uint8_t*)body + lv2_atom_pad_size(size));
+}
+
+/** Return true iff @p i has reached the end of @p body. */
+static inline bool
+lv2_atom_sequence_is_end(const LV2_Atom_Sequence_Body* body,
+ uint32_t size,
+ const LV2_Atom_Event* i)
+{
+ return (const uint8_t*)i >= ((const uint8_t*)body + size);
+}
+
+/** Return an iterator to the element following @p i. */
+static inline const LV2_Atom_Event*
+lv2_atom_sequence_next(const LV2_Atom_Event* i)
+{
+ if (!i) return NULL;
+ return (const LV2_Atom_Event*)((const uint8_t*)i
+ + sizeof(LV2_Atom_Event)
+ + lv2_atom_pad_size(i->body.size));
+}
+
+/**
+ A macro for iterating over all events in a Sequence.
+ @param seq The sequence to iterate over
+ @param iter The name of the iterator
+
+ This macro is used similarly to a for loop (which it expands to), e.g.:
+ @code
+ LV2_ATOM_SEQUENCE_FOREACH(sequence, ev) {
+ // Do something with ev (an LV2_Atom_Event*) here...
+ }
+ @endcode
+*/
+#define LV2_ATOM_SEQUENCE_FOREACH(seq, iter) \
+ for (const LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(&(seq)->body); \
+ !lv2_atom_sequence_is_end(&(seq)->body, (seq)->atom.size, (iter)); \
+ (iter) = lv2_atom_sequence_next(iter))
+
+/** Like LV2_ATOM_SEQUENCE_FOREACH but for a headerless sequence body. */
+#define LV2_ATOM_SEQUENCE_BODY_FOREACH(body, size, iter) \
+ for (const LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(body); \
+ !lv2_atom_sequence_is_end(body, size, (iter)); \
+ (iter) = lv2_atom_sequence_next(iter))
+
+/**
+ @}
+ @name Tuple Iterator
+ @{
+*/
+
+/** Get an iterator pointing to the first element in @p tup. */
+static inline const LV2_Atom*
+lv2_atom_tuple_begin(const LV2_Atom_Tuple* tup)
+{
+ return (const LV2_Atom*)(LV2_ATOM_BODY_CONST(tup));
+}
+
+/** Return true iff @p i has reached the end of @p body. */
+static inline bool
+lv2_atom_tuple_is_end(const void* body, uint32_t size, LV2_Atom* i)
+{
+ return (const uint8_t*)i >= ((const uint8_t*)body + size);
+}
+
+/** Return an iterator to the element following @p i. */
+static inline const LV2_Atom*
+lv2_atom_tuple_next(const LV2_Atom* i)
+{
+ return (const LV2_Atom*)(
+ (const uint8_t*)i + sizeof(LV2_Atom) + lv2_atom_pad_size(i->size));
+}
+
+/**
+ A macro for iterating over all properties of a Tuple.
+ @param tuple The tuple to iterate over
+ @param iter The name of the iterator
+
+ This macro is used similarly to a for loop (which it expands to), e.g.:
+ @code
+ LV2_ATOMO_TUPLE_FOREACH(tuple, elem) {
+ // Do something with elem (an LV2_Atom*) here...
+ }
+ @endcode
+*/
+#define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \
+ for (LV2_Atom* (iter) = lv2_atom_tuple_begin(tuple); \
+ !lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), (tuple)->size, (iter)); \
+ (iter) = lv2_atom_tuple_next(iter))
+
+/** Like LV2_ATOM_TUPLE_FOREACH but for a headerless tuple body. */
+#define LV2_ATOM_TUPLE_BODY_FOREACH(body, size, iter) \
+ for (LV2_Atom* (iter) = (LV2_Atom*)body; \
+ !lv2_atom_tuple_is_end(body, size, (iter)); \
+ (iter) = lv2_atom_tuple_next(iter))
+
+/**
+ @}
+ @name Object Iterator
+ @{
+*/
+
+/** Return a pointer to the first property in @p body. */
+static inline const LV2_Atom_Property_Body*
+lv2_atom_object_begin(const LV2_Atom_Object_Body* body)
+{
+ return (const LV2_Atom_Property_Body*)(body + 1);
+}
+
+/** Return true iff @p i has reached the end of @p obj. */
+static inline bool
+lv2_atom_object_is_end(const LV2_Atom_Object_Body* body,
+ uint32_t size,
+ const LV2_Atom_Property_Body* i)
+{
+ return (const uint8_t*)i >= ((const uint8_t*)body + size);
+}
+
+/** Return an iterator to the property following @p i. */
+static inline const LV2_Atom_Property_Body*
+lv2_atom_object_next(const LV2_Atom_Property_Body* i)
+{
+ const LV2_Atom* const value = (const LV2_Atom*)(
+ (const uint8_t*)i + 2 * sizeof(uint32_t));
+ return (const LV2_Atom_Property_Body*)(
+ (const uint8_t*)i + lv2_atom_pad_size(sizeof(LV2_Atom_Property_Body)
+ + value->size));
+}
+
+/**
+ A macro for iterating over all properties of an Object.
+ @param obj The object to iterate over
+ @param iter The name of the iterator
+
+ This macro is used similarly to a for loop (which it expands to), e.g.:
+ @code
+ LV2_ATOM_OBJECT_FOREACH(object, i) {
+ // Do something with prop (an LV2_Atom_Property_Body*) here...
+ }
+ @endcode
+*/
+#define LV2_ATOM_OBJECT_FOREACH(obj, iter) \
+ for (const LV2_Atom_Property_Body* (iter) = lv2_atom_object_begin(&(obj)->body); \
+ !lv2_atom_object_is_end(&(obj)->body, (obj)->atom.size, (iter)); \
+ (iter) = lv2_atom_object_next(iter))
+
+/** Like LV2_ATOM_OBJECT_FOREACH but for a headerless object body. */
+#define LV2_ATOM_OBJECT_BODY_FOREACH(body, size, iter) \
+ for (const LV2_Atom_Property_Body* (iter) = lv2_atom_object_begin(body); \
+ !lv2_atom_object_is_end(body, size, (iter)); \
+ (iter) = lv2_atom_object_next(iter))
+
+/**
+ @}
+ @name Object Query
+ @{
+*/
+
+/** A single entry in an Object query. */
+typedef struct {
+ uint32_t key; /**< Key to query (input set by user) */
+ const LV2_Atom** value; /**< Found value (output set by query function) */
+} LV2_Atom_Object_Query;
+
+static const LV2_Atom_Object_Query LV2_ATOM_OBJECT_QUERY_END = { 0, NULL };
+
+/**
+ Get an object's values for various keys.
+
+ The value pointer of each item in @p query will be set to the location of
+ the corresponding value in @p object. Every value pointer in @p query MUST
+ be initialised to NULL. This function reads @p object in a single linear
+ sweep. By allocating @p query on the stack, objects can be "queried"
+ quickly without allocating any memory. This function is realtime safe.
+
+ This function can only do "flat" queries, it is not smart enough to match
+ variables in nested objects.
+
+ For example:
+ @code
+ const LV2_Atom* name = NULL;
+ const LV2_Atom* age = NULL;
+ LV2_Atom_Object_Query q[] = {
+ { urids.eg_name, &name },
+ { urids.eg_age, &age },
+ LV2_ATOM_OBJECT_QUERY_END
+ };
+ lv2_atom_object_query(obj, q);
+ // name and age are now set to the appropriate values in obj, or NULL.
+ @endcode
+*/
+static inline int
+lv2_atom_object_query(const LV2_Atom_Object* object,
+ LV2_Atom_Object_Query* query)
+{
+ int matches = 0;
+ int n_queries = 0;
+
+ /* Count number of query keys so we can short-circuit when done */
+ for (LV2_Atom_Object_Query* q = query; q->key; ++q) {
+ ++n_queries;
+ }
+
+ LV2_ATOM_OBJECT_FOREACH(object, prop) {
+ for (LV2_Atom_Object_Query* q = query; q->key; ++q) {
+ if (q->key == prop->key && !*q->value) {
+ *q->value = &prop->value;
+ if (++matches == n_queries) {
+ return matches;
+ }
+ break;
+ }
+ }
+ }
+ return matches;
+}
+
+/**
+ Body only version of lv2_atom_object_get().
+*/
+static inline int
+lv2_atom_object_body_get(uint32_t size, const LV2_Atom_Object_Body* body, ...)
+{
+ int matches = 0;
+ int n_queries = 0;
+
+ /* Count number of keys so we can short-circuit when done */
+ va_list args;
+ va_start(args, body);
+ for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) {
+ if (!va_arg(args, const LV2_Atom**)) {
+ return -1;
+ }
+ }
+ va_end(args);
+
+ LV2_ATOM_OBJECT_BODY_FOREACH(body, size, prop) {
+ va_start(args, body);
+ for (int i = 0; i < n_queries; ++i) {
+ uint32_t qkey = va_arg(args, uint32_t);
+ const LV2_Atom** qval = va_arg(args, const LV2_Atom**);
+ if (qkey == prop->key && !*qval) {
+ *qval = &prop->value;
+ if (++matches == n_queries) {
+ return matches;
+ }
+ break;
+ }
+ }
+ va_end(args);
+ }
+ return matches;
+}
+
+/**
+ Variable argument version of lv2_atom_object_query().
+
+ This is nicer-looking in code, but a bit more error-prone since it is not
+ type safe and the argument list must be terminated.
+
+ The arguments should be a series of uint32_t key and const LV2_Atom** value
+ pairs, terminated by a zero key. The value pointers MUST be initialized to
+ NULL. For example:
+
+ @code
+ const LV2_Atom* name = NULL;
+ const LV2_Atom* age = NULL;
+ lv2_atom_object_get(obj,
+ uris.name_key, &name,
+ uris.age_key, &age,
+ 0);
+ @endcode
+*/
+static inline int
+lv2_atom_object_get(const LV2_Atom_Object* object, ...)
+{
+ int matches = 0;
+ int n_queries = 0;
+
+ /* Count number of keys so we can short-circuit when done */
+ va_list args;
+ va_start(args, object);
+ for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) {
+ if (!va_arg(args, const LV2_Atom**)) {
+ return -1;
+ }
+ }
+ va_end(args);
+
+ LV2_ATOM_OBJECT_FOREACH(object, prop) {
+ va_start(args, object);
+ for (int i = 0; i < n_queries; ++i) {
+ uint32_t qkey = va_arg(args, uint32_t);
+ const LV2_Atom** qval = va_arg(args, const LV2_Atom**);
+ if (qkey == prop->key && !*qval) {
+ *qval = &prop->value;
+ if (++matches == n_queries) {
+ return matches;
+ }
+ break;
+ }
+ }
+ va_end(args);
+ }
+ return matches;
+}
+
+/**
+ @}
+*/
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_ATOM_UTIL_H */
diff --git a/distrho/src/lv2/atom.h b/distrho/src/lv2/atom.h
@@ -0,0 +1,246 @@
+/*
+ Copyright 2008-2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file atom.h C header for the LV2 Atom extension
+ <http://lv2plug.in/ns/ext/atom>.
+*/
+
+#ifndef LV2_ATOM_H
+#define LV2_ATOM_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#define LV2_ATOM_URI "http://lv2plug.in/ns/ext/atom"
+#define LV2_ATOM_PREFIX LV2_ATOM_URI "#"
+
+#define LV2_ATOM__Atom LV2_ATOM_PREFIX "Atom"
+#define LV2_ATOM__AtomPort LV2_ATOM_PREFIX "AtomPort"
+#define LV2_ATOM__Blank LV2_ATOM_PREFIX "Blank"
+#define LV2_ATOM__Bool LV2_ATOM_PREFIX "Bool"
+#define LV2_ATOM__Chunk LV2_ATOM_PREFIX "Chunk"
+#define LV2_ATOM__Double LV2_ATOM_PREFIX "Double"
+#define LV2_ATOM__Event LV2_ATOM_PREFIX "Event"
+#define LV2_ATOM__Float LV2_ATOM_PREFIX "Float"
+#define LV2_ATOM__Int LV2_ATOM_PREFIX "Int"
+#define LV2_ATOM__Literal LV2_ATOM_PREFIX "Literal"
+#define LV2_ATOM__Long LV2_ATOM_PREFIX "Long"
+#define LV2_ATOM__Number LV2_ATOM_PREFIX "Number"
+#define LV2_ATOM__Object LV2_ATOM_PREFIX "Object"
+#define LV2_ATOM__Path LV2_ATOM_PREFIX "Path"
+#define LV2_ATOM__Property LV2_ATOM_PREFIX "Property"
+#define LV2_ATOM__Resource LV2_ATOM_PREFIX "Resource"
+#define LV2_ATOM__Sequence LV2_ATOM_PREFIX "Sequence"
+#define LV2_ATOM__Sound LV2_ATOM_PREFIX "Sound"
+#define LV2_ATOM__String LV2_ATOM_PREFIX "String"
+#define LV2_ATOM__Tuple LV2_ATOM_PREFIX "Tuple"
+#define LV2_ATOM__URI LV2_ATOM_PREFIX "URI"
+#define LV2_ATOM__URID LV2_ATOM_PREFIX "URID"
+#define LV2_ATOM__Vector LV2_ATOM_PREFIX "Vector"
+#define LV2_ATOM__atomTransfer LV2_ATOM_PREFIX "atomTransfer"
+#define LV2_ATOM__beatTime LV2_ATOM_PREFIX "beatTime"
+#define LV2_ATOM__bufferType LV2_ATOM_PREFIX "bufferType"
+#define LV2_ATOM__childType LV2_ATOM_PREFIX "childType"
+#define LV2_ATOM__eventTransfer LV2_ATOM_PREFIX "eventTransfer"
+#define LV2_ATOM__frameTime LV2_ATOM_PREFIX "frameTime"
+#define LV2_ATOM__supports LV2_ATOM_PREFIX "supports"
+#define LV2_ATOM__timeUnit LV2_ATOM_PREFIX "timeUnit"
+
+#define LV2_ATOM_REFERENCE_TYPE 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** This expression will fail to compile if double does not fit in 64 bits. */
+typedef char lv2_atom_assert_double_fits_in_64_bits[
+ ((sizeof(double) <= sizeof(uint64_t)) * 2) - 1];
+
+/**
+ Return a pointer to the contents of an Atom. The "contents" of an atom
+ is the data past the complete type-specific header.
+ @param type The type of the atom, e.g. LV2_Atom_String.
+ @param atom A variable-sized atom.
+*/
+#define LV2_ATOM_CONTENTS(type, atom) \
+ ((uint8_t*)(atom) + sizeof(type))
+
+/**
+ Const version of LV2_ATOM_CONTENTS.
+*/
+#define LV2_ATOM_CONTENTS_CONST(type, atom) \
+ ((const uint8_t*)(atom) + sizeof(type))
+
+/**
+ Return a pointer to the body of an Atom. The "body" of an atom is the
+ data just past the LV2_Atom head (i.e. the same offset for all types).
+*/
+#define LV2_ATOM_BODY(atom) LV2_ATOM_CONTENTS(LV2_Atom, atom)
+
+/**
+ Const version of LV2_ATOM_BODY.
+*/
+#define LV2_ATOM_BODY_CONST(atom) LV2_ATOM_CONTENTS_CONST(LV2_Atom, atom)
+
+/** The header of an atom:Atom. */
+typedef struct {
+ uint32_t size; /**< Size in bytes, not including type and size. */
+ uint32_t type; /**< Type of this atom (mapped URI). */
+} LV2_Atom;
+
+/** An atom:Int or atom:Bool. May be cast to LV2_Atom. */
+typedef struct {
+ LV2_Atom atom; /**< Atom header. */
+ int32_t body; /**< Integer value. */
+} LV2_Atom_Int;
+
+/** An atom:Long. May be cast to LV2_Atom. */
+typedef struct {
+ LV2_Atom atom; /**< Atom header. */
+ int64_t body; /**< Integer value. */
+} LV2_Atom_Long;
+
+/** An atom:Float. May be cast to LV2_Atom. */
+typedef struct {
+ LV2_Atom atom; /**< Atom header. */
+ float body; /**< Floating point value. */
+} LV2_Atom_Float;
+
+/** An atom:Double. May be cast to LV2_Atom. */
+typedef struct {
+ LV2_Atom atom; /**< Atom header. */
+ double body; /**< Floating point value. */
+} LV2_Atom_Double;
+
+/** An atom:Bool. May be cast to LV2_Atom. */
+typedef LV2_Atom_Int LV2_Atom_Bool;
+
+/** An atom:URID. May be cast to LV2_Atom. */
+typedef struct {
+ LV2_Atom atom; /**< Atom header. */
+ uint32_t body; /**< URID. */
+} LV2_Atom_URID;
+
+/** An atom:String. May be cast to LV2_Atom. */
+typedef struct {
+ LV2_Atom atom; /**< Atom header. */
+ /* Contents (a null-terminated UTF-8 string) follow here. */
+} LV2_Atom_String;
+
+/** The body of an atom:Literal. */
+typedef struct {
+ uint32_t datatype; /**< Datatype URID. */
+ uint32_t lang; /**< Language URID. */
+ /* Contents (a null-terminated UTF-8 string) follow here. */
+} LV2_Atom_Literal_Body;
+
+/** An atom:Literal. May be cast to LV2_Atom. */
+typedef struct {
+ LV2_Atom atom; /**< Atom header. */
+ LV2_Atom_Literal_Body body; /**< Body. */
+} LV2_Atom_Literal;
+
+/** An atom:Tuple. May be cast to LV2_Atom. */
+typedef struct {
+ LV2_Atom atom; /**< Atom header. */
+ /* Contents (a series of complete atoms) follow here. */
+} LV2_Atom_Tuple;
+
+/** The body of an atom:Vector. */
+typedef struct {
+ uint32_t child_size; /**< The size of each element in the vector. */
+ uint32_t child_type; /**< The type of each element in the vector. */
+ /* Contents (a series of packed atom bodies) follow here. */
+} LV2_Atom_Vector_Body;
+
+/** An atom:Vector. May be cast to LV2_Atom. */
+typedef struct {
+ LV2_Atom atom; /**< Atom header. */
+ LV2_Atom_Vector_Body body; /**< Body. */
+} LV2_Atom_Vector;
+
+/** The body of an atom:Property (e.g. in an atom:Object). */
+typedef struct {
+ uint32_t key; /**< Key (predicate) (mapped URI). */
+ uint32_t context; /**< Context URID (may be, and generally is, 0). */
+ LV2_Atom value; /**< Value atom header. */
+ /* Value atom body follows here. */
+} LV2_Atom_Property_Body;
+
+/** An atom:Property. May be cast to LV2_Atom. */
+typedef struct {
+ LV2_Atom atom; /**< Atom header. */
+ LV2_Atom_Property_Body body; /**< Body. */
+} LV2_Atom_Property;
+
+/** The body of an atom:Object. May be cast to LV2_Atom. */
+typedef struct {
+ uint32_t id; /**< URID (atom:Resource) or blank ID (atom:Blank). */
+ uint32_t otype; /**< Type URID (same as rdf:type, for fast dispatch). */
+ /* Contents (a series of property bodies) follow here. */
+} LV2_Atom_Object_Body;
+
+/** An atom:Object. May be cast to LV2_Atom. */
+typedef struct {
+ LV2_Atom atom; /**< Atom header. */
+ LV2_Atom_Object_Body body; /**< Body. */
+} LV2_Atom_Object;
+
+/** The header of an atom:Event. Note this type is NOT an LV2_Atom. */
+typedef struct {
+ /** Time stamp. Which type is valid is determined by context. */
+ union {
+ int64_t frames; /**< Time in audio frames. */
+ double beats; /**< Time in beats. */
+ } time;
+ LV2_Atom body; /**< Event body atom header. */
+ /* Body atom contents follow here. */
+} LV2_Atom_Event;
+
+/**
+ The body of an atom:Sequence (a sequence of events).
+
+ The unit field is either a URID that described an appropriate time stamp
+ type, or may be 0 where a default stamp type is known. For
+ LV2_Descriptor::run(), the default stamp type is audio frames.
+
+ The contents of a sequence is a series of LV2_Atom_Event, each aligned
+ to 64-bits, e.g.:
+ <pre>
+ | Event 1 (size 6) | Event 2
+ | | | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+ |FRAMES |SUBFRMS|TYPE |SIZE |DATADATADATAPAD|FRAMES |SUBFRMS|...
+ </pre>
+*/
+typedef struct {
+ uint32_t unit; /**< URID of unit of event time stamps. */
+ uint32_t pad; /**< Currently unused. */
+ /* Contents (a series of events) follow here. */
+} LV2_Atom_Sequence_Body;
+
+/** An atom:Sequence. */
+typedef struct {
+ LV2_Atom atom; /**< Atom header. */
+ LV2_Atom_Sequence_Body body; /**< Body. */
+} LV2_Atom_Sequence;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_ATOM_H */
diff --git a/distrho/src/lv2/buf-size.h b/distrho/src/lv2/buf-size.h
@@ -0,0 +1,30 @@
+/*
+ Copyright 2007-2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+#ifndef LV2_BUF_SIZE_H
+#define LV2_BUF_SIZE_H
+
+#define LV2_BUF_SIZE_URI "http://lv2plug.in/ns/ext/buf-size"
+#define LV2_BUF_SIZE_PREFIX LV2_BUF_SIZE_URI "#"
+
+#define LV2_BUF_SIZE__boundedBlockLength LV2_BUF_SIZE_PREFIX "boundedBlockLength"
+#define LV2_BUF_SIZE__fixedBlockLength LV2_BUF_SIZE_PREFIX "fixedBlockLength"
+#define LV2_BUF_SIZE__maxBlockLength LV2_BUF_SIZE_PREFIX "maxBlockLength"
+#define LV2_BUF_SIZE__minBlockLength LV2_BUF_SIZE_PREFIX "minBlockLength"
+#define LV2_BUF_SIZE__powerOf2BlockLength LV2_BUF_SIZE_PREFIX "powerOf2BlockLength"
+#define LV2_BUF_SIZE__sequenceSize LV2_BUF_SIZE_PREFIX "sequenceSize"
+
+#endif /* LV2_BUF_SIZE_H */
diff --git a/distrho/src/lv2/data-access.h b/distrho/src/lv2/data-access.h
@@ -0,0 +1,63 @@
+/*
+ LV2 Data Access Extension
+ Copyright 2008-2011 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file data-access.h
+ C header for the LV2 Extension Data extension
+ <http://lv2plug.in/ns/ext/data-access>.
+
+ This extension defines a method for (e.g.) plugin UIs to have (possibly
+ marshalled) access to the extension_data function on a plugin instance.
+*/
+
+#ifndef LV2_DATA_ACCESS_H
+#define LV2_DATA_ACCESS_H
+
+#define LV2_DATA_ACCESS_URI "http://lv2plug.in/ns/ext/data-access"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ The data field of the LV2_Feature for this extension.
+
+ To support this feature the host must pass an LV2_Feature struct to the
+ instantiate method with URI "http://lv2plug.in/ns/ext/data-access"
+ and data pointed to an instance of this struct.
+*/
+typedef struct {
+ /**
+ A pointer to a method the UI can call to get data (of a type specified
+ by some other extension) from the plugin.
+
+ This call never is never guaranteed to return anything, UIs should
+ degrade gracefully if direct access to the plugin data is not possible
+ (in which case this function will return NULL).
+
+ This is for access to large data that can only possibly work if the UI
+ and plugin are running in the same process. For all other things, use
+ the normal LV2 UI communication system.
+ */
+ const void* (*data_access)(const char* uri);
+} LV2_Extension_Data_Feature;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_DATA_ACCESS_H */
diff --git a/distrho/src/lv2/dynmanifest.h b/distrho/src/lv2/dynmanifest.h
@@ -0,0 +1,144 @@
+/*
+ Dynamic manifest specification for LV2
+ Copyright 2008-2011 Stefano D'Angelo <zanga.mail@gmail.com>
+
+ 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.
+*/
+
+/**
+ @file dynmanifest.h
+ C header for the LV2 Dynamic Manifest extension
+ <http://lv2plug.in/ns/ext/dynmanifest>.
+ Revision: 1.2
+*/
+
+#ifndef LV2_DYN_MANIFEST_H_INCLUDED
+#define LV2_DYN_MANIFEST_H_INCLUDED
+
+#include <stdio.h>
+
+#include "lv2.h"
+
+#define LV2_DYN_MANIFEST_URI "http://lv2plug.in/ns/ext/dynmanifest"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ Dynamic manifest generator handle.
+
+ This handle indicates a particular status of a dynamic manifest generator.
+ The host MUST NOT attempt to interpret it and, unlikely LV2_Handle, it is
+ NOT even valid to compare this to NULL. The dynamic manifest generator MAY
+ use it to reference internal data.
+*/
+typedef void * LV2_Dyn_Manifest_Handle;
+
+/**
+ Generate the dynamic manifest.
+
+ @param handle Pointer to an uninitialized dynamic manifest generator handle.
+
+ @param features NULL terminated array of LV2_Feature structs which represent
+ the features the host supports. The dynamic manifest generator may refuse to
+ (re)generate the dynamic manifest if required features are not found here
+ (however hosts SHOULD NOT use this as a discovery mechanism, instead of
+ reading the static manifest file). This array must always exist; if a host
+ has no features, it MUST pass a single element array containing NULL.
+
+ @return 0 on success, otherwise a non-zero error code. The host SHOULD
+ evaluate the result of the operation by examining the returned value and
+ MUST NOT try to interpret the value of handle.
+*/
+int lv2_dyn_manifest_open(LV2_Dyn_Manifest_Handle * handle,
+ const LV2_Feature *const * features);
+
+/**
+ Fetch a "list" of subject URIs described in the dynamic manifest.
+
+ The dynamic manifest generator has to fill the resource only with the needed
+ triples to make the host aware of the "objects" it wants to expose. For
+ example, if the plugin library exposes a regular LV2 plugin, it should
+ output only a triple like the following:
+
+ <http://www.example.com/plugin/uri> a lv2:Plugin .
+
+ The objects that are elegible for exposure are those that would need to be
+ represented by a subject node in a static manifest.
+
+ @param handle Dynamic manifest generator handle.
+
+ @param fp FILE * identifying the resource the host has to set up for the
+ dynamic manifest generator. The host MUST pass a writable, empty resource to
+ this function, and the dynamic manifest generator MUST ONLY perform write
+ operations on it at the end of the stream (e.g., using only fprintf(),
+ fwrite() and similar).
+
+ @return 0 on success, otherwise a non-zero error code.
+*/
+int lv2_dyn_manifest_get_subjects(LV2_Dyn_Manifest_Handle handle,
+ FILE * fp);
+
+/**
+ Function that fetches data related to a specific URI.
+
+ The dynamic manifest generator has to fill the resource with data related to
+ object represented by the given URI. For example, if the library exposes a
+ regular LV2 plugin whose URI, as retrieved by the host using
+ lv2_dyn_manifest_get_subjects() is http://www.example.com/plugin/uri, it
+ should output something like:
+
+ <pre>
+ <http://www.example.com/plugin/uri>
+ a lv2:Plugin ;
+ doap:name "My Plugin" ;
+ lv2:binary <mylib.so> ;
+ etc:etc "..." .
+ </pre>
+
+ @param handle Dynamic manifest generator handle.
+
+ @param fp FILE * identifying the resource the host has to set up for the
+ dynamic manifest generator. The host MUST pass a writable resource to this
+ function, and the dynamic manifest generator MUST ONLY perform write
+ operations on it at the current position of the stream (e.g. using only
+ fprintf(), fwrite() and similar).
+
+ @param uri URI to get data about (in the "plain" form, i.e., absolute URI
+ without Turtle prefixes).
+
+ @return 0 on success, otherwise a non-zero error code.
+*/
+int lv2_dyn_manifest_get_data(LV2_Dyn_Manifest_Handle handle,
+ FILE * fp,
+ const char * uri);
+
+/**
+ Function that ends the operations on the dynamic manifest generator.
+
+ This function SHOULD be used by the dynamic manifest generator to perform
+ cleanup operations, etc.
+
+ Once this function is called, referring to handle will cause undefined
+ behavior.
+
+ @param handle Dynamic manifest generator handle.
+*/
+void lv2_dyn_manifest_close(LV2_Dyn_Manifest_Handle handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LV2_DYN_MANIFEST_H_INCLUDED */
diff --git a/distrho/src/lv2/event-helpers.h b/distrho/src/lv2/event-helpers.h
@@ -0,0 +1,263 @@
+/*
+ Copyright 2008-2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file event-helpers.h Helper functions for the LV2 Event extension
+ <http://lv2plug.in/ns/ext/event>.
+*/
+
+#ifndef LV2_EVENT_HELPERS_H
+#define LV2_EVENT_HELPERS_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "event.h"
+
+#ifdef __cplusplus
+extern "C" {
+#else
+# include <stdbool.h>
+#endif
+
+/** @file
+ * Helper functions for the LV2 Event extension
+ * <http://lv2plug.in/ns/ext/event>.
+ *
+ * These functions are provided for convenience only, use of them is not
+ * required for supporting lv2ev (i.e. the events extension is defined by the
+ * raw buffer format described in lv2_event.h and NOT by this API).
+ *
+ * Note that these functions are all static inline which basically means:
+ * do not take the address of these functions. */
+
+
+/** Pad a size to 64 bits (for event sizes) */
+static inline uint16_t
+lv2_event_pad_size(uint16_t size)
+{
+ return (size + 7) & (~7);
+}
+
+
+/** Initialize (empty, reset..) an existing event buffer.
+ * The contents of buf are ignored entirely and overwritten, except capacity
+ * which is unmodified. */
+static inline void
+lv2_event_buffer_reset(LV2_Event_Buffer* buf,
+ uint16_t stamp_type,
+ uint8_t *data)
+{
+ buf->data = data;
+ buf->header_size = sizeof(LV2_Event_Buffer);
+ buf->stamp_type = stamp_type;
+ buf->event_count = 0;
+ buf->size = 0;
+}
+
+
+/** Allocate a new, empty event buffer. */
+static inline LV2_Event_Buffer*
+lv2_event_buffer_new(uint32_t capacity, uint16_t stamp_type)
+{
+ const size_t size = sizeof(LV2_Event_Buffer) + capacity;
+ LV2_Event_Buffer* buf = (LV2_Event_Buffer*)malloc(size);
+ if (buf != NULL) {
+ buf->capacity = capacity;
+ lv2_event_buffer_reset(buf, stamp_type, (uint8_t *)(buf + 1));
+ return buf;
+ } else {
+ return NULL;
+ }
+}
+
+
+/** An iterator over an LV2_Event_Buffer.
+ *
+ * Multiple simultaneous read iterators over a single buffer is fine,
+ * but changing the buffer invalidates all iterators (e.g. RW Lock). */
+typedef struct {
+ LV2_Event_Buffer* buf;
+ uint32_t offset;
+} LV2_Event_Iterator;
+
+
+/** Reset an iterator to point to the start of @a buf.
+ * @return True if @a iter is valid, otherwise false (buffer is empty) */
+static inline bool
+lv2_event_begin(LV2_Event_Iterator* iter,
+ LV2_Event_Buffer* buf)
+{
+ iter->buf = buf;
+ iter->offset = 0;
+ return (buf->size > 0);
+}
+
+
+/** Check if @a iter is valid.
+ * @return True if @a iter is valid, otherwise false (past end of buffer) */
+static inline bool
+lv2_event_is_valid(LV2_Event_Iterator* iter)
+{
+ return (iter->buf && (iter->offset < iter->buf->size));
+}
+
+
+/** Advance @a iter forward one event.
+ * @a iter must be valid.
+ * @return True if @a iter is valid, otherwise false (reached end of buffer) */
+static inline bool
+lv2_event_increment(LV2_Event_Iterator* iter)
+{
+ if (!lv2_event_is_valid(iter)) {
+ return false;
+ }
+
+ LV2_Event* const ev = (LV2_Event*)(
+ (uint8_t*)iter->buf->data + iter->offset);
+
+ iter->offset += lv2_event_pad_size(sizeof(LV2_Event) + ev->size);
+
+ return true;
+}
+
+
+/** Dereference an event iterator (get the event currently pointed at).
+ * @a iter must be valid.
+ * @a data if non-NULL, will be set to point to the contents of the event
+ * returned.
+ * @return A Pointer to the event @a iter is currently pointing at, or NULL
+ * if the end of the buffer is reached (in which case @a data is
+ * also set to NULL). */
+static inline LV2_Event*
+lv2_event_get(LV2_Event_Iterator* iter,
+ uint8_t** data)
+{
+ if (!lv2_event_is_valid(iter)) {
+ return NULL;
+ }
+
+ LV2_Event* const ev = (LV2_Event*)(
+ (uint8_t*)iter->buf->data + iter->offset);
+
+ if (data)
+ *data = (uint8_t*)ev + sizeof(LV2_Event);
+
+ return ev;
+}
+
+
+/** Write an event at @a iter.
+ * The event (if any) pointed to by @a iter will be overwritten, and @a iter
+ * incremented to point to the following event (i.e. several calls to this
+ * function can be done in sequence without twiddling iter in-between).
+ * @return True if event was written, otherwise false (buffer is full). */
+static inline bool
+lv2_event_write(LV2_Event_Iterator* iter,
+ uint32_t frames,
+ uint32_t subframes,
+ uint16_t type,
+ uint16_t size,
+ const uint8_t* data)
+{
+ if (!iter->buf)
+ return false;
+
+ if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + size)
+ return false;
+
+ LV2_Event* const ev = (LV2_Event*)(
+ (uint8_t*)iter->buf->data + iter->offset);
+
+ ev->frames = frames;
+ ev->subframes = subframes;
+ ev->type = type;
+ ev->size = size;
+ memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size);
+ ++iter->buf->event_count;
+
+ size = lv2_event_pad_size(sizeof(LV2_Event) + size);
+ iter->buf->size += size;
+ iter->offset += size;
+
+ return true;
+}
+
+
+/** Reserve space for an event in the buffer and return a pointer to
+ the memory where the caller can write the event data, or NULL if there
+ is not enough room in the buffer. */
+static inline uint8_t*
+lv2_event_reserve(LV2_Event_Iterator* iter,
+ uint32_t frames,
+ uint32_t subframes,
+ uint16_t type,
+ uint16_t size)
+{
+ if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + size)
+ return NULL;
+
+ LV2_Event* const ev = (LV2_Event*)((uint8_t*)iter->buf->data +
+ iter->offset);
+
+ ev->frames = frames;
+ ev->subframes = subframes;
+ ev->type = type;
+ ev->size = size;
+ ++iter->buf->event_count;
+
+ size = lv2_event_pad_size(sizeof(LV2_Event) + size);
+ iter->buf->size += size;
+ iter->offset += size;
+
+ return (uint8_t*)ev + sizeof(LV2_Event);
+}
+
+
+/** Write an event at @a iter.
+ * The event (if any) pointed to by @a iter will be overwritten, and @a iter
+ * incremented to point to the following event (i.e. several calls to this
+ * function can be done in sequence without twiddling iter in-between).
+ * @return True if event was written, otherwise false (buffer is full). */
+static inline bool
+lv2_event_write_event(LV2_Event_Iterator* iter,
+ const LV2_Event* ev,
+ const uint8_t* data)
+{
+ if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + ev->size)
+ return false;
+
+ LV2_Event* const write_ev = (LV2_Event*)(
+ (uint8_t*)iter->buf->data + iter->offset);
+
+ *write_ev = *ev;
+ memcpy((uint8_t*)write_ev + sizeof(LV2_Event), data, ev->size);
+ ++iter->buf->event_count;
+
+ const uint16_t size = lv2_event_pad_size(sizeof(LV2_Event) + ev->size);
+ iter->buf->size += size;
+ iter->offset += size;
+
+ return true;
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_EVENT_HELPERS_H */
+
diff --git a/distrho/src/lv2/event.h b/distrho/src/lv2/event.h
@@ -0,0 +1,294 @@
+/*
+ Copyright 2008-2011 David Robillard <http://drobilla.net>
+ Copyright 2006-2007 Lars Luthman <lars.luthman@gmail.com>
+
+ 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.
+*/
+
+/**
+ @file event.h
+ C API for the LV2 Event extension <http://lv2plug.in/ns/ext/event>.
+
+ This extension is a generic transport mechanism for time stamped events
+ of any type (e.g. MIDI, OSC, ramps, etc). Each port can transport mixed
+ events of any type; the type of events and timestamps are defined by a URI
+ which is mapped to an integer by the host for performance reasons.
+
+ This extension requires the host to support the LV2 URI Map extension.
+ Any host which supports this extension MUST guarantee that any call to
+ the LV2 URI Map uri_to_id function with the URI of this extension as the
+ 'map' argument returns a value within the range of uint16_t.
+*/
+
+#ifndef LV2_EVENT_H
+#define LV2_EVENT_H
+
+#define LV2_EVENT_URI "http://lv2plug.in/ns/ext/event"
+#define LV2_EVENT_PREFIX LV2_EVENT_URI "#"
+
+#define LV2_EVENT__Event LV2_EVENT_PREFIX "Event"
+#define LV2_EVENT__EventPort LV2_EVENT_PREFIX "EventPort"
+#define LV2_EVENT__FrameStamp LV2_EVENT_PREFIX "FrameStamp"
+#define LV2_EVENT__TimeStamp LV2_EVENT_PREFIX "TimeStamp"
+#define LV2_EVENT__generatesTimeStamp LV2_EVENT_PREFIX "generatesTimeStamp"
+#define LV2_EVENT__generic LV2_EVENT_PREFIX "generic"
+#define LV2_EVENT__inheritsEvent LV2_EVENT_PREFIX "inheritsEvent"
+#define LV2_EVENT__inheritsTimeStamp LV2_EVENT_PREFIX "inheritsTimeStamp"
+#define LV2_EVENT__supportsEvent LV2_EVENT_PREFIX "supportsEvent"
+#define LV2_EVENT__supportsTimeStamp LV2_EVENT_PREFIX "supportsTimeStamp"
+
+#define LV2_EVENT_AUDIO_STAMP 0
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ The best Pulses Per Quarter Note for tempo-based uint32_t timestamps.
+ Equal to 2^12 * 5 * 7 * 9 * 11 * 13 * 17, which is evenly divisble
+ by all integers from 1 through 18 inclusive, and powers of 2 up to 2^12.
+*/
+static const uint32_t LV2_EVENT_PPQN = 3136573440U;
+
+/**
+ An LV2 event (header only).
+
+ LV2 events are generic time-stamped containers for any type of event.
+ The type field defines the format of a given event's contents.
+
+ This struct defines the header of an LV2 event. An LV2 event is a single
+ chunk of POD (plain old data), usually contained in a flat buffer (see
+ LV2_EventBuffer below). Unless a required feature says otherwise, hosts may
+ assume a deep copy of an LV2 event can be created safely using a simple:
+
+ memcpy(ev_copy, ev, sizeof(LV2_Event) + ev->size); (or equivalent)
+*/
+typedef struct {
+ /**
+ The frames portion of timestamp. The units used here can optionally be
+ set for a port (with the lv2ev:timeUnits property), otherwise this is
+ audio frames, corresponding to the sample_count parameter of the LV2 run
+ method (e.g. frame 0 is the first frame for that call to run).
+ */
+ uint32_t frames;
+
+ /**
+ The sub-frames portion of timestamp. The units used here can optionally
+ be set for a port (with the lv2ev:timeUnits property), otherwise this is
+ 1/(2^32) of an audio frame.
+ */
+ uint32_t subframes;
+
+ /**
+ The type of this event, as a number which represents some URI
+ defining an event type. This value MUST be some value previously
+ returned from a call to the uri_to_id function defined in the LV2
+ URI map extension (see lv2_uri_map.h).
+ There are special rules which must be followed depending on the type
+ of an event. If the plugin recognizes an event type, the definition
+ of that event type will describe how to interpret the event, and
+ any required behaviour. Otherwise, if the type is 0, this event is a
+ non-POD event and lv2_event_unref MUST be called if the event is
+ 'dropped' (see above). Even if the plugin does not understand an event,
+ it may pass the event through to an output by simply copying (and NOT
+ calling lv2_event_unref). These rules are designed to allow for generic
+ event handling plugins and large non-POD events, but with minimal hassle
+ on simple plugins that "don't care" about these more advanced features.
+ */
+ uint16_t type;
+
+ /**
+ The size of the data portion of this event in bytes, which immediately
+ follows. The header size (12 bytes) is not included in this value.
+ */
+ uint16_t size;
+
+ /* size bytes of data follow here */
+} LV2_Event;
+
+
+/**
+ A buffer of LV2 events (header only).
+
+ Like events (which this contains) an event buffer is a single chunk of POD:
+ the entire buffer (including contents) can be copied with a single memcpy.
+ The first contained event begins sizeof(LV2_EventBuffer) bytes after the
+ start of this struct.
+
+ After this header, the buffer contains an event header (defined by struct
+ LV2_Event), followed by that event's contents (padded to 64 bits), followed
+ by another header, etc:
+
+ | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | | |
+ |FRAMES |SUBFRMS|TYP|LEN|DATA..DATA..PAD|FRAMES | ...
+*/
+typedef struct {
+ /**
+ The contents of the event buffer. This may or may not reside in the
+ same block of memory as this header, plugins must not assume either.
+ The host guarantees this points to at least capacity bytes of allocated
+ memory (though only size bytes of that are valid events).
+ */
+ uint8_t* data;
+
+ /**
+ The size of this event header in bytes (including everything).
+
+ This is to allow for extending this header in the future without
+ breaking binary compatibility. Whenever this header is copied,
+ it MUST be done using this field (and NOT the sizeof this struct).
+ */
+ uint16_t header_size;
+
+ /**
+ The type of the time stamps for events in this buffer.
+ As a special exception, '0' always means audio frames and subframes
+ (1/UINT32_MAX'th of a frame) in the sample rate passed to instantiate.
+
+ INPUTS: The host must set this field to the numeric ID of some URI
+ defining the meaning of the frames/subframes fields of contained events
+ (obtained by the LV2 URI Map uri_to_id function with the URI of this
+ extension as the 'map' argument, see lv2_uri_map.h). The host must
+ never pass a plugin a buffer which uses a stamp type the plugin does not
+ 'understand'. The value of this field must never change, except when
+ connect_port is called on the input port, at which time the host MUST
+ have set the stamp_type field to the value that will be used for all
+ subsequent run calls.
+
+ OUTPUTS: The plugin may set this to any value that has been returned
+ from uri_to_id with the URI of this extension for a 'map' argument.
+ When connected to a buffer with connect_port, output ports MUST set this
+ field to the type of time stamp they will be writing. On any call to
+ connect_port on an event input port, the plugin may change this field on
+ any output port, it is the responsibility of the host to check if any of
+ these values have changed and act accordingly.
+ */
+ uint16_t stamp_type;
+
+ /**
+ The number of events in this buffer.
+
+ INPUTS: The host must set this field to the number of events contained
+ in the data buffer before calling run(). The plugin must not change
+ this field.
+
+ OUTPUTS: The plugin must set this field to the number of events it has
+ written to the buffer before returning from run(). Any initial value
+ should be ignored by the plugin.
+ */
+ uint32_t event_count;
+
+ /**
+ The size of the data buffer in bytes.
+ This is set by the host and must not be changed by the plugin.
+ The host is allowed to change this between run() calls.
+ */
+ uint32_t capacity;
+
+ /**
+ The size of the initial portion of the data buffer containing data.
+
+ INPUTS: The host must set this field to the number of bytes used
+ by all events it has written to the buffer (including headers)
+ before calling the plugin's run().
+ The plugin must not change this field.
+
+ OUTPUTS: The plugin must set this field to the number of bytes
+ used by all events it has written to the buffer (including headers)
+ before returning from run().
+ Any initial value should be ignored by the plugin.
+ */
+ uint32_t size;
+} LV2_Event_Buffer;
+
+
+/**
+ Opaque pointer to host data.
+*/
+typedef void* LV2_Event_Callback_Data;
+
+
+/**
+ Non-POD events feature.
+
+ To support this feature the host must pass an LV2_Feature struct to the
+ plugin's instantiate method with URI "http://lv2plug.in/ns/ext/event"
+ and data pointed to an instance of this struct. Note this feature
+ is not mandatory to support the event extension.
+*/
+typedef struct {
+ /**
+ Opaque pointer to host data.
+
+ The plugin MUST pass this to any call to functions in this struct.
+ Otherwise, it must not be interpreted in any way.
+ */
+ LV2_Event_Callback_Data callback_data;
+
+ /**
+ Take a reference to a non-POD event.
+
+ If a plugin receives an event with type 0, it means the event is a
+ pointer to some object in memory and not a flat sequence of bytes
+ in the buffer. When receiving a non-POD event, the plugin already
+ has an implicit reference to the event. If the event is stored AND
+ passed to an output, lv2_event_ref MUST be called on that event.
+ If the event is only stored OR passed through, this is not necessary
+ (as the plugin already has 1 implicit reference).
+
+ @param event An event received at an input that will not be copied to
+ an output or stored in any way.
+
+ @param context The calling context. Like event types, this is a mapped
+ URI, see lv2_context.h. Simple plugin with just a run() method should
+ pass 0 here (the ID of the 'standard' LV2 run context). The host
+ guarantees that this function is realtime safe iff @a context is
+ realtime safe.
+
+ PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS.
+ */
+ uint32_t (*lv2_event_ref)(LV2_Event_Callback_Data callback_data,
+ LV2_Event* event);
+
+ /**
+ Drop a reference to a non-POD event.
+
+ If a plugin receives an event with type 0, it means the event is a
+ pointer to some object in memory and not a flat sequence of bytes
+ in the buffer. If the plugin does not pass the event through to
+ an output or store it internally somehow, it MUST call this function
+ on the event (more information on using non-POD events below).
+
+ @param event An event received at an input that will not be copied to an
+ output or stored in any way.
+
+ @param context The calling context. Like event types, this is a mapped
+ URI, see lv2_context.h. Simple plugin with just a run() method should
+ pass 0 here (the ID of the 'standard' LV2 run context). The host
+ guarantees that this function is realtime safe iff @a context is
+ realtime safe.
+
+ PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS.
+ */
+ uint32_t (*lv2_event_unref)(LV2_Event_Callback_Data callback_data,
+ LV2_Event* event);
+} LV2_Event_Feature;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_EVENT_H */
diff --git a/distrho/src/lv2/instance-access.h b/distrho/src/lv2/instance-access.h
@@ -0,0 +1,37 @@
+/*
+ LV2 Instance Access Extension
+ Copyright 2008-2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+#ifndef LV2_INSTANCE_ACCESS_H
+#define LV2_INSTANCE_ACCESS_H
+
+#define LV2_INSTANCE_ACCESS_URI "http://lv2plug.in/ns/ext/instance-access"
+
+/**
+ @file instance-access.h
+ C header for the LV2 Instance Access extension
+ <http://lv2plug.in/ns/ext/instance-access>.
+
+ This extension defines a method for (e.g.) plugin UIs to get a direct
+ handle to an LV2 plugin instance (LV2_Handle), if possible.
+
+ To support this feature the host must pass an LV2_Feature struct to the
+ UI instantiate method with URI "http://lv2plug.in/ns/ext/instance-access"
+ and data pointed directly to the LV2_Handle of the plugin instance.
+*/
+
+#endif /* LV2_INSTANCE_ACCESS_H */
+
diff --git a/distrho/src/lv2/log.h b/distrho/src/lv2/log.h
@@ -0,0 +1,99 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file log.h C header for the LV2 Log extension
+ <http://lv2plug.in/ns/ext/log>.
+*/
+
+#ifndef LV2_LOG_H
+#define LV2_LOG_H
+
+#define LV2_LOG_URI "http://lv2plug.in/ns/ext/log"
+#define LV2_LOG_PREFIX LV2_LOG_URI "#"
+
+#define LV2_LOG__Entry LV2_LOG_PREFIX "Entry"
+#define LV2_LOG__Error LV2_LOG_PREFIX "Error"
+#define LV2_LOG__Note LV2_LOG_PREFIX "Note"
+#define LV2_LOG__Trace LV2_LOG_PREFIX "Trace"
+#define LV2_LOG__Warning LV2_LOG_PREFIX "Warning"
+#define LV2_LOG__log LV2_LOG_PREFIX "log"
+
+#include <stdarg.h>
+
+#include "urid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __GNUC__
+/** Allow type checking of printf-like functions. */
+# define LV2_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1)))
+#else
+# define LV2_LOG_FUNC(fmt, arg1)
+#endif
+
+/**
+ Opaque data to host data for LV2_Log_Log.
+*/
+typedef void* LV2_Log_Handle;
+
+/**
+ Log feature (LV2_LOG__log)
+*/
+typedef struct _LV2_Log {
+ /**
+ Opaque pointer to host data.
+
+ This MUST be passed to methods in this struct whenever they are called.
+ Otherwise, it must not be interpreted in any way.
+ */
+ LV2_Log_Handle handle;
+
+ /**
+ Log a message, passing format parameters directly.
+
+ The API of this function matches that of the standard C printf function,
+ except for the addition of the first two parameters. This function may
+ be called from any non-realtime context, or from any context if @p type
+ is @ref LV2_LOG__Trace.
+ */
+ LV2_LOG_FUNC(3, 4)
+ int (*printf)(LV2_Log_Handle handle,
+ LV2_URID type,
+ const char* fmt, ...);
+
+ /**
+ Log a message, passing format parameters in a va_list.
+
+ The API of this function matches that of the standard C vprintf
+ function, except for the addition of the first two parameters. This
+ function may be called from any non-realtime context, or from any
+ context if @p type is @ref LV2_LOG__Trace.
+ */
+ LV2_LOG_FUNC(3, 0)
+ int (*vprintf)(LV2_Log_Handle handle,
+ LV2_URID type,
+ const char* fmt,
+ va_list ap);
+} LV2_Log_Log;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_LOG_H */
diff --git a/distrho/src/lv2/logger.h b/distrho/src/lv2/logger.h
@@ -0,0 +1,145 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file logger.h Convenience API for easy logging in plugin code.
+
+ This file provides simple wrappers for the most common log operations for
+ use in plugin implementations. If host support for logging is not
+ available, then these functions will print to stderr instead.
+
+ This header is non-normative, it is provided for convenience.
+*/
+
+#ifndef LV2_ATOM_LOGGER_H
+#define LV2_ATOM_LOGGER_H
+
+#include <stdio.h>
+
+#include "log.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ Logger convenience API state.
+*/
+typedef struct {
+ LV2_Log_Log* log;
+
+ LV2_URID Error;
+ LV2_URID Note;
+ LV2_URID Trace;
+ LV2_URID Warning;
+} LV2_Log_Logger;
+
+/**
+ Initialise @p logger.
+
+ URIs will be mapped using @p map and stored, a reference to @p map itself is
+ not held. Both @p map and @p log may be NULL when unsupported by the host,
+ in which case the implementation will fall back to printing to stderr.
+*/
+static inline void
+lv2_log_logger_init(LV2_Log_Logger* logger,
+ LV2_URID_Map* map,
+ LV2_Log_Log* log)
+{
+ memset(logger, 0, sizeof(LV2_Log_Logger));
+ logger->log = log;
+ if (map) {
+ logger->Error = map->map(map->handle, LV2_LOG__Error);
+ logger->Note = map->map(map->handle, LV2_LOG__Note);
+ logger->Trace = map->map(map->handle, LV2_LOG__Trace);
+ logger->Warning = map->map(map->handle, LV2_LOG__Warning);
+ }
+}
+
+/**
+ Log a message to the host, or stderr if support is unavailable.
+*/
+LV2_LOG_FUNC(3, 0)
+static inline int
+lv2_log_vprintf(LV2_Log_Logger* logger,
+ LV2_URID type,
+ const char* fmt,
+ va_list args)
+{
+ if (logger->log) {
+ return logger->log->vprintf(logger->log->handle, type, fmt, args);
+ } else {
+ return vfprintf(stderr, fmt, args);
+ }
+}
+
+/** Log an error via lv2_log_vprintf(). */
+LV2_LOG_FUNC(2, 3)
+static inline int
+lv2_log_error(LV2_Log_Logger* logger, const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ const int ret = lv2_log_vprintf(logger, logger->Error, fmt, args);
+ va_end(args);
+ return ret;
+}
+
+/** Log a note via lv2_log_vprintf(). */
+LV2_LOG_FUNC(2, 3)
+static inline int
+lv2_log_note(LV2_Log_Logger* logger, const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ const int ret = lv2_log_vprintf(logger, logger->Note, fmt, args);
+ va_end(args);
+ return ret;
+}
+
+/** Log a trace via lv2_log_vprintf(). */
+LV2_LOG_FUNC(2, 3)
+static inline int
+lv2_log_trace(LV2_Log_Logger* logger, const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ const int ret = lv2_log_vprintf(logger, logger->Trace, fmt, args);
+ va_end(args);
+ return ret;
+}
+
+/** Log a warning via lv2_log_vprintf(). */
+LV2_LOG_FUNC(2, 3)
+static inline int
+lv2_log_warning(LV2_Log_Logger* logger, const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ const int ret = lv2_log_vprintf(logger, logger->Warning, fmt, args);
+ va_end(args);
+ return ret;
+}
+
+/**
+ @}
+*/
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_LOG_LOGGER_H */
diff --git a/distrho/src/lv2/lv2-midifunctions.h b/distrho/src/lv2/lv2-midifunctions.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+
+ lv2-midifunctions.h - support file for using MIDI in LV2 plugins
+
+ Copyright (C) 2006 Lars Luthman <lars.luthman@gmail.com>
+
+ This program 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 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA
+
+****************************************************************************/
+
+#ifndef LV2_MIDIFUNCTIONS
+#define LV2_MIDIFUNCTIONS
+
+#include "lv2-miditype.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ LV2_MIDI* midi;
+ uint32_t frame_count;
+ uint32_t position;
+} LV2_MIDIState;
+
+
+inline double lv2midi_get_event(LV2_MIDIState* state,
+ double* timestamp,
+ uint32_t* size,
+ unsigned char** data) {
+
+ if (state->position >= state->midi->size) {
+ state->position = state->midi->size;
+ *timestamp = state->frame_count;
+ *size = 0;
+ *data = NULL;
+ return *timestamp;
+ }
+
+ *timestamp = *(double*)(state->midi->data + state->position);
+ *size = *(size_t*)(state->midi->data + state->position + sizeof(double));
+ *data = state->midi->data + state->position +
+ sizeof(double) + sizeof(size_t);
+ return *timestamp;
+}
+
+
+inline double lv2midi_step(LV2_MIDIState* state) {
+
+ if (state->position >= state->midi->size) {
+ state->position = state->midi->size;
+ return state->frame_count;
+ }
+
+ state->position += sizeof(double);
+ size_t size = *(size_t*)(state->midi->data + state->position);
+ state->position += sizeof(size_t);
+ state->position += size;
+ return *(double*)(state->midi->data + state->position);
+}
+
+
+inline void lv2midi_put_event(LV2_MIDIState* state,
+ double timestamp,
+ uint32_t size,
+ const unsigned char* data) {
+
+ if (state->midi->size + sizeof(double) + sizeof(size_t) + size < state->midi->capacity)
+ {
+ *((double*)(state->midi->data + state->midi->size)) = timestamp;
+ state->midi->size += sizeof(double);
+ *((size_t*)(state->midi->data + state->midi->size)) = size;
+ state->midi->size += sizeof(size_t);
+ memcpy(state->midi->data + state->midi->size, data, size);
+
+ state->midi->size += size;
+ state->midi->event_count++;
+ }
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
+
diff --git a/distrho/src/lv2/lv2-miditype.h b/distrho/src/lv2/lv2-miditype.h
@@ -0,0 +1,175 @@
+/****************************************************************************
+
+ lv2-miditype.h - header file for using MIDI in LV2 plugins
+
+ Copyright (C) 2006 Lars Luthman <lars.luthman@gmail.com>
+
+ This program 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 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA
+
+****************************************************************************/
+
+#ifndef LV2_MIDITYPE_H
+#define LV2_MIDITYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** This data structure is used to contain the MIDI events for one run()
+ cycle. The port buffer for a LV2 port that has the datatype
+ <http://ll-plugins.nongnu.org/lv2/ext/miditype> should be a pointer
+ to an instance of this struct.
+
+ To store two Note On events on MIDI channel 0 in a buffer, with timestamps
+ 12 and 35.5, you could use something like this code (assuming that
+ midi_data is a variable of type LV2_MIDI):
+ @code
+
+ size_t buffer_offset = 0;
+ *(double*)(midi_data->data + buffer_offset) = 12;
+ buffer_offset += sizeof(double);
+ *(size_t*)(midi_data->data + buffer_offset) = 3;
+ buffer_offset += sizeof(size_t);
+ midi_data->data[buffer_offset++] = 0x90;
+ midi_data->data[buffer_offset++] = 0x48;
+ midi_data->data[buffer_offset++] = 0x64;
+ ++midi_data->event_count;
+
+ *(double*)(midi_data->data + buffer_offset) = 35.5;
+ buffer_offset += sizeof(double);
+ *(size_t*)(midi_data->data + buffer_offset) = 3;
+ buffer_offset += sizeof(size_t);
+ midi_data->data[buffer_offset++] = 0x90;
+ midi_data->data[buffer_offset++] = 0x55;
+ midi_data->data[buffer_offset++] = 0x64;
+ ++midi_data->event_count;
+
+ midi_data->size = buffer_offset;
+
+ @endcode
+
+ This would be done by the host in the case of an input port, and by the
+ plugin in the case of an output port. Whoever is writing events to the
+ buffer must also take care not to exceed the capacity of the data buffer.
+
+ To read events from a buffer, you could do something like this:
+ @code
+
+ size_t buffer_offset = 0;
+ uint32_t i;
+ for (i = 0; i < midi_data->event_count; ++i) {
+ double timestamp = *(double*)(midi_data->data + buffer_offset);
+ buffer_offset += sizeof(double);
+ size_t size = *(size_t*)(midi_data->data + buffer_offset);
+ buffer_offset += sizeof(size_t);
+ do_something_with_event(timestamp, size,
+ midi_data->data + buffer_offset);
+ buffer_offset += size;
+ }
+
+ @endcode
+*/
+typedef struct {
+
+ /** The number of MIDI events in the data buffer.
+ INPUT PORTS: It's the host's responsibility to set this field to the
+ number of MIDI events contained in the data buffer before calling the
+ plugin's run() function. The plugin may not change this field.
+ OUTPUT PORTS: It's the plugin's responsibility to set this field to the
+ number of MIDI events it has stored in the data buffer before returning
+ from the run() function. Any initial value should be ignored by the
+ plugin.
+ */
+ uint32_t event_count;
+
+ /** The size of the data buffer in bytes. It is set by the host and may not
+ be changed by the plugin. The host is allowed to change this between
+ run() calls.
+ */
+ uint32_t capacity;
+
+ /** The size of the initial part of the data buffer that actually contains
+ data.
+ INPUT PORTS: It's the host's responsibility to set this field to the
+ number of bytes used by all MIDI events it has written to the buffer
+ (including timestamps and size fields) before calling the plugin's
+ run() function. The plugin may not change this field.
+ OUTPUT PORTS: It's the plugin's responsibility to set this field to
+ the number of bytes used by all MIDI events it has written to the
+ buffer (including timestamps and size fields) before returning from
+ the run() function. Any initial value should be ignored by the plugin.
+ */
+ uint32_t size;
+
+ /** The data buffer that is used to store MIDI events. The events are packed
+ after each other, and the format of each event is as follows:
+
+ First there is a timestamp, which should have the type "double",
+ i.e. have the same bit size as a double and the same bit layout as a
+ double (whatever that is on the current platform). This timestamp gives
+ the offset from the beginning of the current cycle, in frames, that
+ the MIDI event occurs on. It must be strictly smaller than the 'nframes'
+ parameter to the current run() call. The MIDI events in the buffer must
+ be ordered by their timestamp, e.g. an event with a timestamp of 123.23
+ must be stored after an event with a timestamp of 65.0.
+
+ The second part of the event is a size field, which should have the type
+ "size_t" (as defined in the standard C header stddef.h). It should
+ contain the size of the MIDI data for this event, i.e. the number of
+ bytes used to store the actual MIDI event. The bytes used by the
+ timestamp and the size field should not be counted.
+
+ The third part of the event is the actual MIDI data. There are some
+ requirements that must be followed:
+
+ * Running status is not allowed. Every event must have its own status
+ byte.
+ * Note On events with velocity 0 are not allowed. These events are
+ equivalent to Note Off in standard MIDI streams, but in order to make
+ plugins and hosts easier to write, as well as more efficient, only
+ proper Note Off events are allowed as Note Off.
+ * "Realtime events" (status bytes 0xF8 to 0xFF) are allowed, but may not
+ occur inside other events like they are allowed to in hardware MIDI
+ streams.
+ * All events must be fully contained in a single data buffer, i.e. events
+ may not "wrap around" by storing the first few bytes in one buffer and
+ then wait for the next run() call to store the rest of the event. If
+ there isn't enough space in the current data buffer to store an event,
+ the event will either have to wait until next run() call, be ignored,
+ or compensated for in some more clever way.
+ * All events must be valid MIDI events. This means for example that
+ only the first byte in each event (the status byte) may have the eighth
+ bit set, that Note On and Note Off events are always 3 bytes long etc.
+ The MIDI writer (host or plugin) is responsible for writing valid MIDI
+ events to the buffer, and the MIDI reader (plugin or host) can assume
+ that all events are valid.
+
+ On a platform where double is 8 bytes and size_t is 4 bytes, the data
+ buffer layout for a 3-byte event followed by a 4-byte event may look
+ something like this:
+ _______________________________________________________________
+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ...
+ |TIMESTAMP 1 |SIZE 1 |DATA |TIMESTAMP 2 |SIZE 2 |DATA | ...
+
+ */
+ unsigned char* data;
+
+} LV2_MIDI;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/distrho/src/lv2/lv2.h b/distrho/src/lv2/lv2.h
@@ -0,0 +1,454 @@
+/*
+ LV2 - An audio plugin interface specification.
+ Copyright 2006-2012 Steve Harris, David Robillard.
+
+ Based on LADSPA, Copyright 2000-2002 Richard W.E. Furse,
+ Paul Barton-Davis, Stefan Westerfeld.
+
+ 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.
+*/
+
+/**
+ @file lv2.h
+ API for the LV2 specification <http://lv2plug.in/ns/lv2core>.
+ Revision: 6.5
+*/
+
+#ifndef LV2_H_INCLUDED
+#define LV2_H_INCLUDED
+
+#include <stdint.h>
+
+#define LV2_CORE_URI "http://lv2plug.in/ns/lv2core"
+#define LV2_CORE_PREFIX LV2_CORE_URI "#"
+
+#define LV2_CORE__AllpassPlugin LV2_CORE_PREFIX "AllpassPlugin"
+#define LV2_CORE__AmplifierPlugin LV2_CORE_PREFIX "AmplifierPlugin"
+#define LV2_CORE__AnalyserPlugin LV2_CORE_PREFIX "AnalyserPlugin"
+#define LV2_CORE__AudioPort LV2_CORE_PREFIX "AudioPort"
+#define LV2_CORE__BandpassPlugin LV2_CORE_PREFIX "BandpassPlugin"
+#define LV2_CORE__CVPort LV2_CORE_PREFIX "CVPort"
+#define LV2_CORE__ChorusPlugin LV2_CORE_PREFIX "ChorusPlugin"
+#define LV2_CORE__CombPlugin LV2_CORE_PREFIX "CombPlugin"
+#define LV2_CORE__CompressorPlugin LV2_CORE_PREFIX "CompressorPlugin"
+#define LV2_CORE__ConstantPlugin LV2_CORE_PREFIX "ConstantPlugin"
+#define LV2_CORE__ControlPort LV2_CORE_PREFIX "ControlPort"
+#define LV2_CORE__ConverterPlugin LV2_CORE_PREFIX "ConverterPlugin"
+#define LV2_CORE__DelayPlugin LV2_CORE_PREFIX "DelayPlugin"
+#define LV2_CORE__DistortionPlugin LV2_CORE_PREFIX "DistortionPlugin"
+#define LV2_CORE__DynamicsPlugin LV2_CORE_PREFIX "DynamicsPlugin"
+#define LV2_CORE__EQPlugin LV2_CORE_PREFIX "EQPlugin"
+#define LV2_CORE__EnvelopePlugin LV2_CORE_PREFIX "EnvelopePlugin"
+#define LV2_CORE__ExpanderPlugin LV2_CORE_PREFIX "ExpanderPlugin"
+#define LV2_CORE__ExtensionData LV2_CORE_PREFIX "ExtensionData"
+#define LV2_CORE__Feature LV2_CORE_PREFIX "Feature"
+#define LV2_CORE__FilterPlugin LV2_CORE_PREFIX "FilterPlugin"
+#define LV2_CORE__FlangerPlugin LV2_CORE_PREFIX "FlangerPlugin"
+#define LV2_CORE__FunctionPlugin LV2_CORE_PREFIX "FunctionPlugin"
+#define LV2_CORE__GatePlugin LV2_CORE_PREFIX "GatePlugin"
+#define LV2_CORE__GeneratorPlugin LV2_CORE_PREFIX "GeneratorPlugin"
+#define LV2_CORE__HighpassPlugin LV2_CORE_PREFIX "HighpassPlugin"
+#define LV2_CORE__InputPort LV2_CORE_PREFIX "InputPort"
+#define LV2_CORE__InstrumentPlugin LV2_CORE_PREFIX "InstrumentPlugin"
+#define LV2_CORE__LimiterPlugin LV2_CORE_PREFIX "LimiterPlugin"
+#define LV2_CORE__LowpassPlugin LV2_CORE_PREFIX "LowpassPlugin"
+#define LV2_CORE__MixerPlugin LV2_CORE_PREFIX "MixerPlugin"
+#define LV2_CORE__ModulatorPlugin LV2_CORE_PREFIX "ModulatorPlugin"
+#define LV2_CORE__MultiEQPlugin LV2_CORE_PREFIX "MultiEQPlugin"
+#define LV2_CORE__OscillatorPlugin LV2_CORE_PREFIX "OscillatorPlugin"
+#define LV2_CORE__OutputPort LV2_CORE_PREFIX "OutputPort"
+#define LV2_CORE__ParaEQPlugin LV2_CORE_PREFIX "ParaEQPlugin"
+#define LV2_CORE__PhaserPlugin LV2_CORE_PREFIX "PhaserPlugin"
+#define LV2_CORE__PitchPlugin LV2_CORE_PREFIX "PitchPlugin"
+#define LV2_CORE__Plugin LV2_CORE_PREFIX "Plugin"
+#define LV2_CORE__PluginBase LV2_CORE_PREFIX "PluginBase"
+#define LV2_CORE__Point LV2_CORE_PREFIX "Point"
+#define LV2_CORE__Port LV2_CORE_PREFIX "Port"
+#define LV2_CORE__PortProperty LV2_CORE_PREFIX "PortProperty"
+#define LV2_CORE__Resource LV2_CORE_PREFIX "Resource"
+#define LV2_CORE__ReverbPlugin LV2_CORE_PREFIX "ReverbPlugin"
+#define LV2_CORE__ScalePoint LV2_CORE_PREFIX "ScalePoint"
+#define LV2_CORE__SimulatorPlugin LV2_CORE_PREFIX "SimulatorPlugin"
+#define LV2_CORE__SpatialPlugin LV2_CORE_PREFIX "SpatialPlugin"
+#define LV2_CORE__Specification LV2_CORE_PREFIX "Specification"
+#define LV2_CORE__SpectralPlugin LV2_CORE_PREFIX "SpectralPlugin"
+#define LV2_CORE__UtilityPlugin LV2_CORE_PREFIX "UtilityPlugin"
+#define LV2_CORE__WaveshaperPlugin LV2_CORE_PREFIX "WaveshaperPlugin"
+#define LV2_CORE__appliesTo LV2_CORE_PREFIX "appliesTo"
+#define LV2_CORE__binary LV2_CORE_PREFIX "binary"
+#define LV2_CORE__connectionOptional LV2_CORE_PREFIX "connectionOptional"
+#define LV2_CORE__control LV2_CORE_PREFIX "control"
+#define LV2_CORE__default LV2_CORE_PREFIX "default"
+#define LV2_CORE__designation LV2_CORE_PREFIX "designation"
+#define LV2_CORE__documentation LV2_CORE_PREFIX "documentation"
+#define LV2_CORE__enumeration LV2_CORE_PREFIX "enumeration"
+#define LV2_CORE__extensionData LV2_CORE_PREFIX "extensionData"
+#define LV2_CORE__freeWheeling LV2_CORE_PREFIX "freeWheeling"
+#define LV2_CORE__hardRTCapable LV2_CORE_PREFIX "hardRTCapable"
+#define LV2_CORE__inPlaceBroken LV2_CORE_PREFIX "inPlaceBroken"
+#define LV2_CORE__index LV2_CORE_PREFIX "index"
+#define LV2_CORE__integer LV2_CORE_PREFIX "integer"
+#define LV2_CORE__isLive LV2_CORE_PREFIX "isLive"
+#define LV2_CORE__latency LV2_CORE_PREFIX "latency"
+#define LV2_CORE__maximum LV2_CORE_PREFIX "maximum"
+#define LV2_CORE__microVersion LV2_CORE_PREFIX "microVersion"
+#define LV2_CORE__minimum LV2_CORE_PREFIX "minimum"
+#define LV2_CORE__minorVersion LV2_CORE_PREFIX "minorVersion"
+#define LV2_CORE__name LV2_CORE_PREFIX "name"
+#define LV2_CORE__optionalFeature LV2_CORE_PREFIX "optionalFeature"
+#define LV2_CORE__port LV2_CORE_PREFIX "port"
+#define LV2_CORE__portProperty LV2_CORE_PREFIX "portProperty"
+#define LV2_CORE__project LV2_CORE_PREFIX "project"
+#define LV2_CORE__reportsLatency LV2_CORE_PREFIX "reportsLatency"
+#define LV2_CORE__requiredFeature LV2_CORE_PREFIX "requiredFeature"
+#define LV2_CORE__sampleRate LV2_CORE_PREFIX "sampleRate"
+#define LV2_CORE__scalePoint LV2_CORE_PREFIX "scalePoint"
+#define LV2_CORE__symbol LV2_CORE_PREFIX "symbol"
+#define LV2_CORE__toggled LV2_CORE_PREFIX "toggled"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ Plugin Instance Handle.
+
+ This is a handle for one particular instance of a plugin. It is valid to
+ compare to NULL (or 0 for C++) but otherwise the host MUST NOT attempt to
+ interpret it.
+*/
+typedef void * LV2_Handle;
+
+/**
+ Feature.
+
+ Features allow hosts to make additional functionality available to plugins
+ without requiring modification to the LV2 API. Extensions may define new
+ features and specify the @ref URI and @ref data to be used if necessary.
+ Some features, such as lv2:isLive, do not require the host to pass data.
+*/
+typedef struct _LV2_Feature {
+ /**
+ A globally unique, case-sensitive identifier (URI) for this feature.
+
+ This MUST be a valid URI string as defined by RFC 3986.
+ */
+ const char * URI;
+
+ /**
+ Pointer to arbitrary data.
+
+ The format of this data is defined by the extension which describes the
+ feature with the given @ref URI.
+ */
+ void * data;
+} LV2_Feature;
+
+/**
+ Plugin Descriptor.
+
+ This structure provides the core functions necessary to instantiate and use
+ a plugin.
+*/
+typedef struct _LV2_Descriptor {
+ /**
+ A globally unique, case-sensitive identifier for this plugin.
+
+ This MUST be a valid URI string as defined by RFC 3986. All plugins with
+ the same URI MUST be compatible to some degree, see
+ http://lv2plug.in/ns/lv2core for details.
+ */
+ const char * URI;
+
+ /**
+ Instantiate the plugin.
+
+ Note that instance initialisation should generally occur in activate()
+ rather than here. If a host calls instantiate(), it MUST call cleanup()
+ at some point in the future.
+
+ @param descriptor Descriptor of the plugin to instantiate.
+
+ @param sample_rate Sample rate, in Hz, for the new plugin instance.
+
+ @param bundle_path Path to the LV2 bundle which contains this plugin
+ binary. It MUST include the trailing directory separator (e.g. '/') so
+ that simply appending a filename will yield the path to that file in the
+ bundle.
+
+ @param features A NULL terminated array of LV2_Feature structs which
+ represent the features the host supports. Plugins may refuse to
+ instantiate if required features are not found here. However, hosts MUST
+ NOT use this as a discovery mechanism: instead, use the RDF data to
+ determine which features are required and do not attempt to instantiate
+ unsupported plugins at all. This parameter MUST NOT be NULL, i.e. a host
+ that supports no features MUST pass a single element array containing
+ NULL.
+
+ @return A handle for the new plugin instance, or NULL if instantiation
+ has failed.
+ */
+ LV2_Handle (*instantiate)(const struct _LV2_Descriptor * descriptor,
+ double sample_rate,
+ const char * bundle_path,
+ const LV2_Feature *const * features);
+
+ /**
+ Connect a port on a plugin instance to a memory location.
+
+ Plugin writers should be aware that the host may elect to use the same
+ buffer for more than one port and even use the same buffer for both
+ input and output (see lv2:inPlaceBroken in lv2.ttl).
+
+ If the plugin has the feature lv2:hardRTCapable then there are various
+ things that the plugin MUST NOT do within the connect_port() function;
+ see lv2core.ttl for details.
+
+ connect_port() MUST be called at least once for each port before run()
+ is called, unless that port is lv2:connectionOptional. The plugin must
+ pay careful attention to the block size passed to run() since the block
+ allocated may only just be large enough to contain the data, and is not
+ guaranteed to remain constant between run() calls.
+
+ connect_port() may be called more than once for a plugin instance to
+ allow the host to change the buffers that the plugin is reading or
+ writing. These calls may be made before or after activate() or
+ deactivate() calls.
+
+ @param instance Plugin instance containing the port.
+
+ @param port Index of the port to connect. The host MUST NOT try to
+ connect a port index that is not defined in the plugin's RDF data. If
+ it does, the plugin's behaviour is undefined (a crash is likely).
+
+ @param data_location Pointer to data of the type defined by the port
+ type in the plugin's RDF data (e.g. an array of float for an
+ lv2:AudioPort). This pointer must be stored by the plugin instance and
+ used to read/write data when run() is called. Data present at the time
+ of the connect_port() call MUST NOT be considered meaningful.
+ */
+ void (*connect_port)(LV2_Handle instance,
+ uint32_t port,
+ void * data_location);
+
+ /**
+ Initialise a plugin instance and activate it for use.
+
+ This is separated from instantiate() to aid real-time support and so
+ that hosts can reinitialise a plugin instance by calling deactivate()
+ and then activate(). In this case the plugin instance MUST reset all
+ state information dependent on the history of the plugin instance except
+ for any data locations provided by connect_port(). If there is nothing
+ for activate() to do then this field may be NULL.
+
+ When present, hosts MUST call this function once before run() is called
+ for the first time. This call SHOULD be made as close to the run() call
+ as possible and indicates to real-time plugins that they are now live,
+ however plugins MUST NOT rely on a prompt call to run() after
+ activate().
+
+ The host MUST NOT call activate() again until deactivate() has been
+ called first. If a host calls activate(), it MUST call deactivate() at
+ some point in the future. Note that connect_port() may be called before
+ or after activate().
+ */
+ void (*activate)(LV2_Handle instance);
+
+ /**
+ Run a plugin instance for a block.
+
+ Note that if an activate() function exists then it must be called before
+ run(). If deactivate() is called for a plugin instance then run() may
+ not be called until activate() has been called again.
+
+ If the plugin has the feature lv2:hardRTCapable then there are various
+ things that the plugin MUST NOT do within the run() function (see
+ lv2core.ttl for details).
+
+ As a special case, when @p sample_count == 0, the plugin should update
+ any output ports that represent a single instant in time (e.g. control
+ ports, but not audio ports). This is particularly useful for latent
+ plugins, which should update their latency output port so hosts can
+ pre-roll plugins to compute latency. Plugins MUST NOT crash when
+ @p sample_count == 0.
+
+ @param instance Instance to be run.
+
+ @param sample_count The block size (in samples) for which the plugin
+ instance must run.
+ */
+ void (*run)(LV2_Handle instance,
+ uint32_t sample_count);
+
+ /**
+ Deactivate a plugin instance (counterpart to activate()).
+
+ Hosts MUST deactivate all activated instances after they have been run()
+ for the last time. This call SHOULD be made as close to the last run()
+ call as possible and indicates to real-time plugins that they are no
+ longer live, however plugins MUST NOT rely on prompt deactivation. If
+ there is nothing for deactivate() to do then this field may be NULL
+
+ Deactivation is not similar to pausing since the plugin instance will be
+ reinitialised by activate(). However, deactivate() itself MUST NOT fully
+ reset plugin state. For example, the host may deactivate a plugin, then
+ store its state (using some extension to do so).
+
+ Hosts MUST NOT call deactivate() unless activate() was previously
+ called. Note that connect_port() may be called before or after
+ deactivate().
+ */
+ void (*deactivate)(LV2_Handle instance);
+
+ /**
+ Clean up a plugin instance (counterpart to instantiate()).
+
+ Once an instance of a plugin has been finished with it must be deleted
+ using this function. The instance handle passed ceases to be valid after
+ this call.
+
+ If activate() was called for a plugin instance then a corresponding call
+ to deactivate() MUST be made before cleanup() is called. Hosts MUST NOT
+ call cleanup() unless instantiate() was previously called.
+ */
+ void (*cleanup)(LV2_Handle instance);
+
+ /**
+ Return additional plugin data defined by some extenion.
+
+ A typical use of this facility is to return a struct containing function
+ pointers to extend the LV2_Descriptor API.
+
+ The actual type and meaning of the returned object MUST be specified
+ precisely by the extension. This function MUST return NULL for any
+ unsupported URI. If a plugin does not support any extension data, this
+ field may be NULL.
+
+ The host is never responsible for freeing the returned value.
+ */
+ const void * (*extension_data)(const char * uri);
+} LV2_Descriptor;
+
+/**
+ Put this (LV2_SYMBOL_EXPORT) before any functions that are to be loaded
+ by the host as a symbol from the dynamic library.
+*/
+#ifdef _WIN32
+# define LV2_SYMBOL_EXPORT __declspec(dllexport)
+#else
+# define LV2_SYMBOL_EXPORT
+#endif
+
+/**
+ Prototype for plugin accessor function.
+
+ This is part of the old discovery API, which has been replaced due to being
+ inadequate for some plugins. It is limited because the bundle path is not
+ available during discovery, and it relies on non-portable shared library
+ constructors/destructors. However, this API is still supported and plugins
+ are not required to migrate.
+
+ Plugins are discovered by hosts using RDF data (not by loading libraries).
+ See http://lv2plug.in for details on the discovery process, though most
+ hosts should use an existing library to implement this functionality.
+
+ A plugin library MUST include a function called "lv2_descriptor" with this
+ prototype. This function MUST have C-style linkage (if you are using C++
+ this is taken care of by the 'extern "C"' clause at the top of this file).
+
+ When it is time to load a plugin (designated by its URI), the host loads the
+ plugin's library, gets the lv2_descriptor() function from it, and uses this
+ function to find the LV2_Descriptor for the desired plugin. Plugins are
+ accessed by index using values from 0 upwards. This function MUST return
+ NULL for out of range indices, so the host can enumerate plugins by
+ increasing @p index until NULL is returned.
+
+ Note that @p index has no meaning, hosts MUST NOT depend on it remaining
+ consistent between loads of the plugin library.
+*/
+LV2_SYMBOL_EXPORT
+const LV2_Descriptor * lv2_descriptor(uint32_t index);
+
+/**
+ Type of the lv2_descriptor() function in a library (old discovery API).
+*/
+typedef const LV2_Descriptor *
+(*LV2_Descriptor_Function)(uint32_t index);
+
+/**
+ Handle for a library descriptor.
+*/
+typedef void* LV2_Lib_Handle;
+
+/**
+ Descriptor for a plugin library.
+
+ To access a plugin library, the host creates an LV2_Lib_Descriptor via the
+ lv2_lib_descriptor() function in the shared object.
+*/
+typedef struct {
+ /**
+ Opaque library data which must be passed as the first parameter to all
+ the methods of this struct.
+ */
+ LV2_Lib_Handle handle;
+
+ /**
+ The total size of this struct. This allows for this struct to be
+ expanded in the future if necessary. This MUST be set by the library to
+ sizeof(LV2_Lib_Descriptor). The host MUST NOT access any fields of this
+ struct beyond get_plugin() unless this field indicates they are present.
+ */
+ uint32_t size;
+
+ /**
+ Destroy this library descriptor and free all related resources.
+ */
+ void (*cleanup)(LV2_Lib_Handle handle);
+
+ /**
+ Plugin accessor.
+
+ Plugins are accessed by index using values from 0 upwards. Out of range
+ indices MUST result in this function returning NULL, so the host can
+ enumerate plugins by increasing @a index until NULL is returned.
+ */
+ const LV2_Descriptor * (*get_plugin)(LV2_Lib_Handle handle,
+ uint32_t index);
+} LV2_Lib_Descriptor;
+
+/**
+ Prototype for library accessor function.
+
+ This is the entry point for a plugin library. Hosts load this symbol from
+ the library and call this function to obtain a library descriptor which can
+ be used to access all the contained plugins. The returned object must not
+ be destroyed (using LV2_Lib_Descriptor::cleanup()) until all plugins loaded
+ from that library have been destroyed.
+*/
+const LV2_Lib_Descriptor *
+lv2_lib_descriptor(const char * bundle_path,
+ const LV2_Feature *const * features);
+
+/**
+ Type of the lv2_lib_descriptor() function in an LV2 library.
+*/
+typedef const LV2_Lib_Descriptor *
+(*LV2_Lib_Descriptor_Function)(const char * bundle_path,
+ const LV2_Feature *const * features);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LV2_H_INCLUDED */
diff --git a/distrho/src/lv2/lv2_external_ui.h b/distrho/src/lv2/lv2_external_ui.h
@@ -0,0 +1,107 @@
+/*
+ LV2 External UI extension
+ This work is in public domain.
+
+ This file 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.
+
+ If you have questions, contact Filipe Coelho (aka falkTX) <falktx@falktx.com>
+ or ask in #lad channel, FreeNode IRC network.
+*/
+
+/**
+ @file lv2_external_ui.h
+ C header for the LV2 External UI extension <http://kxstudio.sf.net/ns/lv2ext/external-ui>.
+*/
+
+#ifndef LV2_EXTERNAL_UI_H
+#define LV2_EXTERNAL_UI_H
+
+#include "ui.h"
+
+#define LV2_EXTERNAL_UI_URI "http://kxstudio.sf.net/ns/lv2ext/external-ui"
+#define LV2_EXTERNAL_UI_PREFIX LV2_EXTERNAL_UI_URI "#"
+
+#define LV2_EXTERNAL_UI__Host LV2_EXTERNAL_UI_PREFIX "Host"
+#define LV2_EXTERNAL_UI__Widget LV2_EXTERNAL_UI_PREFIX "Widget"
+
+/** This extension used to be defined by a lv2plug.in URI */
+#define LV2_EXTERNAL_UI_DEPRECATED_URI "http://lv2plug.in/ns/extensions/ui#external"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * When LV2_EXTERNAL_UI__Widget UI is instantiated, the returned
+ * LV2UI_Widget handle must be cast to pointer to LV2_External_UI_Widget.
+ * UI is created in invisible state.
+ */
+typedef struct _LV2_External_UI_Widget {
+ /**
+ * Host calls this function regulary. UI library implementing the
+ * callback may do IPC or redraw the UI.
+ *
+ * @param _this_ the UI context
+ */
+ void (*run)(struct _LV2_External_UI_Widget * _this_);
+
+ /**
+ * Host calls this function to make the plugin UI visible.
+ *
+ * @param _this_ the UI context
+ */
+ void (*show)(struct _LV2_External_UI_Widget * _this_);
+
+ /**
+ * Host calls this function to make the plugin UI invisible again.
+ *
+ * @param _this_ the UI context
+ */
+ void (*hide)(struct _LV2_External_UI_Widget * _this_);
+
+} LV2_External_UI_Widget;
+
+#define LV2_EXTERNAL_UI_RUN(ptr) (ptr)->run(ptr)
+#define LV2_EXTERNAL_UI_SHOW(ptr) (ptr)->show(ptr)
+#define LV2_EXTERNAL_UI_HIDE(ptr) (ptr)->hide(ptr)
+
+/**
+ * On UI instantiation, host must supply LV2_EXTERNAL_UI__Host feature.
+ * LV2_Feature::data must be pointer to LV2_External_UI_Host.
+ */
+typedef struct _LV2_External_UI_Host {
+ /**
+ * Callback that plugin UI will call
+ * when UI (GUI window) is closed by user.
+ * This callback will be called during execution of LV2_External_UI_Widget::run()
+ * (i.e. not from background thread).
+ *
+ * After this callback is called, UI is defunct. Host must call
+ * LV2UI_Descriptor::cleanup(). If host wants to make the UI visible
+ * again UI must be reinstantiated.
+ *
+ * @param controller Host context associated with plugin UI, as
+ * supplied to LV2UI_Descriptor::instantiate()
+ */
+ void (*ui_closed)(LV2UI_Controller controller);
+
+ /**
+ * Optional (may be NULL) "user friendly" identifier which the UI
+ * may display to allow a user to easily associate this particular
+ * UI instance with the correct plugin instance as it is represented
+ * by the host (e.g. "track 1" or "channel 4").
+ *
+ * If supplied by host, the string will be referenced only during
+ * LV2UI_Descriptor::instantiate()
+ */
+ const char * plugin_human_id;
+
+} LV2_External_UI_Host;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_EXTERNAL_UI_H */
diff --git a/distrho/src/lv2/lv2_programs.h b/distrho/src/lv2/lv2_programs.h
@@ -0,0 +1,174 @@
+/*
+ LV2 Programs Extension
+ Copyright 2012 Filipe Coelho <falktx@falktx.com>
+
+ 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.
+*/
+
+/**
+ @file lv2_programs.h
+ C header for the LV2 programs extension <http://kxstudio.sf.net/ns/lv2ext/programs>.
+*/
+
+#ifndef LV2_PROGRAMS_H
+#define LV2_PROGRAMS_H
+
+#include "lv2.h"
+#include "ui.h"
+
+#define LV2_PROGRAMS_URI "http://kxstudio.sf.net/ns/lv2ext/programs"
+#define LV2_PROGRAMS_PREFIX LV2_PROGRAMS_URI "#"
+
+#define LV2_PROGRAMS__Host LV2_PROGRAMS_PREFIX "Host"
+#define LV2_PROGRAMS__Interface LV2_PROGRAMS_PREFIX "Interface"
+#define LV2_PROGRAMS__UIInterface LV2_PROGRAMS_PREFIX "UIInterface"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void* LV2_Programs_Handle;
+
+typedef struct _LV2_Program_Descriptor {
+
+ /** Bank number for this program. Note that this extension does not
+ support MIDI-style separation of bank LSB and MSB values. There is
+ no restriction on the set of available banks: the numbers do not
+ need to be contiguous, there does not need to be a bank 0, etc. */
+ uint32_t bank;
+
+ /** Program number (unique within its bank) for this program. There is
+ no restriction on the set of available programs: the numbers do not
+ need to be contiguous, there does not need to be a program 0, etc. */
+ uint32_t program;
+
+ /** Name of the program. */
+ const char * name;
+
+} LV2_Program_Descriptor;
+
+/**
+ Programs extension, plugin data.
+
+ When the plugin's extension_data is called with argument LV2_PROGRAMS__Interface,
+ the plugin MUST return an LV2_Programs_Instance structure, which remains valid
+ for the lifetime of the plugin.
+*/
+typedef struct _LV2_Programs_Interface {
+ /**
+ * get_program()
+ *
+ * This member is a function pointer that provides a description
+ * of a program (named preset sound) available on this plugin.
+ *
+ * The index argument is an index into the plugin's list of
+ * programs, not a program number as represented by the Program
+ * field of the LV2_Program_Descriptor. (This distinction is
+ * needed to support plugins that use non-contiguous program or
+ * bank numbers.)
+ *
+ * This function returns a LV2_Program_Descriptor pointer that is
+ * guaranteed to be valid only until the next call to get_program
+ * or deactivate, on the same plugin instance. This function must
+ * return NULL if passed an index argument out of range, so that
+ * the host can use it to query the number of programs as well as
+ * their properties.
+ */
+ const LV2_Program_Descriptor *(*get_program)(LV2_Handle handle,
+ uint32_t index);
+
+ /**
+ * select_program()
+ *
+ * This member is a function pointer that selects a new program
+ * for this plugin. The program change should take effect
+ * immediately at the start of the next run() call. (This
+ * means that a host providing the capability of changing programs
+ * between any two notes on a track must vary the block size so as
+ * to place the program change at the right place. A host that
+ * wanted to avoid this would probably just instantiate a plugin
+ * for each program.)
+ *
+ * Plugins should ignore a select_program() call with an invalid
+ * bank or program.
+ *
+ * A plugin is not required to select any particular default
+ * program on activate(): it's the host's duty to set a program
+ * explicitly.
+ *
+ * A plugin is permitted to re-write the values of its input
+ * control ports when select_program is called. The host should
+ * re-read the input control port values and update its own
+ * records appropriately. (This is the only circumstance in which
+ * a LV2 plugin is allowed to modify its own control-input ports.)
+ */
+ void (*select_program)(LV2_Handle handle,
+ uint32_t bank,
+ uint32_t program);
+
+} LV2_Programs_Interface;
+
+/**
+ Programs extension, UI data.
+
+ When the UI's extension_data is called with argument LV2_PROGRAMS__UIInterface,
+ the UI MUST return an LV2_Programs_UI_Interface structure, which remains valid
+ for the lifetime of the UI.
+*/
+typedef struct _LV2_Programs_UI_Interface {
+ /**
+ * select_program()
+ *
+ * This is exactly the same as select_program in LV2_Programs_Instance,
+ * but this struct relates to the UI instead of the plugin.
+ *
+ * When called, UIs should update their state to match the selected program.
+ */
+ void (*select_program)(LV2UI_Handle handle,
+ uint32_t bank,
+ uint32_t program);
+
+} LV2_Programs_UI_Interface;
+
+/**
+ Feature data for LV2_PROGRAMS__Host.
+*/
+typedef struct _LV2_Programs_Host {
+ /**
+ * Opaque host data.
+ */
+ LV2_Programs_Handle handle;
+
+ /**
+ * program_changed()
+ *
+ * Tell the host to reload a plugin's program.
+ * Parameter handle MUST be the 'handle' member of this struct.
+ * Parameter index is program index to change.
+ * When index is -1, host should reload all the programs.
+ *
+ * The plugin MUST NEVER call this function on a RT context or during run().
+ *
+ * NOTE: This call is to inform the host about a program's bank, program or name change.
+ * It DOES NOT change the current selected program.
+ */
+ void (*program_changed)(LV2_Programs_Handle handle,
+ int32_t index);
+
+} LV2_Programs_Host;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_PROGRAMS_H */
diff --git a/distrho/src/lv2/lv2_rtmempool.h b/distrho/src/lv2/lv2_rtmempool.h
@@ -0,0 +1,105 @@
+/*
+ LV2 realtime safe memory pool extension definition
+ This work is in public domain.
+
+ This file 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.
+
+ If you have questions, contact Filipe Coelho (aka falkTX) <falktx@falktx.com>
+ or ask in #lad channel, FreeNode IRC network.
+*/
+
+/**
+ * @file lv2_rtmempool.h
+ * C header for the LV2 rtmempool extension <http://kxstudio.sf.net/ns/lv2ext/rtmempool>.
+ *
+ */
+
+#ifndef LV2_RTMEMPOOL_H
+#define LV2_RTMEMPOOL_H
+
+#define LV2_RTSAFE_MEMORY_POOL_URI "http://kxstudio.sf.net/ns/lv2ext/rtmempool"
+#define LV2_RTSAFE_MEMORY_POOL_PREFIX LV2_RTSAFE_MEMORY_POOL_URI "#"
+
+#define LV2_RTSAFE_MEMORY_POOL__Pool LV2_RTSAFE_MEMORY_POOL_URI "Pool"
+
+/** max size of memory pool name, in chars, including terminating zero char */
+#define LV2_RTSAFE_MEMORY_POOL_NAME_MAX 128
+
+#ifdef __cplusplus
+extern "C" {
+#else
+#include <stdbool.h>
+#endif
+
+/**
+ * Opaque data to host data for LV2_RtMemPool_Pool.
+ */
+typedef void* LV2_RtMemPool_Handle;
+
+/**
+ * On instantiation, host must supply LV2_RTSAFE_MEMORY_POOL__Pool feature.
+ * LV2_Feature::data must be pointer to LV2_RtMemPool_Pool.
+ */
+typedef struct _LV2_RtMemPool_Pool {
+ /**
+ * This function is called when plugin wants to create memory pool
+ *
+ * <b>may/will sleep</b>
+ *
+ * @param pool_name pool name, for debug purposes, max RTSAFE_MEMORY_POOL_NAME_MAX chars, including terminating zero char. May be NULL.
+ * @param data_size memory chunk size
+ * @param min_preallocated min chunks preallocated
+ * @param max_preallocated max chunks preallocated
+ *
+ * @return Success status, true if successful
+ */
+ bool (*create)(LV2_RtMemPool_Handle * handle_ptr,
+ const char * pool_name,
+ size_t data_size,
+ size_t min_preallocated,
+ size_t max_preallocated);
+
+ /**
+ * This function is called when plugin wants to destroy previously created memory pool
+ *
+ * <b>may/will sleep</b>
+ */
+ void (*destroy)(LV2_RtMemPool_Handle handle);
+
+ /**
+ * This function is called when plugin wants to allocate memory in context where sleeping is not allowed
+ *
+ * <b>will not sleep</b>
+ *
+ * @return Pointer to allocated memory or NULL if memory no memory is available
+ */
+ void * (*allocate_atomic)(LV2_RtMemPool_Handle handle);
+
+ /**
+ * This function is called when plugin wants to allocate memory in context where sleeping is allowed
+ *
+ * <b>may/will sleep</b>
+ *
+ * @return Pointer to allocated memory or NULL if memory no memory is available (should not happen under normal conditions)
+ */
+ void * (*allocate_sleepy)(LV2_RtMemPool_Handle handle);
+
+ /**
+ * This function is called when plugin wants to deallocate previously allocated memory
+ *
+ * <b>will not sleep</b>
+ *
+ * @param memory_ptr pointer to previously allocated memory chunk
+ */
+ void (*deallocate)(LV2_RtMemPool_Handle handle,
+ void * memory_ptr);
+
+} LV2_RtMemPool_Pool;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_RTMEMPOOL_H */
diff --git a/distrho/src/lv2/midi.h b/distrho/src/lv2/midi.h
@@ -0,0 +1,226 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file midi.h
+ C definitions for the LV2 MIDI extension <http://lv2plug.in/ns/ext/midi>.
+*/
+
+#ifndef LV2_MIDI_H
+#define LV2_MIDI_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#else
+# include <stdbool.h>
+#endif
+
+#define LV2_MIDI_URI "http://lv2plug.in/ns/ext/midi"
+#define LV2_MIDI_PREFIX LV2_MIDI_URI "#"
+
+#define LV2_MIDI__ActiveSense LV2_MIDI_PREFIX "ActiveSense"
+#define LV2_MIDI__Aftertouch LV2_MIDI_PREFIX "Aftertouch"
+#define LV2_MIDI__Bender LV2_MIDI_PREFIX "Bender"
+#define LV2_MIDI__ChannelPressure LV2_MIDI_PREFIX "ChannelPressure"
+#define LV2_MIDI__Chunk LV2_MIDI_PREFIX "Chunk"
+#define LV2_MIDI__Clock LV2_MIDI_PREFIX "Clock"
+#define LV2_MIDI__Continue LV2_MIDI_PREFIX "Continue"
+#define LV2_MIDI__Controller LV2_MIDI_PREFIX "Controller"
+#define LV2_MIDI__MidiEvent LV2_MIDI_PREFIX "MidiEvent"
+#define LV2_MIDI__NoteOff LV2_MIDI_PREFIX "NoteOff"
+#define LV2_MIDI__NoteOn LV2_MIDI_PREFIX "NoteOn"
+#define LV2_MIDI__ProgramChange LV2_MIDI_PREFIX "ProgramChange"
+#define LV2_MIDI__QuarterFrame LV2_MIDI_PREFIX "QuarterFrame"
+#define LV2_MIDI__Reset LV2_MIDI_PREFIX "Reset"
+#define LV2_MIDI__SongPosition LV2_MIDI_PREFIX "SongPosition"
+#define LV2_MIDI__SongSelect LV2_MIDI_PREFIX "SongSelect"
+#define LV2_MIDI__Start LV2_MIDI_PREFIX "Start"
+#define LV2_MIDI__Stop LV2_MIDI_PREFIX "Stop"
+#define LV2_MIDI__SystemCommon LV2_MIDI_PREFIX "SystemCommon"
+#define LV2_MIDI__SystemExclusive LV2_MIDI_PREFIX "SystemExclusive"
+#define LV2_MIDI__SystemMessage LV2_MIDI_PREFIX "SystemMessage"
+#define LV2_MIDI__SystemRealtime LV2_MIDI_PREFIX "SystemRealtime"
+#define LV2_MIDI__Tick LV2_MIDI_PREFIX "Tick"
+#define LV2_MIDI__TuneRequest LV2_MIDI_PREFIX "TuneRequest"
+#define LV2_MIDI__VoiceMessage LV2_MIDI_PREFIX "VoiceMessage"
+#define LV2_MIDI__benderValue LV2_MIDI_PREFIX "benderValue"
+#define LV2_MIDI__binding LV2_MIDI_PREFIX "binding"
+#define LV2_MIDI__byteNumber LV2_MIDI_PREFIX "byteNumber"
+#define LV2_MIDI__channel LV2_MIDI_PREFIX "channel"
+#define LV2_MIDI__chunk LV2_MIDI_PREFIX "chunk"
+#define LV2_MIDI__controllerNumber LV2_MIDI_PREFIX "controllerNumber"
+#define LV2_MIDI__controllerValue LV2_MIDI_PREFIX "controllerValue"
+#define LV2_MIDI__noteNumber LV2_MIDI_PREFIX "noteNumber"
+#define LV2_MIDI__pressure LV2_MIDI_PREFIX "pressure"
+#define LV2_MIDI__programNumber LV2_MIDI_PREFIX "programNumber"
+#define LV2_MIDI__property LV2_MIDI_PREFIX "property"
+#define LV2_MIDI__songNumber LV2_MIDI_PREFIX "songNumber"
+#define LV2_MIDI__songPosition LV2_MIDI_PREFIX "songPosition"
+#define LV2_MIDI__status LV2_MIDI_PREFIX "status"
+#define LV2_MIDI__statusMask LV2_MIDI_PREFIX "statusMask"
+#define LV2_MIDI__velocity LV2_MIDI_PREFIX "velocity"
+
+/**
+ MIDI Message Type.
+
+ This includes both voice messages (which have a channel) and system messages
+ (which do not), as well as a sentinel value for invalid messages. To get
+ the type of a message suitable for use in a switch statement, use
+ lv2_midi_get_type() on the status byte.
+*/
+typedef enum {
+ LV2_MIDI_MSG_INVALID = 0, /**< Invalid Message */
+ LV2_MIDI_MSG_NOTE_OFF = 0x80, /**< Note Off */
+ LV2_MIDI_MSG_NOTE_ON = 0x90, /**< Note On */
+ LV2_MIDI_MSG_NOTE_PRESSURE = 0xA0, /**< Note Pressure */
+ LV2_MIDI_MSG_CONTROLLER = 0xB0, /**< Controller */
+ LV2_MIDI_MSG_PGM_CHANGE = 0xC0, /**< Program Change */
+ LV2_MIDI_MSG_CHANNEL_PRESSURE = 0xD0, /**< Channel Pressure */
+ LV2_MIDI_MSG_BENDER = 0xE0, /**< Pitch Bender */
+ LV2_MIDI_MSG_SYSTEM_EXCLUSIVE = 0xF0, /**< System Exclusive Begin */
+ LV2_MIDI_MSG_MTC_QUARTER = 0xF1, /**< MTC Quarter Frame */
+ LV2_MIDI_MSG_SONG_POS = 0xF2, /**< Song Position */
+ LV2_MIDI_MSG_SONG_SELECT = 0xF3, /**< Song Select */
+ LV2_MIDI_MSG_TUNE_REQUEST = 0xF6, /**< Tune Request */
+ LV2_MIDI_MSG_CLOCK = 0xF8, /**< Clock */
+ LV2_MIDI_MSG_START = 0xFA, /**< Start */
+ LV2_MIDI_MSG_CONTINUE = 0xFB, /**< Continue */
+ LV2_MIDI_MSG_STOP = 0xFC, /**< Stop */
+ LV2_MIDI_MSG_ACTIVE_SENSE = 0xFE, /**< Active Sensing */
+ LV2_MIDI_MSG_RESET = 0xFF /**< Reset */
+} LV2_Midi_Message_Type;
+
+/**
+ Standard MIDI Controller Numbers.
+*/
+typedef enum {
+ LV2_MIDI_CTL_MSB_BANK = 0x00, /**< Bank Selection */
+ LV2_MIDI_CTL_MSB_MODWHEEL = 0x01, /**< Modulation */
+ LV2_MIDI_CTL_MSB_BREATH = 0x02, /**< Breath */
+ LV2_MIDI_CTL_MSB_FOOT = 0x04, /**< Foot */
+ LV2_MIDI_CTL_MSB_PORTAMENTO_TIME = 0x05, /**< Portamento Time */
+ LV2_MIDI_CTL_MSB_DATA_ENTRY = 0x06, /**< Data Entry */
+ LV2_MIDI_CTL_MSB_MAIN_VOLUME = 0x07, /**< Main Volume */
+ LV2_MIDI_CTL_MSB_BALANCE = 0x08, /**< Balance */
+ LV2_MIDI_CTL_MSB_PAN = 0x0A, /**< Panpot */
+ LV2_MIDI_CTL_MSB_EXPRESSION = 0x0B, /**< Expression */
+ LV2_MIDI_CTL_MSB_EFFECT1 = 0x0C, /**< Effect1 */
+ LV2_MIDI_CTL_MSB_EFFECT2 = 0x0D, /**< Effect2 */
+ LV2_MIDI_CTL_MSB_GENERAL_PURPOSE1 = 0x10, /**< General Purpose 1 */
+ LV2_MIDI_CTL_MSB_GENERAL_PURPOSE2 = 0x11, /**< General Purpose 2 */
+ LV2_MIDI_CTL_MSB_GENERAL_PURPOSE3 = 0x12, /**< General Purpose 3 */
+ LV2_MIDI_CTL_MSB_GENERAL_PURPOSE4 = 0x13, /**< General Purpose 4 */
+ LV2_MIDI_CTL_LSB_BANK = 0x20, /**< Bank Selection */
+ LV2_MIDI_CTL_LSB_MODWHEEL = 0x21, /**< Modulation */
+ LV2_MIDI_CTL_LSB_BREATH = 0x22, /**< Breath */
+ LV2_MIDI_CTL_LSB_FOOT = 0x24, /**< Foot */
+ LV2_MIDI_CTL_LSB_PORTAMENTO_TIME = 0x25, /**< Portamento Time */
+ LV2_MIDI_CTL_LSB_DATA_ENTRY = 0x26, /**< Data Entry */
+ LV2_MIDI_CTL_LSB_MAIN_VOLUME = 0x27, /**< Main Volume */
+ LV2_MIDI_CTL_LSB_BALANCE = 0x28, /**< Balance */
+ LV2_MIDI_CTL_LSB_PAN = 0x2A, /**< Panpot */
+ LV2_MIDI_CTL_LSB_EXPRESSION = 0x2B, /**< Expression */
+ LV2_MIDI_CTL_LSB_EFFECT1 = 0x2C, /**< Effect1 */
+ LV2_MIDI_CTL_LSB_EFFECT2 = 0x2D, /**< Effect2 */
+ LV2_MIDI_CTL_LSB_GENERAL_PURPOSE1 = 0x30, /**< General Purpose 1 */
+ LV2_MIDI_CTL_LSB_GENERAL_PURPOSE2 = 0x31, /**< General Purpose 2 */
+ LV2_MIDI_CTL_LSB_GENERAL_PURPOSE3 = 0x32, /**< General Purpose 3 */
+ LV2_MIDI_CTL_LSB_GENERAL_PURPOSE4 = 0x33, /**< General Purpose 4 */
+ LV2_MIDI_CTL_SUSTAIN = 0x40, /**< Sustain Pedal */
+ LV2_MIDI_CTL_PORTAMENTO = 0x41, /**< Portamento */
+ LV2_MIDI_CTL_SOSTENUTO = 0x42, /**< Sostenuto */
+ LV2_MIDI_CTL_SOFT_PEDAL = 0x43, /**< Soft Pedal */
+ LV2_MIDI_CTL_LEGATO_FOOTSWITCH = 0x44, /**< Legato Foot Switch */
+ LV2_MIDI_CTL_HOLD2 = 0x45, /**< Hold2 */
+ LV2_MIDI_CTL_SC1_SOUND_VARIATION = 0x46, /**< SC1 Sound Variation */
+ LV2_MIDI_CTL_SC2_TIMBRE = 0x47, /**< SC2 Timbre */
+ LV2_MIDI_CTL_SC3_RELEASE_TIME = 0x48, /**< SC3 Release Time */
+ LV2_MIDI_CTL_SC4_ATTACK_TIME = 0x49, /**< SC4 Attack Time */
+ LV2_MIDI_CTL_SC5_BRIGHTNESS = 0x4A, /**< SC5 Brightness */
+ LV2_MIDI_CTL_SC6 = 0x4B, /**< SC6 */
+ LV2_MIDI_CTL_SC7 = 0x4C, /**< SC7 */
+ LV2_MIDI_CTL_SC8 = 0x4D, /**< SC8 */
+ LV2_MIDI_CTL_SC9 = 0x4E, /**< SC9 */
+ LV2_MIDI_CTL_SC10 = 0x4F, /**< SC10 */
+ LV2_MIDI_CTL_GENERAL_PURPOSE5 = 0x50, /**< General Purpose 5 */
+ LV2_MIDI_CTL_GENERAL_PURPOSE6 = 0x51, /**< General Purpose 6 */
+ LV2_MIDI_CTL_GENERAL_PURPOSE7 = 0x52, /**< General Purpose 7 */
+ LV2_MIDI_CTL_GENERAL_PURPOSE8 = 0x53, /**< General Purpose 8 */
+ LV2_MIDI_CTL_PORTAMENTO_CONTROL = 0x54, /**< Portamento Control */
+ LV2_MIDI_CTL_E1_REVERB_DEPTH = 0x5B, /**< E1 Reverb Depth */
+ LV2_MIDI_CTL_E2_TREMOLO_DEPTH = 0x5C, /**< E2 Tremolo Depth */
+ LV2_MIDI_CTL_E3_CHORUS_DEPTH = 0x5D, /**< E3 Chorus Depth */
+ LV2_MIDI_CTL_E4_DETUNE_DEPTH = 0x5E, /**< E4 Detune Depth */
+ LV2_MIDI_CTL_E5_PHASER_DEPTH = 0x5F, /**< E5 Phaser Depth */
+ LV2_MIDI_CTL_DATA_INCREMENT = 0x60, /**< Data Increment */
+ LV2_MIDI_CTL_DATA_DECREMENT = 0x61, /**< Data Decrement */
+ LV2_MIDI_CTL_NRPN_LSB = 0x62, /**< Non-registered Parameter Number */
+ LV2_MIDI_CTL_NRPN_MSB = 0x63, /**< Non-registered Parameter Number */
+ LV2_MIDI_CTL_RPN_LSB = 0x64, /**< Registered Parameter Number */
+ LV2_MIDI_CTL_RPN_MSB = 0x65, /**< Registered Parameter Number */
+ LV2_MIDI_CTL_ALL_SOUNDS_OFF = 0x78, /**< All Sounds Off */
+ LV2_MIDI_CTL_RESET_CONTROLLERS = 0x79, /**< Reset Controllers */
+ LV2_MIDI_CTL_LOCAL_CONTROL_SWITCH = 0x7A, /**< Local Control Switch */
+ LV2_MIDI_CTL_ALL_NOTES_OFF = 0x7B, /**< All Notes Off */
+ LV2_MIDI_CTL_OMNI_OFF = 0x7C, /**< Omni Off */
+ LV2_MIDI_CTL_OMNI_ON = 0x7D, /**< Omni On */
+ LV2_MIDI_CTL_MONO1 = 0x7E, /**< Mono1 */
+ LV2_MIDI_CTL_MONO2 = 0x7F /**< Mono2 */
+} LV2_Midi_Controller;
+
+/**
+ Return true iff @p msg is a MIDI voice message (which has a channel).
+*/
+static inline bool
+lv2_midi_is_voice_message(const uint8_t* msg) {
+ return msg[0] >= 0x80 && msg[0] < 0xF0;
+}
+
+/**
+ Return true iff @p msg is a MIDI system message (which has no channel).
+*/
+static inline bool
+lv2_midi_is_system_message(const uint8_t* msg) {
+ switch (msg[0]) {
+ case 0xF4: case 0xF5: case 0xF7: case 0xF9: case 0xFD:
+ return false;
+ default:
+ return (msg[0] & 0xF0) == 0xF0;
+ }
+}
+
+/**
+ Return the type of a MIDI message.
+ @param msg Pointer to the start (status byte) of a MIDI message.
+*/
+static inline LV2_Midi_Message_Type
+lv2_midi_message_type(const uint8_t* msg) {
+ if (lv2_midi_is_voice_message(msg)) {
+ return (LV2_Midi_Message_Type)(msg[0] & 0xF0);
+ } else if (lv2_midi_is_system_message(msg)) {
+ return (LV2_Midi_Message_Type)msg[0];
+ } else {
+ return LV2_MIDI_MSG_INVALID;
+ }
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_MIDI_H */
diff --git a/distrho/src/lv2/morph.h b/distrho/src/lv2/morph.h
@@ -0,0 +1,34 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+#ifndef LV2_MORPH_H
+#define LV2_MORPH_H
+
+#include <stdint.h>
+
+#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
+#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
+
+#define LV2_MORPH_URI "http://lv2plug.in/ns/ext/morph"
+#define LV2_MORPH_PREFIX LV2_MORPH_URI "#"
+
+#define LV2_MORPH__AutoMorphPort LV2_MORPH_PREFIX "AutoMorphPort"
+#define LV2_MORPH__MorphPort LV2_MORPH_PREFIX "MorphPort"
+#define LV2_MORPH__interface LV2_MORPH_PREFIX "interface"
+#define LV2_MORPH__supportsType LV2_MORPH_PREFIX "supportsType"
+#define LV2_MORPH__currentType LV2_MORPH_PREFIX "currentType"
+
+#endif /* LV2_MORPH_H */
diff --git a/distrho/src/lv2/options.h b/distrho/src/lv2/options.h
@@ -0,0 +1,132 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+#ifndef LV2_OPTIONS_H
+#define LV2_OPTIONS_H
+
+#include <stdint.h>
+
+#include "urid.h"
+#include "lv2.h"
+
+#define LV2_OPTIONS_URI "http://lv2plug.in/ns/ext/options"
+#define LV2_OPTIONS_PREFIX LV2_OPTIONS_URI "#"
+
+#define LV2_OPTIONS__Option LV2_OPTIONS_PREFIX "Option"
+#define LV2_OPTIONS__interface LV2_OPTIONS_PREFIX "interface"
+#define LV2_OPTIONS__options LV2_OPTIONS_PREFIX "options"
+#define LV2_OPTIONS__requiredOption LV2_OPTIONS_PREFIX "requiredOption"
+#define LV2_OPTIONS__supportedOption LV2_OPTIONS_PREFIX "supportedOption"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ The context of an Option, which defines the subject it applies to.
+*/
+typedef enum {
+ /**
+ This option applies to the instance itself. The subject must be
+ ignored.
+ */
+ LV2_OPTIONS_INSTANCE,
+
+ /**
+ This option applies to some named resource. The subject is a URI mapped
+ to an integer (a LV2_URID, like the key)
+ */
+ LV2_OPTIONS_RESOURCE,
+
+ /**
+ This option applies to some blank node. The subject is a blank node
+ identifier, which is valid only within the current local scope.
+ */
+ LV2_OPTIONS_BLANK,
+
+ /**
+ This option applies to a port on the instance. The subject is the
+ port's index.
+ */
+ LV2_OPTIONS_PORT
+} LV2_Options_Context;
+
+/**
+ An option.
+
+ This is a property with a subject, also known as a triple or statement.
+
+ This struct is useful anywhere a statement needs to be passed where no
+ memory ownership issues are present (since the value is a const pointer).
+
+ Options can be passed to an instance via the feature LV2_OPTIONS__options
+ with data pointed to an array of options terminated by a zeroed option, or
+ accessed/manipulated using LV2_Options_Interface.
+*/
+typedef struct _LV2_Options_Option {
+ LV2_Options_Context context; /**< Context (type of subject). */
+ uint32_t subject; /**< Subject. */
+ LV2_URID key; /**< Key (property). */
+ uint32_t size; /**< Size of value in bytes. */
+ LV2_URID type; /**< Type of value (datatype). */
+ const void* value; /**< Pointer to value (object). */
+} LV2_Options_Option;
+
+/** A status code for option functions. */
+typedef enum {
+ LV2_OPTIONS_SUCCESS = 0, /**< Completed successfully. */
+ LV2_OPTIONS_ERR_UNKNOWN = 1, /**< Unknown error. */
+ LV2_OPTIONS_ERR_BAD_SUBJECT = 1 << 1, /**< Invalid/unsupported subject. */
+ LV2_OPTIONS_ERR_BAD_KEY = 1 << 2, /**< Invalid/unsupported key. */
+ LV2_OPTIONS_ERR_BAD_VALUE = 1 << 3 /**< Invalid/unsupported value. */
+} LV2_Options_Status;
+
+/**
+ Interface for dynamically setting options (LV2_OPTIONS__interface).
+*/
+typedef struct _LV2_Options_Interface {
+ /**
+ Get the given options.
+
+ Each element of the passed options array MUST have type, subject, and
+ key set. All other fields (size, type, value) MUST be initialised to
+ zero, and are set to the option value if such an option is found.
+
+ This function is in the "instantiation" LV2 threading class, so no other
+ instance functions may be called concurrently.
+
+ @return Bitwise OR of LV2_Options_Status values.
+ */
+ uint32_t (*get)(LV2_Handle instance,
+ LV2_Options_Option* options);
+
+ /**
+ Set the given options.
+
+ This function is in the "instantiation" LV2 threading class, so no other
+ instance functions may be called concurrently.
+
+ @return Bitwise OR of LV2_Options_Status values.
+ */
+ uint32_t (*set)(LV2_Handle instance,
+ const LV2_Options_Option* options);
+} LV2_Options_Interface;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_OPTIONS_H */
diff --git a/distrho/src/lv2/parameters.h b/distrho/src/lv2/parameters.h
@@ -0,0 +1,49 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+#ifndef LV2_PARAMETERS_H
+#define LV2_PARAMETERS_H
+
+#define LV2_PARAMETERS_URI "http://lv2plug.in/ns/ext/parameters"
+#define LV2_PARAMETERS_PREFIX LV2_PARAMETERS_URI "#"
+
+#define LV2_PARAMETERS__CompressorControls LV2_PARAMETERS_PREFIX "CompressorControls"
+#define LV2_PARAMETERS__ControlGroup LV2_PARAMETERS_PREFIX "ControlGroup"
+#define LV2_PARAMETERS__EnvelopeControls LV2_PARAMETERS_PREFIX "EnvelopeControls"
+#define LV2_PARAMETERS__FilterControls LV2_PARAMETERS_PREFIX "FilterControls"
+#define LV2_PARAMETERS__OscillatorControls LV2_PARAMETERS_PREFIX "OscillatorControls"
+#define LV2_PARAMETERS__amplitude LV2_PARAMETERS_PREFIX "amplitude"
+#define LV2_PARAMETERS__attack LV2_PARAMETERS_PREFIX "attack"
+#define LV2_PARAMETERS__bypass LV2_PARAMETERS_PREFIX "bypass"
+#define LV2_PARAMETERS__cutoffFrequency LV2_PARAMETERS_PREFIX "cutoffFrequency"
+#define LV2_PARAMETERS__decay LV2_PARAMETERS_PREFIX "decay"
+#define LV2_PARAMETERS__delay LV2_PARAMETERS_PREFIX "delay"
+#define LV2_PARAMETERS__dryLevel LV2_PARAMETERS_PREFIX "dryLevel"
+#define LV2_PARAMETERS__frequency LV2_PARAMETERS_PREFIX "frequency"
+#define LV2_PARAMETERS__gain LV2_PARAMETERS_PREFIX "gain"
+#define LV2_PARAMETERS__hold LV2_PARAMETERS_PREFIX "hold"
+#define LV2_PARAMETERS__pulseWidth LV2_PARAMETERS_PREFIX "pulseWidth"
+#define LV2_PARAMETERS__ratio LV2_PARAMETERS_PREFIX "ratio"
+#define LV2_PARAMETERS__release LV2_PARAMETERS_PREFIX "release"
+#define LV2_PARAMETERS__resonance LV2_PARAMETERS_PREFIX "resonance"
+#define LV2_PARAMETERS__sampleRate LV2_PARAMETERS_PREFIX "sampleRate"
+#define LV2_PARAMETERS__sustain LV2_PARAMETERS_PREFIX "sustain"
+#define LV2_PARAMETERS__threshold LV2_PARAMETERS_PREFIX "threshold"
+#define LV2_PARAMETERS__waveform LV2_PARAMETERS_PREFIX "waveform"
+#define LV2_PARAMETERS__wetDryRatio LV2_PARAMETERS_PREFIX "wetDryRatio"
+#define LV2_PARAMETERS__wetLevel LV2_PARAMETERS_PREFIX "wetLevel"
+
+#endif /* LV2_PARAMETERS_H */
diff --git a/distrho/src/lv2/patch.h b/distrho/src/lv2/patch.h
@@ -0,0 +1,55 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file patch.h C header for the LV2 Patch extension
+ <http://lv2plug.in/ns/ext/patch>.
+
+ The patch extension is purely data, this header merely defines URIs
+ for convenience.
+*/
+
+#ifndef LV2_PATCH_H
+#define LV2_PATCH_H
+
+#define LV2_PATCH_URI "http://lv2plug.in/ns/ext/patch"
+#define LV2_PATCH_PREFIX LV2_PATCH_URI "#"
+
+#define LV2_PATCH__Ack LV2_PATCH_PREFIX "Ack"
+#define LV2_PATCH__Delete LV2_PATCH_PREFIX "Delete"
+#define LV2_PATCH__Error LV2_PATCH_PREFIX "Error"
+#define LV2_PATCH__Get LV2_PATCH_PREFIX "Get"
+#define LV2_PATCH__Message LV2_PATCH_PREFIX "Message"
+#define LV2_PATCH__Move LV2_PATCH_PREFIX "Move"
+#define LV2_PATCH__Patch LV2_PATCH_PREFIX "Patch"
+#define LV2_PATCH__Post LV2_PATCH_PREFIX "Post"
+#define LV2_PATCH__Put LV2_PATCH_PREFIX "Put"
+#define LV2_PATCH__Request LV2_PATCH_PREFIX "Request"
+#define LV2_PATCH__Response LV2_PATCH_PREFIX "Response"
+#define LV2_PATCH__Set LV2_PATCH_PREFIX "Set"
+#define LV2_PATCH__add LV2_PATCH_PREFIX "add"
+#define LV2_PATCH__body LV2_PATCH_PREFIX "body"
+#define LV2_PATCH__destination LV2_PATCH_PREFIX "destination"
+#define LV2_PATCH__property LV2_PATCH_PREFIX "property"
+#define LV2_PATCH__readable LV2_PATCH_PREFIX "readable"
+#define LV2_PATCH__remove LV2_PATCH_PREFIX "remove"
+#define LV2_PATCH__request LV2_PATCH_PREFIX "request"
+#define LV2_PATCH__subject LV2_PATCH_PREFIX "subject"
+#define LV2_PATCH__value LV2_PATCH_PREFIX "value"
+#define LV2_PATCH__wildcard LV2_PATCH_PREFIX "wildcard"
+#define LV2_PATCH__writable LV2_PATCH_PREFIX "writable"
+
+#endif /* LV2_PATCH_H */
diff --git a/distrho/src/lv2/port-groups.h b/distrho/src/lv2/port-groups.h
@@ -0,0 +1,64 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file port-groups.h
+ C definitions for the LV2 Port Groups extension
+ <http://lv2plug.in/ns/ext/port-groups>.
+*/
+
+#ifndef LV2_PORT_GROUPS_H
+#define LV2_PORT_GROUPS_H
+
+#define LV2_PORT_GROUPS_URI "http://lv2plug.in/ns/ext/port-groups"
+#define LV2_PORT_GROUPS_PREFIX LV2_PORT_GROUPS_URI "#"
+
+#define LV2_PORT_GROUPS__DiscreteGroup LV2_PORT_GROUPS_PREFIX "DiscreteGroup"
+#define LV2_PORT_GROUPS__Element LV2_PORT_GROUPS_PREFIX "Element"
+#define LV2_PORT_GROUPS__FivePointOneGroup LV2_PORT_GROUPS_PREFIX "FivePointOneGroup"
+#define LV2_PORT_GROUPS__FivePointZeroGroup LV2_PORT_GROUPS_PREFIX "FivePointZeroGroup"
+#define LV2_PORT_GROUPS__FourPointZeroGroup LV2_PORT_GROUPS_PREFIX "FourPointZeroGroup"
+#define LV2_PORT_GROUPS__Group LV2_PORT_GROUPS_PREFIX "Group"
+#define LV2_PORT_GROUPS__InputGroup LV2_PORT_GROUPS_PREFIX "InputGroup"
+#define LV2_PORT_GROUPS__MidSideGroup LV2_PORT_GROUPS_PREFIX "MidSideGroup"
+#define LV2_PORT_GROUPS__MonoGroup LV2_PORT_GROUPS_PREFIX "MonoGroup"
+#define LV2_PORT_GROUPS__OutputGroup LV2_PORT_GROUPS_PREFIX "OutputGroup"
+#define LV2_PORT_GROUPS__SevenPointOneGroup LV2_PORT_GROUPS_PREFIX "SevenPointOneGroup"
+#define LV2_PORT_GROUPS__SevenPointOneWideGroup LV2_PORT_GROUPS_PREFIX "SevenPointOneWideGroup"
+#define LV2_PORT_GROUPS__SixPointOneGroup LV2_PORT_GROUPS_PREFIX "SixPointOneGroup"
+#define LV2_PORT_GROUPS__StereoGroup LV2_PORT_GROUPS_PREFIX "StereoGroup"
+#define LV2_PORT_GROUPS__ThreePointZeroGroup LV2_PORT_GROUPS_PREFIX "ThreePointZeroGroup"
+#define LV2_PORT_GROUPS__center LV2_PORT_GROUPS_PREFIX "center"
+#define LV2_PORT_GROUPS__centerLeft LV2_PORT_GROUPS_PREFIX "centerLeft"
+#define LV2_PORT_GROUPS__centerRight LV2_PORT_GROUPS_PREFIX "centerRight"
+#define LV2_PORT_GROUPS__element LV2_PORT_GROUPS_PREFIX "element"
+#define LV2_PORT_GROUPS__group LV2_PORT_GROUPS_PREFIX "group"
+#define LV2_PORT_GROUPS__left LV2_PORT_GROUPS_PREFIX "left"
+#define LV2_PORT_GROUPS__lowFrequencyEffects LV2_PORT_GROUPS_PREFIX "lowFrequencyEffects"
+#define LV2_PORT_GROUPS__mainInput LV2_PORT_GROUPS_PREFIX "mainInput"
+#define LV2_PORT_GROUPS__mainOutput LV2_PORT_GROUPS_PREFIX "mainOutput"
+#define LV2_PORT_GROUPS__rearCenter LV2_PORT_GROUPS_PREFIX "rearCenter"
+#define LV2_PORT_GROUPS__rearLeft LV2_PORT_GROUPS_PREFIX "rearLeft"
+#define LV2_PORT_GROUPS__rearRight LV2_PORT_GROUPS_PREFIX "rearRight"
+#define LV2_PORT_GROUPS__right LV2_PORT_GROUPS_PREFIX "right"
+#define LV2_PORT_GROUPS__side LV2_PORT_GROUPS_PREFIX "side"
+#define LV2_PORT_GROUPS__sideChainOf LV2_PORT_GROUPS_PREFIX "sideChainOf"
+#define LV2_PORT_GROUPS__sideLeft LV2_PORT_GROUPS_PREFIX "sideLeft"
+#define LV2_PORT_GROUPS__sideRight LV2_PORT_GROUPS_PREFIX "sideRight"
+#define LV2_PORT_GROUPS__source LV2_PORT_GROUPS_PREFIX "source"
+#define LV2_PORT_GROUPS__subGroupOf LV2_PORT_GROUPS_PREFIX "subGroupOf"
+
+#endif /* LV2_PORT_GROUPS_H */
diff --git a/distrho/src/lv2/port-props.h b/distrho/src/lv2/port-props.h
@@ -0,0 +1,42 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file port-props.h
+ C definitions for the LV2 Port Props extension
+ <http://lv2plug.in/ns/ext/port-props>.
+*/
+
+#ifndef LV2_PORT_PROPS_H
+#define LV2_PORT_PROPS_H
+
+#define LV2_PORT_PROPS_URI "http://lv2plug.in/ns/ext/port-props"
+#define LV2_PORT_PROPS_PREFIX LV2_PORT_PROPS_URI "#"
+
+#define LV2_PORT_PROPS__causesArtifacts LV2_PORT_PROPS_PREFIX "causesArtifacts"
+#define LV2_PORT_PROPS__continuousCV LV2_PORT_PROPS_PREFIX "continuousCV"
+#define LV2_PORT_PROPS__discreteCV LV2_PORT_PROPS_PREFIX "discreteCV"
+#define LV2_PORT_PROPS__displayPriority LV2_PORT_PROPS_PREFIX "displayPriority"
+#define LV2_PORT_PROPS__expensive LV2_PORT_PROPS_PREFIX "expensive"
+#define LV2_PORT_PROPS__hasStrictBounds LV2_PORT_PROPS_PREFIX "hasStrictBounds"
+#define LV2_PORT_PROPS__logarithmic LV2_PORT_PROPS_PREFIX "logarithmic"
+#define LV2_PORT_PROPS__notAutomatic LV2_PORT_PROPS_PREFIX "notAutomatic"
+#define LV2_PORT_PROPS__notOnGUI LV2_PORT_PROPS_PREFIX "notOnGUI"
+#define LV2_PORT_PROPS__rangeSteps LV2_PORT_PROPS_PREFIX "rangeSteps"
+#define LV2_PORT_PROPS__supportsStrictBounds LV2_PORT_PROPS_PREFIX "supportsStrictBounds"
+#define LV2_PORT_PROPS__trigger LV2_PORT_PROPS_PREFIX "trigger"
+
+#endif /* LV2_PORT_PROPS_H */
diff --git a/distrho/src/lv2/presets.h b/distrho/src/lv2/presets.h
@@ -0,0 +1,34 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file presets.h
+
+ C definitions for the LV2 Presets extension
+ <http://lv2plug.in/ns/ext/presets>.
+*/
+
+#ifndef LV2_PRESETS_H
+#define LV2_PRESETS_H
+
+#define LV2_PRESETS_URI "http://lv2plug.in/ns/ext/presets"
+#define LV2_PRESETS_PREFIX LV2_PRESETS_URI "#"
+
+#define LV2_PRESETS__Preset LV2_PRESETS_PREFIX "Preset"
+#define LV2_PRESETS__preset LV2_PRESETS_PREFIX "preset"
+#define LV2_PRESETS__value LV2_PRESETS_PREFIX "value"
+
+#endif /* LV2_PRESETS_H */
diff --git a/distrho/src/lv2/resize-port.h b/distrho/src/lv2/resize-port.h
@@ -0,0 +1,72 @@
+/*
+ Copyright 2007-2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+#ifndef LV2_RESIZE_PORT_H
+#define LV2_RESIZE_PORT_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define LV2_RESIZE_PORT_URI "http://lv2plug.in/ns/ext/resize-port"
+#define LV2_RESIZE_PORT_PREFIX LV2_RESIZE_PORT_URI "#"
+
+#define LV2_RESIZE_PORT__asLargeAs LV2_RESIZE_PORT_PREFIX "asLargeAs"
+#define LV2_RESIZE_PORT__minimumSize LV2_RESIZE_PORT_PREFIX "minimumSize"
+#define LV2_RESIZE_PORT__resize LV2_RESIZE_PORT_PREFIX "resize"
+
+#ifdef __cplusplus
+extern "C" {
+#else
+# include <stdbool.h>
+#endif
+
+/** A status code for state functions. */
+typedef enum {
+ LV2_RESIZE_PORT_SUCCESS = 0, /**< Completed successfully. */
+ LV2_RESIZE_PORT_ERR_UNKNOWN = 1, /**< Unknown error. */
+ LV2_RESIZE_PORT_ERR_NO_SPACE = 2 /**< Insufficient space. */
+} LV2_Resize_Port_Status;
+
+typedef void* LV2_Resize_Port_Feature_Data;
+
+typedef struct {
+ LV2_Resize_Port_Feature_Data data;
+
+ /**
+ Resize a port buffer to at least @a size bytes.
+
+ This function MAY return an error, in which case the port buffer was not
+ resized and the port is still connected to the same location. Plugins
+ MUST gracefully handle this situation.
+
+ This function is in the audio threading class.
+
+ The host MUST preserve the contents of the port buffer when resizing.
+
+ Plugins MAY resize a port many times in a single run callback. Hosts
+ SHOULD make this as inexpensive as possible.
+ */
+ LV2_Resize_Port_Status (*resize)(LV2_Resize_Port_Feature_Data data,
+ uint32_t index,
+ size_t size);
+} LV2_Resize_Port_Resize;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_RESIZE_PORT_H */
+
diff --git a/distrho/src/lv2/state.h b/distrho/src/lv2/state.h
@@ -0,0 +1,352 @@
+/*
+ Copyright 2010-2012 David Robillard <http://drobilla.net>
+ Copyright 2010 Leonard Ritter <paniq@paniq.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.
+*/
+
+/**
+ @file state.h
+ C API for the LV2 State extension <http://lv2plug.in/ns/ext/state>.
+*/
+
+#ifndef LV2_STATE_H
+#define LV2_STATE_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "lv2.h"
+
+#define LV2_STATE_URI "http://lv2plug.in/ns/ext/state"
+#define LV2_STATE_PREFIX LV2_STATE_URI "#"
+
+#define LV2_STATE__State LV2_STATE_PREFIX "State"
+#define LV2_STATE__interface LV2_STATE_PREFIX "interface"
+#define LV2_STATE__loadDefaultState LV2_STATE_PREFIX "loadDefaultState"
+#define LV2_STATE__makePath LV2_STATE_PREFIX "makePath"
+#define LV2_STATE__mapPath LV2_STATE_PREFIX "mapPath"
+#define LV2_STATE__state LV2_STATE_PREFIX "state"
+
+#ifdef __cplusplus
+extern "C" {
+#else
+# include <stdbool.h>
+#endif
+
+typedef void* LV2_State_Handle;
+typedef void* LV2_State_Map_Path_Handle;
+typedef void* LV2_State_Make_Path_Handle;
+
+/**
+ Flags describing value characteristics.
+
+ These flags are used along with the value's type URI to determine how to
+ (de-)serialise the value data, or whether it is even possible to do so.
+*/
+typedef enum {
+ /**
+ Plain Old Data.
+
+ Values with this flag contain no pointers or references to other areas
+ of memory. It is safe to copy POD values with a simple memcpy and store
+ them for the duration of the process. A POD value is not necessarily
+ safe to trasmit between processes or machines (e.g. filenames are POD),
+ see LV2_STATE_IS_PORTABLE for details.
+
+ Implementations MUST NOT attempt to copy or serialise a non-POD value if
+ they do not understand its type (and thus know how to correctly do so).
+ */
+ LV2_STATE_IS_POD = 1,
+
+ /**
+ Portable (architecture independent) data.
+
+ Values with this flag are in a format that is usable on any
+ architecture. A portable value saved on one machine can be restored on
+ another machine regardless of architecture. The format of portable
+ values MUST NOT depend on architecture-specific properties like
+ endianness or alignment. Portable values MUST NOT contain filenames.
+ */
+ LV2_STATE_IS_PORTABLE = 1 << 1,
+
+ /**
+ Native data.
+
+ This flag is used by the host to indicate that the saved data is only
+ going to be used locally in the currently running process (e.g. for
+ instance duplication or snapshots), so the plugin should use the most
+ efficient representation possible and not worry about serialisation
+ and portability.
+ */
+ LV2_STATE_IS_NATIVE = 1 << 2
+} LV2_State_Flags;
+
+/** A status code for state functions. */
+typedef enum {
+ LV2_STATE_SUCCESS = 0, /**< Completed successfully. */
+ LV2_STATE_ERR_UNKNOWN = 1, /**< Unknown error. */
+ LV2_STATE_ERR_BAD_TYPE = 2, /**< Failed due to unsupported type. */
+ LV2_STATE_ERR_BAD_FLAGS = 3, /**< Failed due to unsupported flags. */
+ LV2_STATE_ERR_NO_FEATURE = 4, /**< Failed due to missing features. */
+ LV2_STATE_ERR_NO_PROPERTY = 5 /**< Failed due to missing property. */
+} LV2_State_Status;
+
+/**
+ A host-provided function to store a property.
+ @param handle Must be the handle passed to LV2_State_Interface.save().
+ @param key The key to store @p value under (URID).
+ @param value Pointer to the value to be stored.
+ @param size The size of @p value in bytes.
+ @param type The type of @p value (URID).
+ @param flags LV2_State_Flags for @p value.
+ @return 0 on success, otherwise a non-zero error code.
+
+ The host passes a callback of this type to LV2_State_Interface.save(). This
+ callback is called repeatedly by the plugin to store all the properties that
+ describe its current state.
+
+ DO NOT INVENT NONSENSE URI SCHEMES FOR THE KEY. Best is to use keys from
+ existing vocabularies. If nothing appropriate is available, use http URIs
+ that point to somewhere you can host documents so documentation can be made
+ resolvable (e.g. a child of the plugin or project URI). If this is not
+ possible, invent a URN scheme, e.g. urn:myproj:whatever. The plugin MUST
+ NOT pass an invalid URI key.
+
+ The host MAY fail to store a property for whatever reason, but SHOULD
+ store any property that is LV2_STATE_IS_POD and LV2_STATE_IS_PORTABLE.
+ Implementations SHOULD use the types from the LV2 Atom extension
+ (http://lv2plug.in/ns/ext/atom) wherever possible. The plugin SHOULD
+ attempt to fall-back and avoid the error if possible.
+
+ Note that @p size MUST be > 0, and @p value MUST point to a valid region of
+ memory @p size bytes long (this is required to make restore unambiguous).
+
+ The plugin MUST NOT attempt to use this function outside of the
+ LV2_State_Interface.restore() context.
+*/
+typedef LV2_State_Status (*LV2_State_Store_Function)(
+ LV2_State_Handle handle,
+ uint32_t key,
+ const void* value,
+ size_t size,
+ uint32_t type,
+ uint32_t flags);
+
+/**
+ A host-provided function to retrieve a property.
+ @param handle Must be the handle passed to LV2_State_Interface.restore().
+ @param key The key of the property to retrieve (URID).
+ @param size (Output) If non-NULL, set to the size of the restored value.
+ @param type (Output) If non-NULL, set to the type of the restored value.
+ @param flags (Output) If non-NULL, set to the flags for the restored value.
+ @return A pointer to the restored value (object), or NULL if no value
+ has been stored under @p key.
+
+ A callback of this type is passed by the host to
+ LV2_State_Interface.restore(). This callback is called repeatedly by the
+ plugin to retrieve any properties it requires to restore its state.
+
+ The returned value MUST remain valid until LV2_State_Interface.restore()
+ returns. The plugin MUST NOT attempt to use this function, or any value
+ returned from it, outside of the LV2_State_Interface.restore() context.
+*/
+typedef const void* (*LV2_State_Retrieve_Function)(
+ LV2_State_Handle handle,
+ uint32_t key,
+ size_t* size,
+ uint32_t* type,
+ uint32_t* flags);
+
+/**
+ LV2 Plugin State Interface.
+
+ When the plugin's extension_data is called with argument
+ LV2_STATE__interface, the plugin MUST return an LV2_State_Interface
+ structure, which remains valid for the lifetime of the plugin.
+
+ The host can use the contained function pointers to save and restore the
+ state of a plugin instance at any time, provided the threading restrictions
+ of the functions are met.
+
+ Stored data is only guaranteed to be compatible between instances of plugins
+ with the same URI (i.e. if a change to a plugin would cause a fatal error
+ when restoring state saved by a previous version of that plugin, the plugin
+ URI MUST change just as it must when ports change incompatibly). Plugin
+ authors should consider this possibility, and always store sensible data
+ with meaningful types to avoid such problems in the future.
+*/
+typedef struct _LV2_State_Interface {
+ /**
+ Save plugin state using a host-provided @p store callback.
+
+ @param instance The instance handle of the plugin.
+ @param store The host-provided store callback.
+ @param handle An opaque pointer to host data which MUST be passed as the
+ handle parameter to @p store if it is called.
+ @param flags Flags describing desired properties of this save. These
+ flags may be used to determine the most appropriate values to store.
+ @param features Extensible parameter for passing any additional
+ features to be used for this save.
+
+ The plugin is expected to store everything necessary to completely
+ restore its state later. Plugins SHOULD store simple POD data whenever
+ possible, and consider the possibility of state being restored much
+ later on a different machine.
+
+ The @p handle pointer and @p store function MUST NOT be used
+ beyond the scope of save().
+
+ This function has its own special threading class: it may not be called
+ concurrently with any "Instantiation" function, but it may be called
+ concurrently with functions in any other class, unless the definition of
+ that class prohibits it (e.g. it may not be called concurrently with a
+ "Discovery" function, but it may be called concurrently with an "Audio"
+ function. The plugin is responsible for any locking or lock-free
+ techniques necessary to make this possible.
+
+ Note that in the simple case where state is only modified by restore(),
+ there are no synchronization issues since save() is never called
+ concurrently with restore() (though run() may read it during a save).
+
+ Plugins that dynamically modify state while running, however, must take
+ care to do so in such a way that a concurrent call to save() will save a
+ consistent representation of plugin state for a single instant in time.
+ */
+ LV2_State_Status (*save)(LV2_Handle instance,
+ LV2_State_Store_Function store,
+ LV2_State_Handle handle,
+ uint32_t flags,
+ const LV2_Feature *const * features);
+
+ /**
+ Restore plugin state using a host-provided @p retrieve callback.
+
+ @param instance The instance handle of the plugin.
+ @param retrieve The host-provided retrieve callback.
+ @param handle An opaque pointer to host data which MUST be passed as the
+ handle parameter to @p retrieve if it is called.
+ @param flags Currently unused.
+ @param features Extensible parameter for passing any additional
+ features to be used for this restore.
+
+ The plugin MAY assume a restored value was set by a previous call to
+ LV2_State_Interface.save() by a plugin with the same URI.
+
+ The plugin MUST gracefully fall back to a default value when a value can
+ not be retrieved. This allows the host to reset the plugin state with
+ an empty map.
+
+ The @p handle pointer and @p store function MUST NOT be used
+ beyond the scope of restore().
+
+ This function is in the "Instantiation" threading class as defined by
+ LV2. This means it MUST NOT be called concurrently with any other
+ function on the same plugin instance.
+ */
+ LV2_State_Status (*restore)(LV2_Handle instance,
+ LV2_State_Retrieve_Function retrieve,
+ LV2_State_Handle handle,
+ uint32_t flags,
+ const LV2_Feature *const * features);
+} LV2_State_Interface;
+
+/**
+ Feature data for state:mapPath (LV2_STATE__mapPath).
+*/
+typedef struct {
+ /**
+ Opaque host data.
+ */
+ LV2_State_Map_Path_Handle handle;
+
+ /**
+ Map an absolute path to an abstract path for use in plugin state.
+ @param handle MUST be the @p handle member of this struct.
+ @param absolute_path The absolute path of a file.
+ @return An abstract path suitable for use in plugin state.
+
+ The plugin MUST use this function to map any paths that will be stored
+ in plugin state. The returned value is an abstract path which MAY not
+ be an actual file system path; @ref absolute_path() MUST be used to map
+ it to an actual path in order to use the file.
+
+ Plugins MUST NOT make any assumptions about abstract paths except that
+ they can be mapped back to the absolute path of the "same" file (though
+ not necessarily the same original path) using @ref absolute_path().
+
+ This function may only be called within the context of
+ LV2_State_Interface methods. The caller is responsible for freeing the
+ returned value with free().
+ */
+ char* (*abstract_path)(LV2_State_Map_Path_Handle handle,
+ const char* absolute_path);
+
+ /**
+ Map an abstract path from plugin state to an absolute path.
+ @param handle MUST be the @p handle member of this struct.
+ @param abstract_path An abstract path (e.g. a path from plugin state).
+ @return An absolute file system path.
+
+ The plugin MUST use this function in order to actually open or otherwise
+ use any paths loaded from plugin state.
+
+ This function may only be called within the context of
+ LV2_State_Interface methods. The caller is responsible for freeing the
+ returned value with free().
+ */
+ char* (*absolute_path)(LV2_State_Map_Path_Handle handle,
+ const char* abstract_path);
+} LV2_State_Map_Path;
+
+/**
+ Feature data for state:makePath (@ref LV2_STATE__makePath).
+*/
+typedef struct {
+ /**
+ Opaque host data.
+ */
+ LV2_State_Make_Path_Handle handle;
+
+ /**
+ Return a path the plugin may use to create a new file.
+ @param handle MUST be the @p handle member of this struct.
+ @param path The path of the new file within a namespace unique to this
+ plugin instance.
+ @return The absolute path to use for the new file.
+
+ This function can be used by plugins to create files and directories,
+ either at state saving time (if this feature is passed to
+ LV2_State_Interface.save()) or any time (if this feature is passed to
+ LV2_Descriptor.instantiate()).
+
+ The host MUST do whatever is necessary for the plugin to be able to
+ create a file at the returned path (e.g. using fopen), including
+ creating any leading directories.
+
+ If this function is passed to LV2_Descriptor.instantiate(), it may be
+ called from any non-realtime context. If it is passed to
+ LV2_State_Interface.save(), it may only be called within the dynamic
+ scope of that function call.
+
+ The caller is responsible for freeing the returned value with free().
+ */
+ char* (*path)(LV2_State_Make_Path_Handle handle,
+ const char* path);
+} LV2_State_Make_Path;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_STATE_H */
diff --git a/distrho/src/lv2/time.h b/distrho/src/lv2/time.h
@@ -0,0 +1,49 @@
+/*
+ Copyright 2011 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file time.h C header for the LV2 Time extension
+ <http://lv2plug.in/ns/ext/time>.
+*/
+
+#ifndef LV2_TIME_H
+#define LV2_TIME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LV2_TIME_URI "http://lv2plug.in/ns/ext/time"
+
+#define LV2_TIME__Time LV2_TIME_URI "#Time"
+#define LV2_TIME__Position LV2_TIME_URI "#Position"
+#define LV2_TIME__Rate LV2_TIME_URI "#Rate"
+#define LV2_TIME__position LV2_TIME_URI "#position"
+#define LV2_TIME__barBeat LV2_TIME_URI "#barBeat"
+#define LV2_TIME__bar LV2_TIME_URI "#bar"
+#define LV2_TIME__beat LV2_TIME_URI "#beat"
+#define LV2_TIME__beatUnit LV2_TIME_URI "#beatUnit"
+#define LV2_TIME__beatsPerBar LV2_TIME_URI "#beatsPerBar"
+#define LV2_TIME__beatsPerMinute LV2_TIME_URI "#beatsPerMinute"
+#define LV2_TIME__frame LV2_TIME_URI "#frame"
+#define LV2_TIME__framesPerSecond LV2_TIME_URI "#framesPerSecond"
+#define LV2_TIME__speed LV2_TIME_URI "#speed"
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_TIME_H */
diff --git a/distrho/src/lv2/ui.h b/distrho/src/lv2/ui.h
@@ -0,0 +1,407 @@
+/*
+ LV2 UI Extension
+ Copyright 2009-2012 David Robillard <d@drobilla.net>
+ Copyright 2006-2011 Lars Luthman <lars.luthman@gmail.com>
+
+ 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.
+*/
+
+/**
+ @file ui.h
+ C header for the LV2 UI extension <http://lv2plug.in/ns/extensions/ui>.
+*/
+
+#ifndef LV2_UI_H
+#define LV2_UI_H
+
+#include <stdint.h>
+
+#include "lv2.h"
+
+#define LV2_UI_URI "http://lv2plug.in/ns/extensions/ui"
+#define LV2_UI_PREFIX LV2_UI_URI "#"
+
+#define LV2_UI__CocoaUI LV2_UI_PREFIX "CocoaUI"
+#define LV2_UI__Gtk3UI LV2_UI_PREFIX "Gtk3UI"
+#define LV2_UI__GtkUI LV2_UI_PREFIX "GtkUI"
+#define LV2_UI__PortNotification LV2_UI_PREFIX "PortNotification"
+#define LV2_UI__Qt4UI LV2_UI_PREFIX "Qt4UI"
+#define LV2_UI__UI LV2_UI_PREFIX "UI"
+#define LV2_UI__WindowsUI LV2_UI_PREFIX "WindowsUI"
+#define LV2_UI__X11UI LV2_UI_PREFIX "X11UI"
+#define LV2_UI__binary LV2_UI_PREFIX "binary"
+#define LV2_UI__fixedSize LV2_UI_PREFIX "fixedSize"
+#define LV2_UI__idleInterface LV2_UI_PREFIX "idleInterface"
+#define LV2_UI__noUserResize LV2_UI_PREFIX "noUserResize"
+#define LV2_UI__notifyType LV2_UI_PREFIX "notifyType"
+#define LV2_UI__parent LV2_UI_PREFIX "parent"
+#define LV2_UI__plugin LV2_UI_PREFIX "plugin"
+#define LV2_UI__portIndex LV2_UI_PREFIX "portIndex"
+#define LV2_UI__portMap LV2_UI_PREFIX "portMap"
+#define LV2_UI__portNotification LV2_UI_PREFIX "portNotification"
+#define LV2_UI__portSubscribe LV2_UI_PREFIX "portSubscribe"
+#define LV2_UI__resize LV2_UI_PREFIX "resize"
+#define LV2_UI__touch LV2_UI_PREFIX "touch"
+#define LV2_UI__ui LV2_UI_PREFIX "ui"
+
+/**
+ The index returned by LV2_UI_Port_Port::port_index() for unknown ports.
+*/
+#define LV2UI_INVALID_PORT_INDEX ((uint32_t)-1)
+
+#ifdef __cplusplus
+extern "C" {
+#else
+# include <stdbool.h>
+#endif
+
+/**
+ A pointer to some widget or other type of UI handle.
+
+ The actual type is defined by the type of the UI.
+*/
+typedef void* LV2UI_Widget;
+
+/**
+ A pointer to an instance of a UI.
+
+ It is valid to compare this to NULL (0 for C++) but otherwise the host MUST
+ not attempt to interpret it. The UI plugin may use it to reference internal
+ instance data.
+*/
+typedef void* LV2UI_Handle;
+
+/**
+ A pointer to a controller provided by the host.
+
+ It is valid to compare this to NULL (0 for C++) but otherwise the UI plugin
+ MUST NOT attempt to interpret it. The host may use it to reference internal
+ instance data.
+*/
+typedef void* LV2UI_Controller;
+
+/**
+ A pointer to opaque data for a feature.
+*/
+typedef void* LV2UI_Feature_Handle;
+
+/**
+ The type of the host-provided function that the UI can use to
+ send data to a plugin's input ports.
+
+ The @p buffer parameter must point to a block of data, @c buffer_size bytes
+ large. The format of this data and how the host should use it is defined by
+ the @p port_protocol. This buffer is owned by the UI and is only valid for
+ the duration of this call.
+
+ The @p port_protocol parameter should either be 0 or the URID for a
+ ui:PortProtocol. If it is 0, the protocol is implicitly ui:floatProtocol,
+ the port must be an lv2:ControlPort input, @c buffer must point to a single
+ float value, and @c buffer_size must be sizeof(float).
+
+ The UI SHOULD NOT use a PortProtocol not supported by the host (i.e. one not
+ passed by the host as a feature), but the host MUST gracefully ignore any
+ port_protocol it does not understand.
+*/
+typedef void (*LV2UI_Write_Function)(LV2UI_Controller controller,
+ uint32_t port_index,
+ uint32_t buffer_size,
+ uint32_t port_protocol,
+ const void* buffer);
+
+/**
+ The implementation of a UI.
+
+ A pointer to an object of this type is returned by the lv2ui_descriptor()
+ function.
+*/
+typedef struct _LV2UI_Descriptor {
+ /**
+ The URI for this UI (not for the plugin it controls).
+ */
+ const char* URI;
+
+ /**
+ Create a new UI object and return a handle to it. This function works
+ similarly to the instantiate() member in LV2_Descriptor.
+
+ @param descriptor The descriptor for the UI that you want to instantiate.
+
+ @param plugin_uri The URI of the plugin that this UI will control.
+
+ @param bundle_path The path to the bundle containing the RDF data file
+ that references this shared object file, including the trailing '/'.
+
+ @param write_function A function provided by the host that the UI can use
+ to send data to the plugin's input ports.
+
+ @param controller A handle for the plugin instance that should be passed
+ as the first parameter of @p write_function.
+
+ @param widget A pointer to an LV2UI_Widget. The UI will write a widget
+ pointer to this location (what type of widget depends on the RDF class of
+ the UI) that will be the main UI widget.
+
+ @param features An array of LV2_Feature pointers. The host must pass all
+ feature URIs that it and the UI supports and any additional data, just
+ like in the LV2 plugin instantiate() function. Note that UI features and
+ plugin features are NOT necessarily the same, they just share the same
+ data structure - this will probably not be the same array as the one the
+ plugin host passes to a plugin.
+
+ */
+ LV2UI_Handle (*instantiate)(const struct _LV2UI_Descriptor* descriptor,
+ const char* plugin_uri,
+ const char* bundle_path,
+ LV2UI_Write_Function write_function,
+ LV2UI_Controller controller,
+ LV2UI_Widget* widget,
+ const LV2_Feature* const* features);
+
+
+ /**
+ Destroy the UI object and the associated widget. The host must not try
+ to access the widget after calling this function.
+ */
+ void (*cleanup)(LV2UI_Handle ui);
+
+ /**
+ Tell the UI that something interesting has happened at a plugin port.
+
+ What is interesting and how it is written to the buffer passed to this
+ function is defined by the @p format parameter, which has the same
+ meaning as in LV2UI_Write_Function. The only exception is ports of the
+ class lv2:ControlPort, for which this function should be called when the
+ port value changes (it does not have to be called for every single change
+ if the host's UI thread has problems keeping up with the thread the
+ plugin is running in), @p buffer_size should be 4, the buffer should
+ contain a single IEEE-754 float, and @p format should be 0.
+
+ By default, the host should only call this function for input ports of
+ the lv2:ControlPort class. However, this can be modified by using
+ ui:portNotification in the UI data, or the ui:portSubscribe feature.
+
+ The @p buffer is only valid during the time of this function call, so if
+ the UI wants to keep it for later use it has to copy the contents to an
+ internal buffer.
+
+ This member may be set to NULL if the UI is not interested in any
+ port events.
+ */
+ void (*port_event)(LV2UI_Handle ui,
+ uint32_t port_index,
+ uint32_t buffer_size,
+ uint32_t format,
+ const void* buffer);
+
+ /**
+ Return a data structure associated with an extension URI, for example
+ a struct containing additional function pointers.
+
+ Avoid returning function pointers directly since standard C/C++ has no
+ valid way of casting a void* to a function pointer. This member may be set
+ to NULL if the UI is not interested in supporting any extensions. This is
+ similar to the extension_data() member in LV2_Descriptor.
+ */
+ const void* (*extension_data)(const char* uri);
+} LV2UI_Descriptor;
+
+/**
+ UI Resize Feature (LV2_UI__resize)
+
+ This structure may be used in two ways: as a feature passed by the host via
+ LV2UI_Descriptor::instantiate(), or as extension data provided by a UI via
+ LV2UI_Descriptor::extension_data()).
+*/
+typedef struct _LV2UI_Resize {
+ /**
+ Pointer to opaque data which must be passed to ui_resize().
+ */
+ LV2UI_Feature_Handle handle;
+
+ /**
+ Request or advertise a size change.
+
+ When this struct is provided by the host, the UI may call this
+ function to inform the host about the size of the UI.
+
+ When this struct is provided by the UI, the host may call this
+ function to notify the UI that it should change its size accordingly.
+
+ @return 0 on success.
+ */
+ int (*ui_resize)(LV2UI_Feature_Handle handle, int width, int height);
+} LV2UI_Resize;
+
+/**
+ Port Map Feature (LV2_UI__portMap).
+
+ This feature can be used by the UI to get the index for a port with the
+ given symbol. This makes it possible to implement and distribute a UI
+ separately from the plugin (since symbol is a guaranteed stable port
+ identifier while index is not).
+*/
+typedef struct _LV2UI_Port_Map {
+ /**
+ Pointer to opaque data which must be passed to ui_resize().
+ */
+ LV2UI_Feature_Handle handle;
+
+ /**
+ Get the index for the port with the given @p symbol.
+
+ @return The index of the port, or LV2_UI_INVALID_PORT_INDEX if no such
+ port is found.
+ */
+ uint32_t (*port_index)(LV2UI_Feature_Handle handle, const char* symbol);
+} LV2UI_Port_Map;
+
+/**
+ Port subscription feature (LV2_UI__portSubscribe);
+*/
+typedef struct _LV2UI_Port_Subscribe {
+ /**
+ Pointer to opaque data which must be passed to ui_resize().
+ */
+ LV2UI_Feature_Handle handle;
+
+ /**
+ Subscribe to updates for a port.
+
+ This means that the host will call the UI's port_event() function when
+ the port value changes (as defined by protocol).
+
+ Calling this function with the same @p port_index and @p port_protocol
+ as an already active subscription has no effect.
+
+ @param handle The handle field of this struct.
+ @param port_index The index of the port.
+ @param port_protocol The URID of the ui:PortProtocol.
+ @param features Features for this subscription.
+ @return 0 on success.
+ */
+ uint32_t (*subscribe)(LV2UI_Feature_Handle handle,
+ uint32_t port_index,
+ uint32_t port_protocol,
+ const LV2_Feature* const* features);
+
+ /**
+ Unsubscribe from updates for a port.
+
+ This means that the host will cease calling calling port_event() when
+ the port value changes.
+
+ Calling this function with a @p port_index and @p port_protocol that
+ does not refer to an active port subscription has no effect.
+
+ @param handle The handle field of this struct.
+ @param port_index The index of the port.
+ @param port_protocol The URID of the ui:PortProtocol.
+ @param features Features for this subscription.
+ @return 0 on success.
+ */
+ uint32_t (*unsubscribe)(LV2UI_Feature_Handle handle,
+ uint32_t port_index,
+ uint32_t port_protocol,
+ const LV2_Feature* const* features);
+} LV2UI_Port_Subscribe;
+
+/**
+ A feature to notify the host the user has grabbed a UI control.
+*/
+typedef struct _LV2UI_Touch {
+ /**
+ Pointer to opaque data which must be passed to ui_resize().
+ */
+ LV2UI_Feature_Handle handle;
+
+ /**
+ Notify the host that a control has been grabbed or released.
+
+ @param handle The handle field of this struct.
+ @param port_index The index of the port associated with the control.
+ @param grabbed If true, the control has been grabbed, otherwise the
+ control has been released.
+ */
+ void (*touch)(LV2UI_Feature_Handle handle,
+ uint32_t port_index,
+ bool grabbed);
+} LV2UI_Touch;
+
+/**
+ UI Idle Feature (LV2_UI__idle)
+
+ This feature is an addition to the UI API that provides a callback for the
+ host to call rapidly, e.g. to drive the idle callback of a toolkit.
+*/
+typedef struct _LV2UI_Idle_Interface {
+ /**
+ Run a single iteration of the UI's idle loop.
+
+ This will be called "frequently" in the UI thread at a rate appropriate
+ for a toolkit main loop. There are no precise timing guarantees.
+
+ @return 0 on success, or anything else to stop being called.
+ */
+ int (*idle)(LV2UI_Handle ui);
+} LV2UI_Idle_Interface;
+
+/**
+ Peak data for a slice of time, the update format for ui:peakProtocol.
+*/
+typedef struct _LV2UI_Peak_Data {
+ /**
+ The start of the measurement period. This is just a running counter
+ that is only meaningful in comparison to previous values and must not be
+ interpreted as an absolute time.
+ */
+ uint32_t period_start;
+
+ /**
+ The size of the measurement period, in the same units as period_start.
+ */
+ uint32_t period_size;
+
+ /**
+ The peak value for the measurement period. This should be the maximal
+ value for abs(sample) over all the samples in the period.
+ */
+ float peak;
+} LV2UI_Peak_Data;
+
+/**
+ A plugin UI programmer must include a function called "lv2ui_descriptor"
+ with the following function prototype within the shared object file. This
+ function will have C-style linkage (if you are using C++ this is taken care
+ of by the 'extern "C"' clause at the top of the file). This function is
+ loaded from the library by the UI host and called to get a
+ LV2UI_Descriptor for the wanted plugin.
+
+ Just like lv2_descriptor(), this function takes an index parameter. The
+ index should only be used for enumeration and not as any sort of ID number -
+ the host should just iterate from 0 and upwards until the function returns
+ NULL or a descriptor with an URI matching the one the host is looking for.
+*/
+LV2_SYMBOL_EXPORT
+const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index);
+
+/**
+ The type of the lv2ui_descriptor() function.
+*/
+typedef const LV2UI_Descriptor* (*LV2UI_DescriptorFunction)(uint32_t index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LV2_UI_H */
diff --git a/distrho/src/lv2/units.h b/distrho/src/lv2/units.h
@@ -0,0 +1,62 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file units.h
+ C definitions for the LV2 Units extension
+ <http://lv2plug.in/ns/extensions/units>.
+*/
+
+#ifndef LV2_UNITS_H
+#define LV2_UNITS_H
+
+#define LV2_UNITS_URI "http://lv2plug.in/ns/extensions/units"
+#define LV2_UNITS_PREFIX LV2_UNITS_URI "#"
+
+#define LV2_UNITS__Conversion LV2_UNITS_PREFIX "Conversion"
+#define LV2_UNITS__Unit LV2_UNITS_PREFIX "Unit"
+#define LV2_UNITS__bar LV2_UNITS_PREFIX "bar"
+#define LV2_UNITS__beat LV2_UNITS_PREFIX "beat"
+#define LV2_UNITS__bpm LV2_UNITS_PREFIX "bpm"
+#define LV2_UNITS__cent LV2_UNITS_PREFIX "cent"
+#define LV2_UNITS__cm LV2_UNITS_PREFIX "cm"
+#define LV2_UNITS__coef LV2_UNITS_PREFIX "coef"
+#define LV2_UNITS__conversion LV2_UNITS_PREFIX "conversion"
+#define LV2_UNITS__db LV2_UNITS_PREFIX "db"
+#define LV2_UNITS__degree LV2_UNITS_PREFIX "degree"
+#define LV2_UNITS__frame LV2_UNITS_PREFIX "frame"
+#define LV2_UNITS__hz LV2_UNITS_PREFIX "hz"
+#define LV2_UNITS__inch LV2_UNITS_PREFIX "inch"
+#define LV2_UNITS__khz LV2_UNITS_PREFIX "khz"
+#define LV2_UNITS__km LV2_UNITS_PREFIX "km"
+#define LV2_UNITS__m LV2_UNITS_PREFIX "m"
+#define LV2_UNITS__mhz LV2_UNITS_PREFIX "mhz"
+#define LV2_UNITS__midiNote LV2_UNITS_PREFIX "midiNote"
+#define LV2_UNITS__mile LV2_UNITS_PREFIX "mile"
+#define LV2_UNITS__min LV2_UNITS_PREFIX "min"
+#define LV2_UNITS__mm LV2_UNITS_PREFIX "mm"
+#define LV2_UNITS__ms LV2_UNITS_PREFIX "ms"
+#define LV2_UNITS__name LV2_UNITS_PREFIX "name"
+#define LV2_UNITS__oct LV2_UNITS_PREFIX "oct"
+#define LV2_UNITS__pc LV2_UNITS_PREFIX "pc"
+#define LV2_UNITS__prefixConversion LV2_UNITS_PREFIX "prefixConversion"
+#define LV2_UNITS__render LV2_UNITS_PREFIX "render"
+#define LV2_UNITS__s LV2_UNITS_PREFIX "s"
+#define LV2_UNITS__semitone12TET LV2_UNITS_PREFIX "semitone12TET"
+#define LV2_UNITS__symbol LV2_UNITS_PREFIX "symbol"
+#define LV2_UNITS__unit LV2_UNITS_PREFIX "unit"
+
+#endif /* LV2_UNITS_H */
diff --git a/distrho/src/lv2/uri-map.h b/distrho/src/lv2/uri-map.h
@@ -0,0 +1,98 @@
+/*
+ Copyright 2008-2011 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file
+ C header for the LV2 URI Map extension <http://lv2plug.in/ns/ext/uri-map>.
+
+ This extension defines a simple mechanism for plugins to map URIs to
+ integers, usually for performance reasons (e.g. processing events typed by
+ URIs in real time). The expected use case is for plugins to map URIs to
+ integers for things they 'understand' at instantiation time, and store those
+ values for use in the audio thread without doing any string comparison.
+ This allows the extensibility of RDF with the performance of integers (or
+ centrally defined enumerations).
+*/
+
+#ifndef LV2_URI_MAP_H
+#define LV2_URI_MAP_H
+
+#define LV2_URI_MAP_URI "http://lv2plug.in/ns/ext/uri-map"
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ Opaque pointer to host data.
+*/
+typedef void* LV2_URI_Map_Callback_Data;
+
+/**
+ URI Map Feature.
+
+ To support this feature the host must pass an LV2_Feature struct to the
+ plugin's instantiate method with URI "http://lv2plug.in/ns/ext/uri-map"
+ and data pointed to an instance of this struct.
+*/
+typedef struct {
+ /**
+ Opaque pointer to host data.
+
+ The plugin MUST pass this to any call to functions in this struct.
+ Otherwise, it must not be interpreted in any way.
+ */
+ LV2_URI_Map_Callback_Data callback_data;
+
+ /**
+ Get the numeric ID of a URI from the host.
+
+ @param callback_data Must be the callback_data member of this struct.
+ @param map The 'context' of this URI. Certain extensions may define a
+ URI that must be passed here with certain restrictions on the return
+ value (e.g. limited range). This value may be NULL if the plugin needs
+ an ID for a URI in general. Extensions SHOULD NOT define a context
+ unless there is a specific need to do so, e.g. to restrict the range of
+ the returned value.
+ @param uri The URI to be mapped to an integer ID.
+
+ This function is referentially transparent; any number of calls with the
+ same arguments is guaranteed to return the same value over the life of a
+ plugin instance (though the same URI may return different values with a
+ different map parameter). However, this function is not necessarily very
+ fast: plugins SHOULD cache any IDs they might need in performance
+ critical situations.
+
+ The return value 0 is reserved and indicates that an ID for that URI
+ could not be created for whatever reason. Extensions MAY define more
+ precisely what this means in a certain context, but in general plugins
+ SHOULD handle this situation as gracefully as possible. However, hosts
+ SHOULD NOT return 0 from this function in non-exceptional circumstances
+ (e.g. the URI map SHOULD be dynamic). Hosts that statically support only
+ a fixed set of URIs should not expect plugins to function correctly.
+ */
+ uint32_t (*uri_to_id)(LV2_URI_Map_Callback_Data callback_data,
+ const char* map,
+ const char* uri);
+} LV2_URI_Map_Feature;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_URI_MAP_H */
diff --git a/distrho/src/lv2/urid.h b/distrho/src/lv2/urid.h
@@ -0,0 +1,129 @@
+/*
+ Copyright 2008-2012 David Robillard <http://drobilla.net>
+ Copyright 2011 Gabriel M. Beddingfield <gabrbedd@gmail.com>
+
+ 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.
+*/
+
+/**
+ @file urid.h
+ C header for the LV2 URID extension <http://lv2plug.in/ns/ext/urid>
+*/
+
+#ifndef LV2_URID_H
+#define LV2_URID_H
+
+#define LV2_URID_URI "http://lv2plug.in/ns/ext/urid"
+#define LV2_URID_PREFIX LV2_URID_URI "#"
+
+#define LV2_URID__map LV2_URID_PREFIX "map"
+#define LV2_URID__unmap LV2_URID_PREFIX "unmap"
+
+/* Legacy defines */
+#define LV2_URID_MAP_URI LV2_URID__map
+#define LV2_URID_UNMAP_URI LV2_URID__unmap
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ Opaque pointer to host data for LV2_URID_Map.
+*/
+typedef void* LV2_URID_Map_Handle;
+
+/**
+ Opaque pointer to host data for LV2_URID_Unmap.
+*/
+typedef void* LV2_URID_Unmap_Handle;
+
+/**
+ URI mapped to an integer.
+*/
+typedef uint32_t LV2_URID;
+
+/**
+ URID Map Feature (LV2_URID__map)
+*/
+typedef struct _LV2_URID_Map {
+ /**
+ Opaque pointer to host data.
+
+ This MUST be passed to map_uri() whenever it is called.
+ Otherwise, it must not be interpreted in any way.
+ */
+ LV2_URID_Map_Handle handle;
+
+ /**
+ Get the numeric ID of a URI.
+
+ If the ID does not already exist, it will be created.
+
+ This function is referentially transparent; any number of calls with the
+ same arguments is guaranteed to return the same value over the life of a
+ plugin instance. Note, however, that several URIs MAY resolve to the
+ same ID if the host considers those URIs equivalent.
+
+ This function is not necessarily very fast or RT-safe: plugins SHOULD
+ cache any IDs they might need in performance critical situations.
+
+ The return value 0 is reserved and indicates that an ID for that URI
+ could not be created for whatever reason. However, hosts SHOULD NOT
+ return 0 from this function in non-exceptional circumstances (i.e. the
+ URI map SHOULD be dynamic).
+
+ @param handle Must be the callback_data member of this struct.
+ @param uri The URI to be mapped to an integer ID.
+ */
+ LV2_URID (*map)(LV2_URID_Map_Handle handle,
+ const char* uri);
+} LV2_URID_Map;
+
+/**
+ URI Unmap Feature (LV2_URID__unmap)
+*/
+typedef struct _LV2_URID_Unmap {
+ /**
+ Opaque pointer to host data.
+
+ This MUST be passed to unmap() whenever it is called.
+ Otherwise, it must not be interpreted in any way.
+ */
+ LV2_URID_Unmap_Handle handle;
+
+ /**
+ Get the URI for a previously mapped numeric ID.
+
+ Returns NULL if @p urid is not yet mapped. Otherwise, the corresponding
+ URI is returned in a canonical form. This MAY not be the exact same
+ string that was originally passed to LV2_URID_Map::map(), but it MUST be
+ an identical URI according to the URI syntax specification (RFC3986). A
+ non-NULL return for a given @p urid will always be the same for the life
+ of the plugin. Plugins that intend to perform string comparison on
+ unmapped URIs SHOULD first canonicalise URI strings with a call to
+ map_uri() followed by a call to unmap_uri().
+
+ @param handle Must be the callback_data member of this struct.
+ @param urid The ID to be mapped back to the URI string.
+ */
+ const char* (*unmap)(LV2_URID_Unmap_Handle handle,
+ LV2_URID urid);
+} LV2_URID_Unmap;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_URID_H */
diff --git a/distrho/src/lv2/worker.h b/distrho/src/lv2/worker.h
@@ -0,0 +1,158 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ 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.
+*/
+
+/**
+ @file worker.h C header for the LV2 Worker extension
+ <http://lv2plug.in/ns/ext/worker>.
+*/
+
+#ifndef LV2_WORKER_H
+#define LV2_WORKER_H
+
+#include <stdint.h>
+
+#include "lv2.h"
+
+#define LV2_WORKER_URI "http://lv2plug.in/ns/ext/worker"
+#define LV2_WORKER_PREFIX LV2_WORKER_URI "#"
+
+#define LV2_WORKER__interface LV2_WORKER_PREFIX "interface"
+#define LV2_WORKER__schedule LV2_WORKER_PREFIX "schedule"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ A status code for worker functions.
+*/
+typedef enum {
+ LV2_WORKER_SUCCESS = 0, /**< Completed successfully. */
+ LV2_WORKER_ERR_UNKNOWN = 1, /**< Unknown error. */
+ LV2_WORKER_ERR_NO_SPACE = 2 /**< Failed due to lack of space. */
+} LV2_Worker_Status;
+
+typedef void* LV2_Worker_Respond_Handle;
+
+/**
+ A function to respond to run() from the worker method.
+
+ The @p data MUST be safe for the host to copy and later pass to
+ work_response(), and the host MUST guarantee that it will be eventually
+ passed to work_response() if this function returns LV2_WORKER_SUCCESS.
+*/
+typedef LV2_Worker_Status (*LV2_Worker_Respond_Function)(
+ LV2_Worker_Respond_Handle handle,
+ uint32_t size,
+ const void* data);
+
+/**
+ LV2 Plugin Worker Interface.
+
+ This is the interface provided by the plugin to implement a worker method.
+ The plugin's extension_data() method should return an LV2_Worker_Interface
+ when called with LV2_WORKER__interface as its argument.
+*/
+typedef struct _LV2_Worker_Interface {
+ /**
+ The worker method. This is called by the host in a non-realtime context
+ as requested, possibly with an arbitrary message to handle.
+
+ A response can be sent to run() using @p respond. The plugin MUST NOT
+ make any assumptions about which thread calls this method, other than
+ the fact that there are no real-time requirements.
+
+ @param instance The LV2 instance this is a method on.
+ @param respond A function for sending a response to run().
+ @param handle Must be passed to @p respond if it is called.
+ @param size The size of @p data.
+ @param data Data from run(), or NULL.
+ */
+ LV2_Worker_Status (*work)(LV2_Handle instance,
+ LV2_Worker_Respond_Function respond,
+ LV2_Worker_Respond_Handle handle,
+ uint32_t size,
+ const void* data);
+
+ /**
+ Handle a response from the worker. This is called by the host in the
+ run() context when a response from the worker is ready.
+
+ @param instance The LV2 instance this is a method on.
+ @param size The size of @p body.
+ @param body Message body, or NULL.
+ */
+ LV2_Worker_Status (*work_response)(LV2_Handle instance,
+ uint32_t size,
+ const void* body);
+
+ /**
+ Called when all responses for this cycle have been delivered.
+
+ Since work_response() may be called after run() finished, this provides
+ a hook for code that must run after the cycle is completed.
+
+ This field may be NULL if the plugin has no use for it. Otherwise, the
+ host MUST call it after every run(), regardless of whether or not any
+ responses were sent that cycle.
+ */
+ LV2_Worker_Status (*end_run)(LV2_Handle instance);
+} LV2_Worker_Interface;
+
+typedef void* LV2_Worker_Schedule_Handle;
+
+typedef struct _LV2_Worker_Schedule {
+ /**
+ Opaque host data.
+ */
+ LV2_Worker_Schedule_Handle handle;
+
+ /**
+ Request from run() that the host call the worker.
+
+ This function is in the audio threading class. It should be called from
+ run() to request that the host call the work() method in a non-realtime
+ context with the given arguments.
+
+ This function is always safe to call from run(), but it is not
+ guaranteed that the worker is actually called from a different thread.
+ In particular, when free-wheeling (e.g. for offline rendering), the
+ worker may be executed immediately. This allows single-threaded
+ processing with sample accuracy and avoids timing problems when run() is
+ executing much faster or slower than real-time.
+
+ Plugins SHOULD be written in such a way that if the worker runs
+ immediately, and responses from the worker are delivered immediately,
+ the effect of the work takes place immediately with sample accuracy.
+
+ The @p data MUST be safe for the host to copy and later pass to work(),
+ and the host MUST guarantee that it will be eventually passed to work()
+ if this function returns LV2_WORKER_SUCCESS.
+
+ @param handle The handle field of this struct.
+ @param size The size of @p data.
+ @param data Message to pass to work(), or NULL.
+ */
+ LV2_Worker_Status (*schedule_work)(LV2_Worker_Schedule_Handle handle,
+ uint32_t size,
+ const void* data);
+} LV2_Worker_Schedule;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_WORKER_H */
diff --git a/distrho/src/vestige/aeffectx.h b/distrho/src/vestige/aeffectx.h
@@ -0,0 +1,279 @@
+/*
+ * aeffectx.h - simple header to allow VeSTige compilation and eventually work
+ *
+ * Copyright (c) 2006 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
+ *
+ * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
+ *
+ * This program 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 program 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 (see COPYING); if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ */
+#include <stdint.h>
+#ifndef _AEFFECTX_H
+#define _AEFFECTX_H
+
+#define CCONST(a, b, c, d)( ( ( (int) a ) << 24 ) | \
+ ( ( (int) b ) << 16 ) | \
+ ( ( (int) c ) << 8 ) | \
+ ( ( (int) d ) << 0 ) )
+
+#define audioMasterAutomate 0
+#define audioMasterVersion 1
+#define audioMasterCurrentId 2
+#define audioMasterIdle 3
+#define audioMasterPinConnected 4
+// unsupported? 5
+#define audioMasterWantMidi 6
+#define audioMasterGetTime 7
+#define audioMasterProcessEvents 8
+#define audioMasterSetTime 9
+#define audioMasterTempoAt 10
+#define audioMasterGetNumAutomatableParameters 11
+#define audioMasterGetParameterQuantization 12
+#define audioMasterIOChanged 13
+#define audioMasterNeedIdle 14
+#define audioMasterSizeWindow 15
+#define audioMasterGetSampleRate 16
+#define audioMasterGetBlockSize 17
+#define audioMasterGetInputLatency 18
+#define audioMasterGetOutputLatency 19
+#define audioMasterGetPreviousPlug 20
+#define audioMasterGetNextPlug 21
+#define audioMasterWillReplaceOrAccumulate 22
+#define audioMasterGetCurrentProcessLevel 23
+#define audioMasterGetAutomationState 24
+#define audioMasterOfflineStart 25
+#define audioMasterOfflineRead 26
+#define audioMasterOfflineWrite 27
+#define audioMasterOfflineGetCurrentPass 28
+#define audioMasterOfflineGetCurrentMetaPass 29
+#define audioMasterSetOutputSampleRate 30
+// unsupported? 31
+#define audioMasterGetSpeakerArrangement 31 // deprecated in 2.4?
+#define audioMasterGetVendorString 32
+#define audioMasterGetProductString 33
+#define audioMasterGetVendorVersion 34
+#define audioMasterVendorSpecific 35
+#define audioMasterSetIcon 36
+#define audioMasterCanDo 37
+#define audioMasterGetLanguage 38
+#define audioMasterOpenWindow 39
+#define audioMasterCloseWindow 40
+#define audioMasterGetDirectory 41
+#define audioMasterUpdateDisplay 42
+#define audioMasterBeginEdit 43
+#define audioMasterEndEdit 44
+#define audioMasterOpenFileSelector 45
+#define audioMasterCloseFileSelector 46 // currently unused
+#define audioMasterEditFile 47 // currently unused
+#define audioMasterGetChunkFile 48 // currently unused
+#define audioMasterGetInputSpeakerArrangement 49 // currently unused
+
+#define effFlagsHasEditor 1
+#define effFlagsCanReplacing (1 << 4) // very likely
+#define effFlagsIsSynth (1 << 8) // currently unused
+
+#define effOpen 0
+#define effClose 1 // currently unused
+#define effSetProgram 2 // currently unused
+#define effGetProgram 3 // currently unused
+#define effGetProgramName 5 // currently unused
+#define effGetParamName 8 // currently unused
+#define effSetSampleRate 10
+#define effSetBlockSize 11
+#define effMainsChanged 12
+#define effEditGetRect 13
+#define effEditOpen 14
+#define effEditClose 15
+#define effEditIdle 19
+#define effEditTop 20
+#define effProcessEvents 25
+#define effGetEffectName 45
+#define effGetVendorString 47
+#define effGetProductString 48
+#define effGetVendorVersion 49
+#define effCanDo 51 // currently unused
+/* from http://asseca.com/vst-24-specs/efGetParameterProperties.html */
+#define effGetParameterProperties 56
+#define effGetVstVersion 58 // currently unused
+
+#define kEffectMagic (CCONST( 'V', 's', 't', 'P' ))
+#define kVstLangEnglish 1
+#define kVstMidiType 1
+#define kVstTempoValid (1 << 10)
+#define kVstTransportPlaying (1 << 1)
+
+
+struct RemoteVstPlugin;
+
+#define kVstNanosValid (1 << 8)
+#define kVstPpqPosValid (1 << 9)
+#define kVstTempoValid (1 << 10)
+#define kVstBarsValid (1 << 11)
+#define kVstCyclePosValid (1 << 12)
+#define kVstTimeSigValid (1 << 13)
+#define kVstSmpteValid (1 << 14)
+#define kVstClockValid (1 << 15)
+
+struct _VstMidiEvent
+{
+ // 00
+ int type;
+ // 04
+ int byteSize;
+ // 08
+ int deltaFrames;
+ // 0c?
+ int flags;
+ // 10?
+ int noteLength;
+ // 14?
+ int noteOffset;
+ // 18
+ char midiData[4];
+ // 1c?
+ char detune;
+ // 1d?
+ char noteOffVelocity;
+ // 1e?
+ char reserved1;
+ // 1f?
+ char reserved2;
+};
+
+typedef struct _VstMidiEvent VstMidiEvent;
+
+
+struct _VstEvent
+{
+ char dump[sizeof (VstMidiEvent)];
+
+};
+
+typedef struct _VstEvent VstEvent;
+
+struct _VstEvents
+{
+ // 00
+ int numEvents;
+ // 04
+ void *reserved;
+ // 08
+ VstEvent * events[2];
+};
+
+typedef struct _VstEvents VstEvents;
+
+/* this struct taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */
+struct _VstParameterProperties
+{
+ float stepFloat;
+ float smallStepFloat;
+ float largeStepFloat;
+ char label[64];
+ int32_t flags;
+ int32_t minInteger;
+ int32_t maxInteger;
+ int32_t stepInteger;
+ int32_t largeStepInteger;
+ char shortLabel[8];
+};
+
+typedef struct _VstParameterProperties VstParameterProperties;
+
+/* this enum taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */
+enum VstParameterFlags
+{
+ kVstParameterIsSwitch = 1 << 0, /* parameter is a switch (on/off) */
+ kVstParameterUsesIntegerMinMax = 1 << 1, /* minInteger, maxInteger valid */
+ kVstParameterUsesFloatStep = 1 << 2, /* stepFloat, smallStepFloat, largeStepFloat valid */
+ kVstParameterUsesIntStep = 1 << 3, /* stepInteger, largeStepInteger valid */
+ kVstParameterSupportsDisplayIndex = 1 << 4, /* displayIndex valid */
+ kVstParameterSupportsDisplayCategory = 1 << 5, /* category, etc. valid */
+ kVstParameterCanRamp = 1 << 6 /* set if parameter value can ramp up/down */
+};
+
+struct _AEffect
+{
+ // Never use virtual functions!!!
+ // 00-03
+ int magic;
+ // dispatcher 04-07
+ intptr_t (* dispatcher) (struct _AEffect *, int, int, intptr_t, void *, float);
+ // process, quite sure 08-0b
+ void (* process) (struct _AEffect *, float **, float **, int);
+ // setParameter 0c-0f
+ void (* setParameter) (struct _AEffect *, int, float);
+ // getParameter 10-13
+ float (* getParameter) (struct _AEffect *, int);
+ // programs 14-17
+ int numPrograms;
+ // Params 18-1b
+ int numParams;
+ // Input 1c-1f
+ int numInputs;
+ // Output 20-23
+ int numOutputs;
+ // flags 24-27
+ int flags;
+ // Fill somewhere 28-2b
+ void *ptr1;
+ void *ptr2;
+ // Zeroes 2c-2f 30-33 34-37 38-3b
+ char empty3[4 + 4 + 4];
+ // 1.0f 3c-3f
+ float unkown_float;
+ // An object? pointer 40-43
+ void *ptr3;
+ // Zeroes 44-47
+ void *user;
+ // Id 48-4b
+ int32_t uniqueID;
+ // Don't know 4c-4f
+ char unknown1[4];
+ // processReplacing 50-53
+ void (* processReplacing) (struct _AEffect *, float **, float **, int);
+};
+
+typedef struct _AEffect AEffect;
+
+struct _VstTimeInfo
+{
+ // 00
+ double samplePos;
+ // 08
+ double sampleRate;
+ // unconfirmed 10 18
+ char empty1[8 + 8];
+ // 20?
+ double tempo;
+ // unconfirmed 28 30 38
+ char empty2[8 + 8 + 8];
+ // 40?
+ int timeSigNumerator;
+ // 44?
+ int timeSigDenominator;
+ // unconfirmed 48 4c 50
+ char empty3[4 + 4 + 4];
+ // 54
+ int flags;
+};
+
+typedef struct _VstTimeInfo VstTimeInfo;
+
+typedef intptr_t (* audioMasterCallback) (AEffect *, int32_t, int32_t, intptr_t, void *, float);
+
+#endif
diff --git a/lv2-ttl-generator/GNUmakefile b/lv2-ttl-generator/GNUmakefile
@@ -0,0 +1,16 @@
+#!/usr/bin/makefile -f
+
+all: build
+
+build: ../lv2_ttl_generator
+mingw: ../lv2_ttl_generator.exe
+
+../lv2_ttl_generator: lv2_ttl_generator.c
+ $(CXX) lv2_ttl_generator.c -o ../lv2_ttl_generator -ldl
+
+../lv2_ttl_generator.exe: lv2_ttl_generator.c
+ $(CXX) lv2_ttl_generator.c -o ../lv2_ttl_generator.exe -static
+ touch ../lv2_ttl_generator
+
+clean:
+ rm -f ../lv2_ttl_generator ../lv2_ttl_generator.exe
diff --git a/lv2-ttl-generator/lv2_ttl_generator.c b/lv2-ttl-generator/lv2_ttl_generator.c
@@ -0,0 +1,81 @@
+/*
+ * JUCE LV2 *.ttl generator
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef _WIN32
+ #include <windows.h>
+ #define TTL_GENERATOR_WINDOWS
+#else
+ #include <dlfcn.h>
+#endif
+
+#ifndef nullptr
+ #define nullptr (0)
+#endif
+
+typedef void (*TTL_Generator_Function)(const char* basename);
+
+int main(int argc, char* argv[])
+{
+ if (argc != 2)
+ {
+ printf("usage: %s /path/to/plugin-DLL\n", argv[0]);
+ return 1;
+ }
+
+#ifdef TTL_GENERATOR_WINDOWS
+ const HMODULE handle = LoadLibraryA(argv[1]);
+#else
+ void* const handle = dlopen(argv[1], RTLD_LAZY);
+#endif
+
+ if (! handle)
+ {
+#ifdef TTL_GENERATOR_WINDOWS
+ printf("Failed to open plugin DLL\n");
+#else
+ printf("Failed to open plugin DLL, error was:\n%s\n", dlerror());
+#endif
+ return 2;
+ }
+
+#ifdef TTL_GENERATOR_WINDOWS
+ const TTL_Generator_Function ttlFn = (TTL_Generator_Function)GetProcAddress(handle, "lv2_generate_ttl");
+#else
+ const TTL_Generator_Function ttlFn = (TTL_Generator_Function)dlsym(handle, "lv2_generate_ttl");
+#endif
+
+ if (ttlFn != NULL)
+ {
+ char basename[strlen(argv[1])+1];
+
+#ifdef TTL_GENERATOR_WINDOWS
+ if (char* base2 = strrchr(argv[1], '\\'))
+#else
+ if (char* base2 = strrchr(argv[1], '/'))
+#endif
+ {
+ strcpy(basename, base2+1);
+ basename[strrchr(base2, '.')-base2-1] = '\0';
+ }
+ else
+ strcpy(basename, argv[1]);
+
+ printf("Generate ttl data for '%s', basename: '%s'\n", argv[1], basename);
+
+ ttlFn(basename);
+ }
+ else
+ printf("Failed to find 'lv2_generate_ttl' function\n");
+
+#ifdef TTL_GENERATOR_WINDOWS
+ FreeLibrary(handle);
+#else
+ dlclose(handle);
+#endif
+
+ return 0;
+}