Browse Source

Add DPT

tags/1.9.4
falkTX 11 years ago
parent
commit
4c8e2ab192
28 changed files with 7993 additions and 0 deletions
  1. +210
    -0
      source/libs/distrho-plugin-toolkit/DistrhoPlugin.h
  2. +28
    -0
      source/libs/distrho-plugin-toolkit/DistrhoPluginMain.cpp
  3. +92
    -0
      source/libs/distrho-plugin-toolkit/DistrhoUI.h
  4. +35
    -0
      source/libs/distrho-plugin-toolkit/DistrhoUIMain.cpp
  5. +139
    -0
      source/libs/distrho-plugin-toolkit/DistrhoUIOpenGL.h
  6. +307
    -0
      source/libs/distrho-plugin-toolkit/DistrhoUIOpenGLExt.h
  7. +74
    -0
      source/libs/distrho-plugin-toolkit/DistrhoUIQt4.h
  8. +240
    -0
      source/libs/distrho-plugin-toolkit/DistrhoUtils.h
  9. +10
    -0
      source/libs/distrho-plugin-toolkit/Makefile
  10. +289
    -0
      source/libs/distrho-plugin-toolkit/distrho.doxygen
  11. +96
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoDefines.h
  12. +107
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoPlugin.cpp
  13. +360
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoPluginInternal.h
  14. +366
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoPluginJACK.cpp
  15. +685
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoPluginLADSPA+DSSI.cpp
  16. +597
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoPluginLV2.cpp
  17. +347
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoPluginLV2export.cpp
  18. +726
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoPluginVST.cpp
  19. +101
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoUI.cpp
  20. +591
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoUIDSSI.cpp
  21. +566
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoUIInternal.h
  22. +372
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoUILV2.cpp
  23. +82
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoUIOpenGL.cpp
  24. +1495
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoUIOpenGLExt.cpp
  25. +75
    -0
      source/libs/distrho-plugin-toolkit/src/DistrhoUIQt4.cpp
  26. +1
    -0
      source/libs/distrho-plugin-toolkit/src/dssi
  27. +1
    -0
      source/libs/distrho-plugin-toolkit/src/ladspa
  28. +1
    -0
      source/libs/distrho-plugin-toolkit/src/lv2

+ 210
- 0
source/libs/distrho-plugin-toolkit/DistrhoPlugin.h View File

@@ -0,0 +1,210 @@
/*
* DISTRHO Plugin Toolkit (DPT)
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#ifndef __DISTRHO_PLUGIN_H__
#define __DISTRHO_PLUGIN_H__

#include "DistrhoUtils.h"

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;
float step;
float stepSmall;
float stepLarge;

ParameterRanges()
: def(0.0f),
min(0.0f),
max(1.0f),
step(0.001f),
stepSmall(0.00001f),
stepLarge(0.01f) {}

ParameterRanges(float def, float min, float max)
: step(0.001f),
stepSmall(0.00001f),
stepLarge(0.01f)
{
this->def = def;
this->min = min;
this->max = max;
}

ParameterRanges(float def, float min, float max, float step, float stepSmall, float stepLarge)
{
this->def = def;
this->min = min;
this->max = max;
this->step = step;
this->stepSmall = stepSmall;
this->stepLarge = stepLarge;
}

void fixRange(float& value) const
{
if (value < min)
value = min;
else if (value > max)
value = max;
}
};

// -------------------------------------------------
// Parameter

struct Parameter {
uint32_t hints;
d_string name;
d_string symbol;
d_string unit;
ParameterRanges ranges;

Parameter()
: hints(0x0),
name(nullptr),
symbol(nullptr),
unit(nullptr) {}
};

// -------------------------------------------------
// MidiEvent

struct MidiEvent {
uint32_t frame;
uint8_t buffer[3];

MidiEvent()
: frame(0),
buffer{0} {}

void clear()
{
frame = 0;
buffer[0] = 0;
buffer[1] = 0;
buffer[2] = 0;
}
};

// -------------------------------------------------
// TimePos

struct TimePos {
double bpm;

TimePos()
: bpm(120.0) {}
};

// -------------------------------------------------
// Plugin

struct PluginPrivateData;

class Plugin
{
public:
Plugin(uint32_t parameterCount, uint32_t programCount, uint32_t stateCount);
virtual ~Plugin();

// ---------------------------------------------
// Host state

uint32_t d_bufferSize() const;
double d_sampleRate() const;
const TimePos& d_timePos() const;
#if DISTRHO_PLUGIN_WANT_LATENCY
void d_setLatency(uint32_t samples);
#endif

protected:
// ---------------------------------------------
// Information

virtual const char* d_name() const { return DISTRHO_PLUGIN_NAME; }
virtual const char* d_label() const = 0;
virtual const char* d_maker() const = 0;
virtual const char* d_license() const = 0;
virtual uint32_t d_version() const = 0;
virtual long d_uniqueId() const = 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_parameterValue(uint32_t index) = 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() {}
virtual void d_run(float** inputs, float** outputs, uint32_t frames, uint32_t midiEventCount, const MidiEvent* midiEvents) = 0;

// ---------------------------------------------
// Callbacks

virtual void d_bufferSizeChanged(uint32_t newBufferSize);
virtual void d_sampleRateChanged(double newSampleRate);

// ---------------------------------------------

private:
PluginPrivateData* data;
friend class PluginInternal;
};

Plugin* createPlugin();

// -------------------------------------------------

END_NAMESPACE_DISTRHO

#endif // __DISTRHO_PLUGIN_H__

+ 28
- 0
source/libs/distrho-plugin-toolkit/DistrhoPluginMain.cpp View File

@@ -0,0 +1,28 @@
/*
* DISTRHO Plugin Toolkit (DPT)
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#include "src/DistrhoPlugin.cpp"

#if defined(DISTRHO_PLUGIN_TARGET_JACK)
# include "src/DistrhoPluginJACK.cpp"
#elif 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"
#elif defined(DISTRHO_PLUGIN_TARGET_VST)
# include "src/DistrhoPluginVST.cpp"
#endif

+ 92
- 0
source/libs/distrho-plugin-toolkit/DistrhoUI.h View File

@@ -0,0 +1,92 @@
/*
* DISTRHO Plugin Toolkit (DPT)
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#ifndef __DISTRHO_UI_H__
#define __DISTRHO_UI_H__

#include "DistrhoUtils.h"

START_NAMESPACE_DISTRHO

// -------------------------------------------------

struct UIPrivateData;

class UI
{
public:
UI();
virtual ~UI();

// ---------------------------------------------

// Host DSP State
double d_sampleRate() const;
void d_setParameterValue(uint32_t index, float value);
#if DISTRHO_PLUGIN_WANT_STATE
void d_setState(const char* key, const char* value);
#endif

// Host UI State
void d_uiEditParameter(uint32_t index, bool started);
#if DISTRHO_PLUGIN_IS_SYNTH
void d_uiSendNote(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity);
#endif
void d_uiResize(unsigned int width, unsigned int height);

// ---------------------------------------------

protected:
// Information
virtual unsigned int d_width() = 0;
virtual unsigned int d_height() = 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
#if DISTRHO_PLUGIN_IS_SYNTH
virtual void d_uiNoteReceived(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity);
#endif

// UI Callbacks
virtual void d_uiIdle() = 0;

// ---------------------------------------------

private:
UIPrivateData* data;
friend class UIInternal;
#ifdef DISTRHO_UI_QT4
friend class Qt4UI;
#else
friend class OpenGLUI;
friend class OpenGLExtUI;
#endif
};

UI* createUI();

// -------------------------------------------------

END_NAMESPACE_DISTRHO

#endif // __DISTRHO_UI_H__

+ 35
- 0
source/libs/distrho-plugin-toolkit/DistrhoUIMain.cpp View File

@@ -0,0 +1,35 @@
/*
* DISTHRO Plugin Toolkit (DPT)
* Copyright (C) 2012 Filipe Coelho <falktx@gmail.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#include "src/DistrhoUI.cpp"

#if defined(DISTRHO_PLUGIN_TARGET_JACK)
// nothing
#elif 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

#ifdef DISTRHO_UI_QT4
# include "src/DistrhoUIQt4.cpp"
#else
# include "src/DistrhoUIOpenGL.cpp"
# include "src/DistrhoUIOpenGLExt.cpp"
#endif

+ 139
- 0
source/libs/distrho-plugin-toolkit/DistrhoUIOpenGL.h View File

@@ -0,0 +1,139 @@
/*
* DISTRHO Plugin Toolkit (DPT)
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#ifndef __DISTRHO_UI_OPENGL_H__
#define __DISTRHO_UI_OPENGL_H__

#include "src/DistrhoDefines.h"

#ifdef DISTRHO_UI_OPENGL

#include "DistrhoUI.h"

#if DISTRHO_OS_MAC
# include <OpenGL/glu.h>
#else
# include <GL/glu.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

START_NAMESPACE_DISTRHO

// -------------------------------------------------

enum Char {
CHAR_BACKSPACE = 0x08,
CHAR_ESCAPE = 0x1B,
CHAR_DELETE = 0x7F
};

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
};

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 */
};

// -------------------------------------------------

class OpenGLUI : public UI
{
public:
OpenGLUI();
virtual ~OpenGLUI();

// ---------------------------------------------

// Host UI State (OpenGL)
int d_uiGetModifiers();
void d_uiIgnoreKeyRepeat(bool ignore);
void d_uiRepaint();

// ---------------------------------------------

protected:
// Information
virtual unsigned int d_width() = 0;
virtual unsigned int d_height() = 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
virtual void d_uiIdle();
virtual void d_onInit() = 0;
virtual void d_onDisplay() = 0;
virtual void d_onKeyboard(bool press, uint32_t key) = 0;
virtual void d_onMotion(int x, int y) = 0;
virtual void d_onMouse(int button, bool press, int x, int y) = 0;
virtual void d_onReshape(int width, int height) = 0;
virtual void d_onScroll(float dx, float dy) = 0;
virtual void d_onSpecial(bool press, Key key) = 0;
virtual void d_onClose() = 0;

private:
friend class UIInternal;
};

// -------------------------------------------------

END_NAMESPACE_DISTRHO

#endif // DISTRHO_UI_OPENGL

#endif // __DISTRHO_UI_OPENGL_H__

+ 307
- 0
source/libs/distrho-plugin-toolkit/DistrhoUIOpenGLExt.h View File

