@@ -192,10 +192,10 @@ private: | |||||
@code | @code | ||||
const char* txt = "Text me up."; | const char* txt = "Text me up."; | ||||
textBounds(vg, x,y, txt, NULL, bounds); | |||||
beginPath(vg); | |||||
roundedRect(vg, bounds[0], bounds[1], bounds[2]-bounds[0], bounds[3]-bounds[1]); | |||||
fill(vg); | |||||
vg.textBounds(x,y, txt, NULL, bounds); | |||||
vg.beginPath(); | |||||
vg.roundedRect(bounds[0], bounds[1], bounds[2]-bounds[0], bounds[3]-bounds[1]); | |||||
vg.fill(); | |||||
@endcode | @endcode | ||||
Note: currently only solid color fill is supported for text. | Note: currently only solid color fill is supported for text. | ||||
@@ -111,7 +111,7 @@ public: | |||||
/** | /** | ||||
Mouse event. | Mouse event. | ||||
@a button The button number (1 = left, 2 = middle, 3 = right). | @a button The button number (1 = left, 2 = middle, 3 = right). | ||||
@a press True if the key was pressed, false if released. | |||||
@a press True if the button was pressed, false if released. | |||||
@a pos The widget-relative coordinates of the pointer. | @a pos The widget-relative coordinates of the pointer. | ||||
@see onMouse | @see onMouse | ||||
*/ | */ | ||||
@@ -133,6 +133,29 @@ struct AudioPort { | |||||
symbol() {} | symbol() {} | ||||
}; | }; | ||||
/** | |||||
Parameter designation.@n | |||||
Allows a parameter to be specially designated for a task, like bypass. | |||||
Each designation is unique, there must be only one parameter that uses it.@n | |||||
The use of designated parameters is completely optional. | |||||
@note Designated parameters have strict ranges. | |||||
@see ParameterRanges::adjustForDesignation() | |||||
*/ | |||||
enum ParameterDesignation { | |||||
/** | |||||
Null or unset designation. | |||||
*/ | |||||
kParameterDesignationNull = 0, | |||||
/** | |||||
Bypass designation.@n | |||||
When on (> 0.5f), it means the plugin must run in a bypassed state. | |||||
*/ | |||||
kParameterDesignationBypass = 1 | |||||
}; | |||||
/** | /** | ||||
Parameter ranges.@n | Parameter ranges.@n | ||||
This is used to set the default, minimum and maximum values of a parameter. | This is used to set the default, minimum and maximum values of a parameter. | ||||
@@ -289,6 +312,11 @@ struct Parameter { | |||||
*/ | */ | ||||
ParameterRanges ranges; | ParameterRanges ranges; | ||||
/** | |||||
Designation for this parameter. | |||||
*/ | |||||
ParameterDesignation designation; | |||||
/** | /** | ||||
MIDI CC to use by default on this parameter.@n | MIDI CC to use by default on this parameter.@n | ||||
A value of 0 or 32 (bank change) is considered invalid.@n | A value of 0 or 32 (bank change) is considered invalid.@n | ||||
@@ -306,6 +334,7 @@ struct Parameter { | |||||
symbol(), | symbol(), | ||||
unit(), | unit(), | ||||
ranges(), | ranges(), | ||||
designation(kParameterDesignationNull), | |||||
midiCC(0) {} | midiCC(0) {} | ||||
/** | /** | ||||
@@ -317,7 +346,32 @@ struct Parameter { | |||||
symbol(s), | symbol(s), | ||||
unit(u), | unit(u), | ||||
ranges(def, min, max), | ranges(def, min, max), | ||||
designation(kParameterDesignationNull), | |||||
midiCC(0) {} | midiCC(0) {} | ||||
/** | |||||
Initialize a parameter for a specific designation. | |||||
*/ | |||||
void initDesignation(ParameterDesignation d) noexcept | |||||
{ | |||||
designation = d; | |||||
switch (d) | |||||
{ | |||||
case kParameterDesignationNull: | |||||
break; | |||||
case kParameterDesignationBypass: | |||||
hints = kParameterIsAutomable|kParameterIsBoolean|kParameterIsInteger; | |||||
name = "Bypass"; | |||||
symbol = "dpf_bypass"; | |||||
unit = ""; | |||||
midiCC = 0; | |||||
ranges.def = 0.0f; | |||||
ranges.min = 0.0f; | |||||
ranges.max = 1.0f; | |||||
break; | |||||
} | |||||
} | |||||
}; | }; | ||||
/** | /** | ||||
@@ -541,7 +595,7 @@ public: | |||||
Returns false when the host buffer is full, in which case do not call this again until the next run(). | Returns false when the host buffer is full, in which case do not call this again until the next run(). | ||||
@note This function is not implemented yet!@n | @note This function is not implemented yet!@n | ||||
It's here so that developers can prepare MIDI plugins in advance.@n | It's here so that developers can prepare MIDI plugins in advance.@n | ||||
If you plan to use this, please report to DPF authos so it can be implemented. | |||||
If you plan to use this, please report to DPF authors so it can be implemented. | |||||
*/ | */ | ||||
bool writeMidiEvent(const MidiEvent& midiEvent) noexcept; | bool writeMidiEvent(const MidiEvent& midiEvent) noexcept; | ||||
#endif | #endif | ||||
@@ -661,7 +715,7 @@ protected: | |||||
/** | /** | ||||
Get the value of an internal state.@n | Get the value of an internal state.@n | ||||
The host may call this function from any non-realtime context.@n | The host may call this function from any non-realtime context.@n | ||||
Must be implemented by your plugin class if DISTRHO_PLUGIN_WANT_PROGRAMS or DISTRHO_PLUGIN_WANT_FULL_STATE is enabled. | |||||
Must be implemented by your plugin class if DISTRHO_PLUGIN_WANT_FULL_STATE is enabled. | |||||
@note The use of this function breaks compatibility with the DSSI format. | @note The use of this function breaks compatibility with the DSSI format. | ||||
*/ | */ | ||||
virtual String getState(const char* key) const = 0; | virtual String getState(const char* key) const = 0; | ||||
@@ -290,6 +290,13 @@ public: | |||||
return fData->parameters[index].hints; | return fData->parameters[index].hints; | ||||
} | } | ||||
ParameterDesignation getParameterDesignation(const uint32_t index) const noexcept | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, kParameterDesignationNull); | |||||
return fData->parameters[index].designation; | |||||
} | |||||
bool isParameterOutput(const uint32_t index) const noexcept | bool isParameterOutput(const uint32_t index) const noexcept | ||||
{ | { | ||||
return (getParameterHints(index) & kParameterIsOutput); | return (getParameterHints(index) & kParameterIsOutput); | ||||
@@ -97,28 +97,27 @@ public: | |||||
#endif | #endif | ||||
fClient(client) | fClient(client) | ||||
{ | { | ||||
#if DISTRHO_PLUGIN_NUM_INPUTS > 0 || DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||||
char strBuf[0xff+1]; | char strBuf[0xff+1]; | ||||
strBuf[0xff] = '\0'; | strBuf[0xff] = '\0'; | ||||
#if DISTRHO_PLUGIN_NUM_INPUTS > 0 | |||||
# if DISTRHO_PLUGIN_NUM_INPUTS > 0 | |||||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) | for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) | ||||
{ | { | ||||
std::snprintf(strBuf, 0xff, "in%i", i+1); | std::snprintf(strBuf, 0xff, "in%i", i+1); | ||||
fPortAudioIns[i] = jack_port_register(fClient, strBuf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | fPortAudioIns[i] = jack_port_register(fClient, strBuf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | ||||
} | } | ||||
#endif | |||||
#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||||
# endif | |||||
# if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) | for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) | ||||
{ | { | ||||
std::snprintf(strBuf, 0xff, "out%i", i+1); | std::snprintf(strBuf, 0xff, "out%i", i+1); | ||||
fPortAudioOuts[i] = jack_port_register(fClient, strBuf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | fPortAudioOuts[i] = jack_port_register(fClient, strBuf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | ||||
} | } | ||||
# endif | |||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_IS_SYNTH | |||||
fPortMidiIn = jack_port_register(fClient, "midi-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); | |||||
#endif | |||||
fPortEventsIn = jack_port_register(fClient, "events-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); | |||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | #if DISTRHO_PLUGIN_WANT_PROGRAMS | ||||
if (fPlugin.getProgramCount() > 0) | if (fPlugin.getProgramCount() > 0) | ||||
@@ -128,11 +127,18 @@ public: | |||||
fUI.programLoaded(0); | fUI.programLoaded(0); | ||||
# endif | # endif | ||||
} | } | ||||
# if DISTRHO_PLUGIN_HAS_UI | |||||
fProgramChanged = -1; | |||||
# endif | |||||
#endif | #endif | ||||
if (const uint32_t count = fPlugin.getParameterCount()) | if (const uint32_t count = fPlugin.getParameterCount()) | ||||
{ | { | ||||
fLastOutputValues = new float[count]; | fLastOutputValues = new float[count]; | ||||
#if DISTRHO_PLUGIN_HAS_UI | |||||
fParametersChanged = new bool[count]; | |||||
std::memset(fParametersChanged, 0, sizeof(bool)*count); | |||||
#endif | |||||
for (uint32_t i=0; i < count; ++i) | for (uint32_t i=0; i < count; ++i) | ||||
{ | { | ||||
@@ -143,15 +149,18 @@ public: | |||||
else | else | ||||
{ | { | ||||
fLastOutputValues[i] = 0.0f; | fLastOutputValues[i] = 0.0f; | ||||
# if DISTRHO_PLUGIN_HAS_UI | |||||
#if DISTRHO_PLUGIN_HAS_UI | |||||
fUI.parameterChanged(i, fPlugin.getParameterValue(i)); | fUI.parameterChanged(i, fPlugin.getParameterValue(i)); | ||||
# endif | |||||
#endif | |||||
} | } | ||||
} | } | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
fLastOutputValues = nullptr; | fLastOutputValues = nullptr; | ||||
#if DISTRHO_PLUGIN_HAS_UI | |||||
fParametersChanged = nullptr; | |||||
#endif | |||||
} | } | ||||
jack_set_buffer_size_callback(fClient, jackBufferSizeCallback, this); | jack_set_buffer_size_callback(fClient, jackBufferSizeCallback, this); | ||||
@@ -192,10 +201,8 @@ public: | |||||
if (fClient == nullptr) | if (fClient == nullptr) | ||||
return; | return; | ||||
#if DISTRHO_PLUGIN_IS_SYNTH | |||||
jack_port_unregister(fClient, fPortMidiIn); | |||||
fPortMidiIn = nullptr; | |||||
#endif | |||||
jack_port_unregister(fClient, fPortEventsIn); | |||||
fPortEventsIn = nullptr; | |||||
#if DISTRHO_PLUGIN_NUM_INPUTS > 0 | #if DISTRHO_PLUGIN_NUM_INPUTS > 0 | ||||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) | for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) | ||||
@@ -225,20 +232,31 @@ protected: | |||||
if (gCloseSignalReceived) | if (gCloseSignalReceived) | ||||
return fUI.quit(); | return fUI.quit(); | ||||
float value; | |||||
# if DISTRHO_PLUGIN_WANT_PROGRAMS | |||||
if (fProgramChanged >= 0) | |||||
{ | |||||
fUI.programLoaded(fProgramChanged); | |||||
fProgramChanged = -1; | |||||
} | |||||
# endif | |||||
for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | ||||
{ | { | ||||
if (! fPlugin.isParameterOutput(i)) | |||||
continue; | |||||
value = fPlugin.getParameterValue(i); | |||||
if (fPlugin.isParameterOutput(i)) | |||||
{ | |||||
const float value = fPlugin.getParameterValue(i); | |||||
if (fLastOutputValues[i] == value) | |||||
continue; | |||||
if (d_isEqual(fLastOutputValues[i], value)) | |||||
continue; | |||||
fLastOutputValues[i] = value; | |||||
fUI.parameterChanged(i, value); | |||||
fLastOutputValues[i] = value; | |||||
fUI.parameterChanged(i, value); | |||||
} | |||||
else if (fParametersChanged[i]) | |||||
{ | |||||
fParametersChanged[i] = false; | |||||
fUI.parameterChanged(i, fPlugin.getParameterValue(i)); | |||||
} | |||||
} | } | ||||
fUI.exec_idle(); | fUI.exec_idle(); | ||||
@@ -310,14 +328,14 @@ protected: | |||||
fPlugin.setTimePosition(fTimePosition); | fPlugin.setTimePosition(fTimePosition); | ||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_IS_SYNTH | |||||
void* const midiBuf = jack_port_get_buffer(fPortMidiIn, nframes); | |||||
void* const midiBuf = jack_port_get_buffer(fPortEventsIn, nframes); | |||||
if (const uint32_t eventCount = jack_midi_get_event_count(midiBuf)) | if (const uint32_t eventCount = jack_midi_get_event_count(midiBuf)) | ||||
{ | { | ||||
#if DISTRHO_PLUGIN_IS_SYNTH | |||||
uint32_t midiEventCount = 0; | uint32_t midiEventCount = 0; | ||||
MidiEvent midiEvents[eventCount]; | MidiEvent midiEvents[eventCount]; | ||||
#endif | |||||
jack_midi_event_t jevent; | jack_midi_event_t jevent; | ||||
for (uint32_t i=0; i < eventCount; ++i) | for (uint32_t i=0; i < eventCount; ++i) | ||||
@@ -325,6 +343,47 @@ protected: | |||||
if (jack_midi_event_get(&jevent, midiBuf, i) != 0) | if (jack_midi_event_get(&jevent, midiBuf, i) != 0) | ||||
break; | break; | ||||
// Check if message is control change on channel 1 | |||||
if (jevent.buffer[0] == 0xB0 && jevent.size == 3) | |||||
{ | |||||
const uint8_t control = jevent.buffer[1]; | |||||
const uint8_t value = jevent.buffer[2]; | |||||
/* NOTE: This is not optimal, we're iterating all parameters on every CC message. | |||||
Since the JACK standalone is more of a test tool, this will do for now. */ | |||||
for (uint32_t j=0, paramCount=fPlugin.getParameterCount(); j < paramCount; ++j) | |||||
{ | |||||
if (fPlugin.isParameterOutput(j)) | |||||
continue; | |||||
if (fPlugin.getParameterMidiCC(j) != control) | |||||
continue; | |||||
const float scaled = static_cast<float>(value)/127.0f; | |||||
const float fvalue = fPlugin.getParameterRanges(j).getUnnormalizedValue(scaled); | |||||
fPlugin.setParameterValue(j, fvalue); | |||||
#if DISTRHO_PLUGIN_HAS_UI | |||||
fParametersChanged[j] = true; | |||||
#endif | |||||
break; | |||||
} | |||||
} | |||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||||
// Check if message is program change on channel 1 | |||||
else if (jevent.buffer[0] == 0xC0 && jevent.size == 2) | |||||
{ | |||||
const uint8_t program = jevent.buffer[1]; | |||||
if (program < fPlugin.getProgramCount()) | |||||
{ | |||||
fPlugin.loadProgram(program); | |||||
# if DISTRHO_PLUGIN_HAS_UI | |||||
fProgramChanged = program; | |||||
# endif | |||||
} | |||||
} | |||||
#endif | |||||
#if DISTRHO_PLUGIN_IS_SYNTH | |||||
MidiEvent& midiEvent(midiEvents[midiEventCount++]); | MidiEvent& midiEvent(midiEvents[midiEventCount++]); | ||||
midiEvent.frame = jevent.time; | midiEvent.frame = jevent.time; | ||||
@@ -334,10 +393,14 @@ protected: | |||||
midiEvent.dataExt = jevent.buffer; | midiEvent.dataExt = jevent.buffer; | ||||
else | else | ||||
std::memcpy(midiEvent.data, jevent.buffer, midiEvent.size); | std::memcpy(midiEvent.data, jevent.buffer, midiEvent.size); | ||||
#endif | |||||
} | } | ||||
#if DISTRHO_PLUGIN_IS_SYNTH | |||||
fPlugin.run(audioIns, audioOuts, nframes, midiEvents, midiEventCount); | fPlugin.run(audioIns, audioOuts, nframes, midiEvents, midiEventCount); | ||||
#endif | |||||
} | } | ||||
#if DISTRHO_PLUGIN_IS_SYNTH | |||||
else | else | ||||
{ | { | ||||
fPlugin.run(audioIns, audioOuts, nframes, nullptr, 0); | fPlugin.run(audioIns, audioOuts, nframes, nullptr, 0); | ||||
@@ -393,9 +456,7 @@ private: | |||||
#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | ||||
jack_port_t* fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS]; | jack_port_t* fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS]; | ||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_IS_SYNTH | |||||
jack_port_t* fPortMidiIn; | |||||
#endif | |||||
jack_port_t* fPortEventsIn; | |||||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | #if DISTRHO_PLUGIN_WANT_TIMEPOS | ||||
TimePosition fTimePosition; | TimePosition fTimePosition; | ||||
#endif | #endif | ||||
@@ -403,6 +464,14 @@ private: | |||||
// Temporary data | // Temporary data | ||||
float* fLastOutputValues; | float* fLastOutputValues; | ||||
#if DISTRHO_PLUGIN_HAS_UI | |||||
// Store DSP changes to send to UI | |||||
bool* fParametersChanged; | |||||
# if DISTRHO_PLUGIN_WANT_PROGRAMS | |||||
int fProgramChanged; | |||||
# endif | |||||
#endif | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Callbacks | // Callbacks | ||||
@@ -512,6 +512,12 @@ public: | |||||
if (fLastControlValues[i] != curValue && ! fPlugin.isParameterOutput(i)) | if (fLastControlValues[i] != curValue && ! fPlugin.isParameterOutput(i)) | ||||
{ | { | ||||
fLastControlValues[i] = curValue; | fLastControlValues[i] = curValue; | ||||
if (fPlugin.getParameterDesignation(i) == kParameterDesignationBypass) | |||||
{ | |||||
curValue = 1.0f - curValue; | |||||
} | |||||
fPlugin.setParameterValue(i, curValue); | fPlugin.setParameterValue(i, curValue); | ||||
} | } | ||||
} | } | ||||
@@ -589,10 +595,14 @@ public: | |||||
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI | ||||
const uint32_t capacity = fPortEventsOut->atom.size; | const uint32_t capacity = fPortEventsOut->atom.size; | ||||
bool needsInit = true; | |||||
uint32_t size, offset = 0; | uint32_t size, offset = 0; | ||||
LV2_Atom_Event* aev; | LV2_Atom_Event* aev; | ||||
fPortEventsOut->atom.size = sizeof(LV2_Atom_Sequence_Body); | |||||
fPortEventsOut->atom.type = fURIDs.atomSequence; | |||||
fPortEventsOut->body.unit = 0; | |||||
fPortEventsOut->body.pad = 0; | |||||
// TODO - MIDI Output | // TODO - MIDI Output | ||||
for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) | for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) | ||||
@@ -617,15 +627,6 @@ public: | |||||
if (sizeof(LV2_Atom_Event) + msgSize > capacity - offset) | if (sizeof(LV2_Atom_Event) + msgSize > capacity - offset) | ||||
break; | break; | ||||
if (needsInit) | |||||
{ | |||||
fPortEventsOut->atom.size = 0; | |||||
fPortEventsOut->atom.type = fURIDs.atomSequence; | |||||
fPortEventsOut->body.unit = 0; | |||||
fPortEventsOut->body.pad = 0; | |||||
needsInit = false; | |||||
} | |||||
// reserve msg space | // reserve msg space | ||||
char msgBuf[msgSize]; | char msgBuf[msgSize]; | ||||
std::memset(msgBuf, 0, msgSize); | std::memset(msgBuf, 0, msgSize); | ||||
@@ -377,10 +377,34 @@ void lv2_generate_ttl(const char* const basename) | |||||
pluginString += " a lv2:InputPort, lv2:ControlPort ;\n"; | pluginString += " a lv2:InputPort, lv2:ControlPort ;\n"; | ||||
pluginString += " lv2:index " + String(portIndex) + " ;\n"; | pluginString += " lv2:index " + String(portIndex) + " ;\n"; | ||||
pluginString += " lv2:name \"" + plugin.getParameterName(i) + "\" ;\n"; | |||||
// symbol | |||||
bool designated = false; | |||||
// designation | |||||
if (! plugin.isParameterOutput(i)) | |||||
{ | { | ||||
switch (plugin.getParameterDesignation(i)) | |||||
{ | |||||
case kParameterDesignationNull: | |||||
break; | |||||
case kParameterDesignationBypass: | |||||
designated = true; | |||||
pluginString += " lv2:name \"Enabled\" ;\n"; | |||||
pluginString += " lv2:symbol \"lv2_enabled\" ;\n"; | |||||
pluginString += " lv2:default 1 ;\n"; | |||||
pluginString += " lv2:minimum 0 ;\n"; | |||||
pluginString += " lv2:maximum 1 ;\n"; | |||||
pluginString += " lv2:portProperty lv2:toggled , lv2:integer ;\n"; | |||||
pluginString += " lv2:designation lv2:enabled ;\n"; | |||||
break; | |||||
} | |||||
} | |||||
// name and symbol | |||||
if (! designated) | |||||
{ | |||||
pluginString += " lv2:name \"" + plugin.getParameterName(i) + "\" ;\n"; | |||||
String symbol(plugin.getParameterSymbol(i)); | String symbol(plugin.getParameterSymbol(i)); | ||||
if (symbol.isEmpty()) | if (symbol.isEmpty()) | ||||
@@ -390,24 +414,28 @@ void lv2_generate_ttl(const char* const basename) | |||||
} | } | ||||
// ranges | // ranges | ||||
if (! designated) | |||||
{ | { | ||||
const ParameterRanges& ranges(plugin.getParameterRanges(i)); | const ParameterRanges& ranges(plugin.getParameterRanges(i)); | ||||
if (plugin.getParameterHints(i) & kParameterIsInteger) | if (plugin.getParameterHints(i) & kParameterIsInteger) | ||||
{ | { | ||||
pluginString += " lv2:default " + String(int(plugin.getParameterValue(i))) + " ;\n"; | |||||
if (! plugin.isParameterOutput(i)) | |||||
pluginString += " lv2:default " + String(int(plugin.getParameterValue(i))) + " ;\n"; | |||||
pluginString += " lv2:minimum " + String(int(ranges.min)) + " ;\n"; | pluginString += " lv2:minimum " + String(int(ranges.min)) + " ;\n"; | ||||
pluginString += " lv2:maximum " + String(int(ranges.max)) + " ;\n"; | pluginString += " lv2:maximum " + String(int(ranges.max)) + " ;\n"; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
pluginString += " lv2:default " + String(plugin.getParameterValue(i)) + " ;\n"; | |||||
if (! plugin.isParameterOutput(i)) | |||||
pluginString += " lv2:default " + String(plugin.getParameterValue(i)) + " ;\n"; | |||||
pluginString += " lv2:minimum " + String(ranges.min) + " ;\n"; | pluginString += " lv2:minimum " + String(ranges.min) + " ;\n"; | ||||
pluginString += " lv2:maximum " + String(ranges.max) + " ;\n"; | pluginString += " lv2:maximum " + String(ranges.max) + " ;\n"; | ||||
} | } | ||||
} | } | ||||
// unit | // unit | ||||
if (! designated) | |||||
{ | { | ||||
const String& unit(plugin.getParameterUnit(i)); | const String& unit(plugin.getParameterUnit(i)); | ||||
@@ -453,6 +481,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
} | } | ||||
// hints | // hints | ||||
if (! designated) | |||||
{ | { | ||||
const uint32_t hints(plugin.getParameterHints(i)); | const uint32_t hints(plugin.getParameterHints(i)); | ||||
@@ -239,7 +239,7 @@ protected: | |||||
const size_t msgSize(tmpStr.length()+1); | const size_t msgSize(tmpStr.length()+1); | ||||
// reserve atom space | // reserve atom space | ||||
const size_t atomSize(lv2_atom_pad_size(sizeof(LV2_Atom) + msgSize)); | |||||
const size_t atomSize(sizeof(LV2_Atom) + msgSize); | |||||
char atomBuf[atomSize]; | char atomBuf[atomSize]; | ||||
std::memset(atomBuf, 0, atomSize); | std::memset(atomBuf, 0, atomSize); | ||||
@@ -135,6 +135,7 @@ DistrhoPluginNekobi::DistrhoPluginNekobi() | |||||
fParams.decay = 75.0f; | fParams.decay = 75.0f; | ||||
fParams.accent = 25.0f; | fParams.accent = 25.0f; | ||||
fParams.volume = 75.0f; | fParams.volume = 75.0f; | ||||
fParams.bypass = false; | |||||
// Internal stuff | // Internal stuff | ||||
fSynth.waveform = 0.0f; | fSynth.waveform = 0.0f; | ||||
@@ -232,6 +233,9 @@ void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter) | |||||
parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
parameter.ranges.max = 100.0f; | parameter.ranges.max = 100.0f; | ||||
break; | break; | ||||
case paramBypass: | |||||
parameter.initDesignation(kParameterDesignationBypass); | |||||
break; | |||||
} | } | ||||
} | } | ||||
@@ -258,6 +262,8 @@ float DistrhoPluginNekobi::getParameterValue(uint32_t index) const | |||||
return fParams.accent; | return fParams.accent; | ||||
case paramVolume: | case paramVolume: | ||||
return fParams.volume; | return fParams.volume; | ||||
case paramBypass: | |||||
return fParams.bypass ? 1.0f : 0.0f; | |||||
} | } | ||||
return 0.0f; | return 0.0f; | ||||
@@ -307,6 +313,14 @@ void DistrhoPluginNekobi::setParameterValue(uint32_t index, float value) | |||||
fSynth.volume = value/100.0f; | fSynth.volume = value/100.0f; | ||||
DISTRHO_SAFE_ASSERT(fSynth.volume >= 0.0f && fSynth.volume <= 1.0f); | DISTRHO_SAFE_ASSERT(fSynth.volume >= 0.0f && fSynth.volume <= 1.0f); | ||||
break; | break; | ||||
case paramBypass: { | |||||
const bool bypass = (value > 0.5f); | |||||
if (fParams.bypass != bypass) | |||||
{ | |||||
fParams.bypass = bypass; | |||||
nekobee_synth_all_voices_off(&fSynth); | |||||
} | |||||
} break; | |||||
} | } | ||||
} | } | ||||
@@ -342,6 +356,10 @@ void DistrhoPluginNekobi::run(const float**, float** outputs, uint32_t frames, c | |||||
return; | return; | ||||
} | } | ||||
// ignore midi input if bypassed | |||||
if (fParams.bypass) | |||||
midiEventCount = 0; | |||||
while (framesDone < frames) | while (framesDone < frames) | ||||
{ | { | ||||
if (fSynth.nugget_remains == 0) | if (fSynth.nugget_remains == 0) | ||||
@@ -42,6 +42,7 @@ public: | |||||
paramDecay, | paramDecay, | ||||
paramAccent, | paramAccent, | ||||
paramVolume, | paramVolume, | ||||
paramBypass, | |||||
paramCount | paramCount | ||||
}; | }; | ||||
@@ -79,7 +80,7 @@ protected: | |||||
uint32_t getVersion() const noexcept override | uint32_t getVersion() const noexcept override | ||||
{ | { | ||||
return d_version(1, 0, 0); | |||||
return d_version(1, 1, 0); | |||||
} | } | ||||
int64_t getUniqueId() const noexcept override | int64_t getUniqueId() const noexcept override | ||||
@@ -117,6 +118,7 @@ private: | |||||
float decay; | float decay; | ||||
float accent; | float accent; | ||||
float volume; | float volume; | ||||
bool bypass; | |||||
} fParams; | } fParams; | ||||
nekobee_synth_t fSynth; | nekobee_synth_t fSynth; | ||||