@@ -224,7 +224,7 @@ void DistrhoPlugin3BandEQ::d_deactivate() | |||
tmp1LP = tmp2LP = tmp1HP = tmp2HP = 0.0f; | |||
} | |||
void DistrhoPlugin3BandEQ::d_run(float** inputs, float** outputs, uint32_t frames, const MidiEvent*, uint32_t) | |||
void DistrhoPlugin3BandEQ::d_run(float** inputs, float** outputs, uint32_t frames) | |||
{ | |||
float* in1 = inputs[0]; | |||
float* in2 = inputs[1]; | |||
@@ -88,7 +88,7 @@ protected: | |||
void d_activate() override; | |||
void d_deactivate() override; | |||
void d_run(float** inputs, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) override; | |||
void d_run(float** inputs, float** outputs, uint32_t frames) override; | |||
// ------------------------------------------------------------------- | |||
@@ -32,6 +32,4 @@ | |||
#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/3BandEQ" | |||
#define DISTRHO_UI_OPENGL | |||
#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED |
@@ -16,12 +16,14 @@ | |||
#include "DistrhoUI3BandEQ.hpp" | |||
using DGL::Point; | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
DistrhoUI3BandEQ::DistrhoUI3BandEQ() | |||
: OpenGLUI(), | |||
: UI(), | |||
fAboutWindow(this) | |||
{ | |||
// background | |||
@@ -17,7 +17,7 @@ | |||
#ifndef DISTRHO_UI_3BANDEQ_HPP_INCLUDED | |||
#define DISTRHO_UI_3BANDEQ_HPP_INCLUDED | |||
#include "DistrhoUIOpenGL.hpp" | |||
#include "DistrhoUI.hpp" | |||
#include "dgl/ImageAboutWindow.hpp" | |||
#include "dgl/ImageButton.hpp" | |||
@@ -27,11 +27,17 @@ | |||
#include "DistrhoArtwork3BandEQ.hpp" | |||
#include "DistrhoPlugin3BandEQ.hpp" | |||
using DGL::Image; | |||
using DGL::ImageAboutWindow; | |||
using DGL::ImageButton; | |||
using DGL::ImageKnob; | |||
using DGL::ImageSlider; | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
class DistrhoUI3BandEQ : public OpenGLUI, | |||
class DistrhoUI3BandEQ : public UI, | |||
public ImageButton::Callback, | |||
public ImageKnob::Callback, | |||
public ImageSlider::Callback | |||
@@ -37,46 +37,24 @@ struct ParameterRanges { | |||
float def; | |||
float min; | |||
float max; | |||
float step; | |||
float stepSmall; | |||
float stepLarge; | |||
ParameterRanges() noexcept | |||
: def(0.0f), | |||
min(0.0f), | |||
max(1.0f), | |||
step(0.001f), | |||
stepSmall(0.00001f), | |||
stepLarge(0.01f) {} | |||
max(1.0f) {} | |||
ParameterRanges(float def, float min, float max) noexcept | |||
: 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) noexcept | |||
{ | |||
this->def = def; | |||
this->min = min; | |||
this->max = max; | |||
this->step = step; | |||
this->stepSmall = stepSmall; | |||
this->stepLarge = stepLarge; | |||
} | |||
void clear() noexcept | |||
{ | |||
def = 0.0f; | |||
min = 0.0f; | |||
max = 1.0f; | |||
step = 0.001f; | |||
stepSmall = 0.00001f; | |||
stepLarge = 0.01f; | |||
} | |||
void fixValue(float& value) const noexcept | |||
@@ -141,22 +119,17 @@ struct Parameter { | |||
struct MidiEvent { | |||
uint32_t frame; | |||
uint8_t buf[4]; | |||
uint8_t size; | |||
MidiEvent() noexcept | |||
{ | |||
clear(); | |||
} | |||
uint8_t buf[4]; | |||
void clear() noexcept | |||
{ | |||
frame = 0; | |||
size = 0; | |||
buf[0] = 0; | |||
buf[1] = 0; | |||
buf[2] = 0; | |||
buf[3] = 0; | |||
size = 0; | |||
} | |||
}; | |||
@@ -234,7 +207,11 @@ protected: | |||
virtual void d_activate() {} | |||
virtual void d_deactivate() {} | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
virtual void d_run(float** inputs, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) = 0; | |||
#else | |||
virtual void d_run(float** inputs, float** outputs, uint32_t frames) = 0; | |||
#endif | |||
// ------------------------------------------------------------------- | |||
// Callbacks (optional) | |||
@@ -247,7 +224,7 @@ protected: | |||
private: | |||
struct PrivateData; | |||
PrivateData* const pData; | |||
friend class PluginInternal; | |||
friend class PluginExporter; | |||
}; | |||
// ----------------------------------------------------------------------- | |||
@@ -19,12 +19,14 @@ | |||
#include "DistrhoUtils.hpp" | |||
#include "dgl/Widget.hpp" | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
// UI | |||
class UI | |||
class UI : public DGL::Widget | |||
{ | |||
public: | |||
UI(); | |||
@@ -40,7 +42,7 @@ public: | |||
void d_setState(const char* key, const char* value); | |||
#endif | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
void d_sendNote(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity); | |||
void d_sendNote(uint8_t channel, uint8_t note, uint8_t velocity); | |||
#endif | |||
// ------------------------------------------------------------------- | |||
@@ -66,9 +68,6 @@ protected: | |||
#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_noteReceived(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity) = 0; | |||
#endif | |||
// ------------------------------------------------------------------- | |||
// UI Callbacks (optional) | |||
@@ -80,7 +79,7 @@ protected: | |||
private: | |||
struct PrivateData; | |||
PrivateData* const pData; | |||
friend class UIInternal; | |||
friend class UIExporter; | |||
}; | |||
// ----------------------------------------------------------------------- | |||
@@ -141,24 +141,49 @@ public: | |||
// ------------------------------------------------------------------- | |||
// constructors (no explicit conversions allowed) | |||
/* | |||
* Empty string. | |||
*/ | |||
explicit d_string() | |||
{ | |||
_init(); | |||
_dup(nullptr); | |||
} | |||
/* | |||
* Simple character. | |||
*/ | |||
explicit d_string(const char c) | |||
{ | |||
char ch[2]; | |||
ch[0] = c; | |||
ch[1] = '\0'; | |||
_init(); | |||
_dup(ch); | |||
} | |||
/* | |||
* Simple char string. | |||
*/ | |||
explicit d_string(char* const strBuf) | |||
{ | |||
_init(); | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Simple const char string. | |||
*/ | |||
explicit d_string(const char* const strBuf) | |||
{ | |||
_init(); | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Integer. | |||
*/ | |||
explicit d_string(const int value) | |||
{ | |||
char strBuf[0xff+1]; | |||
@@ -169,6 +194,9 @@ public: | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Unsigned integer, possibly in hexadecimal. | |||
*/ | |||
explicit d_string(const unsigned int value, const bool hexadecimal = false) | |||
{ | |||
char strBuf[0xff+1]; | |||
@@ -179,6 +207,9 @@ public: | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Long integer. | |||
*/ | |||
explicit d_string(const long int value) | |||
{ | |||
char strBuf[0xff+1]; | |||
@@ -189,6 +220,9 @@ public: | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Long unsigned integer, possibly hexadecimal. | |||
*/ | |||
explicit d_string(const unsigned long int value, const bool hexadecimal = false) | |||
{ | |||
char strBuf[0xff+1]; | |||
@@ -199,6 +233,9 @@ public: | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Single-precision floating point number. | |||
*/ | |||
explicit d_string(const float value) | |||
{ | |||
char strBuf[0xff+1]; | |||
@@ -209,6 +246,9 @@ public: | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Double-precision floating point number. | |||
*/ | |||
explicit d_string(const double value) | |||
{ | |||
char strBuf[0xff+1]; | |||
@@ -222,6 +262,9 @@ public: | |||
// ------------------------------------------------------------------- | |||
// non-explicit constructor | |||
/* | |||
* Create string from another string. | |||
*/ | |||
d_string(const d_string& str) | |||
{ | |||
_init(); | |||
@@ -231,6 +274,9 @@ public: | |||
// ------------------------------------------------------------------- | |||
// destructor | |||
/* | |||
* Destructor. | |||
*/ | |||
~d_string() | |||
{ | |||
assert(fBuffer != nullptr); | |||
@@ -242,52 +288,64 @@ public: | |||
// ------------------------------------------------------------------- | |||
// public methods | |||
/* | |||
* Get length of the string. | |||
*/ | |||
size_t length() const noexcept | |||
{ | |||
return fBufferLen; | |||
} | |||
/* | |||
* Check if the string is empty. | |||
*/ | |||
bool isEmpty() const noexcept | |||
{ | |||
return (fBufferLen == 0); | |||
} | |||
/* | |||
* Check if the string is not empty. | |||
*/ | |||
bool isNotEmpty() const noexcept | |||
{ | |||
return (fBufferLen != 0); | |||
} | |||
#ifdef __USE_GNU | |||
/* | |||
* Check if the string contains another string, optionally ignoring case. | |||
*/ | |||
bool contains(const char* const strBuf, const bool ignoreCase = false) const | |||
{ | |||
if (strBuf == nullptr) | |||
return false; | |||
if (ignoreCase) | |||
{ | |||
#ifdef __USE_GNU | |||
return (strcasestr(fBuffer, strBuf) != nullptr); | |||
else | |||
return (std::strstr(fBuffer, strBuf) != nullptr); | |||
} | |||
bool contains(const d_string& str, const bool ignoreCase = false) const | |||
{ | |||
return contains(str.fBuffer, ignoreCase); | |||
} | |||
#else | |||
bool contains(const char* const strBuf) const | |||
{ | |||
if (strBuf == nullptr) | |||
return false; | |||
d_string tmp1(fBuffer), tmp2(strBuf); | |||
tmp1.toLower(); | |||
tmp2.toLower(); | |||
return (std::strstr((const char*)tmp1, (const char*)tmp2) != nullptr); | |||
#endif | |||
} | |||
return (std::strstr(fBuffer, strBuf) != nullptr); | |||
} | |||
bool contains(const d_string& str) const | |||
/* | |||
* Overloaded function. | |||
*/ | |||
bool contains(const d_string& str, const bool ignoreCase = false) const | |||
{ | |||
return contains(str.fBuffer); | |||
return contains(str.fBuffer, ignoreCase); | |||
} | |||
#endif | |||
/* | |||
* Check if character at 'pos' is a digit. | |||
*/ | |||
bool isDigit(const size_t pos) const noexcept | |||
{ | |||
if (pos >= fBufferLen) | |||
@@ -296,6 +354,20 @@ public: | |||
return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9'); | |||
} | |||
/* | |||
* Check if the string starts with the character 'c'. | |||
*/ | |||
bool startsWith(const char c) const | |||
{ | |||
if (c == '\0') | |||
return false; | |||
return (fBufferLen > 0 && fBuffer[0] == c); | |||
} | |||
/* | |||
* Check if the string starts with the string 'prefix'. | |||
*/ | |||
bool startsWith(const char* const prefix) const | |||
{ | |||
if (prefix == nullptr) | |||
@@ -309,6 +381,20 @@ public: | |||
return (std::strncmp(fBuffer + (fBufferLen-prefixLen), prefix, prefixLen) == 0); | |||
} | |||
/* | |||
* Check if the string ends with the character 'c'. | |||
*/ | |||
bool endsWith(const char c) const | |||
{ | |||
if (c == '\0') | |||
return false; | |||
return (fBufferLen > 0 && fBuffer[fBufferLen] == c); | |||
} | |||
/* | |||
* Check if the string ends with the string 'suffix'. | |||
*/ | |||
bool endsWith(const char* const suffix) const | |||
{ | |||
if (suffix == nullptr) | |||
@@ -322,56 +408,20 @@ public: | |||
return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0); | |||
} | |||
/* | |||
* Clear the string. | |||
*/ | |||
void clear() noexcept | |||
{ | |||
truncate(0); | |||
} | |||
size_t find(const char c) const noexcept | |||
{ | |||
for (size_t i=0; i < fBufferLen; ++i) | |||
{ | |||
if (fBuffer[i] == c) | |||
return i; | |||
} | |||
return 0; | |||
} | |||
size_t rfind(const char c) const noexcept | |||
{ | |||
for (size_t i=fBufferLen; i > 0; --i) | |||
{ | |||
if (fBuffer[i-1] == c) | |||
return i-1; | |||
} | |||
return 0; | |||
} | |||
size_t rfind(const char* const strBuf) const | |||
{ | |||
if (strBuf == nullptr || strBuf[0] == '\0') | |||
return fBufferLen; | |||
size_t ret = fBufferLen+1; | |||
const char* tmpBuf = fBuffer; | |||
for (size_t i=0; i < fBufferLen; ++i) | |||
{ | |||
if (std::strstr(tmpBuf, strBuf) == nullptr) | |||
break; | |||
--ret; | |||
++tmpBuf; | |||
} | |||
return (ret > fBufferLen) ? fBufferLen : fBufferLen-ret; | |||
} | |||
/* | |||
* Replace all occurrences of character 'before' with character 'after'. | |||
*/ | |||
void replace(const char before, const char after) noexcept | |||
{ | |||
if (after == '\0') | |||
if (before == '\0' || after == '\0') | |||
return; | |||
for (size_t i=0; i < fBufferLen; ++i) | |||
@@ -383,6 +433,9 @@ public: | |||
} | |||
} | |||
/* | |||
* Truncate the string to size 'n'. | |||
*/ | |||
void truncate(const size_t n) noexcept | |||
{ | |||
if (n >= fBufferLen) | |||
@@ -394,6 +447,9 @@ public: | |||
fBufferLen = n; | |||
} | |||
/* | |||
* Convert all non-basic characters to '_'. | |||
*/ | |||
void toBasic() noexcept | |||
{ | |||
for (size_t i=0; i < fBufferLen; ++i) | |||
@@ -411,6 +467,9 @@ public: | |||
} | |||
} | |||
/* | |||
* Convert to all ascii characters to lowercase. | |||
*/ | |||
void toLower() noexcept | |||
{ | |||
static const char kCharDiff('a' - 'A'); | |||
@@ -422,6 +481,9 @@ public: | |||
} | |||
} | |||
/* | |||
* Convert to all ascii characters to uppercase. | |||
*/ | |||
void toUpper() noexcept | |||
{ | |||
static const char kCharDiff('a' - 'A'); | |||
@@ -480,7 +542,10 @@ public: | |||
d_string& operator+=(const char* const strBuf) | |||
{ | |||
const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1; | |||
if (strBuf == nullptr) | |||
return *this; | |||
const size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1; | |||
char newBuf[newBufSize]; | |||
std::strcpy(newBuf, fBuffer); | |||
@@ -502,7 +567,9 @@ public: | |||
char newBuf[newBufSize]; | |||
std::strcpy(newBuf, fBuffer); | |||
std::strcat(newBuf, strBuf); | |||
if (strBuf != nullptr) | |||
std::strcat(newBuf, strBuf); | |||
return d_string(newBuf); | |||
} | |||
@@ -515,10 +582,14 @@ public: | |||
// ------------------------------------------------------------------- | |||
private: | |||
char* fBuffer; | |||
size_t fBufferLen; | |||
bool fFirstInit; | |||
char* fBuffer; // the actual string buffer | |||
size_t fBufferLen; // string length | |||
bool fFirstInit; // true when first initiated | |||
/* | |||
* Shared init function. | |||
* Called on all constructors. | |||
*/ | |||
void _init() noexcept | |||
{ | |||
fBuffer = nullptr; | |||
@@ -526,8 +597,14 @@ private: | |||
fFirstInit = true; | |||
} | |||
// allocate string strBuf if not null | |||
// size > 0 only if strBuf is valid | |||
/* | |||
* Helper function. | |||
* Called whenever the string needs to be allocated. | |||
* | |||
* Notes: | |||
* - Allocates string only if first initiated, or if 'strBuf' is not null and new string contents are different | |||
* - If 'strBuf' is null 'size' must be 0 | |||
*/ | |||
void _dup(const char* const strBuf, const size_t size = 0) | |||
{ | |||
if (strBuf != nullptr) | |||
@@ -580,7 +657,7 @@ static inline | |||
d_string operator+(const d_string& strBefore, const char* const strBufAfter) | |||
{ | |||
const char* const strBufBefore = (const char*)strBefore; | |||
const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1; | |||
const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1; | |||
char newBuf[newBufSize]; | |||
std::strcpy(newBuf, strBufBefore); | |||
@@ -55,12 +55,6 @@ | |||
# error DISTRHO_PLUGIN_WANT_TIMEPOS undefined! | |||
#endif | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
# if ! (defined(DISTRHO_UI_EXTERNAL) || defined(DISTRHO_UI_OPENGL) || defined(DISTRHO_UI_QT)) | |||
# error DISTRHO_PLUGIN_HAS_UI is defined but not its type; please define one of DISTRHO_UI_EXTERNAL, DISTRHO_UI_OPENGL or DISTRHO_UI_QT | |||
# endif | |||
#endif | |||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) | |||
# define DISTRHO_PLUGIN_EXPORT extern "C" __declspec (dllexport) | |||
# define DISTRHO_OS_WINDOWS 1 | |||
@@ -19,16 +19,16 @@ | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
// Static data | |||
// Static data, see DistrhoPluginInternal.hpp | |||
uint32_t d_lastBufferSize = 0; | |||
double d_lastSampleRate = 0.0; | |||
// ----------------------------------------------------------------------- | |||
// Static, fallback data | |||
// Static fallback data, see DistrhoPluginInternal.hpp | |||
const d_string PluginInternal::sFallbackString; | |||
const ParameterRanges PluginInternal::sFallbackRanges; | |||
const d_string PluginExporter::sFallbackString; | |||
const ParameterRanges PluginExporter::sFallbackRanges; | |||
// ----------------------------------------------------------------------- | |||
// Plugin | |||
@@ -92,7 +92,7 @@ void Plugin::d_setLatency(uint32_t frames) noexcept | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
// Callbacks | |||
// Callbacks (optional) | |||
void Plugin::d_bufferSizeChanged(uint32_t) | |||
{ | |||
@@ -22,16 +22,20 @@ | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
// Maxmimum values | |||
#define MAX_MIDI_EVENTS 512 | |||
static const uint32_t kMaxMidiEvents = 512; | |||
// ----------------------------------------------------------------------- | |||
// Static data, see DistrhoPlugin.cpp | |||
extern uint32_t d_lastBufferSize; | |||
extern double d_lastSampleRate; | |||
struct Plugin::PrivateData { | |||
uint32_t bufferSize; | |||
double sampleRate; | |||
// ----------------------------------------------------------------------- | |||
// Plugin private data | |||
struct Plugin::PrivateData { | |||
uint32_t parameterCount; | |||
Parameter* parameters; | |||
@@ -53,12 +57,11 @@ struct Plugin::PrivateData { | |||
TimePos timePos; | |||
#endif | |||
char _d; // dummy | |||
uint32_t bufferSize; | |||
double sampleRate; | |||
PrivateData() | |||
: bufferSize(d_lastBufferSize), | |||
sampleRate(d_lastSampleRate), | |||
parameterCount(0), | |||
PrivateData() noexcept | |||
: parameterCount(0), | |||
parameters(nullptr), | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
programCount(0), | |||
@@ -71,7 +74,8 @@ struct Plugin::PrivateData { | |||
#if DISTRHO_PLUGIN_WANT_LATENCY | |||
latency(0), | |||
#endif | |||
_d(0) | |||
bufferSize(d_lastBufferSize), | |||
sampleRate(d_lastSampleRate) | |||
{ | |||
assert(bufferSize != 0); | |||
assert(sampleRate != 0.0); | |||
@@ -104,11 +108,12 @@ struct Plugin::PrivateData { | |||
}; | |||
// ----------------------------------------------------------------------- | |||
// Plugin exporter class | |||
class PluginInternal | |||
class PluginExporter | |||
{ | |||
public: | |||
PluginInternal() | |||
PluginExporter() | |||
: fPlugin(createPlugin()), | |||
fData((fPlugin != nullptr) ? fPlugin->pData : nullptr) | |||
{ | |||
@@ -131,131 +136,121 @@ public: | |||
#endif | |||
} | |||
~PluginInternal() | |||
~PluginExporter() | |||
{ | |||
if (fPlugin != nullptr) | |||
delete fPlugin; | |||
delete fPlugin; | |||
} | |||
// ------------------------------------------------------------------- | |||
const char* getName() const | |||
const char* getName() const noexcept | |||
{ | |||
assert(fPlugin != nullptr); | |||
return (fPlugin != nullptr) ? fPlugin->d_getName() : ""; | |||
} | |||
const char* getLabel() const | |||
const char* getLabel() const noexcept | |||
{ | |||
assert(fPlugin != nullptr); | |||
return (fPlugin != nullptr) ? fPlugin->d_getLabel() : ""; | |||
} | |||
const char* getMaker() const | |||
const char* getMaker() const noexcept | |||
{ | |||
assert(fPlugin != nullptr); | |||
return (fPlugin != nullptr) ? fPlugin->d_getMaker() : ""; | |||
} | |||
const char* getLicense() const | |||
const char* getLicense() const noexcept | |||
{ | |||
assert(fPlugin != nullptr); | |||
return (fPlugin != nullptr) ? fPlugin->d_getLicense() : ""; | |||
} | |||
uint32_t getVersion() const | |||
uint32_t getVersion() const noexcept | |||
{ | |||
assert(fPlugin != nullptr); | |||
return (fPlugin != nullptr) ? fPlugin->d_getVersion() : 1000; | |||
} | |||
long getUniqueId() const | |||
long getUniqueId() const noexcept | |||
{ | |||
assert(fPlugin != nullptr); | |||
return (fPlugin != nullptr) ? fPlugin->d_getUniqueId() : 0; | |||
} | |||
// ------------------------------------------------------------------- | |||
#if DISTRHO_PLUGIN_WANT_LATENCY | |||
uint32_t getLatency() const | |||
uint32_t getLatency() const noexcept | |||
{ | |||
assert(fData != nullptr); | |||
return (fData != nullptr) ? fData->getLatency : 0; | |||
return (fData != nullptr) ? fData->latency : 0; | |||
} | |||
#endif | |||
uint32_t getParameterCount() const | |||
uint32_t getParameterCount() const noexcept | |||
{ | |||
assert(fData != nullptr); | |||
return (fData != nullptr) ? fData->parameterCount : 0; | |||
} | |||
uint32_t getParameterHints(const uint32_t index) const | |||
uint32_t getParameterHints(const uint32_t index) const noexcept | |||
{ | |||
assert(fData != nullptr && index < fData->parameterCount); | |||
assert(index < fData->parameterCount); | |||
return (fData != nullptr && index < fData->parameterCount) ? fData->parameters[index].hints : 0x0; | |||
} | |||
bool isParameterIsOutput(const uint32_t index) const | |||
bool isParameterOutput(const uint32_t index) const noexcept | |||
{ | |||
return (getParameterHints(index) & PARAMETER_IS_OUTPUT); | |||
} | |||
const d_string& getParameterName(const uint32_t index) const | |||
const d_string& getParameterName(const uint32_t index) const noexcept | |||
{ | |||
assert(fData != nullptr && index < fData->parameterCount); | |||
assert(index < fData->parameterCount); | |||
return (fData != nullptr && index < fData->parameterCount) ? fData->parameters[index].name : sFallbackString; | |||
} | |||
const d_string& getParameterSymbol(const uint32_t index) const | |||
const d_string& getParameterSymbol(const uint32_t index) const noexcept | |||
{ | |||
assert(fData != nullptr && index < fData->parameterCount); | |||
assert(index < fData->parameterCount); | |||
return (fData != nullptr && index < fData->parameterCount) ? fData->parameters[index].symbol : sFallbackString; | |||
} | |||
const d_string& getParameterUnit(const uint32_t index) const | |||
const d_string& getParameterUnit(const uint32_t index) const noexcept | |||
{ | |||
assert(fData != nullptr && index < fData->parameterCount); | |||
assert(index < fData->parameterCount); | |||
return (fData != nullptr && index < fData->parameterCount) ? fData->parameters[index].unit : sFallbackString; | |||
} | |||
const ParameterRanges& getParameterRanges(const uint32_t index) const | |||
const ParameterRanges& getParameterRanges(const uint32_t index) const noexcept | |||
{ | |||
assert(fData != nullptr && index < fData->parameterCount); | |||
assert(index < fData->parameterCount); | |||
return (fData != nullptr && index < fData->parameterCount) ? fData->parameters[index].ranges : sFallbackRanges; | |||
} | |||
float getParameterValue(const uint32_t index) const | |||
float getParameterValue(const uint32_t index) const noexcept | |||
{ | |||
assert(fPlugin != nullptr && index < fData->parameterCount); | |||
assert(index < fData->parameterCount); | |||
return (fPlugin != nullptr && index < fData->parameterCount) ? fPlugin->d_getParameterValue(index) : 0.0f; | |||
} | |||
void setParameterValue(const uint32_t index, const float value) | |||
{ | |||
assert(fPlugin != nullptr && index < fData->parameterCount); | |||
assert(index < fData->parameterCount); | |||
if (fPlugin != nullptr && index < fData->parameterCount) | |||
fPlugin->d_setParameterValue(index, value); | |||
} | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
uint32_t getProgramCount() const | |||
uint32_t getProgramCount() const noexcept | |||
{ | |||
assert(fData != nullptr); | |||
return (fData != nullptr) ? fData->programCount : 0; | |||
} | |||
const d_string& getProgramName(const uint32_t index) const | |||
const d_string& getProgramName(const uint32_t index) const noexcept | |||
{ | |||
assert(fData != nullptr && index < fData->programCount); | |||
assert(index < fData->programCount); | |||
return (fData != nullptr && index < fData->programCount) ? fData->programNames[index] : sFallbackString; | |||
} | |||
void setProgram(const uint32_t index) | |||
{ | |||
assert(fPlugin != nullptr && index < fData->programCount); | |||
assert(index < fData->programCount); | |||
if (fPlugin != nullptr && index < fData->programCount) | |||
fPlugin->d_setProgram(index); | |||
@@ -263,21 +258,20 @@ public: | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
uint32_t getStateCount() const | |||
uint32_t getStateCount() const noexcept | |||
{ | |||
assert(fData != nullptr); | |||
return fData != nullptr ? fData->stateCount : 0; | |||
} | |||
const d_string& getStateKey(const uint32_t index) const | |||
const d_string& getStateKey(const uint32_t index) const noexcept | |||
{ | |||
assert(fData != nullptr && index < fData->stateCount); | |||
assert(index < fData->stateCount); | |||
return (fData != nullptr && index < fData->stateCount) ? fData->stateKeys[index] : sFallbackString; | |||
} | |||
void setState(const char* const key, const char* const value) | |||
{ | |||
assert(fPlugin != nullptr && key != nullptr && value != nullptr); | |||
assert(key != nullptr && value != nullptr); | |||
if (fPlugin != nullptr && key != nullptr && value != nullptr) | |||
fPlugin->d_setState(key, value); | |||
@@ -288,33 +282,34 @@ public: | |||
void activate() | |||
{ | |||
assert(fPlugin != nullptr); | |||
if (fPlugin != nullptr) | |||
fPlugin->d_activate(); | |||
} | |||
void deactivate() | |||
{ | |||
assert(fPlugin != nullptr); | |||
if (fPlugin != nullptr) | |||
fPlugin->d_deactivate(); | |||
} | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
void run(float** const inputs, float** const outputs, const uint32_t frames, const MidiEvent* const midiEvents, const uint32_t midiEventCount) | |||
{ | |||
assert(fPlugin != nullptr); | |||
if (fPlugin != nullptr) | |||
fPlugin->d_run(inputs, outputs, frames, midiEvents, midiEventCount); | |||
} | |||
#else | |||
void run(float** const inputs, float** const outputs, const uint32_t frames) | |||
{ | |||
if (fPlugin != nullptr) | |||
fPlugin->d_run(inputs, outputs, frames); | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
void setBufferSize(const uint32_t bufferSize, bool doCallback = false) | |||
{ | |||
assert(fData != nullptr && fPlugin != nullptr && bufferSize >= 2); | |||
assert(bufferSize >= 2); | |||
if (fData != nullptr) | |||
{ | |||
@@ -334,7 +329,7 @@ public: | |||
void setSampleRate(const double sampleRate, bool doCallback = false) | |||
{ | |||
assert(fData != nullptr && fPlugin != nullptr && sampleRate > 0.0); | |||
assert(sampleRate > 0.0); | |||
if (fData != nullptr) | |||
{ | |||
@@ -352,13 +347,16 @@ public: | |||
} | |||
} | |||
private: | |||
// ------------------------------------------------------------------- | |||
// private members accessed by DistrhoPlugin class | |||
protected: | |||
Plugin* const fPlugin; | |||
Plugin::PrivateData* const fData; | |||
private: | |||
// ------------------------------------------------------------------- | |||
// Static fallback data, see DistrhoPlugin.cpp | |||
static const d_string sFallbackString; | |||
static const ParameterRanges sFallbackRanges; | |||
}; | |||
@@ -32,8 +32,6 @@ | |||
# warning LADSPA/DSSI does not support TimePos | |||
#endif | |||
typedef LADSPA_Data* LADSPA_DataPtr; | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
@@ -54,8 +52,8 @@ public: | |||
{ | |||
const uint32_t count(fPlugin.getParameterCount()); | |||
fPortControls = new LADSPA_DataPtr[count];; | |||
fLastControlValues = new LADSPA_Data[count];; | |||
fPortControls = new LADSPA_Data*[count]; | |||
fLastControlValues = new LADSPA_Data[count]; | |||
for (uint32_t i=0; i < count; ++i) | |||
{ | |||
@@ -86,7 +84,19 @@ public: | |||
// ------------------------------------------------------------------- | |||
void ladspa_connect_port(const unsigned long port, const LADSPA_DataPtr dataLocation) | |||
void ladspa_activate() | |||
{ | |||
fPlugin.activate(); | |||
} | |||
void ladspa_deactivate() | |||
{ | |||
fPlugin.deactivate(); | |||
} | |||
// ------------------------------------------------------------------- | |||
void ladspa_connect_port(const unsigned long port, LADSPA_Data* const dataLocation) | |||
{ | |||
unsigned long index = 0; | |||
@@ -129,91 +139,31 @@ public: | |||
// ------------------------------------------------------------------- | |||
#ifdef DISTRHO_PLUGIN_TARGET_DSSI | |||
# if DISTRHO_PLUGIN_WANT_STATE | |||
char* dssi_configure(const char* const key, const char* const 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; | |||
fPlugin.setState(key, value); | |||
return nullptr; | |||
} | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
const DSSI_Program_Descriptor* dssi_get_program(const unsigned long index) | |||
{ | |||
if (index >= fPlugin.getProgramCount()) | |||
return nullptr; | |||
static DSSI_Program_Descriptor desc; | |||
desc.Bank = index / 128; | |||
desc.Program = index % 128; | |||
desc.Name = fPlugin.getProgramName(index); | |||
return &desc; | |||
} | |||
void dssi_select_program(const unsigned long bank, const unsigned long program) | |||
{ | |||
const unsigned long realProgram(bank * 128 + program); | |||
if (realProgram >= fPlugin.getProgramCount()) | |||
return; | |||
fPlugin.setProgram(realProgram); | |||
// Update parameters | |||
for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | |||
{ | |||
if (fPlugin.isParameterIsOutput(i)) | |||
continue; | |||
fLastControlValues[i] = fPlugin.getParameterValue(i); | |||
if (fPortControls[i] != nullptr) | |||
*fPortControls[i] = fLastControlValues[i]; | |||
} | |||
} | |||
# endif | |||
#endif | |||
// ------------------------------------------------------------------- | |||
void ladspa_activate() | |||
{ | |||
fPlugin.activate(); | |||
} | |||
void ladspa_deactivate() | |||
{ | |||
fPlugin.deactivate(); | |||
} | |||
#ifdef DISTRHO_PLUGIN_TARGET_DSSI | |||
void ladspa_run(const unsigned long bufferSize) | |||
void ladspa_run(const unsigned long sampleCount) | |||
{ | |||
dssi_run_synth(bufferSize, nullptr, 0); | |||
dssi_run_synth(sampleCount, nullptr, 0); | |||
} | |||
void dssi_run_synth(const unsigned long bufferSize, snd_seq_event_t* const events, const unsigned long eventCount) | |||
void dssi_run_synth(const unsigned long sampleCount, snd_seq_event_t* const events, const unsigned long eventCount) | |||
#else | |||
void ladspa_run(const unsigned long bufferSize) | |||
void ladspa_run(const unsigned long sampleCount) | |||
#endif | |||
{ | |||
// pre-roll | |||
if (sampleCount == 0) | |||
return updateParameterOutputs(); | |||
// Check for updated parameters | |||
float curValue; | |||
for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | |||
{ | |||
assert(fPortControls[i] != nullptr); | |||
if (fPortControls[i] == nullptr) | |||
continue; | |||
curValue = *fPortControls[i]; | |||
if (fLastControlValues[i] != curValue && ! fPlugin.isParameterIsOutput(i)) | |||
if (fLastControlValues[i] != curValue && ! fPlugin.isParameterOutput(i)) | |||
{ | |||
fLastControlValues[i] = curValue; | |||
fPlugin.setParameterValue(i, curValue); | |||
@@ -225,94 +175,157 @@ public: | |||
uint32_t midiEventCount = 0; | |||
MidiEvent midiEvents[eventCount]; | |||
for (uint32_t i=0, j; i < eventCount && midiEventCount < MAX_MIDI_EVENTS; ++i) | |||
for (uint32_t i=0, j; i < eventCount; ++i) | |||
{ | |||
const snd_seq_event_t& seqEvent(events[i]); | |||
if (seqEvent.data.note.channel > 0xF) | |||
if (seqEvent.data.note.channel > 0xF || seqEvent.data.control.channel > 0xF) | |||
continue; | |||
switch (seqEvent.type) | |||
{ | |||
case SND_SEQ_EVENT_NOTEON: | |||
case SND_SEQ_EVENT_NOTEOFF: | |||
j = midiEventCount++; | |||
midiEvents[j].frame = seqEvent.time.tick; | |||
midiEvents[j].buf[0] = 0x90 + seqEvent.data.note.channel; | |||
midiEvents[j].size = 3; | |||
midiEvents[j].buf[0] = 0x80 + seqEvent.data.note.channel; | |||
midiEvents[j].buf[1] = seqEvent.data.note.note; | |||
midiEvents[j].buf[2] = seqEvent.data.note.velocity; | |||
midiEvents[j].buf[2] = 0; | |||
midiEvents[j].buf[3] = 0; | |||
midiEvents[j].size = 3; | |||
break; | |||
case SND_SEQ_EVENT_NOTEOFF: | |||
case SND_SEQ_EVENT_NOTEON: | |||
j = midiEventCount++; | |||
midiEvents[j].frame = seqEvent.time.tick; | |||
midiEvents[j].buf[0] = 0x80 + seqEvent.data.note.channel; | |||
midiEvents[j].size = 3; | |||
midiEvents[j].buf[0] = 0x90 + seqEvent.data.note.channel; | |||
midiEvents[j].buf[1] = seqEvent.data.note.note; | |||
midiEvents[j].buf[2] = 0; | |||
midiEvents[j].buf[2] = seqEvent.data.note.velocity; | |||
midiEvents[j].buf[3] = 0; | |||
midiEvents[j].size = 3; | |||
break; | |||
case SND_SEQ_EVENT_KEYPRESS: | |||
j = midiEventCount++; | |||
midiEvents[j].frame = seqEvent.time.tick; | |||
midiEvents[j].size = 3; | |||
midiEvents[j].buf[0] = 0xA0 + seqEvent.data.note.channel; | |||
midiEvents[j].buf[1] = seqEvent.data.note.note; | |||
midiEvents[j].buf[2] = seqEvent.data.note.velocity; | |||
midiEvents[j].buf[3] = 0; | |||
midiEvents[j].size = 3; | |||
break; | |||
case SND_SEQ_EVENT_CONTROLLER: | |||
j = midiEventCount++; | |||
midiEvents[j].frame = seqEvent.time.tick; | |||
midiEvents[j].size = 3; | |||
midiEvents[j].buf[0] = 0xB0 + seqEvent.data.control.channel; | |||
midiEvents[j].buf[1] = seqEvent.data.control.param; | |||
midiEvents[j].buf[2] = seqEvent.data.control.value; | |||
midiEvents[j].buf[3] = 0; | |||
midiEvents[j].size = 3; | |||
break; | |||
case SND_SEQ_EVENT_CHANPRESS: | |||
j = midiEventCount++; | |||
midiEvents[j].frame = seqEvent.time.tick; | |||
midiEvents[j].size = 2; | |||
midiEvents[j].buf[0] = 0xD0 + seqEvent.data.control.channel; | |||
midiEvents[j].buf[1] = seqEvent.data.control.value; | |||
midiEvents[j].buf[2] = 0; | |||
midiEvents[j].buf[3] = 0; | |||
midiEvents[j].size = 2; | |||
break; | |||
#if 0 // TODO | |||
case SND_SEQ_EVENT_PITCHBEND: | |||
j = midiEventCount++; | |||
midiEvents[j].frame = seqEvent.time.tick; | |||
midiEvents[j].size = 3; | |||
midiEvents[j].buf[0] = 0xE0 + seqEvent.data.control.channel; | |||
midiEvents[j].buf[1] = 0; | |||
midiEvents[j].buf[2] = 0; | |||
midiEvents[j].buf[3] = 0; | |||
midiEvents[j].size = 3; | |||
break; | |||
#endif | |||
} | |||
} | |||
fPlugin.run(fPortAudioIns, fPortAudioOuts, bufferSize, midiEvents, midiEventCount); | |||
fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount, midiEvents, midiEventCount); | |||
#else | |||
fPlugin.run(fPortAudioIns, fPortAudioOuts, bufferSize, nullptr, 0); | |||
fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount); | |||
#endif | |||
updateParameterOutputs(); | |||
#if ! DISTRHO_PLUGIN_IS_SYNTH | |||
return; // unused | |||
(void)events; | |||
(void)eventCount; | |||
#endif | |||
} | |||
// ------------------------------------------------------------------- | |||
#ifdef DISTRHO_PLUGIN_TARGET_DSSI | |||
# if DISTRHO_PLUGIN_WANT_STATE | |||
char* dssi_configure(const char* const key, const char* const value) | |||
{ | |||
if (std::strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX, std::strlen(DSSI_RESERVED_CONFIGURE_PREFIX) == 0)) | |||
return nullptr; | |||
if (std::strncmp(key, DSSI_GLOBAL_CONFIGURE_PREFIX, std::strlen(DSSI_GLOBAL_CONFIGURE_PREFIX) == 0)) | |||
return nullptr; | |||
fPlugin.setState(key, value); | |||
return nullptr; | |||
} | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
const DSSI_Program_Descriptor* dssi_get_program(const unsigned long index) | |||
{ | |||
if (index >= fPlugin.getProgramCount()) | |||
return nullptr; | |||
static DSSI_Program_Descriptor desc; | |||
desc.Bank = index / 128; | |||
desc.Program = index % 128; | |||
desc.Name = fPlugin.getProgramName(index); | |||
return &desc; | |||
} | |||
void dssi_select_program(const unsigned long bank, const unsigned long program) | |||
{ | |||
const unsigned long realProgram(bank * 128 + program); | |||
if (realProgram >= fPlugin.getProgramCount()) | |||
return; | |||
fPlugin.setProgram(realProgram); | |||
// Update control inputs | |||
for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | |||
{ | |||
if (fPlugin.isParameterOutput(i)) | |||
continue; | |||
fLastControlValues[i] = fPlugin.getParameterValue(i); | |||
if (fPortControls[i] != nullptr) | |||
*fPortControls[i] = fLastControlValues[i]; | |||
} | |||
} | |||
# endif | |||
#endif | |||
// ------------------------------------------------------------------- | |||
private: | |||
PluginInternal fPlugin; | |||
PluginExporter fPlugin; | |||
LADSPA_DataPtr fPortAudioIns[DISTRHO_PLUGIN_NUM_INPUTS]; | |||
LADSPA_DataPtr fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS]; | |||
LADSPA_DataPtr* fPortControls; | |||
// LADSPA ports | |||
LADSPA_Data* fPortAudioIns[DISTRHO_PLUGIN_NUM_INPUTS]; | |||
LADSPA_Data* fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS]; | |||
LADSPA_Data** fPortControls; | |||
#if DISTRHO_PLUGIN_WANT_LATENCY | |||
LADSPA_DataPtr fPortLatency; | |||
LADSPA_Data* fPortLatency; | |||
#endif | |||
// Temporary data | |||
LADSPA_Data* fLastControlValues; | |||
// ------------------------------------------------------------------- | |||
@@ -321,7 +334,7 @@ private: | |||
{ | |||
for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | |||
{ | |||
if (! fPlugin.isParameterIsOutput(i)) | |||
if (! fPlugin.isParameterOutput(i)) | |||
continue; | |||
fLastControlValues[i] = fPlugin.getParameterValue(i); | |||
@@ -332,7 +345,7 @@ private: | |||
#if DISTRHO_PLUGIN_WANT_LATENCY | |||
if (fPortLatency != nullptr) | |||
*fPortLatency = fPlugin.latency(); | |||
*fPortLatency = fPlugin.getLatency(); | |||
#endif | |||
} | |||
}; | |||
@@ -468,7 +481,7 @@ public: | |||
// Create dummy plugin to get data from | |||
d_lastBufferSize = 512; | |||
d_lastSampleRate = 44100.0; | |||
PluginInternal plugin; | |||
PluginExporter plugin; | |||
d_lastBufferSize = 0; | |||
d_lastSampleRate = 0.0; | |||
@@ -524,7 +537,7 @@ public: | |||
portNames[port] = strdup((const char*)plugin.getParameterName(i)); | |||
portDescriptors[port] = LADSPA_PORT_CONTROL; | |||
if (plugin.isParameterIsOutput(i)) | |||
if (plugin.isParameterOutput(i)) | |||
portDescriptors[port] |= LADSPA_PORT_OUTPUT; | |||
else | |||
portDescriptors[port] |= LADSPA_PORT_INPUT; | |||
@@ -661,3 +674,5 @@ const DSSI_Descriptor* dssi_descriptor(unsigned long index) | |||
return (index == 0) ? &sDssiDescriptor : nullptr; | |||
} | |||
#endif | |||
// ----------------------------------------------------------------------- |
@@ -16,17 +16,20 @@ | |||
#include "DistrhoPluginInternal.hpp" | |||
#include "lv2/lv2.h" | |||
#include "lv2/atom.h" | |||
#include "lv2/atom-util.h" | |||
#include "lv2/buf-size.h" | |||
#include "lv2/midi.h" | |||
#include "lv2/options.h" | |||
#include "lv2/programs.h" | |||
#include "lv2/state.h" | |||
#include "lv2/time.h" | |||
#include "lv2/urid.h" | |||
#include "lv2/worker.h" | |||
#include "lv2/lv2_programs.h" | |||
// #include "lv2/atom-util.h" | |||
// #include "lv2/midi.h" | |||
#ifdef noexcept | |||
# undef noexcept | |||
#endif | |||
#include <map> | |||
@@ -34,9 +37,6 @@ | |||
# error DISTRHO_PLUGIN_URI undefined! | |||
#endif | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
# warning LV2 Synth still TODO | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
# warning LV2 State still TODO | |||
#endif | |||
@@ -44,10 +44,9 @@ | |||
# warning LV2 TimePos still TODO | |||
#endif | |||
#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_STATE || DISTRHO_PLUGIN_WANT_TIMEPOS) | |||
#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_STATE) | |||
#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) | |||
#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | |||
typedef float* floatptr; | |||
typedef std::map<d_string,d_string> StringMap; | |||
START_NAMESPACE_DISTRHO | |||
@@ -60,6 +59,9 @@ public: | |||
PluginLv2(const LV2_URID_Map* const uridMap, const LV2_Worker_Schedule* const worker) | |||
: fPortControls(nullptr), | |||
fLastControlValues(nullptr), | |||
#if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT | |||
fURIDs(uridMap), | |||
#endif | |||
fUridMap(uridMap), | |||
fWorker(worker) | |||
{ | |||
@@ -70,15 +72,15 @@ public: | |||
fPortAudioOuts[i] = nullptr; | |||
{ | |||
const uint32_t count(fPlugin.parameterCount()); | |||
const uint32_t count(fPlugin.getParameterCount()); | |||
fPortControls = new floatptr[count];; | |||
fLastControlValues = new float[count];; | |||
fPortControls = new float*[count]; | |||
fLastControlValues = new float[count]; | |||
for (uint32_t i=0; i < count; ++i) | |||
{ | |||
fPortControls[i] = nullptr; | |||
fLastControlValues[i] = fPlugin.parameterValue(i); | |||
fLastControlValues[i] = fPlugin.getParameterValue(i); | |||
} | |||
} | |||
@@ -91,36 +93,6 @@ public: | |||
#if DISTRHO_PLUGIN_WANT_LATENCY | |||
fPortLatency = nullptr; | |||
#endif | |||
// #if DISTRHO_LV2_USE_EVENTS | |||
// uridIdAtomString = 0; | |||
// # if DISTRHO_PLUGIN_IS_SYNTH | |||
// uridIdMidiEvent = 0; | |||
// # endif | |||
// # if DISTRHO_PLUGIN_WANT_STATE | |||
// # 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; | |||
// } | |||
// } | |||
// #endif | |||
} | |||
~PluginLv2() | |||
@@ -137,11 +109,13 @@ public: | |||
fLastControlValues = nullptr; | |||
} | |||
// #if DISTRHO_PLUGIN_WANT_STATE | |||
// stateMap.clear(); | |||
// #endif | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
fStateMap.clear(); | |||
#endif | |||
} | |||
// ------------------------------------------------------------------- | |||
void lv2_activate() | |||
{ | |||
fPlugin.activate(); | |||
@@ -152,6 +126,8 @@ public: | |||
fPlugin.deactivate(); | |||
} | |||
// ------------------------------------------------------------------- | |||
void lv2_connect_port(const uint32_t port, void* const dataLocation) | |||
{ | |||
uint32_t index = 0; | |||
@@ -160,7 +136,7 @@ public: | |||
{ | |||
if (port == index++) | |||
{ | |||
fPortAudioIns[i] = (floatptr)dataLocation; | |||
fPortAudioIns[i] = (float*)dataLocation; | |||
return; | |||
} | |||
} | |||
@@ -169,7 +145,7 @@ public: | |||
{ | |||
if (port == index++) | |||
{ | |||
fPortAudioOuts[i] = (floatptr)dataLocation; | |||
fPortAudioOuts[i] = (float*)dataLocation; | |||
return; | |||
} | |||
} | |||
@@ -193,77 +169,86 @@ public: | |||
#if DISTRHO_PLUGIN_WANT_LATENCY | |||
if (port == index++) | |||
{ | |||
fPortLatency = (floatptr)dataLocation; | |||
fPortLatency = (float*)dataLocation; | |||
return; | |||
} | |||
#endif | |||
for (uint32_t i=0, count=fPlugin.parameterCount(); i < count; ++i) | |||
for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | |||
{ | |||
if (port == index++) | |||
{ | |||
fPortControls[i] = (floatptr)dataLocation; | |||
fPortControls[i] = (float*)dataLocation; | |||
return; | |||
} | |||
} | |||
} | |||
void lv2_run(const uint32_t bufferSize) | |||
// ------------------------------------------------------------------- | |||
void lv2_run(const uint32_t sampleCount) | |||
{ | |||
if (bufferSize == 0) | |||
{ | |||
updateParameterOutputs(); | |||
return; | |||
} | |||
// pre-roll | |||
if (sampleCount == 0) | |||
return updateParameterOutputs(); | |||
// Check for updated parameters | |||
float curValue; | |||
for (uint32_t i=0, count=fPlugin.parameterCount(); i < count; ++i) | |||
for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | |||
{ | |||
assert(fPortControls[i] != nullptr); | |||
if (fPortControls[i] == nullptr) | |||
continue; | |||
curValue = *fPortControls[i]; | |||
if (fLastControlValues[i] != curValue && ! fPlugin.parameterIsOutput(i)) | |||
if (fLastControlValues[i] != curValue && ! fPlugin.isParameterOutput(i)) | |||
{ | |||
fLastControlValues[i] = curValue; | |||
fPlugin.setParameterValue(i, curValue); | |||
} | |||
} | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
// Get Events, xxx | |||
#if DISTRHO_LV2_USE_EVENTS_IN | |||
# if DISTRHO_PLUGIN_IS_SYNTH | |||
uint32_t midiEventCount = 0; | |||
#if DISTRHO_LV2_USE_EVENTS | |||
LV2_ATOM_SEQUENCE_FOREACH(portEventsIn, iter) | |||
# endif | |||
LV2_ATOM_SEQUENCE_FOREACH(fPortEventsIn, event) | |||
{ | |||
const LV2_Atom_Event* event = /*(const LV2_Atom_Event*)*/iter; | |||
if (! event) | |||
continue; | |||
if (event == nullptr) | |||
break; | |||
# if DISTRHO_PLUGIN_IS_SYNTH | |||
if (event->body.type == uridIdMidiEvent) | |||
if (event->body.type == fURIDs.midiEvent) | |||
{ | |||
if (event->time.frames >= bufferSize || midiEventCount >= MAX_MIDI_EVENTS) | |||
break; | |||
if (event->body.size > 3) | |||
if (event->body.size > 4 || midiEventCount >= kMaxMidiEvents) | |||
continue; | |||
const uint8_t* data = (const uint8_t*)(event + 1); | |||
const uint8_t* data((const uint8_t*)(event + 1)); | |||
MidiEvent& midiEvent(fMidiEvents[midiEventCount]); | |||
midiEvent.frame = event->time.frames; | |||
midiEvent.size = event->body.size; | |||
midiEvents[midiEventCount].frame = event->time.frames; | |||
memcpy(midiEvents[midiEventCount].buffer, data, event->body.size); | |||
uint8_t i; | |||
for (i=0; i < midiEvent.size; ++i) | |||
midiEvent.buf[i] = data[i]; | |||
for (; i < 4; ++i) | |||
midiEvent.buf[i] = 0; | |||
midiEventCount += 1; | |||
++midiEventCount; | |||
continue; | |||
} | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_STATE | |||
if (event->body.type == uridIdPatchMessage) | |||
# if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
if (event->body.type == fURIDs.timePosition) | |||
{ | |||
// TODO | |||
} | |||
# endif | |||
# if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | |||
//if (event->body.type == fURIDs.midiEvent) | |||
{ | |||
// TODO | |||
//if (workerSchedule) | |||
@@ -273,18 +258,38 @@ public: | |||
} | |||
#endif | |||
fPlugin.run(fPortAudioIns, fPortAudioOuts, bufferSize, midiEventCount, midiEvents); | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount, fMidiEvents, midiEventCount); | |||
#else | |||
fPlugin.run(fPortAudioIns, fPortAudioOuts, bufferSize, 0, nullptr); | |||
fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount); | |||
#endif | |||
#if DISTRHO_LV2_USE_EVENTS_OUT | |||
LV2_ATOM_SEQUENCE_FOREACH(fPortEventsOut, event) | |||
{ | |||
if (event == nullptr) | |||
break; | |||
# if DISTRHO_PLUGIN_WANT_STATE | |||
if (event->body.type == fURIDs.midiEvent) | |||
{ | |||
// TODO | |||
//if (workerSchedule) | |||
// workerSchedule->schedule_work(workerSchedule->handle, event->body.size, ) | |||
} | |||
# endif | |||
} | |||
#endif | |||
updateParameterOutputs(); | |||
} | |||
// ------------------------------------------------------------------- | |||
uint32_t lv2_get_options(LV2_Options_Option* const /*options*/) | |||
{ | |||
// currently unused | |||
return LV2_OPTIONS_SUCCESS; | |||
return LV2_OPTIONS_ERR_UNKNOWN; | |||
} | |||
uint32_t lv2_set_options(const LV2_Options_Option* const options) | |||
@@ -297,9 +302,13 @@ public: | |||
{ | |||
const int bufferSize(*(const int*)options[i].value); | |||
fPlugin.setBufferSize(bufferSize); | |||
return LV2_OPTIONS_SUCCESS; | |||
} | |||
else | |||
{ | |||
d_stderr("Host changed maxBlockLength but with wrong value type"); | |||
return LV2_OPTIONS_ERR_BAD_VALUE; | |||
} | |||
} | |||
else if (options[i].key == fUridMap->map(fUridMap->handle, LV2_CORE__sampleRate)) | |||
{ | |||
@@ -307,26 +316,32 @@ public: | |||
{ | |||
const double sampleRate(*(const double*)options[i].value); | |||
fPlugin.setSampleRate(sampleRate); | |||
return LV2_OPTIONS_SUCCESS; | |||
} | |||
else | |||
{ | |||
d_stderr("Host changed sampleRate but with wrong value type"); | |||
return LV2_OPTIONS_ERR_BAD_VALUE; | |||
} | |||
} | |||
} | |||
return LV2_OPTIONS_SUCCESS; | |||
return LV2_OPTIONS_ERR_BAD_KEY; | |||
} | |||
// ------------------------------------------------------------------- | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
const LV2_Program_Descriptor* lv2_get_program(const uint32_t index) | |||
{ | |||
if (index >= fPlugin.programCount()) | |||
if (index >= fPlugin.getProgramCount()) | |||
return nullptr; | |||
static LV2_Program_Descriptor desc; | |||
desc.bank = index / 128; | |||
desc.program = index % 128; | |||
desc.name = fPlugin.programName(index); | |||
desc.name = fPlugin.getProgramName(index); | |||
return &desc; | |||
} | |||
@@ -335,64 +350,68 @@ public: | |||
{ | |||
const uint32_t realProgram(bank * 128 + program); | |||
if (realProgram >= fPlugin.programCount()) | |||
if (realProgram >= fPlugin.getProgramCount()) | |||
return; | |||
fPlugin.setProgram(realProgram); | |||
// Update parameters | |||
for (uint32_t i=0, count=fPlugin.parameterCount(); i < count; ++i) | |||
// Update control inputs | |||
for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | |||
{ | |||
if (! fPlugin.parameterIsOutput(i)) | |||
{ | |||
fLastControlValues[i] = fPlugin.parameterValue(i); | |||
if (fPlugin.isParameterOutput(i)) | |||
continue; | |||
if (fPortControls[i] != nullptr) | |||
*fPortControls[i] = fLastControlValues[i]; | |||
} | |||
fLastControlValues[i] = fPlugin.getParameterValue(i); | |||
if (fPortControls[i] != nullptr) | |||
*fPortControls[i] = fLastControlValues[i]; | |||
} | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
LV2_State_Status lv2_save(LV2_State_Store_Function store, LV2_State_Handle handle, const uint32_t flags, const LV2_Feature* const* /*features*/) | |||
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; | |||
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); | |||
// } | |||
for (auto it = fStateMap.begin(), end = fStateMap.end(); it != end; ++it) | |||
{ | |||
const d_string& key = it->first; | |||
const d_string& value = it->second; | |||
store(handle, fUridMap->map(fUridMap->handle, (const char*)key), (const char*)value, value.length()+1, fURIDs.atomString, flags); | |||
} | |||
return LV2_STATE_SUCCESS; | |||
} | |||
LV2_State_Status lv2_restore(LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, const uint32_t flags, const LV2_Feature* const* /*features*/) | |||
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); | |||
// } | |||
size_t size; | |||
uint32_t type; | |||
for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) | |||
{ | |||
const d_string& key = fPlugin.getStateKey(i); | |||
const void* data = retrieve(handle, fUridMap->map(fUridMap->handle, (const char*)key), &size, &type, &flags); | |||
if (size == 0 || data == nullptr) | |||
continue; | |||
if (type != fURIDs.atomString) | |||
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*/, const uint32_t /*size*/, const void* /*data*/) | |||
{ | |||
// TODO | |||
@@ -406,13 +425,15 @@ public: | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
private: | |||
PluginInternal fPlugin; | |||
PluginExporter fPlugin; | |||
// LV2 ports | |||
floatptr fPortAudioIns[DISTRHO_PLUGIN_NUM_INPUTS]; | |||
floatptr fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS]; | |||
floatptr* fPortControls; | |||
float* fPortAudioIns[DISTRHO_PLUGIN_NUM_INPUTS]; | |||
float* fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS]; | |||
float** fPortControls; | |||
#if DISTRHO_LV2_USE_EVENTS_IN | |||
LV2_Atom_Sequence* fPortEventsIn; | |||
#endif | |||
@@ -420,75 +441,74 @@ private: | |||
LV2_Atom_Sequence* fPortEventsOut; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_LATENCY | |||
floatptr fPortLatency; | |||
float* fPortLatency; | |||
#endif | |||
// Temporary data | |||
float* fLastControlValues; | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
MidiEvent fMidiEvents[kMaxMidiEvents]; | |||
#endif | |||
// #if DISTRHO_PLUGIN_IS_SYNTH | |||
// MidiEvent fMidiEvents[MAX_MIDI_EVENTS]; | |||
// #endif | |||
// LV2 URIDs | |||
#if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT | |||
struct URIDs { | |||
LV2_URID atomString; | |||
LV2_URID midiEvent; | |||
LV2_URID timePosition; | |||
URIDs(const LV2_URID_Map* const uridMap) | |||
: atomString(uridMap->map(uridMap->handle, LV2_ATOM__String)), | |||
midiEvent(uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent)), | |||
timePosition(uridMap->map(uridMap->handle, LV2_TIME__Position)) {} | |||
} fURIDs; | |||
#endif | |||
// Feature data | |||
// LV2 features | |||
const LV2_URID_Map* const fUridMap; | |||
const LV2_Worker_Schedule* const fWorker; | |||
// xxx | |||
// #if DISTRHO_LV2_USE_EVENTS | |||
// | |||
// // 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 | |||
// #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 | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
StringMap fStateMap; | |||
void updateParameterOutputs() | |||
void setState(const char* const newKey, const char* const newValue) | |||
{ | |||
for (uint32_t i=0, count=fPlugin.parameterCount(); i < count; ++i) | |||
fPlugin.setState(newKey, newValue); | |||
// check if key already exists | |||
for (auto it = fStateMap.begin(), end = fStateMap.end(); it != end; ++it) | |||
{ | |||
if (fPlugin.parameterIsOutput(i)) | |||
{ | |||
fLastControlValues[i] = fPlugin.parameterValue(i); | |||
const d_string& key = it->first; | |||
if (fPortControls[i] != nullptr) | |||
*fPortControls[i] = fLastControlValues[i]; | |||
if (key == newKey) | |||
{ | |||
it->second = newValue; | |||
return; | |||
} | |||
} | |||
// add a new one then | |||
d_string d_key(newKey); | |||
fStateMap[d_key] = newValue; | |||
} | |||
#endif | |||
void updateParameterOutputs() | |||
{ | |||
for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | |||
{ | |||
if (! fPlugin.isParameterOutput(i)) | |||
continue; | |||
fLastControlValues[i] = fPlugin.getParameterValue(i); | |||
if (fPortControls[i] != nullptr) | |||
*fPortControls[i] = fLastControlValues[i]; | |||
} | |||
#if DISTRHO_PLUGIN_WANT_LATENCY | |||
if (fPortLatency != nullptr) | |||
*fPortLatency = fPlugin.latency(); | |||
*fPortLatency = fPlugin.getLatency(); | |||
#endif | |||
} | |||
}; | |||
@@ -511,12 +531,26 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, cons | |||
worker = (const LV2_Worker_Schedule*)features[i]->data; | |||
} | |||
if (options == nullptr) | |||
{ | |||
d_stderr("Options feature missing, cannot continue!"); | |||
return nullptr; | |||
} | |||
if (uridMap == nullptr) | |||
{ | |||
d_stderr("URID Map feature missing, cannot continue!"); | |||
return nullptr; | |||
} | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
if (worker == nullptr) | |||
{ | |||
d_stderr("Worker feature missing, cannot continue!"); | |||
return nullptr; | |||
} | |||
#endif | |||
for (int i=0; options[i].key != 0; ++i) | |||
{ | |||
if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength)) | |||
@@ -531,7 +565,7 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, cons | |||
} | |||
if (d_lastBufferSize == 0) | |||
d_lastBufferSize = 512; | |||
d_lastBufferSize = 2048; | |||
d_lastSampleRate = sampleRate; | |||
@@ -565,6 +599,8 @@ static void lv2_cleanup(LV2_Handle instance) | |||
delete instancePtr; | |||
} | |||
// ----------------------------------------------------------------------- | |||
static uint32_t lv2_get_options(LV2_Handle instance, LV2_Options_Option* options) | |||
{ | |||
return instancePtr->lv2_get_options(options); | |||
@@ -575,6 +611,8 @@ static uint32_t lv2_set_options(LV2_Handle instance, const LV2_Options_Option* o | |||
return instancePtr->lv2_set_options(options); | |||
} | |||
// ----------------------------------------------------------------------- | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
static const LV2_Program_Descriptor* lv2_get_program(LV2_Handle instance, uint32_t index) | |||
{ | |||
@@ -587,6 +625,8 @@ static void lv2_select_program(LV2_Handle instance, uint32_t bank, uint32_t prog | |||
} | |||
#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) | |||
{ | |||
@@ -609,6 +649,8 @@ LV2_Worker_Status lv2_work_response(LV2_Handle instance, uint32_t size, const vo | |||
} | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
static const void* lv2_extension_data(const char* uri) | |||
{ | |||
static const LV2_Options_Interface options = { lv2_get_options, lv2_set_options }; | |||
@@ -640,7 +682,7 @@ static const void* lv2_extension_data(const char* uri) | |||
// ----------------------------------------------------------------------- | |||
static LV2_Descriptor sLv2Descriptor = { | |||
static const LV2_Descriptor sLv2Descriptor = { | |||
DISTRHO_PLUGIN_URI, | |||
lv2_instantiate, | |||
lv2_connect_port, | |||
@@ -661,3 +703,5 @@ const LV2_Descriptor* lv2_descriptor(uint32_t index) | |||
USE_NAMESPACE_DISTRHO | |||
return (index == 0) ? &sLv2Descriptor : nullptr; | |||
} | |||
// ----------------------------------------------------------------------- |
@@ -16,18 +16,17 @@ | |||
#include "DistrhoPluginInternal.hpp" | |||
#include "lv2/lv2.h" | |||
#include "lv2/atom.h" | |||
#include "lv2/buf-size.h" | |||
// #include "lv2/midi.h" | |||
#include "lv2/midi.h" | |||
#include "lv2/options.h" | |||
#include "lv2/programs.h" | |||
// #include "lv2/state.h" | |||
#include "lv2/state.h" | |||
#include "lv2/time.h" | |||
// #include "lv2/ui.h" | |||
#include "lv2/urid.h" | |||
#include "lv2/ui.h" | |||
#include "lv2/units.h" | |||
// #include "lv2/worker.h" | |||
#include "lv2/urid.h" | |||
#include "lv2/worker.h" | |||
#include "lv2/lv2_programs.h" | |||
#include <fstream> | |||
#include <iostream> | |||
@@ -36,20 +35,8 @@ | |||
# error DISTRHO_PLUGIN_URI undefined! | |||
#endif | |||
// TODO: UI | |||
#undef DISTRHO_PLUGIN_HAS_UI | |||
#undef DISTRHO_PLUGIN_WANT_LATENCY | |||
#undef DISTRHO_PLUGIN_WANT_PROGRAMS | |||
#undef DISTRHO_PLUGIN_WANT_STATE | |||
#undef DISTRHO_PLUGIN_WANT_TIMEPOS | |||
#define DISTRHO_PLUGIN_WANT_LATENCY 1 | |||
#define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | |||
#define DISTRHO_PLUGIN_WANT_STATE 1 | |||
#define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | |||
#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_STATE || DISTRHO_PLUGIN_WANT_TIMEPOS) | |||
#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_STATE) | |||
#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) | |||
#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | |||
// ----------------------------------------------------------------------- | |||
@@ -61,7 +48,7 @@ void lv2_generate_ttl(const char* const basename) | |||
// Dummy plugin to get data from | |||
d_lastBufferSize = 512; | |||
d_lastSampleRate = 44100.0; | |||
PluginInternal plugin; | |||
PluginExporter plugin; | |||
d_lastBufferSize = 0; | |||
d_lastSampleRate = 0.0; | |||
@@ -99,14 +86,18 @@ void lv2_generate_ttl(const char* const basename) | |||
# else | |||
manifestString += " a ui:X11UI ;\n"; | |||
# endif | |||
manifestString += " ui:binary <" + pluginLabel + "_ui." DISTRHO_DLL_EXTENSION "> .\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"; | |||
manifestString += " ui:binary <" + pluginLabel + "_ui." DISTRHO_DLL_EXTENSION "> ;\n"; | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
manifestString += " lv2:extensionData ui:idleInterface ,\n"; | |||
manifestString += " <" LV2_PROGRAMS__Interface "> ;\n"; | |||
#else | |||
manifestString += " lv2:extensionData ui:idleInterface ;\n"; | |||
#endif | |||
manifestString += " lv2:optionalFeature ui:noUserResize ,\n"; | |||
manifestString += " ui:touch ;\n"; | |||
manifestString += " lv2:requiredFeature ui:resize ,\n"; | |||
manifestString += " <" LV2_OPTIONS__options "> ,\n"; | |||
manifestString += " <" LV2_URID__map "> .\n"; | |||
#endif | |||
manifestFile << manifestString << std::endl; | |||
@@ -121,6 +112,8 @@ void lv2_generate_ttl(const char* const basename) | |||
std::fstream pluginFile(pluginTTL, std::ios::out); | |||
d_string pluginString; | |||
// header | |||
#if DISTRHO_LV2_USE_EVENTS_IN | |||
pluginString += "@prefix atom: <" LV2_ATOM_PREFIX "> .\n"; | |||
#endif | |||
@@ -133,6 +126,7 @@ void lv2_generate_ttl(const char* const basename) | |||
pluginString += "@prefix unit: <" LV2_UNITS_PREFIX "> .\n"; | |||
pluginString += "\n"; | |||
// plugin | |||
pluginString += "<" DISTRHO_PLUGIN_URI ">\n"; | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
pluginString += " a lv2:InstrumentPlugin, lv2:Plugin ;\n"; | |||
@@ -141,35 +135,31 @@ void lv2_generate_ttl(const char* const basename) | |||
#endif | |||
pluginString += "\n"; | |||
#if (DISTRHO_PLUGIN_WANT_STATE || DISTRHO_PLUGIN_WANT_PROGRAMS) | |||
pluginString += " lv2:extensionData <" LV2_OPTIONS__interface "> ,\n"; | |||
# if DISTRHO_PLUGIN_WANT_STATE | |||
pluginString += " <" LV2_STATE__interface "> ,\n"; | |||
pluginString += " <" LV2_WORKER__interface "> \n"; | |||
# if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
pluginString += ",\n"; | |||
# else | |||
pluginString += ";\n"; | |||
# endif | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
pluginString += " <" LV2_PROGRAMS__Interface "> ;\n"; | |||
# endif | |||
// extensionData | |||
pluginString += " lv2:extensionData <" LV2_OPTIONS__interface "> "; | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
pluginString += ",\n <" LV2_OPTIONS__interface "> "; | |||
pluginString += ",\n <" LV2_WORKER__interface "> "; | |||
#endif | |||
pluginString += "\n"; | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
pluginString += ",\n <" LV2_PROGRAMS__Interface "> "; | |||
#endif | |||
pluginString += ";\n\n"; | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
// optionalFeatures | |||
pluginString += " lv2:optionalFeature <" LV2_CORE__hardRTCapable "> ,\n"; | |||
pluginString += " <" LV2_WORKER__schedule "> ;\n"; | |||
#else | |||
pluginString += " lv2:optionalFeature <" LV2_CORE__hardRTCapable "> ;\n"; | |||
#endif | |||
pluginString += " <" LV2_BUF_SIZE__boundedBlockLength "> ;\n"; | |||
pluginString += "\n"; | |||
pluginString += " lv2:requiredFeature <" LV2_BUF_SIZE__boundedBlockLength "> ,\n"; | |||
pluginString += " <" LV2_URID__map "> ;\n"; | |||
pluginString += "\n"; | |||
// requiredFeatures | |||
pluginString += " lv2:requiredFeature <" LV2_OPTIONS__options "> "; | |||
pluginString += ",\n <" LV2_URID__map "> "; | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
pluginString += ",\n <" LV2_WORKER__schedule "> "; | |||
#endif | |||
pluginString += ";\n\n"; | |||
// UI | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
pluginString += " ui:ui <" DISTRHO_UI_URI "> ;\n"; | |||
pluginString += "\n"; | |||
@@ -178,7 +168,7 @@ void lv2_generate_ttl(const char* const basename) | |||
{ | |||
uint32_t portIndex = 0; | |||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) | |||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++portIndex) | |||
{ | |||
if (i == 0) | |||
pluginString += " lv2:port [\n"; | |||
@@ -186,7 +176,7 @@ void lv2_generate_ttl(const char* const basename) | |||
pluginString += " [\n"; | |||
pluginString += " a lv2:InputPort, lv2:AudioPort ;\n"; | |||
pluginString += " lv2:index " + d_string(portIndex++) + " ;\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"; | |||
@@ -196,7 +186,7 @@ void lv2_generate_ttl(const char* const basename) | |||
pluginString += " ] ,\n"; | |||
} | |||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) | |||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++portIndex) | |||
{ | |||
if (i == 0) | |||
pluginString += " lv2:port [\n"; | |||
@@ -204,7 +194,7 @@ void lv2_generate_ttl(const char* const basename) | |||
pluginString += " [\n"; | |||
pluginString += " a lv2:OutputPort, lv2:AudioPort ;\n"; | |||
pluginString += " lv2:index " + d_string(portIndex++) + " ;\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"; | |||
@@ -217,19 +207,22 @@ void lv2_generate_ttl(const char* const basename) | |||
#if DISTRHO_LV2_USE_EVENTS_IN | |||
pluginString += " lv2:port [\n"; | |||
pluginString += " a lv2:InputPort, atom:AtomPort ;\n"; | |||
pluginString += " lv2:index " + d_string(portIndex++) + " ;\n"; | |||
pluginString += " lv2: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_TIMEPOS) // TODO | |||
pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ,\n"; | |||
pluginString += " <" LV2_TIME__Position "> ;\n"; | |||
# elif DISTRHO_PLUGIN_IS_SYNTH | |||
pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | |||
# else | |||
# if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | |||
pluginString += " atom:supports <" LV2_ATOM__String "> ;\n"; | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
pluginString += " atom:supports <" LV2_TIME__Position "> ;\n"; | |||
# endif | |||
# if DISTRHO_PLUGIN_IS_SYNTH | |||
pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | |||
# endif | |||
pluginString += " ] ;\n"; | |||
++portIndex; | |||
#endif | |||
#if DISTRHO_LV2_USE_EVENTS_OUT | |||
@@ -239,38 +232,41 @@ void lv2_generate_ttl(const char* const basename) | |||
pluginString += " lv2:name \"Events Output\" ;\n"; | |||
pluginString += " lv2:symbol \"lv2_events_out\" ;\n"; | |||
pluginString += " atom:bufferType atom:Sequence ;\n"; | |||
pluginString += " atom:supports <something_here> ;\n"; // TODO | |||
pluginString += " atom:supports <" LV2_ATOM__String "> ;\n"; | |||
pluginString += " ] ;\n"; | |||
++portIndex; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_LATENCY | |||
pluginString += " lv2:port [\n"; | |||
pluginString += " a lv2:OutputPort, lv2:ControlPort ;\n"; | |||
pluginString += " lv2:index " + d_string(portIndex++) + " ;\n"; | |||
pluginString += " lv2:index " + d_string(portIndex) + " ;\n"; | |||
pluginString += " lv2:name \"Latency\" ;\n"; | |||
pluginString += " lv2:symbol \"lv2_latency\" ;\n"; | |||
pluginString += " lv2:designation lv2:latency ;\n"; | |||
pluginString += " lv2:portProperty lv2:reportsLatency ;\n"; | |||
pluginString += " ] ;\n"; | |||
++portIndex; | |||
#endif | |||
for (uint32_t i=0; i < plugin.parameterCount(); ++i) | |||
for (uint32_t i=0, count=plugin.getParameterCount(); i < count; ++i, ++portIndex) | |||
{ | |||
if (i == 0) | |||
pluginString += " lv2:port [\n"; | |||
else | |||
pluginString += " [\n"; | |||
if (plugin.parameterIsOutput(i)) | |||
if (plugin.isParameterOutput(i)) | |||
pluginString += " a lv2:OutputPort, lv2:ControlPort ;\n"; | |||
else | |||
pluginString += " a lv2:InputPort, lv2:ControlPort ;\n"; | |||
pluginString += " lv2:index " + d_string(portIndex++) + " ;\n"; | |||
pluginString += " lv2:name \"" + plugin.parameterName(i) + "\" ;\n"; | |||
pluginString += " lv2:index " + d_string(portIndex) + " ;\n"; | |||
pluginString += " lv2:name \"" + plugin.getParameterName(i) + "\" ;\n"; | |||
// symbol | |||
{ | |||
d_string symbol(plugin.parameterSymbol(i)); | |||
d_string symbol(plugin.getParameterSymbol(i)); | |||
if (symbol.isEmpty()) | |||
symbol = "lv2_port_" + d_string(portIndex-1); | |||
@@ -280,17 +276,17 @@ void lv2_generate_ttl(const char* const basename) | |||
// ranges | |||
{ | |||
const ParameterRanges& ranges(plugin.parameterRanges(i)); | |||
const ParameterRanges& ranges(plugin.getParameterRanges(i)); | |||
if (plugin.parameterHints(i) & PARAMETER_IS_INTEGER) | |||
if (plugin.getParameterHints(i) & PARAMETER_IS_INTEGER) | |||
{ | |||
pluginString += " lv2:default " + d_string(int(plugin.parameterValue(i))) + " ;\n"; | |||
pluginString += " lv2:default " + d_string(int(plugin.getParameterValue(i))) + " ;\n"; | |||
pluginString += " lv2:minimum " + d_string(int(ranges.min)) + " ;\n"; | |||
pluginString += " lv2:maximum " + d_string(int(ranges.max)) + " ;\n"; | |||
} | |||
else | |||
{ | |||
pluginString += " lv2:default " + d_string(plugin.parameterValue(i)) + " ;\n"; | |||
pluginString += " lv2:default " + d_string(plugin.getParameterValue(i)) + " ;\n"; | |||
pluginString += " lv2:minimum " + d_string(ranges.min) + " ;\n"; | |||
pluginString += " lv2:maximum " + d_string(ranges.max) + " ;\n"; | |||
} | |||
@@ -298,7 +294,7 @@ void lv2_generate_ttl(const char* const basename) | |||
// unit | |||
{ | |||
const d_string& unit(plugin.parameterUnit(i)); | |||
const d_string& unit(plugin.getParameterUnit(i)); | |||
if (! unit.isEmpty()) | |||
{ | |||
@@ -332,7 +328,7 @@ void lv2_generate_ttl(const char* const basename) | |||
// hints | |||
{ | |||
const uint32_t hints(plugin.parameterHints(i)); | |||
const uint32_t hints(plugin.getParameterHints(i)); | |||
if (hints & PARAMETER_IS_BOOLEAN) | |||
pluginString += " lv2:portProperty lv2:toggled ;\n"; | |||
@@ -340,17 +336,19 @@ void lv2_generate_ttl(const char* const basename) | |||
pluginString += " lv2:portProperty lv2:integer ;\n"; | |||
if (hints & PARAMETER_IS_LOGARITHMIC) | |||
pluginString += " lv2:portProperty <http://lv2plug.in/ns/ext/port-props#logarithmic> ;\n"; | |||
if ((hints & PARAMETER_IS_AUTOMABLE) == 0 && ! plugin.isParameterOutput(i)) | |||
pluginString += " lv2:portProperty <http://lv2plug.in/ns/ext/port-props#expensive> ;\n"; | |||
} | |||
if (i+1 == plugin.parameterCount()) | |||
if (i+1 == count) | |||
pluginString += " ] ;\n\n"; | |||
else | |||
pluginString += " ] ,\n"; | |||
} | |||
} | |||
pluginString += " doap:name \"" + d_string(plugin.name()) + "\" ;\n"; | |||
pluginString += " doap:maintainer [ foaf:name \"" + d_string(plugin.maker()) + "\" ] .\n"; | |||
pluginString += " doap:name \"" + d_string(plugin.getName()) + "\" ;\n"; | |||
pluginString += " doap:maintainer [ foaf:name \"" + d_string(plugin.getMaker()) + "\" ] .\n"; | |||
pluginFile << pluginString << std::endl; | |||
pluginFile.close(); | |||
@@ -18,9 +18,6 @@ | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
# include "DistrhoUIInternal.hpp" | |||
# ifdef DISTRHO_UI_QT | |||
# include <QtGui/QApplication> | |||
# endif | |||
#endif | |||
#ifndef __cdecl | |||
@@ -40,62 +37,27 @@ START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
# ifdef DISTRHO_UI_QT | |||
class QStaticScopedAppInit | |||
void strncpy(char* const dst, const char* const src, const size_t size) | |||
{ | |||
public: | |||
QStaticScopedAppInit() | |||
: fApp(nullptr), | |||
fInitiated(false) {} | |||
void initIfNeeded() | |||
{ | |||
if (fInitiated) | |||
return; | |||
fInitiated = true; | |||
if (QApplication* app = qApp) | |||
{ | |||
fApp = app; | |||
} | |||
else | |||
{ | |||
static int qargc = 0; | |||
static char* qargv[] = { nullptr }; | |||
fApp = new QApplication(qargc, qargv, true); | |||
fApp->setQuitOnLastWindowClosed(false); | |||
} | |||
} | |||
void idle() | |||
{ | |||
initIfNeeded(); | |||
fApp->processEvents(); | |||
} | |||
private: | |||
QApplication* fApp; | |||
bool fInitiated; | |||
}; | |||
std::strncpy(dst, src, size); | |||
dst[size] = '\0'; | |||
} | |||
static QStaticScopedAppInit sApp; | |||
# endif | |||
// ----------------------------------------------------------------------- | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
class UIVst | |||
{ | |||
public: | |||
UIVst(audioMasterCallback audioMaster, AEffect* effect, PluginInternal* plugin, intptr_t winId) | |||
: kAudioMaster(audioMaster), | |||
kEffect(effect), | |||
kPlugin(plugin), | |||
fUi(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, uiResizeCallback), | |||
UIVst(const audioMasterCallback audioMaster, AEffect* const effect, PluginExporter* const plugin, const intptr_t winId) | |||
: fAudioMaster(audioMaster), | |||
fEffect(effect), | |||
fPlugin(plugin), | |||
fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, uiResizeCallback), | |||
fParameterChecks(nullptr), | |||
fParameterValues(nullptr) | |||
{ | |||
const uint32_t paramCount(plugin->parameterCount()); | |||
const uint32_t paramCount(plugin->getParameterCount()); | |||
if (paramCount > 0) | |||
{ | |||
@@ -112,10 +74,6 @@ public: | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
fNextProgram = -1; | |||
#endif | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
fMidiEventCount = 0; | |||
#endif | |||
} | |||
~UIVst() | |||
@@ -140,54 +98,49 @@ public: | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
if (fNextProgram != -1) | |||
{ | |||
fUi.programChanged(fNextProgram); | |||
fUI.programChanged(fNextProgram); | |||
fNextProgram = -1; | |||
} | |||
#endif | |||
for (uint32_t i=0, count = kPlugin->parameterCount(); i < count; ++i) | |||
for (uint32_t i=0, count = fPlugin->getParameterCount(); i < count; ++i) | |||
{ | |||
if (fParameterChecks[i]) | |||
{ | |||
fParameterChecks[i] = false; | |||
fUi.parameterChanged(i, fParameterValues[i]); | |||
fUI.parameterChanged(i, fParameterValues[i]); | |||
} | |||
} | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
// TODO - notes | |||
#endif | |||
fUi.idle(); | |||
fUI.idle(); | |||
} | |||
int16_t getWidth() const | |||
int16_t getWidth() const noexcept | |||
{ | |||
return fUi.width(); | |||
return fUI.getWidth(); | |||
} | |||
int16_t getHeight() const | |||
int16_t getHeight() const noexcept | |||
{ | |||
return fUi.height(); | |||
return fUI.getHeight(); | |||
} | |||
// ------------------------------------------------------------------- | |||
// functions called from the plugin side, RT no block | |||
void setParameterValueFromPlugin(uint32_t index, float perValue) | |||
void setParameterValueFromPlugin(const uint32_t index, const float perValue) | |||
{ | |||
fParameterChecks[index] = true; | |||
fParameterValues[index] = perValue; | |||
} | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
void setProgramFromPlugin(uint32_t index) | |||
void setProgramFromPlugin(const uint32_t index) | |||
{ | |||
fNextProgram = index; | |||
// set previous parameters invalid | |||
for (uint32_t i=0, count = kPlugin->parameterCount(); i < count; ++i) | |||
for (uint32_t i=0, count = fPlugin->getParameterCount(); i < count; ++i) | |||
fParameterChecks[i] = false; | |||
} | |||
#endif | |||
@@ -195,12 +148,12 @@ public: | |||
// ------------------------------------------------------------------- | |||
protected: | |||
intptr_t hostCallback(int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) | |||
intptr_t hostCallback(const int32_t opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt) | |||
{ | |||
return kAudioMaster(kEffect, opcode, index, value, ptr, opt); | |||
return fAudioMaster(fEffect, opcode, index, value, ptr, opt); | |||
} | |||
void editParameter(uint32_t index, bool started) | |||
void editParameter(const uint32_t index, const bool started) | |||
{ | |||
if (started) | |||
hostCallback(audioMasterBeginEdit, index, 0, nullptr, 0.0f); | |||
@@ -208,61 +161,59 @@ protected: | |||
hostCallback(audioMasterEndEdit, index, 0, nullptr, 0.0f); | |||
} | |||
void setParameterValue(uint32_t index, float realValue) | |||
void setParameterValue(const uint32_t index, const float realValue) | |||
{ | |||
const ParameterRanges& ranges(kPlugin->parameterRanges(index)); | |||
const float perValue(ranges.normalizedValue(realValue)); | |||
const ParameterRanges& ranges(fPlugin->getParameterRanges(index)); | |||
const float perValue(ranges.getNormalizedValue(realValue)); | |||
kPlugin->setParameterValue(index, realValue); | |||
fPlugin->setParameterValue(index, realValue); | |||
hostCallback(audioMasterAutomate, index, 0, nullptr, perValue); | |||
} | |||
void setState(const char* key, const char* value) | |||
void setState(const char* const key, const char* const value) | |||
{ | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
kPlugin->setState(key, value); | |||
fPlugin->setState(key, value); | |||
#else | |||
return; // unused | |||
(void)key; | |||
(void)value; | |||
#endif | |||
} | |||
void sendNote(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity) | |||
void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity) | |||
{ | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
// TODO | |||
#endif | |||
return; | |||
// unused | |||
(void)onOff; | |||
#else | |||
return; // unused | |||
(void)channel; | |||
(void)note; | |||
(void)velocity; | |||
#endif | |||
} | |||
void uiResize(unsigned int width, unsigned int height) | |||
void uiResize(const unsigned int width, const unsigned int height) | |||
{ | |||
fUI.setSize(width, height); | |||
hostCallback(audioMasterSizeWindow, width, height, nullptr, 0.0f); | |||
} | |||
private: | |||
// Vst stuff | |||
audioMasterCallback const kAudioMaster; | |||
AEffect* const kEffect; | |||
PluginInternal* const kPlugin; | |||
const audioMasterCallback fAudioMaster; | |||
AEffect* const fEffect; | |||
PluginExporter* const fPlugin; | |||
// Plugin UI | |||
UIInternal fUi; | |||
UIExporter fUI; | |||
// Temporary data | |||
bool* fParameterChecks; | |||
float* fParameterValues; | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
int32_t fNextProgram; | |||
#endif | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
uint32_t fMidiEventCount; | |||
MidiEvent fMidiEvents[MAX_MIDI_EVENTS]; | |||
#endif | |||
// ------------------------------------------------------------------- | |||
// Callbacks | |||
@@ -284,9 +235,9 @@ private: | |||
handlePtr->setState(key, value); | |||
} | |||
static void sendNoteCallback(void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velocity) | |||
static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity) | |||
{ | |||
handlePtr->sendNote(onOff, channel, note, velocity); | |||
handlePtr->sendNote(channel, note, velocity); | |||
} | |||
static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height) | |||
@@ -303,18 +254,10 @@ private: | |||
class PluginVst | |||
{ | |||
public: | |||
PluginVst(audioMasterCallback audioMaster, AEffect* effect) | |||
: kAudioMaster(audioMaster), | |||
kEffect(effect) | |||
PluginVst(const audioMasterCallback audioMaster, AEffect* const effect) | |||
: fAudioMaster(audioMaster), | |||
fEffect(effect) | |||
{ | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
fVstUi = nullptr; | |||
fVstRect.top = 0; | |||
fVstRect.left = 0; | |||
fVstRect.bottom = 0; | |||
fVstRect.right = 0; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
fCurProgram = -1; | |||
#endif | |||
@@ -322,13 +265,17 @@ public: | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
fMidiEventCount = 0; | |||
#endif | |||
} | |||
~PluginVst() | |||
{ | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
fVstUi = nullptr; | |||
fVstRect.top = 0; | |||
fVstRect.left = 0; | |||
fVstRect.bottom = 0; | |||
fVstRect.right = 0; | |||
#endif | |||
} | |||
intptr_t vst_dispatcher(int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) | |||
intptr_t vst_dispatcher(const int32_t opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt) | |||
{ | |||
int32_t ret = 0; | |||
@@ -336,7 +283,7 @@ public: | |||
{ | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
case effSetProgram: | |||
if (value >= 0 && value < static_cast<intptr_t>(fPlugin.programCount())) | |||
if (value >= 0 && value < static_cast<intptr_t>(fPlugin.getProgramCount())) | |||
{ | |||
fCurProgram = value; | |||
fPlugin.setProgram(fCurProgram); | |||
@@ -359,21 +306,19 @@ public: | |||
break; | |||
case effGetProgramName: | |||
if (ptr != nullptr && fCurProgram >= 0 && fCurProgram < static_cast<int32_t>(fPlugin.programCount())) | |||
if (ptr != nullptr && fCurProgram >= 0 && fCurProgram < static_cast<int32_t>(fPlugin.getProgramCount())) | |||
{ | |||
char* buf = (char*)ptr; | |||
std::strncpy(buf, fPlugin.programName(fCurProgram), kVstMaxProgNameLen); | |||
buf[kVstMaxProgNameLen] = '\0'; | |||
DISTRHO::strncpy((char*)ptr, fPlugin.getProgramName(fCurProgram), kVstMaxProgNameLen); | |||
ret = 1; | |||
} | |||
break; | |||
#endif | |||
case effGetParamDisplay: | |||
if (ptr != nullptr && index < static_cast<int32_t>(fPlugin.parameterCount())) | |||
if (ptr != nullptr && index < static_cast<int32_t>(fPlugin.getParameterCount())) | |||
{ | |||
char* buf = (char*)ptr; | |||
std::snprintf((char*)ptr, kVstMaxParamStrLen, "%f", fPlugin.parameterValue(index)); | |||
std::snprintf((char*)ptr, kVstMaxParamStrLen, "%f", fPlugin.getParameterValue(index)); | |||
buf[kVstMaxParamStrLen] = '\0'; | |||
ret = 1; | |||
} | |||
@@ -396,14 +341,40 @@ public: | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
case effEditGetRect: | |||
createUiIfNeeded(0); | |||
if (fVstUi != nullptr) | |||
{ | |||
fVstRect.right = fVstUi->getWidth(); | |||
fVstRect.bottom = fVstUi->getHeight(); | |||
} | |||
else | |||
{ | |||
d_lastUiSampleRate = fAudioMaster(fEffect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f); | |||
UIExporter tmpUI(nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr); | |||
fVstRect.right = tmpUI.getWidth(); | |||
fVstRect.bottom = tmpUI.getHeight(); | |||
} | |||
*(ERect**)ptr = &fVstRect; | |||
ret = 1; | |||
break; | |||
case effEditOpen: | |||
createUiIfNeeded((intptr_t)ptr); // FIXME - use FromVstPtr<> | |||
ret = 1; | |||
if (fVstUi == nullptr) | |||
{ | |||
d_lastUiSampleRate = fAudioMaster(fEffect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f); | |||
fVstUi = new UIVst(fAudioMaster, fEffect, &fPlugin, (intptr_t)ptr); | |||
# if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
if (fCurProgram >= 0) | |||
fVstUi->setProgramFromPlugin(fCurProgram); | |||
# endif | |||
for (uint32_t i=0, count = fPlugin.getParameterCount(); i < count; ++i) | |||
fVstUi->setParameterValueFromPlugin(i, fPlugin.getParameterValue(i)); | |||
fVstUi->idle(); | |||
ret = 1; | |||
} | |||
break; | |||
case effEditClose: | |||
@@ -411,9 +382,6 @@ public: | |||
{ | |||
delete fVstUi; | |||
fVstUi = nullptr; | |||
# ifdef DISTRHO_UI_QT4 | |||
sApp.idle(); | |||
# endif | |||
ret = 1; | |||
} | |||
break; | |||
@@ -421,9 +389,6 @@ public: | |||
case effEditIdle: | |||
if (fVstUi != nullptr) | |||
fVstUi->idle(); | |||
# ifdef DISTRHO_UI_QT4 | |||
sApp.idle(); | |||
# endif | |||
break; | |||
#endif | |||
@@ -445,9 +410,9 @@ public: | |||
#endif | |||
case effCanBeAutomated: | |||
if (index < static_cast<int32_t>(fPlugin.parameterCount())) | |||
if (index < static_cast<int32_t>(fPlugin.getParameterCount())) | |||
{ | |||
uint32_t hints = fPlugin.parameterHints(index); | |||
const uint32_t hints(fPlugin.getParameterHints(index)); | |||
// must be automable, and not output | |||
if ((hints & PARAMETER_IS_AUTOMABLE) != 0 && (hints & PARAMETER_IS_OUTPUT) == 0) | |||
@@ -457,8 +422,14 @@ public: | |||
case effCanDo: | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
if (const char* const canDo = (const char*)ptr) | |||
{ | |||
if (std::strcmp(canDo, "receiveVstEvents") == 0) | |||
ret = 1; | |||
else if (std::strcmp(canDo, "receiveVstMidiEvent") == 0) | |||
ret = 1; | |||
} | |||
#endif | |||
// TODO | |||
break; | |||
case effStartProcess: | |||
@@ -469,16 +440,16 @@ public: | |||
return ret; | |||
} | |||
float vst_getParameter(int32_t index) | |||
float vst_getParameter(const int32_t index) | |||
{ | |||
const ParameterRanges& ranges(fPlugin.parameterRanges(index)); | |||
return ranges.normalizedValue(fPlugin.parameterValue(index)); | |||
const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); | |||
return ranges.getNormalizedValue(fPlugin.getParameterValue(index)); | |||
} | |||
void vst_setParameter(int32_t index, float value) | |||
void vst_setParameter(const int32_t index, const float value) | |||
{ | |||
const ParameterRanges& ranges(fPlugin.parameterRanges(index)); | |||
const float realValue(ranges.unnormalizedValue(value)); | |||
const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); | |||
const float realValue(ranges.getUnnormalizedValue(value)); | |||
fPlugin.setParameterValue(index, realValue); | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
@@ -487,14 +458,12 @@ public: | |||
#endif | |||
} | |||
void vst_processReplacing(float** inputs, float** outputs, int32_t sampleFrames) | |||
void vst_processReplacing(float** const inputs, float** const outputs, const int32_t sampleFrames) | |||
{ | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
fPlugin.run(inputs, outputs, sampleFrames, fMidiEventCount, fMidiEvents); | |||
// TODO - send notes to UI | |||
#else | |||
fPlugin.run(inputs, outputs, sampleFrames, 0, nullptr); | |||
fPlugin.run(inputs, outputs, sampleFrames); | |||
#endif | |||
} | |||
@@ -502,68 +471,35 @@ public: | |||
private: | |||
// VST stuff | |||
audioMasterCallback const kAudioMaster; | |||
AEffect* const kEffect; | |||
const audioMasterCallback fAudioMaster; | |||
AEffect* const fEffect; | |||
// Plugin | |||
PluginInternal fPlugin; | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
// UI | |||
UIVst* fVstUi; | |||
ERect fVstRect; | |||
#endif | |||
PluginExporter fPlugin; | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
int32_t fCurProgram; | |||
#endif | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
uint32_t fMidiEventCount; | |||
MidiEvent fMidiEvents[MAX_MIDI_EVENTS]; | |||
MidiEvent fMidiEvents[kMaxMidiEvents]; | |||
#endif | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
void createUiIfNeeded(intptr_t ptr) | |||
{ | |||
if (fVstUi != nullptr) | |||
return; | |||
d_lastUiSampleRate = kAudioMaster(kEffect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f); | |||
if (ptr == 0) | |||
{ | |||
// fake temporary window, just to set ui size | |||
UIVst tmpUi(kAudioMaster, kEffect, &fPlugin, ptr); | |||
fVstRect.right = tmpUi.getWidth(); | |||
fVstRect.bottom = tmpUi.getHeight(); | |||
} | |||
else | |||
{ | |||
// real parented ui | |||
fVstUi = new UIVst(kAudioMaster, kEffect, &fPlugin, ptr); | |||
fVstRect.right = fVstUi->getWidth(); | |||
fVstRect.bottom = fVstUi->getHeight(); | |||
# if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
if (fCurProgram >= 0) | |||
fVstUi->setProgramFromPlugin(fCurProgram); | |||
# endif | |||
for (uint32_t i=0, count = fPlugin.parameterCount(); i < count; ++i) | |||
fVstUi->setParameterValueFromPlugin(i, fPlugin.parameterValue(i)); | |||
} | |||
} | |||
UIVst* fVstUi; | |||
ERect fVstRect; | |||
#endif | |||
}; | |||
// ----------------------------------------------------------------------- | |||
#define handlePtr ((PluginVst*)effect->object) | |||
#define handlePtr ((PluginVst*)effect->resvd2) | |||
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); | |||
bool doInternalInit = (opcode == -1729 && index == 0xdead && value == 0xf00d); | |||
if (doInternalInit) | |||
{ | |||
@@ -573,7 +509,7 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||
} | |||
// Create dummy plugin to get data from | |||
static PluginInternal plugin; | |||
static PluginExporter plugin; | |||
if (doInternalInit) | |||
{ | |||
@@ -581,7 +517,7 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||
d_lastBufferSize = 0; | |||
d_lastSampleRate = 0.0; | |||
*(PluginInternal**)ptr = &plugin; | |||
*(PluginExporter**)ptr = &plugin; | |||
return 0; | |||
} | |||
@@ -589,47 +525,49 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||
switch (opcode) | |||
{ | |||
case effOpen: | |||
if (effect != nullptr && effect->object == nullptr) | |||
if (effect != nullptr && effect->object != nullptr /*&& dynamic_cast<audioMasterCallback>(effect->object)*/) | |||
{ | |||
audioMasterCallback audioMaster = (audioMasterCallback)effect->user; | |||
audioMasterCallback audioMaster = (audioMasterCallback)effect->object; | |||
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); | |||
PluginVst* const plugin(new PluginVst(audioMaster, effect)); | |||
effect->resvd2 = (intptr_t)plugin; | |||
return 1; | |||
} | |||
return 0; | |||
case effClose: | |||
if (effect != nullptr && effect->object != nullptr) | |||
if (effect != nullptr && effect->resvd2 != 0) | |||
{ | |||
delete (PluginVst*)effect->object; | |||
delete (PluginVst*)effect->resvd2; | |||
effect->object = nullptr; | |||
effect->resvd2 = 0; | |||
delete effect; | |||
return 1; | |||
} | |||
return 0; | |||
case effGetParamLabel: // FIXME - proper close buf/ptr | |||
if (ptr != nullptr && index < static_cast<int32_t>(plugin.parameterCount())) | |||
case effGetParamLabel: | |||
if (ptr != nullptr && index < static_cast<int32_t>(plugin.getParameterCount())) | |||
{ | |||
std::strncpy((char*)ptr, plugin.parameterUnit(index), kVstMaxParamStrLen); | |||
DISTRHO::strncpy((char*)ptr, plugin.getParameterUnit(index), kVstMaxParamStrLen); | |||
return 1; | |||
} | |||
return 0; | |||
case effGetParamName: | |||
if (ptr != nullptr && index < static_cast<int32_t>(plugin.parameterCount())) | |||
if (ptr != nullptr && index < static_cast<int32_t>(plugin.getParameterCount())) | |||
{ | |||
std::strncpy((char*)ptr, plugin.parameterName(index), kVstMaxParamStrLen); | |||
DISTRHO::strncpy((char*)ptr, plugin.getParameterName(index), kVstMaxParamStrLen); | |||
return 1; | |||
} | |||
return 0; | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
case effGetProgramNameIndexed: | |||
if (ptr != nullptr && index < static_cast<int32_t>(plugin.parameterCount())) | |||
if (ptr != nullptr && index < static_cast<int32_t>(plugin.getProgramCount())) | |||
{ | |||
std::strncpy((char*)ptr, plugin.programName(index), kVstMaxProgNameLen); | |||
DISTRHO::strncpy((char*)ptr, plugin.getProgramName(index), kVstMaxProgNameLen); | |||
return 1; | |||
} | |||
return 0; | |||
@@ -639,13 +577,13 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
return kPlugCategSynth; | |||
#else | |||
return kPlugCategUnknown; | |||
return kPlugCategEffect; | |||
#endif | |||
case effGetEffectName: | |||
if (ptr != nullptr) | |||
{ | |||
std::strncpy((char*)ptr, plugin.name(), kVstMaxProductStrLen); | |||
DISTRHO::strncpy((char*)ptr, plugin.getName(), kVstMaxProductStrLen); | |||
return 1; | |||
} | |||
return 0; | |||
@@ -653,7 +591,7 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||
case effGetVendorString: | |||
if (ptr != nullptr) | |||
{ | |||
std::strncpy((char*)ptr, plugin.maker(), kVstMaxVendorStrLen); | |||
DISTRHO::strncpy((char*)ptr, plugin.getMaker(), kVstMaxVendorStrLen); | |||
return 1; | |||
} | |||
return 0; | |||
@@ -661,20 +599,20 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||
case effGetProductString: | |||
if (ptr != nullptr) | |||
{ | |||
std::strncpy((char*)ptr, plugin.label(), kVstMaxEffectNameLen); | |||
DISTRHO::strncpy((char*)ptr, plugin.getLabel(), kVstMaxEffectNameLen); | |||
return 1; | |||
} | |||
return 0; | |||
case effGetVendorVersion: | |||
return plugin.version(); | |||
return plugin.getVersion(); | |||
case effGetVstVersion: | |||
return kVstVersion; | |||
}; | |||
// handle object opcodes | |||
if (effect != nullptr && effect->object != nullptr) | |||
// handle advanced opcodes | |||
if (effect != nullptr && effect->resvd2 != 0) | |||
return handlePtr->vst_dispatcher(opcode, index, value, ptr, opt); | |||
return 0; | |||
@@ -682,26 +620,26 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||
static float vst_getParameterCallback(AEffect* effect, int32_t index) | |||
{ | |||
if (effect != nullptr && effect->object != nullptr) | |||
if (effect != nullptr && effect->resvd2 != 0) | |||
return handlePtr->vst_getParameter(index); | |||
return 0.0f; | |||
} | |||
static void vst_setParameterCallback(AEffect* effect, int32_t index, float value) | |||
{ | |||
if (effect != nullptr && effect->object != nullptr) | |||
if (effect != nullptr && effect->resvd2 != 0) | |||
handlePtr->vst_setParameter(index, value); | |||
} | |||
static void vst_processCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames) | |||
{ | |||
if (effect != nullptr && effect->object != nullptr) | |||
if (effect != nullptr && effect->resvd2 != 0) | |||
handlePtr->vst_processReplacing(inputs, outputs, sampleFrames); | |||
} | |||
static void vst_processReplacingCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames) | |||
{ | |||
if (effect != nullptr && effect->object != nullptr) | |||
if (effect != nullptr && effect->resvd2 != 0) | |||
handlePtr->vst_processReplacing(inputs, outputs, sampleFrames); | |||
} | |||
@@ -720,35 +658,31 @@ const AEffect* VSTPluginMain(audioMasterCallback audioMaster) | |||
if (audioMaster(nullptr, audioMasterVersion, 0, 0, nullptr, 0.0f) == 0) | |||
return nullptr; | |||
PluginInternal* plugin = nullptr; | |||
vst_dispatcherCallback(nullptr, -1, 0xdead, 0xf00d, &plugin, 0.0f); | |||
// first internal init | |||
PluginExporter* plugin = nullptr; | |||
vst_dispatcherCallback(nullptr, -1729, 0xdead, 0xf00d, &plugin, 0.0f); | |||
AEffect* effect = new AEffect; | |||
memset(effect, 0, sizeof(AEffect)); | |||
AEffect* const effect(new AEffect); | |||
std::memset(effect, 0, sizeof(AEffect)); | |||
// vst fields | |||
effect->magic = kEffectMagic; | |||
effect->uniqueID = plugin->uniqueId(); | |||
effect->version = plugin->version(); | |||
effect->uniqueID = plugin->getUniqueId(); | |||
effect->version = plugin->getVersion(); | |||
// plugin fields | |||
effect->numParams = plugin->parameterCount(); | |||
effect->numParams = plugin->getParameterCount(); | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
effect->numPrograms = plugin->programCount(); | |||
effect->numPrograms = plugin->getProgramCount(); | |||
#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_IS_SYNTH | |||
effect->flags |= effFlagsIsSynth; | |||
#endif | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
effect->flags |= effFlagsHasEditor; | |||
#endif | |||
@@ -756,9 +690,16 @@ const AEffect* VSTPluginMain(audioMasterCallback audioMaster) | |||
effect->flags |= effFlagsProgramChunks; | |||
#endif | |||
// static calls | |||
effect->dispatcher = vst_dispatcherCallback; | |||
effect->process = vst_processCallback; | |||
effect->getParameter = vst_getParameterCallback; | |||
effect->setParameter = vst_setParameterCallback; | |||
effect->processReplacing = vst_processReplacingCallback; | |||
effect->processDoubleReplacing = nullptr; | |||
// pointers | |||
effect->object = nullptr; | |||
effect->user = (void*)audioMaster; | |||
effect->object = (void*)audioMaster; | |||
return effect; | |||
} |
@@ -16,6 +16,10 @@ | |||
#include "DistrhoUIInternal.hpp" | |||
START_NAMESPACE_DGL | |||
extern Window* dgl_lastUiParent; | |||
END_NAMESPACE_DGL | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
@@ -27,8 +31,12 @@ double d_lastUiSampleRate = 0.0; | |||
// UI | |||
UI::UI() | |||
: pData(new PrivateData()) | |||
: DGL::Widget(*DGL::dgl_lastUiParent), | |||
pData(new PrivateData()) | |||
{ | |||
assert(DGL::dgl_lastUiParent != nullptr); | |||
DGL::dgl_lastUiParent = nullptr; | |||
} | |||
UI::~UI() | |||
@@ -46,7 +54,7 @@ double UI::d_getSampleRate() const noexcept | |||
void UI::d_editParameter(uint32_t index, bool started) | |||
{ | |||
pData->editParamCallback(index, started); | |||
pData->editParamCallback(index + pData->parameterOffset, started); | |||
} | |||
void UI::d_setParameterValue(uint32_t index, float value) | |||
@@ -62,9 +70,9 @@ void UI::d_setState(const char* key, const char* value) | |||
#endif | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
void UI::d_sendNote(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity) | |||
void UI::d_sendNote(uint8_t channel, uint8_t note, uint8_t velocity) | |||
{ | |||
pData->sendNoteCallback(onOff, channel, note, velocity); | |||
pData->sendNoteCallback(channel, note, velocity); | |||
} | |||
#endif | |||
@@ -16,20 +16,11 @@ | |||
#include "DistrhoUIInternal.hpp" | |||
#ifdef DISTRHO_UI_EXTERNAL | |||
# error DSSI always uses external UI, no wrapper needed! | |||
#endif | |||
#include "dgl/App.hpp" | |||
#include "dgl/Window.hpp" | |||
#include <lo/lo.h> | |||
#ifdef DISTRHO_UI_QT | |||
# include <QtGui/QApplication> | |||
# include <QtGui/QMainWindow> | |||
#else | |||
# include "dgl/App.hpp" | |||
# include "dgl/Window.hpp" | |||
#endif | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
@@ -95,78 +86,34 @@ struct OscData { | |||
// ----------------------------------------------------------------------- | |||
#ifdef DISTRHO_UI_QT | |||
class UIDssi : public QMainWindow | |||
#else | |||
class UIDssi | |||
#endif | |||
{ | |||
public: | |||
UIDssi(const OscData& oscData, const char* const uiTitle) | |||
#ifdef DISTRHO_UI_QT | |||
: QMainWindow(nullptr), | |||
fUI(this, 0, nullptr, setParameterCallback, setStateCallback, uiSendNoteCallback, uiResizeCallback), | |||
: fUI(this, 0, nullptr, setParameterCallback, setStateCallback, sendNoteCallback, uiResizeCallback), | |||
fHostClosed(false), | |||
qtTimer(0), | |||
#else | |||
: fUI(this, 0, nullptr, setParameterCallback, setStateCallback, uiSendNoteCallback, uiResizeCallback), | |||
fHostClosed(false), | |||
glApp(fUI.getApp()), | |||
glWindow(fUI.getWindow()), | |||
#endif | |||
fOscData(oscData) | |||
{ | |||
#ifdef DISTRHO_UI_QT | |||
QtUI* const qtUI(fUI.getQt4Ui()); | |||
setCentralWidget(qtUI); | |||
setWindowTitle(uiTitle); | |||
if (qtUI->d_resizable()) | |||
{ | |||
adjustSize(); | |||
} | |||
else | |||
{ | |||
setFixedSize(qtUI->width(), qtUI->height()); | |||
# ifdef DISTRHO_OS_WINDOWS | |||
setWindowFlags(windowFlags()|Qt::MSWindowsFixedSizeDialogHint); | |||
# endif | |||
} | |||
#else | |||
glWindow.setTitle(uiTitle); | |||
#endif | |||
fUI.setTitle(uiTitle); | |||
} | |||
~UIDssi() | |||
{ | |||
#ifdef DISTRHO_UI_QT | |||
if (qtTimer != 0) | |||
{ | |||
killTimer(qtTimer); | |||
qtTimer = 0; | |||
} | |||
#endif | |||
if (fOscData.server != nullptr && ! fHostClosed) | |||
fOscData.send_exiting(); | |||
} | |||
void exec() | |||
{ | |||
#ifdef DISTRHO_UI_QT | |||
assert(qtTimer == 0); | |||
qtTimer = startTimer(50); | |||
qApp->exec(); | |||
#else | |||
while (! glApp.isQuiting()) | |||
for (;;) | |||
{ | |||
fOscData.idle(); | |||
fUI.idle(); | |||
msleep(50); | |||
if (! fUI.idle()) | |||
break; | |||
d_msleep(50); | |||
} | |||
#endif | |||
} | |||
// ------------------------------------------------------------------- | |||
@@ -190,70 +137,26 @@ public: | |||
} | |||
#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]; | |||
fUI.noteReceived(false, channel, note, 0); | |||
} | |||
else if (status == 0x90) | |||
{ | |||
uint8_t note = data[2]; | |||
uint8_t velo = data[3]; | |||
fUI.noteReceived(true, channel, note, velo); | |||
} | |||
} | |||
#endif | |||
void dssiui_show() | |||
{ | |||
#ifdef DISTRHO_UI_QT | |||
show(); | |||
#else | |||
glWindow.show(); | |||
#endif | |||
fUI.setVisible(true); | |||
} | |||
void dssiui_hide() | |||
{ | |||
#ifdef DISTRHO_UI_QT | |||
hide(); | |||
#else | |||
glWindow.hide(); | |||
#endif | |||
fUI.setVisible(false); | |||
} | |||
void dssiui_quit() | |||
{ | |||
fHostClosed = true; | |||
#ifdef DISTRHO_UI_QT | |||
if (qtTimer != 0) | |||
{ | |||
killTimer(qtTimer); | |||
qtTimer = 0; | |||
} | |||
close(); | |||
qApp->quit(); | |||
#else | |||
glWindow.close(); | |||
glApp.quit(); | |||
#endif | |||
fUI.quit(); | |||
} | |||
// ------------------------------------------------------------------- | |||
protected: | |||
void setParameterValue(uint32_t rindex, float value) | |||
void setParameterValue(const uint32_t rindex, const float value) | |||
{ | |||
if (fOscData.server == nullptr) | |||
return; | |||
@@ -261,7 +164,7 @@ protected: | |||
fOscData.send_control(rindex, value); | |||
} | |||
void setState(const char* key, const char* value) | |||
void setState(const char* const key, const char* const value) | |||
{ | |||
if (fOscData.server == nullptr) | |||
return; | |||
@@ -269,7 +172,7 @@ protected: | |||
fOscData.send_configure(key, value); | |||
} | |||
void uiSendNote(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity) | |||
void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity) | |||
{ | |||
if (fOscData.server == nullptr) | |||
return; | |||
@@ -277,47 +180,20 @@ protected: | |||
return; | |||
uint8_t mdata[4] = { 0, channel, note, velocity }; | |||
mdata[1] += onOff ? 0x90 : 0x80; | |||
mdata[1] += (velocity != 0) ? 0x90 : 0x80; | |||
fOscData.send_midi(mdata); | |||
} | |||
void uiResize(unsigned int width, unsigned int height) | |||
{ | |||
#ifdef DISTRHO_UI_QT | |||
setFixedSize(width, height); | |||
#else | |||
glWindow.setSize(width, height); | |||
#endif | |||
} | |||
#ifdef DISTRHO_UI_QT | |||
void timerEvent(QTimerEvent* event) | |||
void uiResize(const unsigned int width, const unsigned int height) | |||
{ | |||
if (event->timerId() == uiTimer) | |||
{ | |||
fOscData.idle(); | |||
fUI.idle(); | |||
} | |||
QMainWindow::timerEvent(event); | |||
fUI.setSize(width, height); | |||
} | |||
#endif | |||
private: | |||
// Plugin UI | |||
UIInternal fUI; | |||
UIExporter fUI; | |||
bool fHostClosed; | |||
#ifdef DISTRHO_UI_QT | |||
// Qt4 stuff | |||
int qtTimer; | |||
#else | |||
// OpenGL stuff | |||
App& glApp; | |||
Window& glWindow; | |||
#endif | |||
const OscData& fOscData; | |||
// ------------------------------------------------------------------- | |||
@@ -335,9 +211,9 @@ private: | |||
uiPtr->setState(key, value); | |||
} | |||
static void uiSendNoteCallback(void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velocity) | |||
static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity) | |||
{ | |||
uiPtr->uiSendNote(onOff, channel, note, velocity); | |||
uiPtr->sendNote(channel, note, velocity); | |||
} | |||
static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height) | |||
@@ -431,19 +307,6 @@ int osc_program_handler(const char*, const char*, lo_arg** argv, int, lo_message | |||
} | |||
#endif | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
int osc_midi_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*) | |||
{ | |||
d_debug("osc_midi_handler()"); | |||
initUiIfNeeded(); | |||
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; | |||
@@ -470,7 +333,7 @@ int osc_hide_handler(const char*, const char*, lo_arg**, int, lo_message, void*) | |||
d_debug("osc_hide_handler()"); | |||
if (globalUI != nullptr) | |||
globalUI->dssiui_hide(); | |||
globalUI->dssiui_hide(); | |||
return 0; | |||
} | |||
@@ -481,10 +344,6 @@ int osc_quit_handler(const char*, const char*, lo_arg**, int, lo_message, void*) | |||
if (globalUI != nullptr) | |||
globalUI->dssiui_quit(); | |||
#ifdef DISTRHO_UI_QT | |||
else if (QApplication* app = qApp) | |||
app->quit(); | |||
#endif | |||
return 0; | |||
} | |||
@@ -500,9 +359,6 @@ int main(int argc, char* argv[]) | |||
// dummy test mode | |||
if (argc == 1) | |||
{ | |||
#ifdef DISTRHO_UI_QT | |||
QApplication app(argc, argv, true); | |||
#endif | |||
gUiTitle = "DSSI UI Test"; | |||
initUiIfNeeded(); | |||
@@ -518,10 +374,6 @@ int main(int argc, char* argv[]) | |||
return 1; | |||
} | |||
#ifdef DISTRHO_UI_QT | |||
QApplication app(argc, argv, true); | |||
#endif | |||
const char* oscUrl = argv[1]; | |||
const char* uiTitle = argv[4]; | |||
@@ -561,13 +413,6 @@ int main(int argc, char* argv[]) | |||
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"); | |||
@@ -628,9 +473,6 @@ int main(int argc, char* argv[]) | |||
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, ""); | |||
@@ -638,10 +480,10 @@ int main(int argc, char* argv[]) | |||
lo_server_del_method(oscServer, oscPathQuit, ""); | |||
lo_server_del_method(oscServer, nullptr, nullptr); | |||
free(oscServerPath); | |||
free(oscHost); | |||
free(oscPort); | |||
free(oscPath); | |||
std::free(oscServerPath); | |||
std::free(oscHost); | |||
std::free(oscPort); | |||
std::free(oscPath); | |||
lo_address_free(oscAddr); | |||
lo_server_free(oscServer); | |||
@@ -1,35 +0,0 @@ | |||
/* | |||
* DISTRHO Plugin Toolkit (DPT) | |||
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
* permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "DistrhoUIInternal.hpp" | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
// External UI | |||
ExternalUI::ExternalUI() | |||
: UI() | |||
{ | |||
} | |||
ExternalUI::~ExternalUI() | |||
{ | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO |
@@ -19,33 +19,28 @@ | |||
#include "../DistrhoUI.hpp" | |||
#if defined(DISTRHO_UI_EXTERNAL) | |||
# include "../DistrhoUIExternal.hpp" | |||
#elif defined(DISTRHO_UI_OPENGL) | |||
# include "../DistrhoUIOpenGL.hpp" | |||
# include "../dgl/App.hpp" | |||
# include "../dgl/Window.hpp" | |||
#elif defined(DISTRHO_UI_QT) | |||
# include "../DistrhoUIQt.hpp" | |||
#else | |||
# error Invalid UI type | |||
#endif | |||
#include <cassert> | |||
#include "../dgl/App.hpp" | |||
#include "../dgl/Window.hpp" | |||
#include <lo/lo_osc_types.h> | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
// Static data, see DistrhoUI.cpp | |||
extern double d_lastUiSampleRate; | |||
typedef void (*editParamFunc) (void* ptr, uint32_t index, bool started); | |||
typedef void (*setParamFunc) (void* ptr, uint32_t index, float value); | |||
// ----------------------------------------------------------------------- | |||
// UI callbacks | |||
typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started); | |||
typedef void (*setParamFunc) (void* ptr, uint32_t rindex, float value); | |||
typedef void (*setStateFunc) (void* ptr, const char* key, const char* value); | |||
typedef void (*sendNoteFunc) (void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velo); | |||
typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8_t velo); | |||
typedef void (*uiResizeFunc) (void* ptr, unsigned int width, unsigned int height); | |||
extern double d_lastUiSampleRate; | |||
// ----------------------------------------------------------------------- | |||
// UI private data | |||
struct UI::PrivateData { | |||
// DSP | |||
@@ -60,7 +55,7 @@ struct UI::PrivateData { | |||
uiResizeFunc uiResizeCallbackFunc; | |||
void* ptr; | |||
PrivateData() | |||
PrivateData() noexcept | |||
: sampleRate(d_lastUiSampleRate), | |||
parameterOffset(0), | |||
editParamCallbackFunc(nullptr), | |||
@@ -77,34 +72,42 @@ struct UI::PrivateData { | |||
# if DISTRHO_PLUGIN_WANT_LATENCY | |||
parameterOffset += 1; | |||
# endif | |||
#endif | |||
#ifdef DISTRHO_PLUGIN_TARGET_LV2 | |||
# if (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE) | |||
parameterOffset += 1; | |||
# if DISTRHO_PLUGIN_WANT_STATE | |||
parameterOffset += 1; | |||
# endif | |||
# endif | |||
#endif | |||
} | |||
void editParamCallback(uint32_t index, bool started) | |||
void editParamCallback(const uint32_t rindex, const bool started) | |||
{ | |||
if (editParamCallbackFunc != nullptr) | |||
editParamCallbackFunc(ptr, index, started); | |||
editParamCallbackFunc(ptr, rindex, started); | |||
} | |||
void setParamCallback(uint32_t rindex, float value) | |||
void setParamCallback(const uint32_t rindex, const float value) | |||
{ | |||
if (setParamCallbackFunc != nullptr) | |||
setParamCallbackFunc(ptr, rindex, value); | |||
} | |||
void setStateCallback(const char* key, const char* value) | |||
void setStateCallback(const char* const key, const char* const value) | |||
{ | |||
if (setStateCallbackFunc != nullptr) | |||
setStateCallbackFunc(ptr, key, value); | |||
} | |||
void sendNoteCallback(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity) | |||
void sendNoteCallback(const uint8_t channel, const uint8_t note, const uint8_t velocity) | |||
{ | |||
if (sendNoteCallbackFunc != nullptr) | |||
sendNoteCallbackFunc(ptr, onOff, channel, note, velocity); | |||
sendNoteCallbackFunc(ptr, channel, note, velocity); | |||
} | |||
void uiResizeCallback(unsigned int width, unsigned int height) | |||
void uiResizeCallback(const unsigned int width, const unsigned int height) | |||
{ | |||
if (uiResizeCallbackFunc != nullptr) | |||
uiResizeCallbackFunc(ptr, width, height); | |||
@@ -112,18 +115,16 @@ struct UI::PrivateData { | |||
}; | |||
// ----------------------------------------------------------------------- | |||
// UI exporter class | |||
class UIInternal | |||
class UIExporter | |||
{ | |||
public: | |||
UIInternal(void* ptr, intptr_t winId, editParamFunc editParamCall, setParamFunc setParamCall, setStateFunc setStateCall, sendNoteFunc sendNoteCall, uiResizeFunc uiResizeCall) | |||
#ifdef DISTRHO_UI_OPENGL | |||
UIExporter(void* const ptr, const intptr_t winId, | |||
const editParamFunc editParamCall, const setParamFunc setParamCall, const setStateFunc setStateCall, const sendNoteFunc sendNoteCall, const uiResizeFunc uiResizeCall) | |||
: glApp(), | |||
glWindow(glApp, winId), | |||
fUi(createUI()), | |||
#else | |||
: fUi(createUI()), | |||
#endif | |||
fData((fUi != nullptr) ? fUi->pData : nullptr) | |||
{ | |||
assert(fUi != nullptr); | |||
@@ -138,145 +139,106 @@ public: | |||
fData->sendNoteCallbackFunc = sendNoteCall; | |||
fData->uiResizeCallbackFunc = uiResizeCall; | |||
#ifdef DISTRHO_UI_OPENGL | |||
glWindow.setSize(fUi->d_getWidth(), fUi->d_getHeight()); | |||
glWindow.setResizable(false); | |||
#else | |||
assert(winId == 0); | |||
return; | |||
// unused | |||
(void)winId; | |||
#endif | |||
} | |||
~UIInternal() | |||
~UIExporter() | |||
{ | |||
if (fUi != nullptr) | |||
delete fUi; | |||
delete fUi; | |||
} | |||
// ------------------------------------------------------------------- | |||
const char* getName() const | |||
const char* getName() const noexcept | |||
{ | |||
assert(fUi != nullptr); | |||
return (fUi != nullptr) ? fUi->d_getName() : ""; | |||
} | |||
unsigned int getWidth() const | |||
unsigned int getWidth() const noexcept | |||
{ | |||
assert(fUi != nullptr); | |||
return (fUi != nullptr) ? fUi->d_getWidth() : 0; | |||
} | |||
unsigned int getHeight() const | |||
unsigned int getHeight() const noexcept | |||
{ | |||
assert(fUi != nullptr); | |||
return (fUi != nullptr) ? fUi->d_getHeight() : 0; | |||
} | |||
// ------------------------------------------------------------------- | |||
void parameterChanged(uint32_t index, float value) | |||
uint32_t getParameterOffset() const noexcept | |||
{ | |||
assert(fUi != nullptr); | |||
return (fData != nullptr) ? fData->parameterOffset : 0; | |||
} | |||
// ------------------------------------------------------------------- | |||
void parameterChanged(const uint32_t index, const float value) | |||
{ | |||
if (fUi != nullptr) | |||
fUi->d_parameterChanged(index, value); | |||
} | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
void programChanged(uint32_t index) | |||
void programChanged(const uint32_t index) | |||
{ | |||
assert(fUi != nullptr); | |||
if (fUi != nullptr) | |||
fUi->d_programChanged(index); | |||
} | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
void stateChanged(const char* key, const char* value) | |||
void stateChanged(const char* const key, const char* const value) | |||
{ | |||
assert(fUi != nullptr); | |||
if (fUi != nullptr) | |||
fUi->d_stateChanged(key, value); | |||
} | |||
#endif | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
void noteReceived(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity) | |||
{ | |||
assert(fUi != nullptr); | |||
if (fUi != nullptr) | |||
fUi->d_noteReceived(onOff, channel, note, velocity); | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
void idle() | |||
bool idle() | |||
{ | |||
assert(fUi != nullptr); | |||
if (fUi != nullptr) | |||
fUi->d_uiIdle(); | |||
#ifdef DISTRHO_UI_OPENGL | |||
glApp.idle(); | |||
#endif | |||
} | |||
#if defined(DISTRHO_UI_EXTERNAL) | |||
const char* getExternalFilename() const | |||
{ | |||
return ((ExternalUI*)fUi)->d_getExternalFilename(); | |||
} | |||
#elif defined(DISTRHO_UI_OPENGL) | |||
DGL::App& getApp() | |||
{ | |||
return glApp; | |||
return ! glApp.isQuiting(); | |||
} | |||
DGL::Window& getWindow() | |||
void quit() | |||
{ | |||
return glWindow; | |||
glWindow.close(); | |||
glApp.quit(); | |||
} | |||
/*intptr_t getWindowId() const | |||
void setSize(const unsigned int width, const unsigned int height) | |||
{ | |||
return glWindow.getWindowId(); | |||
}*/ | |||
glWindow.setSize(width, height); | |||
} | |||
/*void fixWindowSize() | |||
void setTitle(const char* const uiTitle) | |||
{ | |||
assert(fUi != nullptr); | |||
glWindow.setSize(fUi->d_getWidth(), fUi->d_getHeight()); | |||
}*/ | |||
#elif defined(DISTRHO_UI_QT) | |||
/*QtUI* getQtUI() const | |||
{ | |||
return (QtUI*)fUi; | |||
}*/ | |||
glWindow.setTitle(uiTitle); | |||
} | |||
bool isResizable() const | |||
void setVisible(const bool yesNo) | |||
{ | |||
return ((QtUI*)fUi)->d_isResizable(); | |||
glWindow.setVisible(yesNo); | |||
} | |||
#endif | |||
private: | |||
// ------------------------------------------------------------------- | |||
// DGL Application and Window for this plugin | |||
#ifdef DISTRHO_UI_OPENGL | |||
private: | |||
DGL::App glApp; | |||
DGL::Window glWindow; | |||
#endif | |||
protected: | |||
// ------------------------------------------------------------------- | |||
// private members accessed by DistrhoPlugin class | |||
UI* const fUi; | |||
UI::PrivateData* const fData; | |||
}; | |||
@@ -0,0 +1,301 @@ | |||
/* | |||
* DISTRHO Plugin Toolkit (DPT) | |||
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
* permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "DistrhoUIInternal.hpp" | |||
#include "lv2/atom.h" | |||
#include "lv2/options.h" | |||
#include "lv2/ui.h" | |||
#include "lv2/urid.h" | |||
#include "lv2/lv2_programs.h" | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
class UiLv2 | |||
{ | |||
public: | |||
UiLv2(const intptr_t winId, const LV2_URID_Map* const uridMap, const LV2UI_Resize* const uiResz, const LV2UI_Touch* uiTouch, const LV2UI_Controller controller, const LV2UI_Write_Function writeFunc) | |||
: fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, uiResizeCallback), | |||
fUridMap(uridMap), | |||
fUiResize(uiResz), | |||
fUiTouch(uiTouch), | |||
fController(controller), | |||
fWriteFunction(writeFunc) | |||
{ | |||
fUiResize->ui_resize(fUiResize->handle, fUI.getWidth(), fUI.getHeight()); | |||
} | |||
// ------------------------------------------------------------------- | |||
void lv2ui_port_event(const uint32_t rindex, const uint32_t bufferSize, const uint32_t format, const void* const buffer) | |||
{ | |||
if (format == 0) | |||
{ | |||
const uint32_t parameterOffset(fUI.getParameterOffset()); | |||
if (rindex < parameterOffset) | |||
return; | |||
if (bufferSize != sizeof(float)) | |||
return; | |||
const float value(*(const float*)buffer); | |||
fUI.parameterChanged(rindex-parameterOffset, value); | |||
d_stderr("port changed %i, %i, %f", rindex, parameterOffset, value); | |||
} | |||
else | |||
{ | |||
//fUI.stateChanged(key, value); | |||
} | |||
} | |||
// ------------------------------------------------------------------- | |||
int lv2ui_idle() | |||
{ | |||
fUI.idle(); | |||
return 0; | |||
} | |||
// ------------------------------------------------------------------- | |||
void lv2ui_select_program(const uint32_t bank, const uint32_t program) | |||
{ | |||
const uint32_t realProgram(bank * 128 + program); | |||
fUI.programChanged(realProgram); | |||
} | |||
// ------------------------------------------------------------------- | |||
protected: | |||
void editParameterValue(const uint32_t rindex, const bool started) | |||
{ | |||
if (fUiTouch != nullptr && fUiTouch->touch != nullptr) | |||
fUiTouch->touch(fUiTouch->handle, rindex, started); | |||
} | |||
void setParameterValue(const uint32_t rindex, const float value) | |||
{ | |||
if (fWriteFunction != nullptr) | |||
fWriteFunction(fController, rindex, sizeof(float), 0, &value); | |||
} | |||
void setState(const char* const /*key*/, const char* const /*value*/) | |||
{ | |||
} | |||
void sendNote(const uint8_t /*channel*/, const uint8_t /*note*/, const uint8_t /*velocity*/) | |||
{ | |||
} | |||
void uiResize(const unsigned int width, const unsigned int height) | |||
{ | |||
fUI.setSize(width, height); | |||
fUiResize->ui_resize(fUiResize->handle, width, height); | |||
} | |||
private: | |||
UIExporter fUI; | |||
// LV2 features | |||
const LV2_URID_Map* const fUridMap; | |||
const LV2UI_Resize* const fUiResize; | |||
const LV2UI_Touch* const fUiTouch; | |||
// LV2 UI stuff | |||
const LV2UI_Controller fController; | |||
const LV2UI_Write_Function fWriteFunction; | |||
// ------------------------------------------------------------------- | |||
// Callbacks | |||
#define uiPtr ((UiLv2*)ptr) | |||
static void editParameterCallback(void* ptr, uint32_t rindex, bool started) | |||
{ | |||
uiPtr->editParameterValue(rindex, started); | |||
} | |||
static void setParameterCallback(void* ptr, uint32_t rindex, float value) | |||
{ | |||
uiPtr->setParameterValue(rindex, value); | |||
} | |||
static void setStateCallback(void* ptr, const char* key, const char* value) | |||
{ | |||
uiPtr->setState(key, value); | |||
} | |||
static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity) | |||
{ | |||
uiPtr->sendNote(channel, note, velocity); | |||
} | |||
static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height) | |||
{ | |||
uiPtr->uiResize(width, height); | |||
} | |||
#undef uiPtr | |||
}; | |||
// ----------------------------------------------------------------------- | |||
static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const char* uri, const char*, LV2UI_Write_Function writeFunction, LV2UI_Controller controller, LV2UI_Widget* widget, const LV2_Feature* const* features) | |||
{ | |||
if (uri == nullptr || std::strcmp(uri, DISTRHO_PLUGIN_URI) != 0) | |||
{ | |||
d_stderr("Invalid plugin URI"); | |||
return nullptr; | |||
} | |||
const LV2_Options_Option* options = nullptr; | |||
const LV2_URID_Map* uridMap = nullptr; | |||
const LV2UI_Resize* uiResize = nullptr; | |||
const LV2UI_Touch* uiTouch = nullptr; | |||
void* parentId = nullptr; | |||
for (int i=0; features[i] != nullptr; ++i) | |||
{ | |||
if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0) | |||
options = (const LV2_Options_Option*)features[i]->data; | |||
else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0) | |||
uridMap = (const LV2_URID_Map*)features[i]->data; | |||
else if (std::strcmp(features[i]->URI, LV2_UI__resize) == 0) | |||
uiResize = (const LV2UI_Resize*)features[i]->data; | |||
else if (std::strcmp(features[i]->URI, LV2_UI__parent) == 0) | |||
parentId = features[i]->data; | |||
} | |||
if (options == nullptr) | |||
{ | |||
d_stderr("Options feature missing, cannot continue!"); | |||
return nullptr; | |||
} | |||
if (uridMap == nullptr) | |||
{ | |||
d_stderr("URID Map feature missing, cannot continue!"); | |||
return nullptr; | |||
} | |||
if (uiResize == nullptr) | |||
{ | |||
d_stderr("UI Resize feature missing, cannot continue!"); | |||
return nullptr; | |||
} | |||
if (parentId == nullptr) | |||
{ | |||
d_stderr("Parent Window Id missing, cannot continue!"); | |||
return nullptr; | |||
} | |||
*widget = parentId; | |||
const intptr_t winId(*((intptr_t*)&parentId)); | |||
for (int i=0; options[i].key != 0; ++i) | |||
{ | |||
if (options[i].key == uridMap->map(uridMap->handle, LV2_CORE__sampleRate)) | |||
{ | |||
if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Double)) | |||
d_lastUiSampleRate = *(const double*)options[i].value; | |||
else | |||
d_stderr("Host provides sampleRate but has wrong value type"); | |||
break; | |||
} | |||
} | |||
if (d_lastUiSampleRate == 0.0) | |||
d_lastUiSampleRate = 44100.0; | |||
return new UiLv2(winId, uridMap, uiResize, uiTouch, controller, writeFunction); | |||
} | |||
#define uiPtr ((UiLv2*)ui) | |||
static void lv2ui_cleanup(LV2UI_Handle ui) | |||
{ | |||
delete uiPtr; | |||
} | |||
static void lv2ui_port_event(LV2UI_Handle ui, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) | |||
{ | |||
uiPtr->lv2ui_port_event(portIndex, bufferSize, format, buffer); | |||
} | |||
// ----------------------------------------------------------------------- | |||
static int lv2ui_idle(LV2UI_Handle ui) | |||
{ | |||
return uiPtr->lv2ui_idle(); | |||
} | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
static void lv2ui_select_program(LV2UI_Handle ui, uint32_t bank, uint32_t program) | |||
{ | |||
uiPtr->lv2ui_select_program(bank, program); | |||
} | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
static const void* lv2ui_extension_data(const char* uri) | |||
{ | |||
static const LV2UI_Idle_Interface uiIdle = { lv2ui_idle }; | |||
if (std::strcmp(uri, LV2_UI__idleInterface) == 0) | |||
return &uiIdle; | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
static const LV2_Programs_UI_Interface uiPrograms = { lv2ui_select_program }; | |||
if (std::strcmp(uri, LV2_PROGRAMS__UIInterface) == 0) | |||
return &uiPrograms; | |||
#endif | |||
return nullptr; | |||
} | |||
#undef instancePtr | |||
// ----------------------------------------------------------------------- | |||
static const LV2UI_Descriptor sLv2UiDescriptor = { | |||
DISTRHO_UI_URI, | |||
lv2ui_instantiate, | |||
lv2ui_cleanup, | |||
lv2ui_port_event, | |||
lv2ui_extension_data | |||
}; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO | |||
DISTRHO_PLUGIN_EXPORT | |||
const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) | |||
{ | |||
USE_NAMESPACE_DISTRHO | |||
return (index == 0) ? &sLv2UiDescriptor : nullptr; | |||
} | |||
// ----------------------------------------------------------------------- |
@@ -1,43 +0,0 @@ | |||
/* | |||
* DISTRHO Plugin Toolkit (DPT) | |||
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
* permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "DistrhoUIInternal.hpp" | |||
START_NAMESPACE_DGL | |||
extern Window* dgl_lastUiParent; | |||
END_NAMESPACE_DGL | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
// OpenGL UI | |||
OpenGLUI::OpenGLUI() | |||
: UI(), | |||
Widget(*DGL::dgl_lastUiParent) | |||
{ | |||
assert(DGL::dgl_lastUiParent != nullptr); | |||
DGL::dgl_lastUiParent = nullptr; | |||
} | |||
OpenGLUI::~OpenGLUI() | |||
{ | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO |
@@ -1,50 +0,0 @@ | |||
/* | |||
* DISTRHO Plugin Toolkit (DPT) | |||
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
* permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "DistrhoUIInternal.hpp" | |||
#include <QtGui/QResizeEvent> | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
// Qt UI | |||
QtUI::QtUI() | |||
: UI(), | |||
QWidget(nullptr) | |||
{ | |||
} | |||
QtUI::~QtUI() | |||
{ | |||
} | |||
// ----------------------------------------------------------------------- | |||
void QtUI::setSize(unsigned int width, unsigned int height) | |||
{ | |||
if (d_isResizable()) | |||
resize(width, height); | |||
else | |||
setFixedSize(width, height); | |||
d_uiResize(width, height); | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO |
@@ -8,9 +8,7 @@ include ../Makefile.mk | |||
# -------------------------------------------------------------- | |||
BUILD_CXX_FLAGS += -I../backend -I../includes -I../modules -I../modules/distrho -I../utils | |||
BUILD_CXX_FLAGS += -DWANT_NATIVE -DWANT_LADSPA -DWANT_DSSI -DWANT_LV2 -DWANT_VST -DWANT_AU -DWANT_CSOUND -DWANT_FLUIDSYNTH -DWANT_LINUXSAMPLER | |||
BUILD_CXX_FLAGS += -DWANT_OPENGL -DWANT_AUDIOFILE -DWANT_MIDIFILE -DWANT_ZYNADDSUBFX -DWANT_ZYNADDSUBFX_UI | |||
BUILD_CXX_FLAGS += -I. -I../backend -I../includes -I../modules -I../modules/distrho -I../utils | |||
BUILD_CXX_FLAGS += -std=c++11 -Wzero-as-null-pointer-constant | |||
BUILD_CXX_FLAGS += -isystem /opt/kxstudio/include | |||
# BUILD_CXX_FLAGS += -isystem /usr/include/qt5 | |||
@@ -58,6 +56,13 @@ CarlaString: CarlaString.cpp ../utils/CarlaString.hpp | |||
$(CXX) $< $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -o $@ | |||
# valgrind ./CarlaString | |||
DISTRHO: DISTRHO.cpp ../modules/distrho/*.hpp ../modules/distrho/src/*.cpp | |||
$(CXX) $< ../modules/dgl.a $(BUILD_CXX_FLAGS) -I../modules/distrho $(LINK_FLAGS) $(DGL_LIBS) $(shell pkg-config --libs liblo) -o $@ | |||
./DISTRHO | |||
DISTRHO.so: DISTRHO.cpp ../modules/distrho/*.hpp ../modules/distrho/src/*.cpp | |||
$(CXX) $< ../modules/dgl.a $(BUILD_CXX_FLAGS) -I../modules/distrho -DSHARED_DLL $(LINK_FLAGS) $(DGL_LIBS) -shared -Wl,--no-undefined -o $@ | |||
DGL: DGL.cpp ../modules/distrho/dgl/src/Window.cpp | |||
$(CXX) $< $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) -o $@ | |||
# ./DGL | |||