@@ -0,0 +1,307 @@
/*
* DISTRHO Plugin Toolkit (DPT)
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#ifndef __DISTRHO_UI_OPENGL_EXT_H__
#define __DISTRHO_UI_OPENGL_EXT_H__

#include "src/DistrhoDefines.h"

#ifdef DISTRHO_UI_OPENGL

#include "DistrhoUIOpenGL.h"
#include <GL/gl.h>

START_NAMESPACE_DISTRHO

// -------------------------------------------------

class Point
{
public:
Point(int x, int y);
Point(const Point& pos);

int getX() const;
int getY() const;

void setX(int x);
void setY(int y);

Point& operator=(const Point& pos);
Point& operator+=(const Point& pos);
Point& operator-=(const Point& pos);
bool operator==(const Point& pos) const;
bool operator!=(const Point& pos) const;

private:
int _x, _y;
friend class Rectangle;
};

class Size
{
public:
Size(int width, int height);
Size(const Size& size);

int getWidth() const;
int getHeight() const;

void setWidth(int width);
void setHeight(int height);

Size& operator=(const Size& size);
Size& operator+=(const Size& size);
Size& operator-=(const Size& size);
Size& operator*=(int m);
Size& operator/=(int d);
Size& operator*=(float m);
Size& operator/=(float d);

private:
int _width, _height;
friend class Rectangle;
};

class Rectangle
{
public:
Rectangle(int x, int y, int width, int height);
Rectangle(int x, int y, const Size& size);
Rectangle(const Point& pos, int width, int height);
Rectangle(const Point& pos, const Size& size);
Rectangle(const Rectangle& rect);

int getX() const;
int getY() const;
int getWidth() const;
int getHeight() const;

const Point& getPos() const;
const Size& getSize() const;

bool contains(int x, int y) const;
bool contains(const Point& pos) const;
bool containsX(int x) const;
bool containsY(int y) const;

void setX(int x);
void setY(int y);
void setPos(int x, int y);
void setPos(const Point& pos);

void move(int x, int y);
void move(const Point& pos);

void setWidth(int width);
void setHeight(int height);
void setSize(int width, int height);
void setSize(const Size& size);

void grow(int m);
void grow(float m);
void grow(int width, int height);
void grow(const Size& size);

void shrink(int m);
void shrink(float m);
void shrink(int width, int height);
void shrink(const Size& size);

Rectangle& operator=(const Rectangle& rect);
Rectangle& operator+=(const Point& pos);
Rectangle& operator-=(const Point& pos);
Rectangle& operator+=(const Size& size);
Rectangle& operator-=(const Size& size);

private:
Point _pos;
Size _size;
};

// -------------------------------------------------

class Image
{
public:
Image(const char* data, int width, int height, GLenum format = GL_BGRA, GLenum type = GL_UNSIGNED_BYTE);
Image(const char* data, const Size& size, GLenum format = GL_BGRA, GLenum type = GL_UNSIGNED_BYTE);
Image(const Image& image);

bool isValid() const;

int getWidth() const;
int getHeight() const;
const Size& getSize() const;

const char* getData() const;
GLenum getFormat() const;
GLenum getType() const;

Image& operator=(const Image& image);

private:
const char* _data;
Size _size;
GLenum _format;
GLenum _type;
friend class OpenGLExtUI;
};

class ImageButton
{
public:
ImageButton(const Image& imageNormal, const Image& imageHover, const Image& imageDown, const Point& pos);
ImageButton(const ImageButton& imageButton);

int getWidth() const;
int getHeight() const;
const Size& getSize() const;

ImageButton& operator=(const ImageButton& imageButton);

private:
Image _imageNormal;
Image _imageHover;
Image _imageDown;
Image* _curImage;
Point _pos;
Rectangle _area;
friend class OpenGLExtUI;
};

class ImageKnob
{
public:
enum Orientation {
Horizontal,
Vertical
};

ImageKnob(const Image& image, const Point& pos, Orientation orientation = Vertical);
ImageKnob(const ImageKnob& imageKnob);

void setOrientation(Orientation orientation);
void setRange(float min, float max);
void setValue(float value);

ImageKnob& operator=(const ImageKnob& slider);

private:
Image _image;
Point _pos;
Orientation _orientation;
bool _isVertical;
int _layerSize;
int _layerCount;
Rectangle _area;
float _min, _max, _value;
friend class OpenGLExtUI;
};

class ImageSlider
{
public:
ImageSlider(const Image& image, const Point& startPos, const Point& endPos);
ImageSlider(const ImageSlider& imageSlider);

int getWidth() const;
int getHeight() const;

void setRange(float min, float max);
void setValue(float value);

ImageSlider& operator=(const ImageSlider& slider);

private:
Image _image;
Point _startPos;
Point _endPos;
Rectangle _area;
float _min, _max, _value;
friend class OpenGLExtUI;
};

// -------------------------------------------------

struct OpenGLExtUIPrivateData;

class OpenGLExtUI : public OpenGLUI
{
public:
OpenGLExtUI();
virtual ~OpenGLExtUI();

// ---------------------------------------------

protected:
// Information
virtual unsigned int d_width() = 0;
virtual unsigned int d_height() = 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
virtual void d_uiIdle();

// Extended Calls
void setBackgroundImage(const Image& image);

void addImageButton(ImageButton* button);
void addImageKnob(ImageKnob* knob);
void addImageSlider(ImageSlider* slider);

void showImageModalDialog(const Image& image, const char* title);

// Extended Callbacks
virtual void imageButtonClicked(ImageButton* button);
virtual void imageKnobDragStarted(ImageKnob* knob);
virtual void imageKnobDragFinished(ImageKnob* knob);
virtual void imageKnobValueChanged(ImageKnob* knob, float value);
virtual void imageSliderDragStarted(ImageSlider* slider);
virtual void imageSliderDragFinished(ImageSlider* slider);
virtual void imageSliderValueChanged(ImageSlider* slider, float value);

private:
OpenGLExtUIPrivateData* data;

// Implemented internally
void d_onInit();
void d_onDisplay();
void d_onKeyboard(bool press, uint32_t key);
void d_onMotion(int x, int y);
void d_onMouse(int button, bool press, int x, int y);
void d_onReshape(int width, int height);
void d_onScroll(float dx, float dy);
void d_onSpecial(bool press, Key key);
void d_onClose();
};

// -------------------------------------------------

END_NAMESPACE_DISTRHO

#endif // DISTRHO_UI_OPENGL

#endif // __DISTRHO_UI_OPENGL_EXT_H__

+ 74
- 0
source/libs/distrho-plugin-toolkit/DistrhoUIQt4.h View File

@@ -0,0 +1,74 @@
/*
* DISTRHO Plugin Toolkit (DPT)
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#ifndef __DISTRHO_UI_QT4_H__
#define __DISTRHO_UI_QT4_H__

#include "src/DistrhoDefines.h"

#ifdef DISTRHO_UI_QT4

#include "DistrhoUI.h"

#include <QtGui/QWidget>

START_NAMESPACE_DISTRHO

// -------------------------------------------------

class Qt4UI : public UI,
public QWidget
{
public:
Qt4UI();
virtual ~Qt4UI();

// ---------------------------------------------

protected:
// Information
virtual bool d_resizable() { return false; }
virtual int d_minimumWidth() { return 100; }
virtual int d_minimumHeight() { return 100; }

// 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
virtual void d_uiIdle();

// Implement resize internally
unsigned int d_width() { return width(); }
unsigned int d_height() { return height(); }

private:
friend class UIInternal;
};

// -------------------------------------------------

END_NAMESPACE_DISTRHO

#endif // DISTRHO_UI_QT4

#endif // __DISTRHO_UI_QT4_H__

+ 240
- 0
source/libs/distrho-plugin-toolkit/DistrhoUtils.h View File

@@ -0,0 +1,240 @@
/*
* DISTRHO Plugin Toolkit (DPT)
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#ifndef __DISTRHO_UTILS_H__
#define __DISTRHO_UTILS_H__

#include "src/DistrhoDefines.h"

#if DISTRHO_OS_WINDOWS
# include <windows.h>
#else
# include <unistd.h>
#endif

#include <cstdio>
#include <cstdint>
#include <cstdlib>
#include <cstring>

// -------------------------------------------------

inline
long d_cconst(int a, int b, int c, int d)
{
return (a << 24) | (b << 16) | (c << 8) | (d << 0);
}

inline
void d_sleep(unsigned int secs)
{
#if DISTRHO_OS_WINDOWS
Sleep(secs * 1000);
#else
sleep(secs);
#endif
}

inline
void d_msleep(unsigned int msecs)
{
#if DISTRHO_OS_WINDOWS
Sleep(msecs);
#else
usleep(msecs * 1000);
#endif
}

inline
void d_usleep(unsigned int usecs)
{
#if DISTRHO_OS_WINDOWS
Sleep(usecs / 1000);
#else
usleep(usecs);
#endif
}

inline
void d_setenv(const char* key, const char* value)
{
#if DISTRHO_OS_WINDOWS
SetEnvironmentVariableA(key, value);
#else
setenv(key, value, 1);
#endif
}

// -------------------------------------------------

// TODO - import new stuff from Carla, when ready

class d_string
{
public:
d_string()
{
buffer = strdup("");
}

d_string(const char* strBuf)
{
buffer = strdup(strBuf ? strBuf : "");
}

d_string(const d_string& str)
{
buffer = strdup(str.buffer);
}

d_string(int value)
{
size_t strBufSize = abs(value/10) + 3;
char strBuf[strBufSize];
snprintf(strBuf, strBufSize, "%d", value);

buffer = strdup(strBuf);
}

d_string(unsigned int value)
{
size_t strBufSize = value/10 + 2;
char strBuf[strBufSize];
snprintf(strBuf, strBufSize, "%u", value);

buffer = strdup(strBuf);
}

d_string(float value)
{
char strBuf[255];
snprintf(strBuf, 255, "%f", value);

buffer = strdup(strBuf);
}

~d_string()
{
free(buffer);
}

size_t length() const
{
return strlen(buffer);
}

bool isEmpty() const
{
return (*buffer == 0);
}

// ---------------------------------------------

operator const char*() const
{
return buffer;
}

bool operator==(const char* strBuf) const
{
return (strcmp(buffer, strBuf) == 0);
}

bool operator==(const d_string& str) const
{
return operator==(str.buffer);
}

bool operator!=(const char* strBuf) const
{
return !operator==(strBuf);
}

bool operator!=(const d_string& str) const
{
return !operator==(str.buffer);
}

d_string& operator=(const char* strBuf)
{
free(buffer);

buffer = strdup(strBuf);

return *this;
}

d_string& operator=(const d_string& str)
{
return operator=(str.buffer);
}

d_string& operator+=(const char* strBuf)
{
size_t newBufSize = strlen(buffer) + strlen(strBuf) + 1;
char newBuf[newBufSize];

strcpy(newBuf, buffer);
strcat(newBuf, strBuf);
free(buffer);

buffer = strdup(newBuf);

return *this;
}

d_string& operator+=(const d_string& str)
{
return operator+=(str.buffer);
}

d_string operator+(const char* strBuf)
{
size_t newBufSize = strlen(buffer) + strlen(strBuf) + 1;
char newBuf[newBufSize];

strcpy(newBuf, buffer);
strcat(newBuf, strBuf);

return d_string(newBuf);
}

d_string operator+(const d_string& str)
{
return operator+(str.buffer);
}

private:
char* buffer;
};

static inline
d_string operator+(const char* strBufBefore, const d_string& strAfter)
{
const char* strBufAfter = (const char*)strAfter;
size_t newBufSize = strlen(strBufBefore) + strlen(strBufAfter) + 1;
char newBuf[newBufSize];

strcpy(newBuf, strBufBefore);
strcat(newBuf, strBufAfter);

return d_string(newBuf);
}

// -------------------------------------------------

#endif // __DISTRHO_UTILS_H__

+ 10
- 0
source/libs/distrho-plugin-toolkit/Makefile View File

@@ -0,0 +1,10 @@
#!/usr/bin/make -f
# Makefile for distrho (docs) #
# ----------------------------------------- #
# Created by falkTX
#

all:

doxygen: distrho.doxygen
doxygen $<

+ 289
- 0
source/libs/distrho-plugin-toolkit/distrho.doxygen View File

@@ -0,0 +1,289 @@
# Doxyfile 1.7.6.1

#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "DISTRHO Plugin Toolkit"
PROJECT_NUMBER =
PROJECT_BRIEF =
PROJECT_LOGO =
OUTPUT_DIRECTORY = ../../doc/distrho
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF =
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES =
TCL_SUBST =
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
EXTENSION_MAPPING =
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
SYMBOL_CACHE_SIZE = 0
LOOKUP_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = YES
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = YES
EXTRACT_ANON_NSPACES = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
FORCE_LOCAL_INCLUDES = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = NO
SORT_BRIEF_DOCS = NO
SORT_MEMBERS_CTORS_1ST = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = NO
SHOW_FILES = YES
SHOW_NAMESPACES = YES
FILE_VERSION_FILTER =
LAYOUT_FILE =
CITE_BIB_FILES =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT =
INPUT_ENCODING = UTF-8
FILE_PATTERNS =
RECURSIVE = NO
EXCLUDE = DistrhoPluginMain.cpp DistrhoUIMain.cpp
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXCLUDE_SYMBOLS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS =
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
REFERENCES_LINK_SOURCE = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = .
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = YES
HTML_ALIGN_MEMBERS = YES
HTML_DYNAMIC_SECTIONS = NO
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_NAME = Publisher
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
CHM_INDEX_ENCODING =
BINARY_TOC = NO
TOC_EXPAND = NO
GENERATE_QHP = NO
QCH_FILE =
QHP_NAMESPACE = org.doxygen.Project
QHP_VIRTUAL_FOLDER = doc
QHP_CUST_FILTER_NAME =
QHP_CUST_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS =
QHG_LOCATION =
GENERATE_ECLIPSEHELP = NO
ECLIPSE_DOC_ID = org.doxygen.Project
DISABLE_INDEX = NO
GENERATE_TREEVIEW = NO
ENUM_VALUES_PER_LINE = 4
USE_INLINE_TREES = NO
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
USE_MATHJAX = NO
MATHJAX_RELPATH = http://www.mathjax.org/mathjax
MATHJAX_EXTENSIONS =
SEARCHENGINE = YES
SERVER_BASED_SEARCH = NO
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4
EXTRA_PACKAGES =
LATEX_HEADER =
LATEX_FOOTER =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED = DOXYGEN \
DISTRHO_PLUGIN_HAS_UI DISTRHO_PLUGIN_IS_SYNTH DISTRHO_PLUGIN_WANT_PROGRAMS DISTRHO_PLUGIN_WANT_STATE \
DISTRHO_UI_OPENGL DISTRHO_UI_QT4
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
MSCGEN_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
DOT_NUM_THREADS = 0
DOT_FONTNAME = Helvetica
DOT_FONTSIZE = 10
DOT_FONTPATH =
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
INTERACTIVE_SVG = NO
DOT_PATH =
DOTFILE_DIRS =
MSCFILE_DIRS =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = YES
GENERATE_LEGEND = YES
DOT_CLEANUP = YES

+ 96
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoDefines.h View File

@@ -0,0 +1,96 @@
/*
* DISTRHO Plugin Toolkit (DPT)
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#ifndef __DISTRHO_DEFINES_H__
#define __DISTRHO_DEFINES_H__

#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

#if defined(__WIN32__) || defined(__WIN64__)
# 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

#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

#ifndef DISTRHO_UI_QT4
# define DISTRHO_UI_OPENGL
#endif

#define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI"

#endif // __DISTRHO_DEFINES_H__

+ 107
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoPlugin.cpp View File

@@ -0,0 +1,107 @@
/*
* DISTRHO Plugin Toolkit (DPT)
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#include "DistrhoPluginInternal.h"

START_NAMESPACE_DISTRHO

// -------------------------------------------------
// Static data

uint32_t d_lastBufferSize = 0;
double d_lastSampleRate = 0.0;

// -------------------------------------------------
// Static, fallback data

const d_string PluginInternal::fallbackString;
const ParameterRanges PluginInternal::fallbackRanges;

// -------------------------------------------------
// Plugin

Plugin::Plugin(uint32_t parameterCount, uint32_t programCount, uint32_t stateCount)
{
data = new PluginPrivateData;

if (parameterCount > 0)
{
data->parameterCount = parameterCount;
data->parameters = new Parameter [parameterCount];
}

if (programCount > 0)
{
#if DISTRHO_PLUGIN_WANT_PROGRAMS
data->programCount = programCount;
data->programNames = new d_string [programCount];
#endif
}

if (stateCount > 0)
{
#if DISTRHO_PLUGIN_WANT_STATE
data->stateCount = stateCount;
data->stateKeys = new d_string [stateCount];
#endif
}
}

Plugin::~Plugin()
{
delete data;
}

// -------------------------------------------------
// Host state

uint32_t Plugin::d_bufferSize() const
{
return data->bufferSize;
}

double Plugin::d_sampleRate() const
{
return data->sampleRate;
}

const TimePos& Plugin::d_timePos() const
{
return data->timePos;
}

#if DISTRHO_PLUGIN_WANT_LATENCY
void Plugin::d_setLatency(uint32_t samples)
{
data->latency = samples;
}
#endif

// -------------------------------------------------
// Callbacks

void Plugin::d_bufferSizeChanged(uint32_t)
{
}

void Plugin::d_sampleRateChanged(double)
{
}

// -------------------------------------------------

END_NAMESPACE_DISTRHO

+ 360
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoPluginInternal.h View File

@@ -0,0 +1,360 @@
/*
* DISTRHO Plugin Toolkit (DPT)
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#ifndef __DISTRHO_PLUGIN_INTERNAL_H__
#define __DISTRHO_PLUGIN_INTERNAL_H__

#include "DistrhoPlugin.h"

#include <cassert>

START_NAMESPACE_DISTRHO

// -------------------------------------------------

#define MAX_MIDI_EVENTS 512

extern uint32_t d_lastBufferSize;
extern double d_lastSampleRate;

struct PluginPrivateData {
uint32_t bufferSize;
double sampleRate;

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
TimePos timePos;

PluginPrivateData()
: bufferSize(d_lastBufferSize),
sampleRate(d_lastSampleRate),
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
timePos()
{
assert(d_lastBufferSize != 0);
assert(d_lastSampleRate != 0.0);
}

~PluginPrivateData()
{
if (parameterCount > 0 && parameters)
delete[] parameters;

#if DISTRHO_PLUGIN_WANT_PROGRAMS
if (programCount > 0 && programNames)
delete[] programNames;
#endif

#if DISTRHO_PLUGIN_WANT_STATE
if (stateCount > 0 && stateKeys)
delete[] stateKeys;
#endif
}
};

// -------------------------------------------------

class PluginInternal
{
public:
PluginInternal()
: plugin(createPlugin()),
data(plugin ? plugin->data : nullptr)
{
assert(plugin);

if (! plugin)
return;

for (uint32_t i=0, count=data->parameterCount; i < count; i++)
plugin->d_initParameter(i, data->parameters[i]);

#if DISTRHO_PLUGIN_WANT_PROGRAMS
for (uint32_t i=0, count=data->programCount; i < count; i++)
plugin->d_initProgramName(i, data->programNames[i]);
#endif

#if DISTRHO_PLUGIN_WANT_STATE
for (uint32_t i=0, count=data->stateCount; i < count; i++)
plugin->d_initStateKey(i, data->stateKeys[i]);
#endif
}

~PluginInternal()
{
if (plugin)
delete plugin;
}

// ---------------------------------------------

const char* name() const
{
assert(plugin);
return plugin ? plugin->d_name() : "";
}

const char* label() const
{
assert(plugin);
return plugin ? plugin->d_label() : "";
}

const char* maker() const
{
assert(plugin);
return plugin ? plugin->d_maker() : "";
}

const char* license() const
{
assert(plugin);
return plugin ? plugin->d_license() : "";
}

uint32_t version() const
{
assert(plugin);
return plugin ? plugin->d_version() : 1000;
}

long uniqueId() const
{
assert(plugin);
return plugin ? plugin->d_uniqueId() : 0;
}

// ---------------------------------------------

#if DISTRHO_PLUGIN_WANT_LATENCY
uint32_t latency() const
{
assert(data);
return data ? data->latency : 0;
}
#endif

uint32_t parameterCount() const
{
assert(data);
return data ? data->parameterCount : 0;
}

uint32_t parameterHints(uint32_t index) const
{
assert(data && index < data->parameterCount);
return (data && index < data->parameterCount) ? data->parameters[index].hints : 0x0;
}

bool parameterIsOutput(uint32_t index) const
{
uint32_t hints = parameterHints(index);
return (hints & PARAMETER_IS_OUTPUT);
}

const d_string& parameterName(uint32_t index) const
{
assert(data && index < data->parameterCount);
return (data && index < data->parameterCount) ? data->parameters[index].name : fallbackString;
}

const d_string& parameterSymbol(uint32_t index) const
{
assert(data && index < data->parameterCount);
return (data && index < data->parameterCount) ? data->parameters[index].symbol : fallbackString;
}

const d_string& parameterUnit(uint32_t index) const
{
assert(data && index < data->parameterCount);
return (data && index < data->parameterCount) ? data->parameters[index].unit : fallbackString;
}

const ParameterRanges& parameterRanges(uint32_t index) const
{
assert(data && index < data->parameterCount);
return (data && index < data->parameterCount) ? &data->parameters[index].ranges : fallbackRanges;
}

float parameterValue(uint32_t index)
{
assert(plugin && index < data->parameterCount);
return (plugin && index < data->parameterCount) ? plugin->d_parameterValue(index) : 0.0f;
}

void setParameterValue(uint32_t index, float value)
{
assert(plugin && index < data->parameterCount);

if (plugin && index < data->parameterCount)
plugin->d_setParameterValue(index, value);
}

#if DISTRHO_PLUGIN_WANT_PROGRAMS
uint32_t programCount() const
{
assert(data);
return data ? data->programCount : 0;
}

const d_string& programName(uint32_t index) const
{
assert(data && index < data->programCount);
return (data && index < data->programCount) ? data->programNames[index] : fallbackString;
}

void setProgram(uint32_t index)
{
assert(plugin && index < data->programCount);

if (plugin && index < data->programCount)
plugin->d_setProgram(index);
}
#endif

#if DISTRHO_PLUGIN_WANT_STATE
uint32_t stateCount() const
{
assert(data);
return data ? data->stateCount : 0;
}

const d_string& stateKey(uint32_t index) const
{
assert(data && index < data->stateCount);
return (data && index < data->stateCount) ? data->stateKeys[index] : fallbackString;
}

void setState(const char* key, const char* value)
{
assert(plugin && key && value);

if (plugin && key && value)
plugin->d_setState(key, value);
}
#endif

// ---------------------------------------------

void activate()
{
assert(plugin);

if (plugin)
plugin->d_activate();
}

void deactivate()
{
assert(plugin);

if (plugin)
plugin->d_deactivate();
}

void run(float** inputs, float** outputs, uint32_t frames, uint32_t midiEventCount, const MidiEvent* midiEvents)
{
assert(plugin);

if (plugin)
plugin->d_run(inputs, outputs, frames, midiEventCount, midiEvents);
}

// ---------------------------------------------

void setBufferSize(uint32_t bufferSize, bool callback = false)
{
assert(data && plugin && bufferSize >= 2);

if (data)
{
data->bufferSize = bufferSize;

if (callback && data->bufferSize == bufferSize)
callback = false;
}

if (plugin && callback)
{
plugin->d_deactivate();
plugin->d_bufferSizeChanged(bufferSize);
plugin->d_activate();
}
}

void setSampleRate(double sampleRate, bool callback = false)
{
assert(data && plugin && sampleRate > 0.0);

if (data)
{
data->sampleRate = sampleRate;

if (callback && data->sampleRate == sampleRate)
callback = false;
}

if (plugin && callback)
{
plugin->d_deactivate();
plugin->d_sampleRateChanged(sampleRate);
plugin->d_activate();
}
}

// ---------------------------------------------

protected:
Plugin* const plugin;
PluginPrivateData* const data;

private:
static const d_string fallbackString;
static const ParameterRanges fallbackRanges;
};

// -------------------------------------------------

END_NAMESPACE_DISTRHO

#endif // __DISTRHO_PLUGIN_INTERNAL_H__

+ 366
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoPluginJACK.cpp View File

@@ -0,0 +1,366 @@
/*
* DISTHRO Plugin Toolkit (DPT)
* Copyright (C) 2012 Filipe Coelho <falktx@gmail.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#ifdef DISTRHO_PLUGIN_TARGET_JACK

#include "DistrhoDefines.h"

#if ! DISTRHO_PLUGIN_HAS_UI
# error Standalone JACK mode requires UI
#endif

#include "DistrhoPluginInternal.h"
#include "DistrhoUIInternal.h"

#include <jack/jack.h>
#include <jack/midiport.h>
#include <jack/transport.h>

#include <QtCore/QSettings>
#include <QtGui/QApplication>
#include <QtGui/QMainWindow>
#include <QtGui/QMessageBox>

// -------------------------------------------------

START_NAMESPACE_DISTRHO

class PluginJack : public QMainWindow
{
public:
PluginJack(jack_client_t* client_)
: QMainWindow(nullptr),
widget(this),
settings("DISTRHO", DISTRHO_PLUGIN_NAME),
ui(this, widget.winId(), setParameterCallback, setStateCallback, nullptr, uiNoteCallback, uiResizeCallback),
client(client_)
{
setCentralWidget(&widget);
setFixedSize(ui.getWidth(), ui.getHeight());
setWindowTitle(DISTRHO_PLUGIN_NAME);

if (DISTRHO_PLUGIN_NUM_INPUTS > 0)
{
portsIn = new jack_port_t* [DISTRHO_PLUGIN_NUM_INPUTS];

for (int i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; i++)
portsIn[i] = jack_port_register(client, d_string("Audio Input ") + d_string(i+1), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
}
else
portsIn = nullptr;

if (DISTRHO_PLUGIN_NUM_OUTPUTS > 0)
{
portsOut = new jack_port_t* [DISTRHO_PLUGIN_NUM_OUTPUTS];

for (int i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; i++)
portsOut[i] = jack_port_register(client, d_string("Audio Output ") + d_string(i+1), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
}
else
portsOut = nullptr;

#if DISTRHO_PLUGIN_IS_SYNTH
portMidi = jack_port_register(client, "Midi Input", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
#endif

jack_set_process_callback(client, jackProcessCallback, this);

uiTimer = startTimer(30);

// load settings
restoreGeometry(settings.value("Global/Geometry", QByteArray()).toByteArray());

for (uint32_t i=0; i < plugin.parameterCount(); i++)
{
bool ok;
float value = settings.value(QString("Parameters/%1").arg(i)).toFloat(&ok);

if (ok)
{
plugin.setParameterValue(i, value);
ui.parameterChanged(i, value);
}
}

#if DISTRHO_PLUGIN_WANT_STATE
for (uint32_t i=0; i < plugin.stateCount(); i++)
{
const char* key = plugin.stateKey(i);
QString stringValue(settings.value(key).toString());

if (! stringValue.isEmpty())
ui.stateChanged(key, stringValue.toUtf8().constData());
}
#endif
}

~PluginJack()
{
// save settings
settings.setValue("Global/Geometry", saveGeometry());

if (uiTimer)
killTimer(uiTimer);

if (portsIn)
delete[] portsIn;

if (portsOut)
delete[] portsOut;
}

// ---------------------------------------------

protected:
void setParameterValue(uint32_t index, float value)
{
plugin.setParameterValue(index, value);
settings.setValue(QString("Parameters/%1").arg(index), value);
}

#if DISTRHO_PLUGIN_WANT_STATE
void setState(const char* key, const char* value)
{
plugin.setState(key, value);
settings.setValue(key, value);
}
#endif

#if DISTRHO_PLUGIN_IS_SYNTH
void uiNote(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity)
{
// TODO
}
#endif

void uiResize(unsigned int width, unsigned int height)
{
widget.setFixedSize(width, height);
setFixedSize(width, height);
}

int jackProcess(jack_nframes_t nframes)
{
if (nframes <= 1)
return 1;

// Check for updated bufferSize
if (nframes != d_lastBufferSize)
{
d_lastBufferSize = nframes;
plugin.setBufferSize(nframes, true);
}

const float* ins[DISTRHO_PLUGIN_NUM_INPUTS];
float* outs[DISTRHO_PLUGIN_NUM_OUTPUTS];

for (int i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; i++)
ins[i] = (float*)jack_port_get_buffer(portsIn[i], nframes);

for (int i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; i++)
outs[i] = (float*)jack_port_get_buffer(portsOut[i], nframes);

#if DISTRHO_PLUGIN_IS_SYNTH
uint32_t midiEventCount = 0;

void* mIn = jack_port_get_buffer(portMidi, nframes);
// TODO

plugin.run(ins, outs, nframes, midiEventCount, midiEvents);
#else
plugin.run(ins, outs, nframes, 0, nullptr);
#endif

return 0;
}

// ---------------------------------------------

void closeEvent(QCloseEvent* event)
{
QMainWindow::closeEvent(event);

qApp->quit();
}

void timerEvent(QTimerEvent* event)
{
if (event->timerId() == uiTimer)
ui.idle();

QMainWindow::timerEvent(event);
}

// ---------------------------------------------

private:
// Qt4 stuff
int uiTimer;
QWidget widget;
QSettings settings;

PluginInternal plugin;
UIInternal ui;

jack_client_t* const client;
jack_port_t** portsIn;
jack_port_t** portsOut;

#if DISTRHO_PLUGIN_IS_SYNTH
jack_port_t* portMidi;
MidiEvent midiEvents[MAX_MIDI_EVENTS];
#endif

// ---------------------------------------------
// Callbacks

static void setParameterCallback(void* ptr, uint32_t index, float value)
{
PluginJack* _this_ = (PluginJack*)ptr;
assert(_this_);

_this_->setParameterValue(index, value);
}

static void setStateCallback(void* ptr, const char* key, const char* value)
{
#if DISTRHO_PLUGIN_WANT_STATE
PluginJack* _this_ = (PluginJack*)ptr;
assert(_this_);

_this_->setState(key, value);
#else
Q_UNUSED(ptr);
Q_UNUSED(key);
Q_UNUSED(value);
#endif
}

static void uiNoteCallback(void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velocity)
{
#if DISTRHO_PLUGIN_IS_SYNTH
PluginJack* _this_ = (PluginJack*)ptr;
assert(_this_);

_this_->uiNote(onOff, channel, note, velocity);
#else
Q_UNUSED(ptr);
Q_UNUSED(onOff);
Q_UNUSED(channel);
Q_UNUSED(note);
Q_UNUSED(velocity);
#endif
}

static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height)
{
PluginJack* _this_ = (PluginJack*)ptr;
assert(_this_);

_this_->uiResize(width, height);
}

static int jackProcessCallback(jack_nframes_t nframes, void* arg)
{
PluginJack* _this_ = (PluginJack*)arg;
assert(_this_);

return _this_->jackProcess(nframes);
}
};

// -------------------------------------------------

END_NAMESPACE_DISTRHO

// -------------------------------------------------

std::string jack_status_get_error_string(const jack_status_t& status)
{
std::string errorString;

if (status & JackFailure)
errorString += "Overall operation failed;\n";
if (status & JackInvalidOption)
errorString += "The operation contained an invalid or unsupported option;\n";
if (status & JackNameNotUnique)
errorString += "The desired client name was not unique;\n";
if (status & JackServerStarted)
errorString += "The JACK server was started as a result of this operation;\n";
if (status & JackServerFailed)
errorString += "Unable to connect to the JACK server;\n";
if (status & JackServerError)
errorString += "Communication error with the JACK server;\n";
if (status & JackNoSuchClient)
errorString += "Requested client does not exist;\n";
if (status & JackLoadFailure)
errorString += "Unable to load internal client;\n";
if (status & JackInitFailure)
errorString += "Unable to initialize client;\n";
if (status & JackShmFailure)
errorString += "Unable to access shared memory;\n";
if (status & JackVersionError)
errorString += "Client's protocol version does not match;\n";
if (status & JackBackendError)
errorString += "Backend Error;\n";
if (status & JackClientZombie)
errorString += "Client is being shutdown against its will;\n";

if (errorString.size() > 0)
errorString.replace(errorString.size()-2, 2, ".");

return errorString;
}

int main(int argc, char* argv[])
{
USE_NAMESPACE_DISTRHO
QApplication app(argc, argv, true);

jack_status_t status;
jack_client_t* client = jack_client_open(DISTRHO_PLUGIN_NAME, JackNullOption, &status);

if (! client)
{
std::string errorString(jack_status_get_error_string(status));
QMessageBox::critical(nullptr, app.translate(DISTRHO_PLUGIN_NAME, "Error"),
app.translate(DISTRHO_PLUGIN_NAME,
"Could not connect to JACK, possible reasons:\n"
"%1").arg(QString::fromStdString(errorString)));
return 1;
}

d_lastBufferSize = jack_get_buffer_size(client);
d_lastSampleRate = jack_get_sample_rate(client);
setLastUiSampleRate(d_lastSampleRate);

PluginJack plugin(client);
plugin.show();

jack_activate(client);

int ret = app.exec();

jack_deactivate(client);
jack_client_close(client);

return ret;
}

// -------------------------------------------------

#endif // DISTRHO_PLUGIN_TARGET_JACK

+ 685
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoPluginLADSPA+DSSI.cpp View File

@@ -0,0 +1,685 @@
/*
* DISTRHO Plugin Toolkit (DPT)
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#if defined(DISTRHO_PLUGIN_TARGET_LADSPA) || defined(DISTRHO_PLUGIN_TARGET_DSSI)

#include "DistrhoPluginInternal.h"

#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

#include <vector>

typedef LADSPA_Data* LADSPA_DataPtr;
typedef std::vector<LADSPA_Data> LADSPA_DataVector;
typedef std::vector<LADSPA_DataPtr> LADSPA_DataPtrVector;

// -------------------------------------------------

START_NAMESPACE_DISTRHO

class PluginLadspaDssi
{
public:
PluginLadspaDssi()
: lastBufferSize(d_lastBufferSize),
lastSampleRate(d_lastSampleRate),
portAudioIns{nullptr},
portAudioOuts{nullptr}
{
for (uint32_t i=0, count=plugin.parameterCount(); i < count; i++)
{
lastControlValues.push_back(plugin.parameterValue(i));
portControls.push_back(nullptr);
}

#if DISTRHO_PLUGIN_WANT_LATENCY
portLatency = nullptr;
#endif
#if defined(DISTRHO_PLUGIN_TARGET_DSSI) && DISTRHO_PLUGIN_HAS_UI
portSampleRate = nullptr;
#endif
}

~PluginLadspaDssi()
{
lastControlValues.clear();
portControls.clear();
}

// ---------------------------------------------

void ladspa_connect_port(unsigned long port, LADSPA_DataPtr dataLocation)
{
unsigned long i, index = 0;

for (i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; i++)
{
if (port == index++)
{
portAudioIns[i] = dataLocation;
return;
}
}

for (i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; i++)
{
if (port == index++)
{
portAudioOuts[i] = dataLocation;
return;
}
}

#if DISTRHO_PLUGIN_WANT_LATENCY
if (port == index++)
{
portLatency = dataLocation;
return;
}
#endif

#if defined(DISTRHO_PLUGIN_TARGET_DSSI) && DISTRHO_PLUGIN_HAS_UI
if (port == index++)
{
portSampleRate = dataLocation;
return;
}
#endif

for (i=0, count=plugin.parameterCount(); i < count; i++)
{
if (port == index++)
{
portControls[i] = dataLocation;
return;
}
}
}

// ---------------------------------------------

#ifdef DISTRHO_PLUGIN_TARGET_DSSI
# if DISTRHO_PLUGIN_WANT_STATE
char* dssi_configure(const char* key, const char* value)
{
if (strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX, strlen(DSSI_RESERVED_CONFIGURE_PREFIX) == 0))
return nullptr;
if (strncmp(key, DSSI_GLOBAL_CONFIGURE_PREFIX, strlen(DSSI_GLOBAL_CONFIGURE_PREFIX) == 0))
return nullptr;

plugin.setState(key, value);
return nullptr;
}
# endif

# if DISTRHO_PLUGIN_WANT_PROGRAMS
const DSSI_Program_Descriptor* dssi_get_program(unsigned long index)
{
if (index >= plugin.programCount())
return nullptr;

static DSSI_Program_Descriptor desc;
desc.Bank = index / 128;
desc.Program = index % 128;
desc.Name = plugin.programName(index);
return &desc;
}

void dssi_select_program(unsigned long bank, unsigned long program)
{
const unsigned long realProgram = bank * 128 + program;

if (realProgram >= plugin.programCount())
return;

plugin.setProgram(realProgram);

// Update parameters
for (uint32_t i=0, count=plugin.parameterCount(); i < count; i++)
{
if (! plugin.parameterIsOutput(i))
{
lastControlValues[i] = plugin.parameterValue(i);

if (portControls[i])
*portControls[i] = lastControlValues[i];
}
}
}
# endif
#endif

// ---------------------------------------------

void ladspa_activate()
{
plugin.activate();
}

void ladspa_deactivate()
{
plugin.deactivate();
}

#ifdef DISTRHO_PLUGIN_TARGET_DSSI
void ladspa_run(unsigned long bufferSize)
{
dssi_run_synth(bufferSize, nullptr, 0);
}

void dssi_run_synth(unsigned long bufferSize, snd_seq_event_t* events, unsigned long eventCount)
#else
void ladspa_run(unsigned long bufferSize)
#endif
{
// Check for updated parameters
float curValue;

for (uint32_t i=0, count=plugin.parameterCount(); i < count; i++)
{
curValue = *portControls[i];

if (lastControlValues[i] != curValue && ! plugin.parameterIsOutput(i))
{
lastControlValues[i] = curValue;
plugin.setParameterValue(i, curValue);
}
}

#ifdef DISTRHO_PLUGIN_TARGET_DSSI
# if DISTRHO_PLUGIN_IS_SYNTH
// Get MIDI Events
uint32_t midiEventCount = 0;

for (uint32_t i=0, j; i < eventCount && midiEventCount < MAX_MIDI_EVENTS; i++)
{
snd_seq_event_t* event = &events[i];

if (event->type == SND_SEQ_EVENT_NOTEON)
{
j = midiEventCount++;
midiEvents[j].frame = event->time.tick;
midiEvents[j].buffer[0] = 0x90 + event->data.note.channel;
midiEvents[j].buffer[1] = event->data.note.note;
midiEvents[j].buffer[2] = event->data.note.velocity;
}
else if (event->type == SND_SEQ_EVENT_NOTEOFF)
{
j = midiEventCount++;
midiEvents[j].frame = event->time.tick;
midiEvents[j].buffer[0] = 0x80 + event->data.note.channel;
midiEvents[j].buffer[1] = event->data.note.note;
midiEvents[j].buffer[2] = 0;
}
else if (event->type == SND_SEQ_EVENT_KEYPRESS)
{
j = midiEventCount++;
midiEvents[j].frame = event->time.tick;
midiEvents[j].buffer[0] = 0xA0 + event->data.note.channel;
midiEvents[j].buffer[1] = event->data.note.note;
midiEvents[j].buffer[2] = event->data.note.velocity;
}
else if (event->type == SND_SEQ_EVENT_CONTROLLER)
{
j = midiEventCount++;
midiEvents[j].frame = event->time.tick;
midiEvents[j].buffer[0] = 0xB0 + event->data.control.channel;
midiEvents[j].buffer[1] = event->data.control.param;
midiEvents[j].buffer[2] = event->data.control.value;
}
else if (event->type == SND_SEQ_EVENT_CHANPRESS)
{
j = midiEventCount++;
midiEvents[j].frame = event->time.tick;
midiEvents[j].buffer[0] = 0xD0 + event->data.control.channel;
midiEvents[j].buffer[1] = event->data.control.value;
midiEvents[j].buffer[2] = 0;
}
else if (event->type == SND_SEQ_EVENT_PITCHBEND)
{
// TODO
//j = midiEventCount++;
//midiEvents[j].frame = event->time.tick;
//midiEvents[j].buffer[0] = 0xE0 + event->data.control.channel;
//midiEvents[j].buffer[1] = 0;
//midiEvents[j].buffer[2] = 0;
}
}
# else
// unused
(void)events;
(void)eventCount;
# endif
#endif

// Run plugin for this cycle
#if DISTRHO_PLUGIN_IS_SYNTH
plugin.run(portAudioIns, portAudioOuts, bufferSize, midiEventCount, midiEvents);
#else
plugin.run(portAudioIns, portAudioOuts, bufferSize, 0, nullptr);
#endif

updateParameterOutputs();
}

// ---------------------------------------------

private:
PluginInternal plugin;

// Temporary data
const unsigned long lastBufferSize;
const double lastSampleRate;
LADSPA_DataVector lastControlValues;

#if DISTRHO_PLUGIN_IS_SYNTH
MidiEvent midiEvents[MAX_MIDI_EVENTS];
#endif

// LADSPA ports
LADSPA_DataPtr portAudioIns[DISTRHO_PLUGIN_NUM_INPUTS];
LADSPA_DataPtr portAudioOuts[DISTRHO_PLUGIN_NUM_INPUTS];
LADSPA_DataPtrVector portControls;
#if DISTRHO_PLUGIN_WANT_LATENCY
LADSPA_DataPtr portLatency;
#endif
#if defined(DISTRHO_PLUGIN_TARGET_DSSI) && DISTRHO_PLUGIN_HAS_UI
LADSPA_DataPtr portSampleRate;
#endif

// ---------------------------------------------

void updateParameterOutputs()
{
for (uint32_t i=0, count=plugin.parameterCount(); i < count; i++)
{
if (plugin.parameterIsOutput(i))
{
lastControlValues[i] = plugin.parameterValue(i);

if (portControls[i])
*portControls[i] = lastControlValues[i];
}
}

#if DISTRHO_PLUGIN_WANT_LATENCY
if (portLatency)
*portLatency = plugin.latency();
#endif

#if defined(DISTRHO_PLUGIN_TARGET_DSSI) && DISTRHO_PLUGIN_HAS_UI
if (portSampleRate)
*portSampleRate = lastSampleRate;
#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();
}

static void ladspa_connect_port(LADSPA_Handle instance, unsigned long port, LADSPA_Data* dataLocation)
{
PluginLadspaDssi* plugin = (PluginLadspaDssi*)instance;
assert(plugin);

plugin->ladspa_connect_port(port, dataLocation);
}

static void ladspa_activate(LADSPA_Handle instance)
{
PluginLadspaDssi* plugin = (PluginLadspaDssi*)instance;
assert(plugin);

plugin->ladspa_activate();
}

static void ladspa_run(LADSPA_Handle instance, unsigned long sampleCount)
{
PluginLadspaDssi* plugin = (PluginLadspaDssi*)instance;
assert(plugin);

plugin->ladspa_run(sampleCount);
}

static void ladspa_deactivate(LADSPA_Handle instance)
{
PluginLadspaDssi* plugin = (PluginLadspaDssi*)instance;
assert(plugin);

plugin->ladspa_deactivate();
}

static void ladspa_cleanup(LADSPA_Handle instance)
{
PluginLadspaDssi* plugin = (PluginLadspaDssi*)instance;
assert(plugin);

delete plugin;
}

#ifdef DISTRHO_PLUGIN_TARGET_DSSI
# if DISTRHO_PLUGIN_WANT_STATE
static char* dssi_configure(LADSPA_Handle instance, const char* key, const char* value)
{
PluginLadspaDssi* plugin = (PluginLadspaDssi*)instance;
assert(plugin);

return plugin->dssi_configure(key, value);
}
# endif

# if DISTRHO_PLUGIN_WANT_PROGRAMS
static const DSSI_Program_Descriptor* dssi_get_program(LADSPA_Handle instance, unsigned long index)
{
PluginLadspaDssi* plugin = (PluginLadspaDssi*)instance;
assert(plugin);

return plugin->dssi_get_program(index);
}

static void dssi_select_program(LADSPA_Handle instance, unsigned long bank, unsigned long program)
{
PluginLadspaDssi* plugin = (PluginLadspaDssi*)instance;
assert(plugin);

plugin->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)
{
PluginLadspaDssi* plugin = (PluginLadspaDssi*)instance;
assert(plugin);

plugin->dssi_run_synth(sampleCount, events, eventCount);
}
# endif
#endif

// -------------------------------------------------

static LADSPA_Descriptor ldescriptor = {
/* 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 descriptor = {
1,
&ldescriptor,
# 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;
PluginInternal plugin;
d_lastBufferSize = 0;
d_lastSampleRate = 0.0;

// Get port count, init
unsigned long i, port = 0;
const unsigned long portCount = DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS + plugin.parameterCount();
#if DISTRHO_PLUGIN_WANT_LATENCY
portCount += 1;
#endif
#if defined(DISTRHO_PLUGIN_TARGET_DSSI) && DISTRHO_PLUGIN_HAS_UI
portCount += 1; // sample-rate
#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
for (i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; i++, port++)
{
char const portName[24] = { 0 };
sprintf(portName, "Audio Input %lu", i+1);

portNames[port] = strdup(portName);
portDescriptors[port] = LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT;

portRangeHints[port].HintDescriptor = 0;
portRangeHints[port].LowerBound = 0.0f;
portRangeHints[port].UpperBound = 1.0f;
}

for (i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; i++, port++)
{
char const portName[24] = { 0 };
sprintf(portName, "Audio Output %lu", i+1);

portNames[port] = strdup(portName);
portDescriptors[port] = LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT;

portRangeHints[port].HintDescriptor = 0;
portRangeHints[port].LowerBound = 0.0f;
portRangeHints[port].UpperBound = 1.0f;
}

#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

#if defined(DISTRHO_PLUGIN_TARGET_DSSI) && DISTRHO_PLUGIN_HAS_UI
// Set sample-rate port
portNames[port] = strdup("_sample-rate");
portDescriptors[port] = LADSPA_PORT_CONTROL | LADSPA_PORT_OUTPUT;
portRangeHints[port].HintDescriptor = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
portRangeHints[port].LowerBound = 0.0f;
portRangeHints[port].UpperBound = 512000.0f;
port++;
#endif

for (i=0; i < plugin.parameterCount(); i++, port++)
{
portNames[port] = strdup((const char*)plugin.parameterName(i));
portDescriptors[port] = LADSPA_PORT_CONTROL;

if (plugin.parameterIsOutput(i))
portDescriptors[port] |= LADSPA_PORT_OUTPUT;
else
portDescriptors[port] |= LADSPA_PORT_INPUT;

{
const ParameterRanges& ranges = plugin.parameterRanges(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 + ranges.max/2;
const float middleLow = (ranges.min/2 + middleValue/2)/2 + middleValue/2;
const float middleHigh = (ranges.max/2 + middleValue/2)/2 + middleValue/2;

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.parameterHints(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
ldescriptor.UniqueID = plugin.uniqueId();
ldescriptor.Label = strdup(plugin.label());
ldescriptor.Name = strdup(plugin.name());
ldescriptor.Maker = strdup(plugin.maker());
ldescriptor.Copyright = strdup(plugin.license());
ldescriptor.PortCount = portCount;
ldescriptor.PortNames = portNames;
ldescriptor.PortDescriptors = portDescriptors;
ldescriptor.PortRangeHints = portRangeHints;
}

~DescriptorInitializer()
{
if (ldescriptor.Label)
free((void*)ldescriptor.Label);

if (ldescriptor.Name)
free((void*)ldescriptor.Name);

if (ldescriptor.Maker)
free((void*)ldescriptor.Maker);

if (ldescriptor.Copyright)
free((void*)ldescriptor.Copyright);

if (ldescriptor.PortDescriptors)
delete[] ldescriptor.PortDescriptors;

if (ldescriptor.PortRangeHints)
delete[] ldescriptor.PortRangeHints;

if (ldescriptor.PortNames)
{
for (unsigned long i=0; i < ldescriptor.PortCount; i++)
{
if (ldescriptor.PortNames[i])
free((void*)ldescriptor.PortNames[i]);
}

delete[] ldescriptor.PortNames;
}
}
};

static DescriptorInitializer init;

END_NAMESPACE_DISTRHO

// -------------------------------------------------

DISTRHO_PLUGIN_EXPORT
const LADSPA_Descriptor* ladspa_descriptor(unsigned long index)
{
USE_NAMESPACE_DISTRHO
return (index == 0) ? &ldescriptor : nullptr;
}

#ifdef DISTRHO_PLUGIN_TARGET_DSSI
DISTRHO_PLUGIN_EXPORT
const DSSI_Descriptor* dssi_descriptor(unsigned long index)
{
USE_NAMESPACE_DISTRHO
return (index == 0) ? &descriptor : nullptr;
}
#endif

// -------------------------------------------------

#endif // DISTRHO_PLUGIN_TARGET_LADSPA || DISTRHO_PLUGIN_TARGET_DSSI

+ 597
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoPluginLV2.cpp View File

@@ -0,0 +1,597 @@
/*
* DISTHRO Plugin Toolkit (DPT)
* Copyright (C) 2012 Filipe Coelho <falktx@gmail.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#ifdef DISTRHO_PLUGIN_TARGET_LV2

#include "DistrhoPluginInternal.h"

#include "lv2-sdk/lv2.h"
#include "lv2-sdk/atom.h"
#include "lv2-sdk/atom-util.h"
#include "lv2-sdk/midi.h"
#include "lv2-sdk/patch.h"
#include "lv2-sdk/programs.h"
#include "lv2-sdk/state.h"
#include "lv2-sdk/urid.h"
#include "lv2-sdk/worker.h"

#include <map>
#include <vector>

#ifndef DISTRHO_PLUGIN_URI
# error DISTRHO_PLUGIN_URI undefined!
#endif

#define DISTRHO_LV2_USE_EVENTS (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_STATE)
#define DISTRHO_LV2_USE_EXTENSION_DATA (DISTRHO_PLUGIN_WANT_PROGRAMS || DISTRHO_PLUGIN_WANT_STATE)

typedef float* floatptr;
typedef std::vector<float> floatVector;
typedef std::vector<floatptr> floatptrVector;

typedef std::map<d_string,d_string> stringMap;

// -------------------------------------------------

START_NAMESPACE_DISTRHO

class PluginLv2
{
public:
PluginLv2(const LV2_Feature* const* features)
: lastBufferSize(d_lastBufferSize),
lastSampleRate(d_lastSampleRate)
{
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; i++)
portAudioIns.push_back(nullptr);

for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; i++)
portAudioOuts.push_back(nullptr);

for (uint32_t i=0; i < plugin.parameterCount(); i++)
{
portControls.push_back(nullptr);
lastControlValues.push_back(plugin.parameterValue(i));
}

portLatency = nullptr;
#if DISTRHO_PLUGIN_HAS_UI
portSampleRate = nullptr;
#endif

#if DISTRHO_LV2_USE_EVENTS
portEventsIn = nullptr;

// URIDs
uridMap = nullptr;

uridIdAtomString = 0;
# if DISTRHO_PLUGIN_IS_SYNTH
uridIdMidiEvent = 0;
# endif
# if DISTRHO_PLUGIN_WANT_STATE
uridIdPatchMessage = 0;
workerSchedule = nullptr;
# endif

for (uint32_t i=0; features[i]; i++)
{
if (strcmp(features[i]->URI, LV2_URID__map) == 0)
{
uridMap = (LV2_URID_Map*)features[i]->data;

uridIdAtomString = uridMap->map(uridMap->handle, LV2_ATOM__String);
# if DISTRHO_PLUGIN_IS_SYNTH
uridIdMidiEvent = uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent);
# endif
# if DISTRHO_PLUGIN_WANT_STATE
uridIdPatchMessage = uridMap->map(uridMap->handle, LV2_PATCH__Message);
# endif
}
else if (strcmp(features[i]->URI, LV2_WORKER__schedule) == 0)
{
workerSchedule = (LV2_Worker_Schedule*)features[i]->data;
}
}
#else
// unused
(void)features;
#endif
}

~PluginLv2()
{
portAudioIns.clear();
portAudioOuts.clear();
portControls.clear();
lastControlValues.clear();

#if DISTRHO_PLUGIN_WANT_STATE
stateMap.clear();
#endif
}

void lv2_activate()
{
plugin.activate();
updateParameterOutputs();
}

void lv2_deactivate()
{
plugin.deactivate();
}

void lv2_connect_port(uint32_t port, void* dataLocation)
{
uint32_t i, index = 0;

for (i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; i++)
{
if (port == index++)
{
portAudioIns[i] = (floatptr)dataLocation;
return;
}
}

for (i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; i++)
{
if (port == index++)
{
portAudioOuts[i] = (floatptr)dataLocation;
return;
}
}

for (i=0; i < plugin.parameterCount(); i++)
{
if (port == index++)
{
portControls[i] = (floatptr)dataLocation;
return;
}
}

#if DISTRHO_LV2_USE_EVENTS
if (port == index++)
{
portEventsIn = (LV2_Atom_Sequence*)dataLocation;
return;
}
#endif

if (port == index++)
{
portLatency = (floatptr)dataLocation;
return;
}

#if DISTRHO_PLUGIN_HAS_UI
if (port == index++)
{
portSampleRate = (floatptr)dataLocation;
return;
}
#endif
}

void lv2_run(uint32_t bufferSize)
{
if (bufferSize <= 1)
return;

// Check for updated bufferSize
if (bufferSize != lastBufferSize)
{
lastBufferSize = bufferSize;
d_lastBufferSize = bufferSize;
plugin.setBufferSize(bufferSize, true);
}

// Check for updated parameters
float curValue;

for (uint32_t i=0; i < plugin.parameterCount(); i++)
{
curValue = *portControls[i];

if (lastControlValues[i] != curValue && ! plugin.parameterIsOutput(i))
{
lastControlValues[i] = curValue;
plugin.setParameterValue(i, curValue);
}
}

// Get Events, xxx
uint32_t midiEventCount = 0;

#if DISTRHO_LV2_USE_EVENTS
LV2_ATOM_SEQUENCE_FOREACH(portEventsIn, iter)
{
const LV2_Atom_Event* event = /*(const LV2_Atom_Event*)*/iter;

