@@ -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__ |
@@ -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 |
@@ -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__ |
@@ -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 |
@@ -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__ |
@@ -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__ |
@@ -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__ |
@@ -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__ |
@@ -0,0 +1,10 @@ | |||
#!/usr/bin/make -f | |||
# Makefile for distrho (docs) # | |||
# ----------------------------------------- # | |||
# Created by falkTX | |||
# | |||
all: | |||
doxygen: distrho.doxygen | |||
doxygen $< |
@@ -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 |
@@ -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__ |
@@ -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 |
@@ -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__ |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 = ▭ | |||
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 |
@@ -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 |
@@ -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 |
@@ -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__ |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -0,0 +1 @@ | |||
../../../includes/dssi |
@@ -0,0 +1 @@ | |||
../../../includes/ladspa |
@@ -0,0 +1 @@ | |||
../../../includes/lv2 |