if (! event)
continue;

# if DISTRHO_PLUGIN_IS_SYNTH
if (event->body.type == uridIdMidiEvent)
{
if (event->time.frames >= bufferSize || midiEventCount >= MAX_MIDI_EVENTS)
break;

if (event->body.size > 3)
continue;

const uint8_t* data = (const uint8_t*)(event + 1);

midiEvents[midiEventCount].frame = event->time.frames;
memcpy(midiEvents[midiEventCount].buffer, data, event->body.size);

midiEventCount += 1;
continue;
}
# endif
# if DISTRHO_PLUGIN_WANT_STATE
if (event->body.type == uridIdPatchMessage)
{
// TODO
//if (workerSchedule)
// workerSchedule->schedule_work(workerSchedule->handle, event->body.size, )
}
# endif
}
#endif

// Run plugin for this cycle
const float* inputs[DISTRHO_PLUGIN_NUM_INPUTS];
float* outputs[DISTRHO_PLUGIN_NUM_OUTPUTS];

for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; i++)
inputs[i] = portAudioIns[i];

for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; i++)
outputs[i] = portAudioOuts[i];

plugin.run(inputs, outputs, bufferSize, midiEventCount, midiEvents);

updateParameterOutputs();
}

#if DISTRHO_PLUGIN_WANT_PROGRAMS
const LV2_Program_Descriptor* lv2_get_program(uint32_t index)
{
if (index >= plugin.programCount())
return nullptr;

static LV2_Program_Descriptor desc;
desc.bank = index / 128;
desc.program = index % 128;
desc.name = plugin.programName(index);
return &desc;
}

void lv2_select_program(uint32_t bank, uint32_t program)
{
const uint32_t realProgram = bank * 128 + program;

if (realProgram >= plugin.programCount())
return;

plugin.setProgram(realProgram);

// Update parameters
for (uint32_t i=0; i < plugin.parameterCount(); i++)
{
if (! plugin.parameterIsOutput(i))
lastControlValues[i] = *portControls[i] = plugin.parameterValue(i);
}
}
#endif

#if DISTRHO_PLUGIN_WANT_STATE
LV2_State_Status lv2_save(LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const* /*features*/)
{
flags = LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE;

for (auto i = stateMap.begin(); i != stateMap.end(); i++)
{
const d_string& key = i->first;
const d_string& value = i->second;

store(handle, uridMap->map(uridMap->handle, (const char*)key), (const char*)value, value.length(), uridIdAtomString, flags);
}

return LV2_STATE_SUCCESS;
}

LV2_State_Status lv2_restore(LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const* /*features*/)
{
size_t size;
uint32_t type;

for (uint32_t i=0; i < plugin.stateCount(); i++)
{
const d_string& key = plugin.stateKey(i);

const void* data = retrieve(handle, uridMap->map(uridMap->handle, (const char*)key), &size, &type, &flags);

if (size == 0 || ! data)
continue;
if (type != uridIdAtomString)
continue;

const char* value = (const char*)data;
setState(key, value);
}

return LV2_STATE_SUCCESS;
}

LV2_Worker_Status lv2_work(LV2_Worker_Respond_Function /*respond*/, LV2_Worker_Respond_Handle /*handle*/, uint32_t /*size*/, const void* /*data*/)
{
// TODO
return LV2_WORKER_SUCCESS;
}

LV2_Worker_Status lv2_work_response(uint32_t /*size*/, const void* /*body*/)
{
// TODO
return LV2_WORKER_SUCCESS;
}
#endif

private:
PluginInternal plugin;

// LV2 ports
floatptrVector portAudioIns;
floatptrVector portAudioOuts;
floatptrVector portControls;
floatptr portLatency;
#if DISTRHO_PLUGIN_HAS_UI
floatptr portSampleRate;
#endif

// xxx
#if DISTRHO_LV2_USE_EVENTS
LV2_Atom_Sequence* portEventsIn;

// URIDs
LV2_URID_Map* uridMap;
LV2_URID uridIdAtomString;
# if DISTRHO_PLUGIN_IS_SYNTH
LV2_URID uridIdMidiEvent;
# endif
# if DISTRHO_PLUGIN_WANT_STATE
LV2_URID uridIdPatchMessage;
LV2_Worker_Schedule* workerSchedule;
# endif
#endif

// Temporary data
uint32_t lastBufferSize;
const double lastSampleRate;
floatVector lastControlValues;

#if DISTRHO_PLUGIN_IS_SYNTH
MidiEvent midiEvents[MAX_MIDI_EVENTS];
#else
MidiEvent midiEvents[0];
#endif

#if DISTRHO_PLUGIN_WANT_STATE
stringMap stateMap;

void setState(const char* newKey, const char* newValue)
{
plugin.setState(newKey, newValue);

// check if key already exists
for (auto i = stateMap.begin(); i != stateMap.end(); i++)
{
const d_string& key = i->first;

if (key == newKey)
{
i->second = newValue;
return;
}
}

// add a new one then
stateMap[newKey] = newValue;
}
#endif

void updateParameterOutputs()
{
for (uint32_t i=0; i < plugin.parameterCount(); i++)
{
if (plugin.parameterIsOutput(i))
lastControlValues[i] = *portControls[i] = plugin.parameterValue(i);
}

if (portLatency)
*portLatency = plugin.latency();

#if DISTRHO_PLUGIN_HAS_UI
if (portSampleRate)
*portSampleRate = lastSampleRate;
#endif
}
};

// -------------------------------------------------

static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, const char*, const LV2_Feature* const* features)
{
// TODO - search features for initial bufferSize

if (d_lastBufferSize == 0)
d_lastBufferSize = 512;
d_lastSampleRate = sampleRate;

return new PluginLv2(features);
}

static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation)
{
PluginLv2* plugin = (PluginLv2*)instance;
assert(plugin);

plugin->lv2_connect_port(port, dataLocation);
}

static void lv2_activate(LV2_Handle instance)
{
PluginLv2* plugin = (PluginLv2*)instance;
assert(plugin);

plugin->lv2_activate();
}

static void lv2_run(LV2_Handle instance, uint32_t sampleCount)
{
PluginLv2* plugin = (PluginLv2*)instance;
assert(plugin);

plugin->lv2_run(sampleCount);
}

static void lv2_deactivate(LV2_Handle instance)
{
PluginLv2* plugin = (PluginLv2*)instance;
assert(plugin);

plugin->lv2_deactivate();
}

static void lv2_cleanup(LV2_Handle instance)
{
PluginLv2* plugin = (PluginLv2*)instance;
assert(plugin);

delete plugin;
}

#if DISTRHO_LV2_USE_EXTENSION_DATA
# if DISTRHO_PLUGIN_WANT_PROGRAMS
static const LV2_Program_Descriptor* lv2_get_program(LV2_Handle instance, uint32_t index)
{
PluginLv2* plugin = (PluginLv2*)instance;
assert(plugin);

return plugin->lv2_get_program(index);
}

static void lv2_select_program(LV2_Handle instance, uint32_t bank, uint32_t program)
{
PluginLv2* plugin = (PluginLv2*)instance;
assert(plugin);

plugin->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* features)
{
PluginLv2* plugin = (PluginLv2*)instance;
assert(plugin);

return plugin->lv2_save(store, handle, flags, features);
}

static LV2_State_Status lv2_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const* features)
{
PluginLv2* plugin = (PluginLv2*)instance;
assert(plugin);

return plugin->lv2_restore(retrieve, handle, flags, features);
}

LV2_Worker_Status lv2_work(LV2_Handle instance, LV2_Worker_Respond_Function respond, LV2_Worker_Respond_Handle handle, uint32_t size, const void* data)
{
PluginLv2* plugin = (PluginLv2*)instance;
assert(plugin);

return plugin->lv2_work(respond, handle, size, data);
}

LV2_Worker_Status lv2_work_response(LV2_Handle instance, uint32_t size, const void* body)
{
PluginLv2* plugin = (PluginLv2*)instance;
assert(plugin);

return plugin->lv2_work_response(size, body);
}
# endif

static const void* lv2_extension_data(const char* uri)
{
# if DISTRHO_PLUGIN_WANT_PROGRAMS
static const LV2_Programs_Interface programs = { lv2_get_program, lv2_select_program };
if (strcmp(uri, LV2_PROGRAMS__Interface) == 0)
return &programs;
# endif

# if DISTRHO_PLUGIN_WANT_STATE
static const LV2_State_Interface state = { lv2_save, lv2_restore };
if (strcmp(uri, LV2_STATE__interface) == 0)
return &state;

static const LV2_Worker_Interface worker = { lv2_work, lv2_work_response, nullptr };
if (strcmp(uri, LV2_WORKER__interface) == 0)
return &worker;
# endif

return nullptr;
}
#endif

// -------------------------------------------------

static LV2_Descriptor descriptor = {
DISTRHO_PLUGIN_URI,
lv2_instantiate,
lv2_connect_port,
lv2_activate,
lv2_run,
lv2_deactivate,
lv2_cleanup,
#if DISTRHO_LV2_USE_EXTENSION_DATA
lv2_extension_data
#else
/* extension_data */ nullptr
#endif
};

END_NAMESPACE_DISTRHO

// -------------------------------------------------

DISTRHO_PLUGIN_EXPORT
const LV2_Descriptor* lv2_descriptor(uint32_t index)
{
USE_NAMESPACE_DISTRHO
return (index == 0) ? &descriptor : nullptr;
}

// -------------------------------------------------

#endif // DISTRHO_PLUGIN_TARGET_LV2

+ 347
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoPluginLV2export.cpp View File

@@ -0,0 +1,347 @@
/*
* DISTHRO Plugin Toolkit (DPT)
* Copyright (C) 2012 Filipe Coelho <falktx@gmail.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#ifdef DISTRHO_PLUGIN_TARGET_LV2

#include "DistrhoPluginInternal.h"

#include "lv2-sdk/lv2.h"
#include "lv2-sdk/atom.h"
#include "lv2-sdk/midi.h"
#include "lv2-sdk/patch.h"
#include "lv2-sdk/programs.h"
#include "lv2-sdk/state.h"
#include "lv2-sdk/urid.h"
#include "lv2-sdk/ui.h"
#include "lv2-sdk/units.h"
#include "lv2-sdk/worker.h"

#include <fstream>
#include <iostream>

#ifndef DISTRHO_PLUGIN_URI
# error DISTRHO_PLUGIN_URI undefined!
#endif

#define DISTRHO_LV2_USE_EVENTS (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_STATE)

// -------------------------------------------------

START_NAMESPACE_DISTRHO

void lv2_generate_ttl_func()
{
PluginInternal plugin;

d_string pluginLabel = plugin.label();
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_EXT "> ;\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_EXT "> ;\n";
# if DISTRHO_LV2_USE_EVENTS
manifestString += " lv2:optionalFeature <" LV2_URID__map "> ,\n";
manifestString += " ui:noUserResize .\n";
# else
manifestString += " lv2:optionalFeature ui:noUserResize .\n";
# endif
manifestString += "\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;
#if DISTRHO_LV2_USE_EVENTS
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";

pluginString += "<" DISTRHO_PLUGIN_URI ">\n";
#if DISTRHO_PLUGIN_IS_SYNTH
pluginString += " a lv2:InstrumentPlugin, lv2:Plugin ;\n";
#else
pluginString += " a lv2:Plugin ;\n";
#endif

#if (DISTRHO_PLUGIN_IS_SYNTH && DISTRHO_PLUGIN_WANT_STATE)
pluginString += " lv2:optionalFeature <" LV2_CORE__hardRTCapable "> ,\n";
pluginString += " <" LV2_WORKER__schedule "> ;\n";
pluginString += " lv2:requiredFeature <" LV2_URID__map "> ;\n";
#elif DISTRHO_PLUGIN_IS_SYNTH
pluginString += " lv2:optionalFeature <" LV2_CORE__hardRTCapable "> ;\n";
pluginString += " lv2:requiredFeature <" LV2_URID__map "> ;\n";
#elif DISTRHO_PLUGIN_WANT_STATE
pluginString += " lv2:optionalFeature <" LV2_CORE__hardRTCapable "> ,\n";
pluginString += " <" LV2_URID__map "> ,\n";
pluginString += " <" LV2_WORKER__schedule "> ;\n";
#endif

#if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_WANT_PROGRAMS)
pluginString += " lv2:extensionData <" LV2_STATE__interface "> ,\n";
pluginString += " <" LV2_WORKER__interface "> ,\n";
pluginString += " <" LV2_PROGRAMS__Interface "> ;\n";
#elif DISTRHO_PLUGIN_WANT_STATE
pluginString += " lv2:extensionData <" LV2_STATE__interface "> ,\n";
pluginString += " <" LV2_WORKER__interface "> ;\n";
#elif DISTRHO_PLUGIN_WANT_PROGRAMS
pluginString += " lv2:extensionData <" LV2_PROGRAMS__Interface "> ;\n";
#endif
pluginString += "\n";

#if DISTRHO_PLUGIN_HAS_UI
pluginString += " ui:ui <" DISTRHO_UI_URI "> ;\n";
pluginString += "\n";
#endif

{
uint32_t i, portIndex = 0;

for (i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; i++)
{
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";
}

for (i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; i++)
{
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";
}

for (i=0; i < plugin.parameterCount(); i++)
{
if (i == 0)
pluginString += " lv2:port [\n";
else
pluginString += " [\n";

if (plugin.parameterIsOutput(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.parameterName(i) + "\" ;\n";

// symbol
{
d_string symbol(plugin.parameterSymbol(i));

if (symbol.isEmpty())
symbol = "lv2_port_" + d_string(portIndex-1);

pluginString += " lv2:symbol \"" + symbol + "\" ;\n";
}

// ranges
{
const ParameterRanges* ranges = plugin.parameterRanges(i);

if (plugin.parameterHints(i) & PARAMETER_IS_INTEGER)
{
pluginString += " lv2:default " + d_string(int(plugin.parameterValue(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.parameterValue(i)) + " ;\n";
pluginString += " lv2:minimum " + d_string(ranges->min) + " ;\n";
pluginString += " lv2:maximum " + d_string(ranges->max) + " ;\n";
}
}

// unit
{
const d_string& unit = plugin.parameterUnit(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
{
pluginString += " unit:unit [\n";
pluginString += " a unit:Unit ;\n";
pluginString += " unit:name \"" + unit + "\" ;\n";
pluginString += " unit:symbol \"" + unit + "\" ;\n";
pluginString += " unit:render \"%f f\" ;\n";
pluginString += " ] ;\n";
}
}
}

// hints
{
uint32_t hints = plugin.parameterHints(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 (i+1 == plugin.parameterCount())
pluginString += " ] ;\n\n";
else
pluginString += " ] ,\n";
}

pluginString += " lv2:port [\n";

#if DISTRHO_LV2_USE_EVENTS
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_IS_SYNTH && DISTRHO_PLUGIN_WANT_STATE)
pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ,\n";
pluginString += " <" LV2_PATCH__Message "> ;\n";
# elif DISTRHO_PLUGIN_IS_SYNTH
pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n";
# else
pluginString += " atom:supports <" LV2_PATCH__Message "> ;\n";
# endif
pluginString += " ] ,\n";
pluginString += " [\n";
#endif
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";
#if ! DISTRHO_PLUGIN_HAS_UI
pluginString += " ] ;\n\n";
#else
pluginString += " ] ,\n";
pluginString += " [\n";
pluginString += " a lv2:OutputPort, lv2:ControlPort ;\n";
pluginString += " lv2:index " + d_string(portIndex++) + " ;\n";
pluginString += " lv2:name \"Sample Rate\" ;\n";
pluginString += " lv2:symbol \"lv2_sample_rate\" ;\n";
pluginString += " lv2:designation <http://lv2plug.in/ns/ext/parameters#sampleRate> ;\n";
pluginString += " ] ;\n\n";
#endif
}

pluginString += " doap:name \"" + d_string(plugin.name()) + "\" ;\n";
pluginString += " doap:maintainer [ foaf:name \"" + d_string(plugin.maker()) + "\" ] .\n";

pluginFile << pluginString << std::endl;
pluginFile.close();
std::cout << " done!" << std::endl;
}
}

// unused stuff
void d_unusedStuff()
{
(void)d_lastBufferSize;
(void)d_lastSampleRate;
}

END_NAMESPACE_DISTRHO

// -------------------------------------------------

int main()
{
USE_NAMESPACE_DISTRHO
lv2_generate_ttl_func();
}

// -------------------------------------------------

#endif // DISTRHO_PLUGIN_TARGET_LV2

+ 726
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoPluginVST.cpp View File

@@ -0,0 +1,726 @@
/*
* DISTHRO Plugin Toolkit (DPT)
* Copyright (C) 2012 Filipe Coelho <falktx@gmail.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#ifdef DISTRHO_PLUGIN_TARGET_VST

#include "DistrhoPluginInternal.h"

#if DISTRHO_PLUGIN_HAS_UI
# include "DistrhoUIInternal.h"
#endif

#define VST_FORCE_DEPRECATED 0
#include <pluginterfaces/vst2.x/aeffectx.h>

// -------------------------------------------------

START_NAMESPACE_DISTRHO

#if DISTRHO_PLUGIN_HAS_UI
class UIVst
{
public:
UIVst(audioMasterCallback audioMaster, AEffect* effect, PluginInternal* plugin, intptr_t winId)
: m_audioMaster(audioMaster),
m_effect(effect),
m_plugin(plugin),
ui(this, winId, setParameterCallback, setStateCallback, uiEditParameterCallback, uiSendNoteCallback, uiResizeCallback)
{
uint32_t paramCount = plugin->parameterCount();

if (paramCount > 0)
{
parameterChecks = new bool [paramCount];
parameterValues = new float [paramCount];

for (uint32_t i=0; i < paramCount; i++)
{
parameterChecks[i] = false;
parameterValues[i] = 0.0f;
}
}
else
{
parameterChecks = nullptr;
parameterValues = nullptr;
}

#if DISTRHO_PLUGIN_WANT_PROGRAMS
nextProgram = -1;
#endif

#if DISTRHO_PLUGIN_IS_SYNTH
midiEventCount = 0;
#endif
}

~UIVst()
{
if (parameterChecks)
delete[] parameterChecks;

if (parameterValues)
delete[] parameterValues;
}

// ---------------------------------------------

void idle()
{
#if DISTRHO_PLUGIN_WANT_PROGRAMS
if (nextProgram != -1)
{
ui.programChanged(nextProgram);
nextProgram = -1;
}
#endif

for (uint32_t i=0, count = m_plugin->parameterCount(); i < count; i++)
{
if (parameterChecks[i])
{
parameterChecks[i] = false;

ui.parameterChanged(i, parameterValues[i]);
}
}

#if DISTRHO_PLUGIN_IS_SYNTH
// TODO - notes
#endif

ui.idle();
}

int16_t getWidth()
{
return ui.getWidth();
}

int16_t getHeight()
{
return ui.getHeight();
}

void setParameterValueFromPlugin(uint32_t index, float perValue)
{
parameterChecks[index] = true;
parameterValues[index] = perValue;
}

#if DISTRHO_PLUGIN_WANT_PROGRAMS
void setProgramFromPlugin(uint32_t index)
{
nextProgram = index;

// set previous parameters invalid
for (uint32_t i=0, count = m_plugin->parameterCount(); i < count; i++)
parameterChecks[i] = false;
}
#endif

// ---------------------------------------------

protected:
intptr_t hostCallback(int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt)
{
return m_audioMaster(m_effect, opcode, index, value, ptr, opt);
}

void setParameterValue(uint32_t index, float realValue)
{
const ParameterRanges* ranges = m_plugin->parameterRanges(index);
float perValue = (realValue - ranges->min) / (ranges->max - ranges->min);

m_plugin->setParameterValue(index, realValue);

hostCallback(audioMasterAutomate, index, 0, nullptr, perValue);
}

#if DISTRHO_PLUGIN_WANT_STATE
void setState(const char* key, const char* value)
{
m_plugin->setState(key, value);
}
#endif

void uiEditParameter(uint32_t index, bool started)
{
if (started)
hostCallback(audioMasterBeginEdit, index, 0, nullptr, 0.0f);
else
hostCallback(audioMasterEndEdit, index, 0, nullptr, 0.0f);
}

#if DISTRHO_PLUGIN_IS_SYNTH
void uiSendNote(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity)
{
// TODO
}
#endif

void uiResize(unsigned int width, unsigned int height)
{
hostCallback(audioMasterSizeWindow, width, height, nullptr, 0.0f);
}

private:
// Vst stuff
audioMasterCallback const m_audioMaster;
AEffect* const m_effect;
PluginInternal* const m_plugin;

// Plugin UI
UIInternal ui;

// Temporary data
bool* parameterChecks;
float* parameterValues;

#if DISTRHO_PLUGIN_WANT_PROGRAMS
int32_t nextProgram;
#endif
#if DISTRHO_PLUGIN_IS_SYNTH
uint32_t midiEventCount;
MidiEvent midiEvents[MAX_MIDI_EVENTS];
#endif

// ---------------------------------------------
// Callbacks

static void setParameterCallback(void* ptr, uint32_t rindex, float value)
{
UIVst* _this_ = (UIVst*)ptr;
assert(_this_);

_this_->setParameterValue(rindex, value);
}

static void setStateCallback(void* ptr, const char* key, const char* value)
{
#if DISTRHO_PLUGIN_WANT_STATE
UIVst* _this_ = (UIVst*)ptr;
assert(_this_);

_this_->setState(key, value);
#else
// unused
(void)ptr;
(void)key;
(void)value;
#endif
}

static void uiEditParameterCallback(void* ptr, uint32_t index, bool started)
{
UIVst* _this_ = (UIVst*)ptr;
assert(_this_);

_this_->uiEditParameter(index, started);
}

static void uiSendNoteCallback(void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velocity)
{
#if DISTRHO_PLUGIN_IS_SYNTH
UIVst* _this_ = (UIVst*)ptr;
assert(_this_);

_this_->uiSendNote(onOff, channel, note, velocity);
#else
// unused
(void)ptr;
(void)onOff;
(void)channel;
(void)note;
(void)velocity;
#endif
}

static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height)
{
UIVst* _this_ = (UIVst*)ptr;
assert(_this_);

_this_->uiResize(width, height);
}
};
#endif

class PluginVst
{
public:
PluginVst(audioMasterCallback audioMaster, AEffect* effect)
: m_audioMaster(audioMaster),
m_effect(effect)
{
#if DISTRHO_PLUGIN_HAS_UI
vstui = nullptr;
rect.top = 0;
rect.left = 0;
rect.bottom = 0;
rect.right = 0;
#endif

#if DISTRHO_PLUGIN_WANT_PROGRAMS
curProgram = -1;
#endif
#if DISTRHO_PLUGIN_IS_SYNTH
midiEventCount = 0;
#endif
}

~PluginVst()
{
}

intptr_t vst_dispatcher(int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt)
{
int32_t ret = 0;

switch (opcode)
{
#if DISTRHO_PLUGIN_WANT_PROGRAMS
case effSetProgram:
if (value >= 0 && value < plugin.programCount())
{
curProgram = value;
plugin.setProgram(curProgram);

if (vstui)
vstui->setProgramFromPlugin(curProgram);

ret = 1;
}
break;

case effGetProgram:
ret = curProgram;
break;

case effSetProgramName:
break;

case effGetProgramName:
if (ptr && curProgram >= 0 && curProgram < (int32_t)plugin.programCount())
{
strncpy((char*)ptr, plugin.programName(curProgram), kVstMaxProgNameLen);
ret = 1;
}
break;
#endif

case effGetParamDisplay:
if (ptr && index < (int32_t)plugin.parameterCount())
{
snprintf((char*)ptr, kVstMaxParamStrLen, "%f", plugin.parameterValue(index));
ret = 1;
}
break;

case effSetSampleRate:
// should not happen
break;

case effSetBlockSize:
plugin.setBufferSize(value, true);
break;

case effMainsChanged:
if (value)
plugin.activate();
else
plugin.deactivate();
break;

#if DISTRHO_PLUGIN_HAS_UI
case effEditGetRect:
if (rect.bottom == 0 && ! vstui)
{
// This is stupid, but some hosts want to know the UI size before creating it,
// so we have to create a temporary UI here
setLastUiSampleRate(d_lastSampleRate);

UIInternal tempUI(nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr);
rect.bottom = tempUI.getHeight();
rect.right = tempUI.getWidth();
}
else
{
rect.bottom = vstui->getHeight();
rect.right = vstui->getWidth();
}

*(ERect**)ptr = &rect;
ret = 1;

break;

case effEditOpen:
if (! vstui)
{
setLastUiSampleRate(d_lastSampleRate);
vstui = new UIVst(m_audioMaster, m_effect, &plugin, (intptr_t)ptr);
}

#if DISTRHO_PLUGIN_WANT_PROGRAMS
if (curProgram >= 0)
vstui->setProgramFromPlugin(curProgram);
#endif

for (uint32_t i=0, count = plugin.parameterCount(); i < count; i++)
vstui->setParameterValueFromPlugin(i, plugin.parameterValue(i));

ret = 1;
break;

case effEditClose:
if (vstui)
{
delete vstui;
vstui = nullptr;
ret = 1;
}
break;

case effEditIdle:
if (vstui)
vstui->idle();
break;
#endif

case effGetChunk:
case effSetChunk:
// TODO
break;

#if DISTRHO_PLUGIN_IS_SYNTH
case effProcessEvents:
if (ptr)
{
//VstEvents* events = (VstEvents*)ptr;
// TODO
}
break;
#endif

case effCanBeAutomated:
if (index < (int32_t)plugin.parameterCount())
{
uint32_t hints = plugin.parameterHints(index);

// must be automable, and not output
if ((hints & PARAMETER_IS_AUTOMABLE) > 0 && (hints & PARAMETER_IS_OUTPUT) == 0)
ret = 1;
}
break;

case effCanDo:
// TODO
break;

case effStartProcess:
case effStopProcess:
break;
}

return ret;

// unused
(void)opt;
}

float vst_getParameter(int32_t index)
{
const ParameterRanges* ranges = plugin.parameterRanges(index);
float realValue = plugin.parameterValue(index);
float perValue = (realValue - ranges->min) / (ranges->max - ranges->min);
return perValue;
}

void vst_setParameter(int32_t index, float value)
{
const ParameterRanges* ranges = plugin.parameterRanges(index);
float realValue = ranges->min + (ranges->max - ranges->min) * value;
plugin.setParameterValue(index, realValue);

if (vstui)
vstui->setParameterValueFromPlugin(index, realValue);
}

void vst_processReplacing(float** inputs, float** outputs, int32_t sampleFrames)
{
#if DISTRHO_PLUGIN_IS_SYNTH
plugin.run((const float**)inputs, outputs, sampleFrames, midiEventCount, midiEvents);

// TODO - send notes to UI

#else
plugin.run((const float**)inputs, outputs, sampleFrames, 0, nullptr);
#endif
}

// ---------------------------------------------

private:
// VST stuff
audioMasterCallback const m_audioMaster;
AEffect* const m_effect;

// Plugin
PluginInternal plugin;

#if DISTRHO_PLUGIN_HAS_UI
// UI
UIVst* vstui;
ERect rect;
#endif

#if DISTRHO_PLUGIN_WANT_PROGRAMS
int32_t curProgram;
#endif
#if DISTRHO_PLUGIN_IS_SYNTH
uint32_t midiEventCount;
MidiEvent midiEvents[MAX_MIDI_EVENTS];
#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 == -1 && 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 PluginInternal plugin;

if (doInternalInit)
{
// unset
d_lastBufferSize = 0;
d_lastSampleRate = 0.0;

*(PluginInternal**)ptr = &plugin;
return 0;
}

// handle opcodes
switch (opcode)
{
case effOpen:
if (! effect->object)
{
audioMasterCallback audioMaster = (audioMasterCallback)effect->user;
d_lastBufferSize = audioMaster(effect, audioMasterGetBlockSize, 0, 0, nullptr, 0.0f);
d_lastSampleRate = audioMaster(effect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f);
effect->object = new PluginVst(audioMaster, effect);
return 1;
}
return 0;

case effClose:
if (effect->object)
{
delete (PluginVst*)effect->object;
effect->object = nullptr;
delete effect;
return 1;
}
return 0;

case effGetParamLabel:
if (ptr && index < (int32_t)plugin.parameterCount())
{
strncpy((char*)ptr, plugin.parameterUnit(index), kVstMaxParamStrLen);
return 1;
}
return 0;

case effGetParamName:
if (ptr && index < (int32_t)plugin.parameterCount())
{
strncpy((char*)ptr, plugin.parameterName(index), kVstMaxParamStrLen);
return 1;
}
return 0;

#if DISTRHO_PLUGIN_WANT_PROGRAMS
case effGetProgramNameIndexed:
if (ptr && index < (int32_t)plugin.programCount())
{
strncpy((char*)ptr, plugin.programName(index), kVstMaxProgNameLen);
return 1;
}
return 0;
#endif

case effGetPlugCategory:
#if DISTRHO_PLUGIN_IS_SYNTH
return kPlugCategSynth;
#else
return kPlugCategUnknown;
#endif

case effGetEffectName:
if (ptr)
{
strncpy((char*)ptr, plugin.name(), kVstMaxProductStrLen);
return 1;
}
return 0;

case effGetVendorString:
if (ptr)
{
strncpy((char*)ptr, plugin.maker(), kVstMaxVendorStrLen);
return 1;
}
return 0;

case effGetProductString:
if (ptr)
{
strncpy((char*)ptr, plugin.label(), kVstMaxEffectNameLen);
return 1;
}
return 0;

case effGetVendorVersion:
return plugin.version();

case effGetVstVersion:
return kVstVersion;
};

if (effect->object)
{
PluginVst* _this_ = (PluginVst*)effect->object;
return _this_->vst_dispatcher(opcode, index, value, ptr, opt);
}

return 0;
}

static float vst_getParameterCallback(AEffect* effect, int32_t index)
{
PluginVst* _this_ = (PluginVst*)effect->object;
assert(_this_);

if (_this_)
return _this_->vst_getParameter(index);

return 0.0f;
}

static void vst_setParameterCallback(AEffect* effect, int32_t index, float value)
{
PluginVst* _this_ = (PluginVst*)effect->object;
assert(_this_);

if (_this_)
_this_->vst_setParameter(index, value);
}

static void vst_processCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
{
PluginVst* _this_ = (PluginVst*)effect->object;
assert(_this_);

if (_this_)
_this_->vst_processReplacing(inputs, outputs, sampleFrames);
}

static void vst_processReplacingCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
{
PluginVst* _this_ = (PluginVst*)effect->object;
assert(_this_);

if (_this_)
_this_->vst_processReplacing(inputs, outputs, sampleFrames);
}

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))
return nullptr;

PluginInternal* plugin = nullptr;
vst_dispatcherCallback(nullptr, -1, 0xdead, 0xf00d, &plugin, 0.0f);

AEffect* effect = new AEffect;
memset(effect, 0, sizeof(AEffect));

// vst fields
effect->magic = kEffectMagic;
effect->uniqueID = plugin->uniqueId();
effect->version = plugin->version();

// plugin fields
effect->numParams = plugin->parameterCount();
#if DISTRHO_PLUGIN_WANT_PROGRAMS
effect->numPrograms = plugin->programCount();
#endif
effect->numInputs = DISTRHO_PLUGIN_NUM_INPUTS;
effect->numOutputs = DISTRHO_PLUGIN_NUM_OUTPUTS;

// static calls
effect->dispatcher = vst_dispatcherCallback;
effect->process = vst_processCallback;
effect->getParameter = vst_getParameterCallback;
effect->setParameter = vst_setParameterCallback;
effect->processReplacing = vst_processReplacingCallback;
effect->processDoubleReplacing = nullptr;

// plugin flags
effect->flags |= effFlagsCanReplacing;

#if DISTRHO_PLUGIN_HAS_UI
# ifdef DISTRHO_UI_QT4
if (QApplication::instance())
# endif
effect->flags |= effFlagsHasEditor;
#endif

#if DISTRHO_PLUGIN_WANT_STATE
effect->flags |= effFlagsProgramChunks;
#endif

// pointers
effect->object = nullptr;
effect->user = (void*)audioMaster;

return effect;
}

// -------------------------------------------------

#endif // DISTRHO_PLUGIN_TARGET_VST

+ 101
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoUI.cpp View File

@@ -0,0 +1,101 @@
/*
* DISTHRO Plugin Toolkit (DPT)
* Copyright (C) 2012 Filipe Coelho <falktx@gmail.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#include "DistrhoUIInternal.h"

START_NAMESPACE_DISTRHO

// -------------------------------------------------

double d_lastUiSampleRate = 0.0;

// -------------------------------------------------

UI::UI()
{
data = new UIPrivateData;

#if (defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2))
data->parameterOffset = DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
# if DISTRHO_PLUGIN_WANT_LATENCY
data->parameterOffset += 1;
# endif
data->parameterOffset += 1; // sample-rate
#endif

#ifdef DISTRHO_UI_QT4
data->widget = (Qt4UI*)this;
#endif
}

UI::~UI()
{
delete data;
}

// -------------------------------------------------
// Host DSP State

double UI::d_sampleRate() const
{
return data->sampleRate;
}

void UI::d_setParameterValue(uint32_t index, float value)
{
data->setParamCallback(index + data->parameterOffset, value);
}

#if DISTRHO_PLUGIN_WANT_STATE
void UI::d_setState(const char* key, const char* value)
{
data->setStateCallback(key, value);
}
#endif

// -------------------------------------------------
// Host UI State

void UI::d_uiEditParameter(uint32_t index, bool started)
{
data->uiEditParamCallback(index, started);
}

#if DISTRHO_PLUGIN_IS_SYNTH
void UI::d_uiSendNote(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity)
{
data->uiSendNoteCallback(onOff, channel, note, velocity);
}
#endif

void UI::d_uiResize(unsigned int width, unsigned int height)
{
data->uiResizeCallback(width, height);
}

// -------------------------------------------------
// DSP Callbacks

#if DISTRHO_PLUGIN_IS_SYNTH
void UI::d_uiNoteReceived(bool, uint8_t, uint8_t, uint8_t)
{
}
#endif

// -------------------------------------------------

END_NAMESPACE_DISTRHO

+ 591
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoUIDSSI.cpp View File

@@ -0,0 +1,591 @@
/*
* DISTRHO Plugin Toolkit (DPT)
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#include "DistrhoDefines.h"

#if defined(DISTRHO_PLUGIN_TARGET_DSSI) && DISTRHO_PLUGIN_HAS_UI

#include "DistrhoUIInternal.h"

#include <QtCore/QSettings>
#include <QtGui/QApplication>
#include <QtGui/QMainWindow>

#include <lo/lo.h>

// -------------------------------------------------

START_NAMESPACE_DISTRHO

struct OscData {
lo_address addr;
const char* path;
lo_server server;
};

struct StringData {
d_string key;
d_string value;
};

#if DISTRHO_PLUGIN_WANT_STATE
void osc_send_configure(const OscData* oscData, const char* const key, const char* const value)
{
char targetPath[strlen(oscData->path)+11];
strcpy(targetPath, oscData->path);
strcat(targetPath, "/configure");
lo_send(oscData->addr, targetPath, "ss", key, value);
}
#endif

void osc_send_control(const OscData* oscData, const int32_t index, const float value)
{
char targetPath[strlen(oscData->path)+9];
strcpy(targetPath, oscData->path);
strcat(targetPath, "/control");
lo_send(oscData->addr, targetPath, "if", index, value);
}

#if DISTRHO_PLUGIN_IS_SYNTH
void osc_send_midi(const OscData* oscData, unsigned char data[4])
{
char targetPath[strlen(oscData->path)+6];
strcpy(targetPath, oscData->path);
strcat(targetPath, "/midi");
lo_send(oscData->addr, targetPath, "m", data);
}
#endif

void osc_send_update(const OscData* oscData, const char* const url)
{
char targetPath[strlen(oscData->path)+8];
strcpy(targetPath, oscData->path);
strcat(targetPath, "/update");
lo_send(oscData->addr, targetPath, "s", url);
}

void osc_send_exiting(const OscData* oscData)
{
char targetPath[strlen(oscData->path)+9];
strcpy(targetPath, oscData->path);
strcat(targetPath, "/exiting");
lo_send(oscData->addr, targetPath, "");
}

// stuff that we might receive while waiting for sample-rate
static bool globalShow = false;

class UIDssi : public QMainWindow
{
public:
UIDssi(const OscData* oscData_, const char* title)
: QMainWindow(nullptr),
widget(this),
settings("DISTRHO", DISTRHO_PLUGIN_NAME),
ui(this, widget.winId(), setParameterCallback, setStateCallback, nullptr, uiSendNoteCallback, uiResizeCallback),
oscData(oscData_)
{
setCentralWidget(&widget);
setFixedSize(ui.getWidth(), ui.getHeight());
setWindowTitle(title);

uiTimer = startTimer(30);

// load settings
restoreGeometry(settings.value("Global/Geometry", QByteArray()).toByteArray());

#if DISTRHO_PLUGIN_WANT_STATE
for (size_t i=0; i < globalConfigures.size(); i++)
dssiui_configure(globalConfigures.at(i).key, globalConfigures.at(i).value);
#endif

#if DISTRHO_PLUGIN_WANT_PROGRAMS
if (globalProgram[0] >= 0 && globalProgram[1] >= 0)
dssiui_program(globalProgram[0], globalProgram[1]);
#endif

for (size_t i=0; i < globalControls.size(); i++)
dssiui_control(i, globalControls.at(i));

if (globalShow)
show();
}

~UIDssi()
{
// save settings
settings.setValue("Global/Geometry", saveGeometry());

if (uiTimer)
{
killTimer(uiTimer);
osc_send_exiting(oscData);
}
}

// ---------------------------------------------

#if DISTRHO_PLUGIN_WANT_STATE
void dssiui_configure(const char* key, const char* value)
{
ui.stateChanged(key, value);
}
#endif

void dssiui_control(unsigned long index, float value)
{
ui.parameterChanged(index, value);
}

#if DISTRHO_PLUGIN_WANT_PROGRAMS
void dssiui_program(unsigned long bank, unsigned long program)
{
unsigned long index = bank * 128 + program;
ui.programChanged(index);
}
#endif

#if DISTRHO_PLUGIN_IS_SYNTH
void dssiui_midi(uint8_t data[4])
{
uint8_t status = data[1] & 0xF0;
uint8_t channel = data[1] & 0x0F;

// fix bad note-off
if (status == 0x90 && data[3] == 0)
status -= 0x10;

if (status == 0x80)
{
uint8_t note = data[2];
ui.noteReceived(false, channel, note, 0);
}
else if (status == 0x90)
{
uint8_t note = data[2];
uint8_t velo = data[3];
ui.noteReceived(true, channel, note, velo);
}
}
#endif

void dssiui_quit()
{
if (uiTimer)
{
killTimer(uiTimer);
uiTimer = 0;
}
close();
qApp->quit();
}

// ---------------------------------------------

protected:
void setParameterValue(uint32_t rindex, float value)
{
osc_send_control(oscData, rindex, value);
}

#if DISTRHO_PLUGIN_WANT_STATE
void setState(const char* key, const char* value)
{
osc_send_configure(oscData, key, value);
}
#endif

#if DISTRHO_PLUGIN_IS_SYNTH
void uiSendNote(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity)
{
uint8_t mdata[4] = { 0, channel, note, velocity };
mdata[1] += onOff ? 0x90 : 0x80;

osc_send_midi(oscData, mdata);
}
#endif

void uiResize(unsigned int width, unsigned int height)
{
widget.setFixedSize(width, height);
setFixedSize(width, height);
}

void timerEvent(QTimerEvent* event)
{
if (event->timerId() == uiTimer)
{
ui.idle();

while (lo_server_recv_noblock(oscData->server, 0) != 0) {}
}

QMainWindow::timerEvent(event);
}

private:
// Qt4 stuff
int uiTimer;
QWidget widget;
QSettings settings;

// Plugin UI
UIInternal ui;

const OscData* const oscData;

// ---------------------------------------------
// Callbacks

static void setParameterCallback(void* ptr, uint32_t rindex, float value)
{
UIDssi* _this_ = (UIDssi*)ptr;
assert(_this_);

_this_->setParameterValue(rindex, value);
}

static void setStateCallback(void* ptr, const char* key, const char* value)
{
#if DISTRHO_PLUGIN_WANT_STATE
UIDssi* _this_ = (UIDssi*)ptr;
assert(_this_);

_this_->setState(key, value);
#else
Q_UNUSED(ptr);
Q_UNUSED(key);
Q_UNUSED(value);
#endif
}

static void uiSendNoteCallback(void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velocity)
{
#if DISTRHO_PLUGIN_IS_SYNTH
UIDssi* _this_ = (UIDssi*)ptr;
assert(_this_);

_this_->uiSendNote(onOff, channel, note, velocity);
#else
Q_UNUSED(ptr);
Q_UNUSED(onOff);
Q_UNUSED(channel);
Q_UNUSED(note);
Q_UNUSED(velocity);
#endif
}

static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height)
{
UIDssi* _this_ = (UIDssi*)ptr;
assert(_this_);

_this_->uiResize(width, height);
}
};

// -------------------------------------------------

static UIDssi* globalUI = nullptr;

void osc_error_handler(int num, const char* msg, const char* path)
{
qCritical("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;
qDebug("osc_configure_handler(\"%s\", \"%s\")", key, value);

if (globalUI)
{
globalUI->dssiui_configure(key, value);
}
else
{
StringData data = { key, value };
globalConfigures.push_back(data);
}

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;
qDebug("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
// sample-rate
index -= 1;

if (index == -1)
{
setLastUiSampleRate(value);
return 0;
}

if (index < 0)
return 0;

if (globalUI)
{
globalUI->dssiui_control(index, value);
}
else
{
if (index >= (int32_t)globalControls.size())
{
for (int32_t i=globalControls.size(); i < index; i++)
globalControls.push_back(0.0f);
}

globalControls[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;
qDebug("osc_program_handler(%i, %i)", bank, program);

if (globalUI)
{
globalUI->dssiui_program(bank, program);
}
else
{
globalProgram[0] = bank;
globalProgram[1] = program;
}

return 0;
}
#endif

#if DISTRHO_PLUGIN_IS_SYNTH
int osc_midi_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*)
{
qDebug("osc_midi_handler()");

if (globalUI)
globalUI->dssiui_midi(argv[0]->m);

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;
qDebug("osc_sample_rate_handler(%i)", sampleRate);

setLastUiSampleRate(sampleRate);

return 0;
}

int osc_show_handler(const char*, const char*, lo_arg**, int, lo_message, void*)
{
qDebug("osc_show_handler()");

if (globalUI)
globalUI->show();

return 0;
}

int osc_hide_handler(const char*, const char*, lo_arg**, int, lo_message, void*)
{
qDebug("osc_hide_handler()");

if (globalUI)
globalUI->hide();

return 0;
}

int osc_quit_handler(const char*, const char*, lo_arg**, int, lo_message, void*)
{
qDebug("osc_quit_handler()");

if (globalUI)
globalUI->dssiui_quit();

return 0;
}

int osc_debug_handler(const char* path, const char*, lo_arg**, int, lo_message, void*)
{
qDebug("osc_debug_handler(\"%s\")", path);

return 0;
}

END_NAMESPACE_DISTRHO

// -------------------------------------------------

int main(int argc, char* argv[])
{
USE_NAMESPACE_DISTRHO

if (argc != 5)
{
qWarning("Usage: %s <osc-url> <so-file> <plugin-label> <instance-name>", argv[0]);
return 1;
}

QApplication app(argc, argv, true);

const char* const oscUrl = argv[1];
const char* const 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(nullptr, osc_error_handler);

OscData oscData = { oscAddr, oscPath, oscServer };

#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);

#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

#if DISTRHO_PLUGIN_IS_SYNTH
char oscPathMidi[oscPathSize+6];
strcpy(oscPathMidi, oscPath);
strcat(oscPathMidi, "/midi");
lo_server_add_method(oscServer, oscPathMidi, "m", osc_midi_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);

char* const serverPath = lo_server_get_url(oscServer);
char* const pluginPath = strdup(QString("%1%2").arg(serverPath).arg(oscPathSize > 1 ? oscPath + 1 : oscPath).toUtf8().constData());
free(serverPath);

// send update msg and wait for sample-rate
osc_send_update(&oscData, pluginPath);

// wait for sample-rate
for (int i=0; i < 1000; i++)
{
if (d_lastUiSampleRate != 0.0)
break;

lo_server_recv(oscServer);
d_msleep(50);
}

int ret;

if (d_lastUiSampleRate != 0.0)
{
globalUI = new UIDssi(&oscData, uiTitle);

ret = app.exec();

delete globalUI;
globalUI = nullptr;
}
else
{
ret = 1;
}

#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
#if DISTRHO_PLUGIN_IS_SYNTH
lo_server_del_method(oscServer, oscPathMidi, "m");
#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);

free(oscHost);
free(oscPort);
free(oscPath);
free(pluginPath);

lo_address_free(oscAddr);
lo_server_free(oscServer);

return ret;
}

// -------------------------------------------------

#endif // DISTRHO_PLUGIN_TARGET_DSSI && DISTRHO_PLUGIN_HAS_UI

+ 566
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoUIInternal.h View File

@@ -0,0 +1,566 @@
/*
* DISTRHO Plugin Toolkit (DPT)
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#ifndef __DISTRHO_UI_INTERNAL_H__
#define __DISTRHO_UI_INTERNAL_H__

#include "DistrhoUI.h"

#ifdef DISTRHO_UI_OPENGL
# include "DistrhoUIOpenGL.h"
# include "pugl/pugl.h"
#else
# include "DistrhoUIQt4.h"
# include <QtGui/QApplication>
# include <QtGui/QMouseEvent>
# include <QtGui/QSizeGrip>
# include <QtGui/QVBoxLayout>
# ifdef Q_WS_X11
# include <QtGui/QX11EmbedWidget>
# endif
#endif

#include <cassert>

START_NAMESPACE_DISTRHO

// -------------------------------------------------

#ifdef DISTRHO_UI_OPENGL
typedef PuglView* NativeWidget;
#else
typedef QWidget* NativeWidget;
#endif

typedef void (*setParamFunc) (void* ptr, uint32_t index, float value);
typedef void (*setStateFunc) (void* ptr, const char* key, const char* value);
typedef void (*uiEditParamFunc) (void* ptr, uint32_t index, bool started);
typedef void (*uiSendNoteFunc) (void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velo);
typedef void (*uiResizeFunc) (void* ptr, unsigned int width, unsigned int height);

extern double d_lastUiSampleRate;

// -------------------------------------------------

#ifdef DISTRHO_UI_QT4
# ifdef Q_WS_X11
class QEmbedWidget : public QX11EmbedWidget
# else
class QEmbedWidget : public QWidget
# endif
{
public:
QEmbedWidget();
~QEmbedWidget();

void embedInto(WId id);
WId containerWinId() const;
};
#endif

// -------------------------------------------------

struct UIPrivateData {
// DSP
double sampleRate;
uint32_t parameterOffset;

// UI
void* ptr;
NativeWidget widget;

// Callbacks
setParamFunc setParamCallbackFunc;
setStateFunc setStateCallbackFunc;
uiEditParamFunc uiEditParamCallbackFunc;
uiSendNoteFunc uiSendNoteCallbackFunc;
uiResizeFunc uiResizeCallbackFunc;

UIPrivateData()
: sampleRate(d_lastUiSampleRate),
parameterOffset(0),
ptr(nullptr),
widget(nullptr),
setParamCallbackFunc(nullptr),
setStateCallbackFunc(nullptr),
uiEditParamCallbackFunc(nullptr),
uiSendNoteCallbackFunc(nullptr),
uiResizeCallbackFunc(nullptr)
{
assert(d_lastUiSampleRate != 0.0);
}

~UIPrivateData()
{
}

void setParamCallback(uint32_t rindex, float value)
{
if (setParamCallbackFunc)
setParamCallbackFunc(ptr, rindex, value);
}

void setStateCallback(const char* key, const char* value)
{
if (setStateCallbackFunc)
setStateCallbackFunc(ptr, key, value);
}

void uiEditParamCallback(uint32_t index, bool started)
{
if (uiEditParamCallbackFunc)
uiEditParamCallbackFunc(ptr, index, started);
}

void uiSendNoteCallback(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity)
{
if (uiSendNoteCallbackFunc)
uiSendNoteCallbackFunc(ptr, onOff, channel, note, velocity);
}

void uiResizeCallback(unsigned int width, unsigned int height)
{
if (uiResizeCallbackFunc)
uiResizeCallbackFunc(ptr, width, height);
}
};

// -------------------------------------------------

#ifdef DISTRHO_UI_QT4
class UIInternal : public QObject // needed for eventFilter()
#else
class UIInternal
#endif
{
public:
UIInternal(void* ptr, intptr_t winId, setParamFunc setParamCall, setStateFunc setStateCall, uiEditParamFunc uiEditParamCall, uiSendNoteFunc uiSendNoteCall, uiResizeFunc uiResizeCall)
: ui(createUI()),
data(ui ? ui->data : nullptr)
{
assert(ui);

#ifdef DISTRHO_UI_QT4
qt_grip = nullptr;
qt_widget = nullptr;
#else
gl_initiated = false;
#endif

if (winId == 0 || ! ui)
return;

data->ptr = ptr;
data->setParamCallbackFunc = setParamCall;
data->setStateCallbackFunc = setStateCall;
data->uiEditParamCallbackFunc = uiEditParamCall;
data->uiSendNoteCallbackFunc = uiSendNoteCall;
data->uiResizeCallbackFunc = uiResizeCall;

createWindow(winId);
}

~UIInternal()
{
if (ui)
{
destroyWindow();
delete ui;
}
}

// ---------------------------------------------

void idle()
{
assert(ui);

if (ui)
ui->d_uiIdle();
}

unsigned int getWidth()
{
assert(ui);
return ui ? ui->d_width() : 0;
}

unsigned int getHeight()
{
assert(ui);
return ui ? ui->d_height() : 0;
}

intptr_t getWindowId()
{
#ifdef DISTRHO_UI_QT4
assert(qt_widget);
return qt_widget ? qt_widget->winId() : 0;
#else
assert(data && data->widget);
return (data && data->widget) ? puglGetNativeWindow(data->widget) : 0;
#endif
}

// ---------------------------------------------

void parameterChanged(uint32_t index, float value)
{
assert(ui);

if (ui)
ui->d_parameterChanged(index, value);
}

#if DISTRHO_PLUGIN_WANT_PROGRAMS
void programChanged(uint32_t index)
{
assert(ui);

if (ui)
ui->d_programChanged(index);
}
#endif

#if DISTRHO_PLUGIN_WANT_STATE
void stateChanged(const char* key, const char* value)
{
assert(ui);

if (ui)
ui->d_stateChanged(key, value);
}
#endif

#if DISTRHO_PLUGIN_IS_SYNTH
void noteReceived(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity)
{
assert(ui);

if (ui)
ui->d_uiNoteReceived(onOff, channel, note, velocity);
}
#endif

// ---------------------------------------------

void createWindow(intptr_t parent)
{
#ifdef DISTRHO_UI_QT4
assert(ui && ! qt_widget);

// create embedable widget
qt_widget = new QEmbedWidget;

// set layout
qt_widget->setLayout(new QVBoxLayout(qt_widget));
qt_widget->layout()->addWidget(data->widget);
qt_widget->layout()->setContentsMargins(0, 0, 0, 0);
qt_widget->setFixedSize(ui->d_width(), ui->d_height());

// listen for resize on the plugin widget
data->widget->installEventFilter(this);

// set resize grip
if (((Qt4UI*)ui)->d_resizable())
{
qt_grip = new QSizeGrip(qt_widget);
qt_grip->resize(qt_grip->sizeHint());
qt_grip->setCursor(Qt::SizeFDiagCursor);
qt_grip->move(ui->d_width() - qt_grip->width(), ui->d_height() - qt_grip->height());
qt_grip->show();
qt_grip->raise();
qt_grip->installEventFilter(this);
}

// reparent widget
qt_widget->embedInto(parent);

// show it
qt_widget->show();
#else
assert(ui);

if ((data && data->widget) || ! ui)
return;

data->widget = puglCreate(parent, DISTRHO_PLUGIN_NAME, ui->d_width(), ui->d_height(), false);

assert(data->widget);

if (! data->widget)
return;

puglSetHandle(data->widget, this);
puglSetDisplayFunc(data->widget, gl_onDisplayCallback);
puglSetKeyboardFunc(data->widget, gl_onKeyboardCallback);
puglSetMotionFunc(data->widget, gl_onMotionCallback);
puglSetMouseFunc(data->widget, gl_onMouseCallback);
puglSetScrollFunc(data->widget, gl_onScrollCallback);
puglSetSpecialFunc(data->widget, gl_onSpecialCallback);
puglSetReshapeFunc(data->widget, gl_onReshapeCallback);
puglSetCloseFunc(data->widget, gl_onCloseCallback);
#endif
}

void destroyWindow()
{
#ifdef DISTRHO_UI_QT4
if (qt_widget)
{
// remove main widget, to prevent it from being auto-deleted
data->widget->hide();
qt_widget->layout()->removeWidget(data->widget);
data->widget->setParent(nullptr);
data->widget->close();

qt_widget->close();

if (qt_grip)
delete qt_grip;

delete qt_widget;
}
#else
((OpenGLUI*)ui)->d_onClose();

if (data && data->widget)
{
puglDestroy(data->widget);
data->widget = nullptr;
}
#endif
}

// ---------------------------------------------

#ifdef DISTRHO_UI_OPENGL
void gl_onDisplay()
{
OpenGLUI* uiGL = (OpenGLUI*)ui;
assert(uiGL);

if (uiGL)
uiGL->d_onDisplay();
}

void gl_onKeyboard(bool press, uint32_t key)
{
OpenGLUI* uiGL = (OpenGLUI*)ui;
assert(uiGL);

if (uiGL)
uiGL->d_onKeyboard(press, key);
}

void gl_onMotion(int x, int y)
{
OpenGLUI* uiGL = (OpenGLUI*)ui;
assert(uiGL);

if (uiGL)
uiGL->d_onMotion(x, y);
}

void gl_onMouse(int button, bool press, int x, int y)
{
OpenGLUI* uiGL = (OpenGLUI*)ui;
assert(uiGL);

if (uiGL)
uiGL->d_onMouse(button, press, x, y);
}

void gl_onReshape(int width, int height)
{
OpenGLUI* uiGL = (OpenGLUI*)ui;
assert(uiGL);

if (uiGL)
{
if (! gl_initiated)
{
uiGL->d_onInit();
gl_initiated = true;
}
else
uiGL->d_onReshape(width, height);
}
}

void gl_onScroll(float dx, float dy)
{
OpenGLUI* uiGL = (OpenGLUI*)ui;
assert(uiGL);

if (uiGL)
uiGL->d_onScroll(dx, dy);
}

void gl_onSpecial(bool press, Key key)
{
OpenGLUI* uiGL = (OpenGLUI*)ui;
assert(uiGL);

if (uiGL)
uiGL->d_onSpecial(press, key);
}

void gl_onClose()
{
OpenGLUI* uiGL = (OpenGLUI*)ui;
assert(uiGL);

if (uiGL)
uiGL->d_onClose();
}

// ---------------------------------------------

static void gl_onDisplayCallback(PuglView* view)
{
if (UIInternal* _this_ = (UIInternal*)puglGetHandle(view))
_this_->gl_onDisplay();
}

static void gl_onKeyboardCallback(PuglView* view, bool press, uint32_t key)
{
if (UIInternal* _this_ = (UIInternal*)puglGetHandle(view))
_this_->gl_onKeyboard(press, key);
}

static void gl_onMotionCallback(PuglView* view, int x, int y)
{
if (UIInternal* _this_ = (UIInternal*)puglGetHandle(view))
_this_->gl_onMotion(x, y);
}

static void gl_onMouseCallback(PuglView* view, int button, bool press, int x, int y)
{
if (UIInternal* _this_ = (UIInternal*)puglGetHandle(view))
_this_->gl_onMouse(button, press, x, y);
}

static void gl_onReshapeCallback(PuglView* view, int width, int height)
{
if (UIInternal* _this_ = (UIInternal*)puglGetHandle(view))
_this_->gl_onReshape(width, height);
}

static void gl_onScrollCallback(PuglView* view, float dx, float dy)
{
if (UIInternal* _this_ = (UIInternal*)puglGetHandle(view))
_this_->gl_onScroll(dx, dy);
}

static void gl_onSpecialCallback(PuglView* view, bool press, PuglKey key)
{
if (UIInternal* _this_ = (UIInternal*)puglGetHandle(view))
_this_->gl_onSpecial(press, (Key)key);
}

static void gl_onCloseCallback(PuglView* view)
{
if (UIInternal* _this_ = (UIInternal*)puglGetHandle(view))
_this_->gl_onClose();
}
#endif

// ---------------------------------------------

protected:
UI* const ui;
UIPrivateData* const data;

#ifdef DISTRHO_UI_QT4
bool eventFilter(QObject* obj, QEvent* event)
{
if (obj == qt_grip)
{
if (event->type() == QEvent::MouseButtonPress)
{
QMouseEvent* mEvent = (QMouseEvent*)event;
if (mEvent->button() == Qt::LeftButton)
qt_mouseDown = true;
return true;
}

else if (event->type() == QEvent::MouseMove)
{
if (qt_mouseDown)
{
Qt4UI* qt_ui = (Qt4UI*)ui;
QMouseEvent* mEvent = (QMouseEvent*)event;
int width = ui->d_width() + mEvent->x() - qt_grip->width();
int height = ui->d_height() + mEvent->y() - qt_grip->height();

if (width < qt_ui->d_minimumWidth())
width = qt_ui->d_minimumWidth();
if (height < qt_ui->d_minimumHeight())
height = qt_ui->d_minimumHeight();

if (data && data->widget)
data->widget->setFixedSize(width, height);

return true;
}

// FIXME?
//return true;
}

else if (event->type() == QEvent::MouseButtonRelease)
{
QMouseEvent* mEvent = (QMouseEvent*)event;
if (mEvent->button() == Qt::LeftButton)
qt_mouseDown = false;
return true;
}
}
else if (data && obj == data->widget)
{
if (event->type() == QEvent::Resize)
{
QResizeEvent* rEvent = (QResizeEvent*)event;
const QSize& size = rEvent->size();

qt_widget->setFixedSize(size.width(), size.height());
qt_grip->move(size.width() - qt_grip->width(), size.height() - qt_grip->height());

ui->d_uiResize(size.width(), size.height());
}
}

return QObject::eventFilter(obj, event);
}
#endif

private:
#ifdef DISTRHO_UI_QT4
bool qt_mouseDown;
QSizeGrip* qt_grip;
QEmbedWidget* qt_widget;
#else
bool gl_initiated;
#endif
};

// -------------------------------------------------

END_NAMESPACE_DISTRHO

#endif // __DISTRHO_UI_INTERNAL_H__

+ 372
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoUILV2.cpp View File

@@ -0,0 +1,372 @@
/*
* DISTHRO Plugin Toolkit (DPT)
* Copyright (C) 2012 Filipe Coelho <falktx@gmail.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#include "DistrhoDefines.h"

#if defined(DISTRHO_PLUGIN_TARGET_LV2) && DISTRHO_PLUGIN_HAS_UI

#include "DistrhoUIInternal.h"

#include "lv2-sdk/lv2.h"
//#include "lv2-sdk/atom.h"
//#include "lv2-sdk/atom-util.h"
//#include "lv2-sdk/midi.h"
#include "lv2-sdk/patch.h"
#include "lv2-sdk/programs.h"
//#include "lv2-sdk/state.h"
#include "lv2-sdk/urid.h"
#include "lv2-sdk/ui.h"

#include <cassert>
#include <cstring>
#include <thread>

#ifdef DISTRHO_UI_QT4
# include <QtCore/QTimerEvent>
#endif

#ifndef DISTRHO_PLUGIN_URI
# error DISTRHO_PLUGIN_URI undefined!
#endif

#define DISTRHO_LV2UI_USE_EXTENSION_DATA (DISTRHO_PLUGIN_WANT_PROGRAMS)

// -------------------------------------------------

START_NAMESPACE_DISTRHO

#ifdef DISTRHO_UI_QT4
class UILv2 : public QObject
#else
class UILv2
#endif
{
public:
UILv2(intptr_t parent, LV2UI_Controller controller, LV2UI_Write_Function writeFunction, LV2UI_Widget* widget, const LV2_Feature* const* features)
: ui(this, parent, setParameterCallback, setStateCallback, uiNoteCallback, uiResizeCallback),
lv2Controller(controller),
lv2WriteFunction(writeFunction),
lv2UiResize(nullptr),
#if DISTRHO_PLUGIN_WANT_STATE
uridIdPatchMessage(0),
#endif
#ifdef DISTRHO_UI_QT4
uiTimer(0)
#else
threadExitNow(false),
threadRunning(false),
thread(uiThreadCallback, this)
#endif
{
// Get Features
for (uint32_t i = 0; features[i]; i++)
{
if (strcmp(features[i]->URI, LV2_URID__map) == 0)
{
#if DISTRHO_PLUGIN_WANT_STATE
LV2_URID_Map* uridMap = (LV2_URID_Map*)features[i]->data;
uridIdPatchMessage = uridMap->map(uridMap->handle, LV2_PATCH__Message);
#endif
}

else if (strcmp(features[i]->URI, LV2_UI__resize) == 0)
lv2UiResize = (LV2UI_Resize*)features[i]->data;
}

#ifndef DISTRHO_UI_QT4
assert(parent);

if (parent == 0)
return;
#endif

if (lv2UiResize)
lv2UiResize->ui_resize(lv2UiResize->handle, ui.getWidth(), ui.getHeight());

#ifdef DISTRHO_UI_QT4
uiTimer = startTimer(30);
#endif

*widget = (void*)ui.getWindowId();
}

~UILv2()
{
#ifdef DISTRHO_UI_QT4
if (uiTimer)
killTimer(uiTimer);
#else
uiThreadClose();
#endif
}

// ---------------------------------------------

void lv2ui_port_event(uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer)
{
if (format == 0)
{
if (bufferSize != sizeof(float))
return;
if (int32_t(portIndex - DISTRHO_PLUGIN_NUM_INPUTS - DISTRHO_PLUGIN_NUM_OUTPUTS) < 0)
return;

float value = *(float*)buffer;
ui.parameterChanged(portIndex - DISTRHO_PLUGIN_NUM_INPUTS - DISTRHO_PLUGIN_NUM_OUTPUTS, value);
}
// TODO - atom events
}

#if DISTRHO_PLUGIN_WANT_PROGRAMS
void lv2ui_select_program(uint32_t bank, uint32_t program)
{
const uint32_t index = bank * 128 + program;
ui.programChanged(index);
}
#endif

// ---------------------------------------------

protected:
void setParameterValue(uint32_t index, float value)
{
if (lv2WriteFunction)
lv2WriteFunction(lv2Controller, DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS + index, sizeof(float), 0, &value);
}

void setState(const char* key, const char* value)
{
// TODO
(void)key;
(void)value;

//if (lv2WriteFunction && uridMap)
{

}
}

void uiResize(unsigned int width, unsigned int height)
{
if (lv2UiResize)
lv2UiResize->ui_resize(lv2UiResize->handle, width, height);
}

#ifdef DISTRHO_UI_QT4
void timerEvent(QTimerEvent* event)
{
if (event->timerId() == uiTimer)
ui.idle();

QObject::timerEvent(event);
}
#else
void uiThreadRun()
{
threadRunning = true;

while (! threadExitNow)
{
ui.idle();
d_msleep(1000 / 25); // 25 FPS
}

thread.detach();
threadRunning = false;
}

void uiThreadClose()
{
threadExitNow = true;

while (threadRunning)
d_msleep(1000 / 25); // 25 FPS
}
#endif

private:
UIInternal ui;

// LV2 Stuff
LV2UI_Controller const lv2Controller;
LV2UI_Write_Function const lv2WriteFunction;
const LV2UI_Resize* lv2UiResize;

#if DISTRHO_PLUGIN_WANT_STATE
LV2_URID uridIdPatchMessage;
#endif

#ifdef DISTRHO_UI_QT4
int uiTimer;
#else
// UI Thread
bool threadExitNow;
bool threadRunning;
std::thread thread;
#endif

// ---------------------------------------------
// Callbacks

static void setParameterCallback(void* ptr, uint32_t index, float value)
{
UILv2* _this_ = (UILv2*)ptr;
assert(_this_);

_this_->setParameterValue(index, value);
}

static void setStateCallback(void* ptr, const char* key, const char* value)
{
#if DISTRHO_PLUGIN_WANT_STATE
UILv2* _this_ = (UILv2*)ptr;
assert(_this_);

_this_->setState(key, value);
#else
// unused
(void)ptr;
(void)key;
(void)value;
#endif
}

static void uiNoteCallback(void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velocity)
{
#if DISTRHO_PLUGIN_IS_SYNTH
UILv2* _this_ = (UILv2*)ptr;
assert(_this_);

_this_->uiNote(onOff, channel, note, velocity);
#else
// unused
(void)ptr;
(void)onOff;
(void)channel;
(void)note;
(void)velocity;
#endif
}

static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height)
{
UILv2* _this_ = (UILv2*)ptr;
assert(_this_);

_this_->uiResize(width, height);
}

#ifndef DISTRHO_UI_QT4
static void uiThreadCallback(void* ptr)
{
UILv2* _this_ = (UILv2*)ptr;
assert(_this_);

_this_->uiThreadRun();
}
#endif
};

// -------------------------------------------------

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 (strcmp(uri, DISTRHO_PLUGIN_URI) != 0)
return nullptr;

// Get parent
intptr_t parent = 0;

for (uint32_t i = 0; features[i]; i++)
{
if (strcmp(features[i]->URI, LV2_UI__parent) == 0)
{
parent = (intptr_t)features[i]->data;
break;
}
}

return new UILv2(parent, controller, writeFunction, widget, features);
}

static void lv2ui_cleanup(LV2UI_Handle instance)
{
UILv2* ui = (UILv2*)instance;
assert(ui);

delete ui;
}

static void lv2ui_port_event(LV2UI_Handle instance, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer)
{
UILv2* ui = (UILv2*)instance;
assert(ui);

ui->lv2ui_port_event(portIndex, bufferSize, format, buffer);
}

#if DISTRHO_LV2UI_USE_EXTENSION_DATA
# if DISTRHO_PLUGIN_WANT_PROGRAMS
static void lv2ui_select_program(LV2_Handle instance, uint32_t bank, uint32_t program)
{
UILv2* ui = (UILv2*)instance;
assert(ui);

ui->lv2ui_select_program(bank, program);
}
# endif

static const void* lv2ui_extension_data(const char* uri)
{
# if DISTRHO_PLUGIN_WANT_PROGRAMS
static const LV2_Programs_UI_Interface programs = { lv2ui_select_program };
if (strcmp(uri, LV2_PROGRAMS__UIInterface) == 0)
return &programs;
# endif

return nullptr;
}
#endif

// -------------------------------------------------

static LV2UI_Descriptor uidescriptor = {
DISTRHO_UI_URI,
lv2ui_instantiate,
lv2ui_cleanup,
lv2ui_port_event,
#if DISTRHO_LV2UI_USE_EXTENSION_DATA
lv2ui_extension_data
#else
/* extension_data */ nullptr
#endif
};

END_NAMESPACE_DISTRHO

// -------------------------------------------------

DISTRHO_PLUGIN_EXPORT
const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
{
USE_NAMESPACE_DISTRHO
return (index == 0) ? &uidescriptor : nullptr;
}

// -------------------------------------------------

#endif // DISTRHO_PLUGIN_TARGET_LV2 && DISTRHO_PLUGIN_HAS_UI

+ 82
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoUIOpenGL.cpp View File

@@ -0,0 +1,82 @@
/*
* DISTHRO Plugin Toolkit (DPT)
* Copyright (C) 2012 Filipe Coelho <falktx@gmail.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#include "DistrhoDefines.h"

#ifdef DISTRHO_UI_OPENGL

#include "DistrhoUIInternal.h"

START_NAMESPACE_DISTRHO

// -------------------------------------------------

OpenGLUI::OpenGLUI()
: UI()
{
}

OpenGLUI::~OpenGLUI()
{
}

// -------------------------------------------------
// Host UI State

int OpenGLUI::d_uiGetModifiers()
{
if (data && data->widget)
return puglGetModifiers(data->widget);
return 0;
}

void OpenGLUI::d_uiIgnoreKeyRepeat(bool ignore)
{
if (data && data->widget)
puglIgnoreKeyRepeat(data->widget, ignore);
}

void OpenGLUI::d_uiRepaint()
{
if (data && data->widget)
puglPostRedisplay(data->widget);
}

// -------------------------------------------------
// UI Callbacks

void OpenGLUI::d_uiIdle()
{
if (data && data->widget)
puglProcessEvents(data->widget);
}

// -------------------------------------------------

END_NAMESPACE_DISTRHO

#ifndef DISTRHO_NAMESPACE
# if DISTRHO_OS_WINDOWS
# include "pugl/pugl_win.cpp"
# elif DISTRHO_OS_MAC
# include "pugl/pugl_osx.m"
# else
# include "pugl/pugl_x11.c"
# endif
#endif

#endif // DISTRHO_UI_OPENGL

+ 1495
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoUIOpenGLExt.cpp
File diff suppressed because it is too large
View File


+ 75
- 0
source/libs/distrho-plugin-toolkit/src/DistrhoUIQt4.cpp View File

@@ -0,0 +1,75 @@
/*
* DISTHRO Plugin Toolkit (DPT)
* Copyright (C) 2012 Filipe Coelho <falktx@gmail.com>
*
* 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 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.
*
* For a full copy of the license see the GPL.txt file
*/

#include "DistrhoDefines.h"

#ifdef DISTRHO_UI_QT4

#include "DistrhoUIInternal.h"

START_NAMESPACE_DISTRHO

// -------------------------------------------------
// QEmbedWidget

QEmbedWidget::QEmbedWidget()
{
}

QEmbedWidget::~QEmbedWidget()
{
}

void QEmbedWidget::embedInto(WId id)
{
#ifdef Q_WS_X11
QX11EmbedWidget::embedInto(id);
#endif
}

WId QEmbedWidget::containerWinId() const
{
#ifdef Q_WS_X11
return QX11EmbedWidget::containerWinId();
#endif
}

// -------------------------------------------------
// Qt4UI

Qt4UI::Qt4UI()
: UI(),
QWidget(nullptr)
{
}

Qt4UI::~Qt4UI()
{
}

// -------------------------------------------------
// UI Callbacks

void Qt4UI::d_uiIdle()
{
}

// -------------------------------------------------

END_NAMESPACE_DISTRHO

#endif // DISTRHO_UI_QT4

+ 1
- 0
source/libs/distrho-plugin-toolkit/src/dssi View File

@@ -0,0 +1 @@
../../../includes/dssi

+ 1
- 0
source/libs/distrho-plugin-toolkit/src/ladspa View File

@@ -0,0 +1 @@
../../../includes/ladspa

+ 1
- 0
source/libs/distrho-plugin-toolkit/src/lv2 View File

@@ -0,0 +1 @@
../../../includes/lv2

Loading…
Cancel
Save