| @@ -34,13 +34,13 @@ | |||
| #define MIDI_STATUS_CHANNEL_PRESSURE 0xD0 // pressure (0-127), none | |||
| #define MIDI_STATUS_PITCH_WHEEL_CONTROL 0xE0 // LSB (0-127), MSB (0-127) | |||
| #define MIDI_IS_STATUS_NOTE_OFF(status) (((status) & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_OFF) | |||
| #define MIDI_IS_STATUS_NOTE_ON(status) (((status) & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_ON) | |||
| #define MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) (((status) & MIDI_STATUS_BIT) == MIDI_STATUS_POLYPHONIC_AFTERTOUCH) | |||
| #define MIDI_IS_STATUS_CONTROL_CHANGE(status) (((status) & MIDI_STATUS_BIT) == MIDI_STATUS_CONTROL_CHANGE) | |||
| #define MIDI_IS_STATUS_PROGRAM_CHANGE(status) (((status) & MIDI_STATUS_BIT) == MIDI_STATUS_PROGRAM_CHANGE) | |||
| #define MIDI_IS_STATUS_CHANNEL_PRESSURE(status) (((status) & MIDI_STATUS_BIT) == MIDI_STATUS_CHANNEL_PRESSURE) | |||
| #define MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) (((status) & MIDI_STATUS_BIT) == MIDI_STATUS_PITCH_WHEEL_CONTROL) | |||
| #define MIDI_IS_STATUS_NOTE_OFF(status) (((status) < 0xF0) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_OFF) | |||
| #define MIDI_IS_STATUS_NOTE_ON(status) (((status) < 0xF0) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_ON) | |||
| #define MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) (((status) < 0xF0) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_POLYPHONIC_AFTERTOUCH) | |||
| #define MIDI_IS_STATUS_CONTROL_CHANGE(status) (((status) < 0xF0) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_CONTROL_CHANGE) | |||
| #define MIDI_IS_STATUS_PROGRAM_CHANGE(status) (((status) < 0xF0) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_PROGRAM_CHANGE) | |||
| #define MIDI_IS_STATUS_CHANNEL_PRESSURE(status) (((status) < 0xF0) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_CHANNEL_PRESSURE) | |||
| #define MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) (((status) < 0xF0) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_PITCH_WHEEL_CONTROL) | |||
| // MIDI Utils | |||
| #define MIDI_GET_STATUS_FROM_DATA(data) ((data[0] < 0xF0) ? data[0] & MIDI_STATUS_BIT : data[0]) | |||
| @@ -23,6 +23,7 @@ using namespace juce; | |||
| #include "vex/cChorus.h" | |||
| #include "vex/cDelay.h" | |||
| #include "vex/cReverb.h" | |||
| #include "vex/cSyntModule.h" | |||
| // ----------------------------------------------------------------------- | |||
| @@ -192,7 +193,7 @@ protected: | |||
| // ------------------------------------------------------------------- | |||
| // Plugin state calls | |||
| void setParameterValue(const uint32_t index, const float value) | |||
| void setParameterValue(const uint32_t index, const float value) override | |||
| { | |||
| switch (index) | |||
| { | |||
| @@ -375,7 +376,7 @@ protected: | |||
| // ------------------------------------------------------------------- | |||
| // Plugin state calls | |||
| void setParameterValue(const uint32_t index, const float value) | |||
| void setParameterValue(const uint32_t index, const float value) override | |||
| { | |||
| if (index < kParamCount) | |||
| parameters[index] = value; | |||
| @@ -490,7 +491,7 @@ protected: | |||
| // ------------------------------------------------------------------- | |||
| // Plugin state calls | |||
| void setParameterValue(const uint32_t index, const float value) | |||
| void setParameterValue(const uint32_t index, const float value) override | |||
| { | |||
| if (index < kParamCount) | |||
| parameters[index] = value; | |||
| @@ -612,7 +613,7 @@ protected: | |||
| // ------------------------------------------------------------------- | |||
| // Plugin state calls | |||
| void setParameterValue(const uint32_t index, const float value) | |||
| void setParameterValue(const uint32_t index, const float value) override | |||
| { | |||
| if (index < kParamCount) | |||
| parameters[index] = value; | |||
| @@ -641,6 +642,170 @@ private: | |||
| // ----------------------------------------------------------------------- | |||
| class VexSynthPlugin : public PluginClass | |||
| { | |||
| public: | |||
| static const unsigned int kParamCount = 1; | |||
| VexSynthPlugin(const HostDescriptor* const host) | |||
| : PluginClass(host), | |||
| synth(parameters) | |||
| { | |||
| std::memset(parameters, 0, sizeof(float)*92); | |||
| for (int i = 0; i < 3; ++i) | |||
| { | |||
| const int offset = i * 24; | |||
| parameters[offset + 1] = 0.5f; | |||
| parameters[offset + 2] = 0.5f; | |||
| parameters[offset + 3] = 0.5f; | |||
| parameters[offset + 4] = 0.5f; | |||
| parameters[offset + 5] = 0.9f; | |||
| parameters[offset + 6] = 0.0f; | |||
| parameters[offset + 7] = 1.0f; | |||
| parameters[offset + 8] = 0.5f; | |||
| parameters[offset + 9] = 0.0f; | |||
| parameters[offset + 10] = 0.2f; | |||
| parameters[offset + 11] = 0.0f; | |||
| parameters[offset + 12] = 0.5f; | |||
| parameters[offset + 13] = 0.5f; | |||
| parameters[offset + 14] = 0.0f; | |||
| parameters[offset + 15] = 0.3f; | |||
| parameters[offset + 16] = 0.7f; | |||
| parameters[offset + 17] = 0.1f; | |||
| parameters[offset + 18] = 0.5f; | |||
| parameters[offset + 19] = 0.5f; | |||
| parameters[offset + 20] = 0.0f; | |||
| parameters[offset + 21] = 0.0f; | |||
| parameters[offset + 22] = 0.5f; | |||
| parameters[offset + 23] = 0.5f; | |||
| parameters[offset + 24] = 0.5f; | |||
| } | |||
| parameters[89] = 1.0f; | |||
| synth.setSampleRate(getSampleRate()); | |||
| synth.update(89); | |||
| } | |||
| protected: | |||
| // ------------------------------------------------------------------- | |||
| // Plugin parameter calls | |||
| uint32_t getParameterCount() const override | |||
| { | |||
| return kParamCount; | |||
| } | |||
| const Parameter* getParameterInfo(const uint32_t index) const override | |||
| { | |||
| static Parameter paramInfo; | |||
| int hints = PARAMETER_IS_ENABLED|PARAMETER_IS_AUTOMABLE; | |||
| paramInfo.name = nullptr; | |||
| paramInfo.unit = nullptr; | |||
| paramInfo.ranges.def = 0.0f; | |||
| paramInfo.ranges.min = 0.0f; | |||
| paramInfo.ranges.max = 1.0f; | |||
| paramInfo.ranges.step = 1.0f; | |||
| paramInfo.ranges.stepSmall = 1.0f; | |||
| paramInfo.ranges.stepLarge = 1.0f; | |||
| paramInfo.scalePointCount = 0; | |||
| paramInfo.scalePoints = nullptr; | |||
| switch (index) | |||
| { | |||
| case 0: | |||
| hints |= PARAMETER_IS_INTEGER; | |||
| paramInfo.name = "Wave"; | |||
| paramInfo.ranges.def = 0.0f; | |||
| paramInfo.ranges.min = 0.0f; | |||
| paramInfo.ranges.max = WaveRenderer::getWaveTableSize(); | |||
| break; | |||
| } | |||
| paramInfo.hints = static_cast<ParameterHints>(hints); | |||
| return ¶mInfo; | |||
| } | |||
| float getParameterValue(const uint32_t index) const override | |||
| { | |||
| if (index < kParamCount) | |||
| return parameters[index]; | |||
| return 0.0f; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin state calls | |||
| void setParameterValue(const uint32_t index, const float value) override | |||
| { | |||
| if (index < kParamCount) | |||
| { | |||
| parameters[index] = value; | |||
| synth.setWaveLater(1, WaveRenderer::getWaveTableName(value)); | |||
| //synth.update(index); | |||
| } | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin process calls | |||
| void process(float**, float** outBuffer, const uint32_t frames, const MidiEvent* const midiEvents, const uint32_t midiEventCount) override | |||
| { | |||
| for (uint32_t i=0; i < midiEventCount; ++i) | |||
| { | |||
| const MidiEvent* const midiEvent(&midiEvents[i]); | |||
| const uint8_t status(MIDI_GET_STATUS_FROM_DATA(midiEvent->data)); | |||
| if (status == MIDI_STATUS_NOTE_ON) | |||
| { | |||
| synth.playNote(midiEvent->data[1], midiEvent->data[2], 0, 1); | |||
| } | |||
| else if (status == MIDI_STATUS_NOTE_OFF) | |||
| { | |||
| synth.releaseNote(midiEvent->data[1], 0, 1); | |||
| } | |||
| else if (status == MIDI_STATUS_CONTROL_CHANGE) | |||
| { | |||
| const uint8_t control(midiEvent->data[1]); | |||
| if (control == MIDI_CONTROL_ALL_SOUND_OFF) | |||
| synth.kill(); | |||
| else if (control == MIDI_CONTROL_ALL_NOTES_OFF) | |||
| synth.releaseAll(1); | |||
| } | |||
| } | |||
| carla_zeroFloat(outBuffer[0], frames); | |||
| carla_zeroFloat(outBuffer[1], frames); | |||
| synth.doProcess(outBuffer[0], outBuffer[1], frames); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin dispatcher calls | |||
| void sampleRateChanged(const double sampleRate) override | |||
| { | |||
| synth.setSampleRate(sampleRate); | |||
| } | |||
| private: | |||
| VexSyntModule synth; | |||
| float parameters[92]; | |||
| PluginClassEND(VexSynthPlugin) | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VexSynthPlugin) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| static const PluginDescriptor vexArpDesc = { | |||
| /* category */ PLUGIN_CATEGORY_UTILITY, | |||
| /* hints */ static_cast<PluginHints>(0x0), | |||
| @@ -651,7 +816,7 @@ static const PluginDescriptor vexArpDesc = { | |||
| /* midiOuts */ 1, | |||
| /* paramIns */ VexArpPlugin::kParamCount, | |||
| /* paramOuts */ 0, | |||
| /* name */ "Vex Arp", | |||
| /* name */ "VexArp", | |||
| /* label */ "vexArp", | |||
| /* maker */ "falkTX", | |||
| /* copyright */ "GNU GPL v2+", | |||
| @@ -668,7 +833,7 @@ static const PluginDescriptor vexChorusDesc = { | |||
| /* midiOuts */ 0, | |||
| /* paramIns */ VexChorusPlugin::kParamCount, | |||
| /* paramOuts */ 0, | |||
| /* name */ "Vex Chorus", | |||
| /* name */ "VexChorus", | |||
| /* label */ "vexChorus", | |||
| /* maker */ "falkTX", | |||
| /* copyright */ "GNU GPL v2+", | |||
| @@ -685,7 +850,7 @@ static const PluginDescriptor vexDelayDesc = { | |||
| /* midiOuts */ 0, | |||
| /* paramIns */ VexDelayPlugin::kParamCount, | |||
| /* paramOuts */ 0, | |||
| /* name */ "Vex Delay", | |||
| /* name */ "VexDelay", | |||
| /* label */ "vexDelay", | |||
| /* maker */ "falkTX", | |||
| /* copyright */ "GNU GPL v2+", | |||
| @@ -702,13 +867,30 @@ static const PluginDescriptor vexReverbDesc = { | |||
| /* midiOuts */ 0, | |||
| /* paramIns */ VexReverbPlugin::kParamCount, | |||
| /* paramOuts */ 0, | |||
| /* name */ "Vex Reverb", | |||
| /* name */ "VexReverb", | |||
| /* label */ "vexReverb", | |||
| /* maker */ "falkTX", | |||
| /* copyright */ "GNU GPL v2+", | |||
| PluginDescriptorFILL(VexReverbPlugin) | |||
| }; | |||
| static const PluginDescriptor vexSynthDesc = { | |||
| /* category */ PLUGIN_CATEGORY_SYNTH, | |||
| /* hints */ static_cast<PluginHints>(0x0), | |||
| /* supports */ static_cast<PluginSupports>(0x0), | |||
| /* audioIns */ 0, | |||
| /* audioOuts */ 2, | |||
| /* midiIns */ 1, | |||
| /* midiOuts */ 0, | |||
| /* paramIns */ VexSynthPlugin::kParamCount, | |||
| /* paramOuts */ 0, | |||
| /* name */ "VexSynth", | |||
| /* label */ "vexSynth", | |||
| /* maker */ "falkTX", | |||
| /* copyright */ "GNU GPL v2+", | |||
| PluginDescriptorFILL(VexSynthPlugin) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| CARLA_EXPORT | |||
| @@ -718,6 +900,7 @@ void carla_register_native_plugin_vex() | |||
| carla_register_native_plugin(&vexChorusDesc); | |||
| carla_register_native_plugin(&vexDelayDesc); | |||
| carla_register_native_plugin(&vexReverbDesc); | |||
| carla_register_native_plugin(&vexSynthDesc); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| @@ -726,4 +909,8 @@ void carla_register_native_plugin_vex() | |||
| #include "vex/freeverb/comb.cpp" | |||
| #include "vex/freeverb/revmodel.cpp" | |||
| #include "vex/cVoice.cpp" | |||
| #include "vex/cWaveRenderer.cpp" | |||
| #include "vex/ResourceFile.cpp" | |||
| // ----------------------------------------------------------------------- | |||
| @@ -0,0 +1,174 @@ | |||
| /* (Auto-generated binary data file). */ | |||
| #ifndef BINARY_RESOURCEFILE_H | |||
| #define BINARY_RESOURCEFILE_H | |||
| namespace Wavetables | |||
| { | |||
| extern const char* asym_saw; | |||
| extern const char* asym_saw_ext; | |||
| const int asym_saw_size = 1024; | |||
| extern const char* bass_tone; | |||
| extern const char* bass_tone_ext; | |||
| const int bass_tone_size = 1024; | |||
| extern const char* buzz_1; | |||
| extern const char* buzz_1_ext; | |||
| const int buzz_1_size = 1024; | |||
| extern const char* buzz_2; | |||
| extern const char* buzz_2_ext; | |||
| const int buzz_2_size = 1024; | |||
| extern const char* dark_strings; | |||
| extern const char* dark_strings_ext; | |||
| const int dark_strings_size = 131072; | |||
| extern const char* deep_ring_1; | |||
| extern const char* deep_ring_1_ext; | |||
| const int deep_ring_1_size = 1024; | |||
| extern const char* deep_ring_2; | |||
| extern const char* deep_ring_2_ext; | |||
| const int deep_ring_2_size = 1024; | |||
| extern const char* epiano_tone; | |||
| extern const char* epiano_tone_ext; | |||
| const int epiano_tone_size = 4096; | |||
| extern const char* ghost_1; | |||
| extern const char* ghost_1_ext; | |||
| const int ghost_1_size = 131072; | |||
| extern const char* ghost_2; | |||
| extern const char* ghost_2_ext; | |||
| const int ghost_2_size = 131072; | |||
| extern const char* ghost_3; | |||
| extern const char* ghost_3_ext; | |||
| const int ghost_3_size = 131072; | |||
| extern const char* ghost_4; | |||
| extern const char* ghost_4_ext; | |||
| const int ghost_4_size = 131072; | |||
| extern const char* grind_1; | |||
| extern const char* grind_1_ext; | |||
| const int grind_1_size = 131072; | |||
| extern const char* grind_2; | |||
| extern const char* grind_2_ext; | |||
| const int grind_2_size = 131072; | |||
| extern const char* more_strings; | |||
| extern const char* more_strings_ext; | |||
| const int more_strings_size = 131072; | |||
| extern const char* multi_pulse; | |||
| extern const char* multi_pulse_ext; | |||
| const int multi_pulse_size = 1024; | |||
| extern const char* one_string; | |||
| extern const char* one_string_ext; | |||
| const int one_string_size = 131072; | |||
| extern const char* organ_1; | |||
| extern const char* organ_1_ext; | |||
| const int organ_1_size = 131072; | |||
| extern const char* organ_2; | |||
| extern const char* organ_2_ext; | |||
| const int organ_2_size = 131072; | |||
| extern const char* phasing_sqr; | |||
| extern const char* phasing_sqr_ext; | |||
| const int phasing_sqr_size = 131072; | |||
| extern const char* pulse; | |||
| extern const char* pulse_ext; | |||
| const int pulse_size = 1024; | |||
| extern const char* saw; | |||
| extern const char* saw_ext; | |||
| const int saw_size = 1024; | |||
| extern const char* sharp_1; | |||
| extern const char* sharp_1_ext; | |||
| const int sharp_1_size = 1024; | |||
| extern const char* sharp_2; | |||
| extern const char* sharp_2_ext; | |||
| const int sharp_2_size = 1024; | |||
| extern const char* sine; | |||
| extern const char* sine_ext; | |||
| const int sine_size = 1024; | |||
| extern const char* soft_1; | |||
| extern const char* soft_1_ext; | |||
| const int soft_1_size = 1024; | |||
| extern const char* soft_2; | |||
| extern const char* soft_2_ext; | |||
| const int soft_2_size = 1024; | |||
| extern const char* soft_3; | |||
| extern const char* soft_3_ext; | |||
| const int soft_3_size = 1024; | |||
| extern const char* soft_4; | |||
| extern const char* soft_4_ext; | |||
| const int soft_4_size = 1024; | |||
| extern const char* square; | |||
| extern const char* square_ext; | |||
| const int square_size = 1024; | |||
| extern const char* strings_1; | |||
| extern const char* strings_1_ext; | |||
| const int strings_1_size = 131072; | |||
| extern const char* strings_2; | |||
| extern const char* strings_2_ext; | |||
| const int strings_2_size = 131072; | |||
| extern const char* string_fuzz; | |||
| extern const char* string_fuzz_ext; | |||
| const int string_fuzz_size = 131072; | |||
| extern const char* syn_choir_1; | |||
| extern const char* syn_choir_1_ext; | |||
| const int syn_choir_1_size = 131072; | |||
| extern const char* syn_choir_2; | |||
| extern const char* syn_choir_2_ext; | |||
| const int syn_choir_2_size = 131072; | |||
| extern const char* syn_choir_3; | |||
| extern const char* syn_choir_3_ext; | |||
| const int syn_choir_3_size = 131072; | |||
| extern const char* thin_1; | |||
| extern const char* thin_1_ext; | |||
| const int thin_1_size = 1024; | |||
| extern const char* thin_2; | |||
| extern const char* thin_2_ext; | |||
| const int thin_2_size = 1024; | |||
| extern const char* two_strings; | |||
| extern const char* two_strings_ext; | |||
| const int two_strings_size = 131072; | |||
| extern const char* voice_1; | |||
| extern const char* voice_1_ext; | |||
| const int voice_1_size = 131072; | |||
| extern const char* voice_2; | |||
| extern const char* voice_2_ext; | |||
| const int voice_2_size = 131072; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,196 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCETICE project - Copyright 2008 by Lucio Asnaghi. | |||
| JUCETICE is based around the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2008 by Julian Storer. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE and JUCETICE can be redistributed and/or modified under the terms of | |||
| the GNU Lesser General Public License, as published by the Free Software | |||
| Foundation; either version 2 of the License, or (at your option) any later | |||
| version. | |||
| JUCE and JUCETICE are distributed in the hope that they will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with JUCE and JUCETICE; if not, visit www.gnu.org/licenses or write to | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ============================================================================== | |||
| @author rockhardbuns | |||
| @tweaker Lucio Asnaghi | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCETICE_VEXCADSR_HEADER__ | |||
| #define __JUCETICE_VEXCADSR_HEADER__ | |||
| #ifdef CARLA_EXPORT | |||
| #include "JuceHeader.h" | |||
| #else | |||
| #include "../StandardHeader.h" | |||
| #endif | |||
| //Process every sample in a buffer | |||
| class VexADSR | |||
| { | |||
| public: | |||
| enum State { | |||
| kStateDone = 0, | |||
| kStateAttack, | |||
| kStateDecay, | |||
| kStateSustain, | |||
| kStateRelease, | |||
| kStateQRelease, | |||
| kStateCount | |||
| }; | |||
| typedef void (VexADSR::*StateFunc)(); | |||
| VexADSR() | |||
| : state(kStateAttack), | |||
| attackRate(0.1f), | |||
| decayRate(0.3f), | |||
| sustainLevel(0.5f), | |||
| releaseRate(0.1f), | |||
| preCount(0), | |||
| postCount(0), | |||
| value(0.0f) | |||
| { | |||
| stateFn[kStateDone] = &VexADSR::fn_done; | |||
| stateFn[kStateAttack] = &VexADSR::fn_attack; | |||
| stateFn[kStateDecay] = &VexADSR::fn_decay; | |||
| stateFn[kStateSustain] = &VexADSR::fn_sustain; | |||
| stateFn[kStateRelease] = &VexADSR::fn_release; | |||
| stateFn[kStateQRelease] = &VexADSR::fn_qrelease; | |||
| } | |||
| // Process a buffer | |||
| void doProcess(float* BufferL, float* BufferR, int bSize) | |||
| { | |||
| for(int i = 0; i < bSize; i++) | |||
| { | |||
| (this->*stateFn[state])(); | |||
| BufferL[i] *= value * value; | |||
| BufferR[i] *= value * value; | |||
| } | |||
| } | |||
| // Process a Sample | |||
| float getSample() | |||
| { | |||
| (this->*stateFn[state])(); | |||
| return value * value; | |||
| } | |||
| void reset(int p) | |||
| { | |||
| preCount = p; | |||
| state = kStateAttack; | |||
| value = 0.0f; | |||
| } | |||
| void release(int p) | |||
| { | |||
| postCount = p; | |||
| state = kStateRelease; | |||
| } | |||
| void quickRelease() | |||
| { | |||
| state = kStateQRelease; | |||
| } | |||
| bool getState() | |||
| { | |||
| return (state != kStateDone); | |||
| } | |||
| void kill() | |||
| { | |||
| state = kStateDone; | |||
| } | |||
| void setADSR(double a, double d, double s, double r, double sr) | |||
| { | |||
| double rate = sr * 5.0; | |||
| attackRate = float(1.0f / (rate * jmax(a * a, 0.001))); | |||
| decayRate = float(1.0f / (rate * jmax(d * d, 0.005))); | |||
| releaseRate = float(1.0f / (rate * jmax(r * r, 0.0002))); | |||
| sustainLevel = (float)s; | |||
| } | |||
| private: | |||
| void fn_done() | |||
| { | |||
| } | |||
| void fn_attack() | |||
| { | |||
| --preCount; | |||
| value += attackRate * float(preCount < 1); | |||
| if (value >= 1.0f) | |||
| { | |||
| state = kStateDecay; | |||
| value = 1.0f; | |||
| } | |||
| } | |||
| void fn_decay() | |||
| { | |||
| value -= decayRate; | |||
| if (value <= sustainLevel) | |||
| state = kStateSustain; | |||
| } | |||
| void fn_sustain() | |||
| { | |||
| } | |||
| void fn_release() | |||
| { | |||
| --postCount; | |||
| value -= releaseRate * bool(postCount < 1); | |||
| postCount -= int(postCount > 0); | |||
| if (value <= 0.0f) | |||
| { | |||
| state = kStateDone; | |||
| value = 0.0f; | |||
| } | |||
| } | |||
| void fn_qrelease() | |||
| { | |||
| value -= 0.006f; | |||
| if (value <= 0.0f) | |||
| { | |||
| state = kStateDone; | |||
| value = 0.0f; | |||
| } | |||
| } | |||
| State state; | |||
| StateFunc stateFn[kStateCount]; //Function pointer array for the state functions | |||
| float attackRate, decayRate, sustainLevel, releaseRate; | |||
| int preCount, postCount; //counter to delay release to sync with the sampleframe | |||
| float value; //this is the current value of the envelope | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VexADSR) | |||
| }; | |||
| #endif | |||
| @@ -158,7 +158,7 @@ public: | |||
| } | |||
| // BarSync | |||
| const int samplesPerStep = int((60.0 / bpm) * sampleRate * 4) / timeSig; | |||
| const unsigned int samplesPerStep = int((60.0 / bpm) * sampleRate * 4) / timeSig; | |||
| if (isPlaying && arpSet->syncMode == 2) | |||
| { | |||
| @@ -300,12 +300,14 @@ private: | |||
| const VexArpSettings* arpSet; | |||
| MidiBuffer outMidiBuffer; | |||
| bool dead, notesPlaying, doSync; | |||
| char nextStep; | |||
| unsigned int nextStep; | |||
| unsigned int sampleCount, sampleRate; | |||
| int meter[4]; | |||
| char cKeysDown[kMaxNotes]; | |||
| char cKeysVelocity[kMaxNotes]; | |||
| char cNotesToKill[kMaxNotes]; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VexArp) | |||
| }; | |||
| #endif | |||
| @@ -151,6 +151,8 @@ private: | |||
| int iRead, iWrite; | |||
| AudioSampleBuffer buffer; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VexChorus) | |||
| }; | |||
| #endif | |||
| @@ -123,6 +123,8 @@ private: | |||
| float sampleRate; | |||
| int bufferSize, iRead, iWrite; | |||
| AudioSampleBuffer buffer; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VexDelay) | |||
| }; | |||
| #endif | |||
| @@ -79,6 +79,8 @@ public: | |||
| private: | |||
| revmodel model; | |||
| const float* parameters; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VexReverb) | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,400 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCETICE project - Copyright 2008 by Lucio Asnaghi. | |||
| JUCETICE is based around the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2008 by Julian Storer. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE and JUCETICE can be redistributed and/or modified under the terms of | |||
| the GNU Lesser General Public License, as published by the Free Software | |||
| Foundation; either version 2 of the License, or (at your option) any later | |||
| version. | |||
| JUCE and JUCETICE are distributed in the hope that they will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with JUCE and JUCETICE; if not, visit www.gnu.org/licenses or write to | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ============================================================================== | |||
| @author rockhardbuns | |||
| @tweaker Lucio Asnaghi | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCETICE_VEXCSYNTMODULE_HEADER__ | |||
| #define __JUCETICE_VEXCSYNTMODULE_HEADER__ | |||
| #ifdef CARLA_EXPORT | |||
| #include "JuceHeader.h" | |||
| #else | |||
| #include "../StandardHeader.h" | |||
| #endif | |||
| #include "cVoice.h" | |||
| class VexSyntModule | |||
| { | |||
| public: | |||
| VexSyntModule(const float* const p) | |||
| : parameters(p), | |||
| sampleRate(44100), | |||
| benchwarmer(0), | |||
| playCount(1), | |||
| part1(false), | |||
| part2(false), | |||
| part3(false) | |||
| { | |||
| for (int i = 0; i < kNumVoices; ++i) | |||
| { | |||
| vo1[i] = new VexVoice(p, 0, wr1); | |||
| vo2[i] = new VexVoice(p, 24, wr2); | |||
| vo3[i] = new VexVoice(p, 48, wr3); | |||
| } | |||
| } | |||
| ~VexSyntModule() | |||
| { | |||
| for (int i = 0; i < kNumVoices; ++i) | |||
| { | |||
| delete vo1[i]; | |||
| delete vo2[i]; | |||
| delete vo3[i]; | |||
| } | |||
| } | |||
| #ifdef CARLA_EXPORT | |||
| void doProcess(float* const outPtrL, float* const outPtrR, const int numSamples) | |||
| { | |||
| #else | |||
| void doProcess(AudioSampleBuffer& assbf, AudioSampleBuffer& obf, AudioSampleBuffer& ebf1, AudioSampleBuffer& ebf2, AudioSampleBuffer& ebf3) | |||
| { | |||
| const int numSamples = obf.getNumSamples(); | |||
| float* const outPtrL = assbf.getSampleData(0,0); | |||
| float* const outPtrR = assbf.getSampleData(1,0); | |||
| #endif | |||
| if (part1) | |||
| { | |||
| #ifndef CARLA_EXPORT | |||
| float right = parameters[86] * parameters[83]; | |||
| float left = parameters[86] * (1.0f - parameters[83]); | |||
| #endif | |||
| for (int i = 0; i < kNumVoices; ++i) | |||
| { | |||
| if (vo1[i]->getIsOn()) | |||
| { | |||
| vo1[i]->doProcess(outPtrL, outPtrR, numSamples); | |||
| #ifndef CARLA_EXPORT | |||
| obf.addFrom(0, 0, assbf, 0, 0, numSamples, left); | |||
| obf.addFrom(1, 0, assbf, 1, 0, numSamples, right); | |||
| ebf1.addFrom(0, 0, assbf, 0, 0, numSamples, parameters[22] * left); | |||
| ebf1.addFrom(1, 0, assbf, 1, 0, numSamples, parameters[22] * right); | |||
| ebf2.addFrom(0, 0, assbf, 0, 0, numSamples, parameters[23] * left); | |||
| ebf2.addFrom(1, 0, assbf, 1, 0, numSamples, parameters[23] * right); | |||
| ebf3.addFrom(0, 0, assbf, 0, 0, numSamples, parameters[24] * left); | |||
| ebf3.addFrom(1, 0, assbf, 1, 0, numSamples, parameters[24] * right); | |||
| #endif | |||
| } | |||
| } | |||
| } | |||
| if (part2) | |||
| { | |||
| #ifndef CARLA_EXPORT | |||
| float right = parameters[87] * parameters[84]; | |||
| float left = parameters[87] * (1.0f - parameters[84]); | |||
| #endif | |||
| for (int i = 0; i < kNumVoices; ++i) | |||
| { | |||
| if (vo2[i]->getIsOn()) | |||
| { | |||
| vo2[i]->doProcess(outPtrL, outPtrR, numSamples); | |||
| #ifndef CARLA_EXPORT | |||
| obf.addFrom(0, 0, assbf, 0, 0, numSamples, left); | |||
| obf.addFrom(1, 0, assbf, 1, 0, numSamples, right); | |||
| ebf1.addFrom(0, 0, assbf, 0, 0, numSamples, parameters[22 + 24] * left); | |||
| ebf1.addFrom(1, 0, assbf, 1, 0, numSamples, parameters[22 + 24] * right); | |||
| ebf2.addFrom(0, 0, assbf, 0, 0, numSamples, parameters[23 + 24] * left); | |||
| ebf2.addFrom(1, 0, assbf, 1, 0, numSamples, parameters[23 + 24] * right); | |||
| ebf3.addFrom(0, 0, assbf, 0, 0, numSamples, parameters[24 + 24] * left); | |||
| ebf3.addFrom(1, 0, assbf, 1, 0, numSamples, parameters[24 + 24] * right); | |||
| #endif | |||
| } | |||
| } | |||
| } | |||
| if (part3) | |||
| { | |||
| #ifndef CARLA_EXPORT | |||
| float right = parameters[88] * parameters[85]; | |||
| float left = parameters[88] * (1.0f - parameters[85]); | |||
| #endif | |||
| for (int i = 0; i < kNumVoices; ++i) | |||
| { | |||
| if (vo3[i]->getIsOn()) | |||
| { | |||
| vo3[i]->doProcess(outPtrL, outPtrR, numSamples); | |||
| #ifndef CARLA_EXPORT | |||
| obf.addFrom(0, 0, assbf, 0, 0, numSamples, left); | |||
| obf.addFrom(1, 0, assbf, 1, 0, numSamples, right); | |||
| ebf1.addFrom(0, 0, assbf, 0, 0, numSamples, parameters[22 + 48] * left); | |||
| ebf1.addFrom(1, 0, assbf, 1, 0, numSamples, parameters[22 + 48] * right); | |||
| ebf2.addFrom(0, 0, assbf, 0, 0, numSamples, parameters[23 + 48] * left); | |||
| ebf2.addFrom(1, 0, assbf, 1, 0, numSamples, parameters[23 + 48] * right); | |||
| ebf3.addFrom(0, 0, assbf, 0, 0, numSamples, parameters[24 + 48] * left); | |||
| ebf3.addFrom(1, 0, assbf, 1, 0, numSamples, parameters[24 + 48] * right); | |||
| #endif | |||
| } | |||
| } | |||
| } | |||
| } | |||
| void setSampleRate(const double s) | |||
| { | |||
| sampleRate = s; | |||
| } | |||
| void updateParameterPtr(const float* const p) | |||
| { | |||
| parameters = p; | |||
| for (int i = 0; i < kNumVoices; ++i) | |||
| { | |||
| vo1[i]->updateParameterPtr(parameters); | |||
| vo2[i]->updateParameterPtr(parameters); | |||
| vo3[i]->updateParameterPtr(parameters); | |||
| } | |||
| } | |||
| void playNote(const int n, const int vel, const int preroll, const int part) | |||
| { | |||
| VexVoice** v = nullptr; | |||
| const int note = n + 12; | |||
| switch (part) | |||
| { | |||
| case 1: | |||
| if (!part1) return; | |||
| v = vo1; | |||
| break; | |||
| case 2: | |||
| if (!part2) return; | |||
| v = vo2; | |||
| break; | |||
| case 3: | |||
| if (!part3) return; | |||
| v = vo3; | |||
| break; | |||
| } | |||
| if (v == nullptr) | |||
| return; | |||
| int OldestOn = kNumVoices-1; | |||
| int OldestOff = kNumVoices-1; | |||
| int OldestReleased = kNumVoices-1; | |||
| int tmpOn = 100000000; | |||
| //int tmpOff = 100000000; | |||
| int tmpReleased = 100000000; | |||
| for (int i = 0; i < kNumVoices; ++i) | |||
| { | |||
| if (i == benchwarmer) | |||
| continue; | |||
| if (! v[i]->getIsOn()) | |||
| { | |||
| OldestOff = i; | |||
| break; | |||
| } | |||
| if (vo1[i]->getIsReleased()) | |||
| { | |||
| OldestReleased = (v[i]->getOrdinal() < tmpReleased) ? i : OldestReleased; | |||
| tmpReleased = v[OldestReleased]->getOrdinal(); | |||
| continue; | |||
| } | |||
| OldestOn = (v[i]->getOrdinal() < tmpOn) ? i : OldestOn; | |||
| tmpOn = v[OldestOn]->getOrdinal(); | |||
| } | |||
| float noteInHertz = (float)MidiMessage::getMidiNoteInHertz(note); | |||
| playCount++; | |||
| if (OldestOff < kNumVoices) | |||
| { | |||
| v[OldestOff]->start(noteInHertz, float(vel)/127.0f, note, preroll, sampleRate, playCount); | |||
| return; | |||
| } | |||
| if (OldestReleased < kNumVoices) | |||
| { | |||
| v[benchwarmer]->start(noteInHertz, float(vel)/127.0f, note, preroll, sampleRate, playCount); | |||
| benchwarmer = OldestReleased; | |||
| v[OldestReleased]->quickRelease(); | |||
| return; | |||
| } | |||
| if (OldestOn < kNumVoices) | |||
| { | |||
| v[benchwarmer]->start(noteInHertz, float(vel)/127.0f, note, preroll, sampleRate, playCount); | |||
| benchwarmer = OldestOn; | |||
| v[OldestReleased]->quickRelease(); | |||
| return; | |||
| } | |||
| } | |||
| void releaseNote(const int n, const int preroll, const int part) | |||
| { | |||
| VexVoice** v = nullptr; | |||
| const int note = n + 12; | |||
| switch (part) | |||
| { | |||
| case 1: | |||
| if (!part1) return; | |||
| v = vo1; | |||
| break; | |||
| case 2: | |||
| if (!part2) return; | |||
| v = vo2; | |||
| break; | |||
| case 3: | |||
| if (!part3) return; | |||
| v = vo3; | |||
| break; | |||
| } | |||
| if (v == nullptr) | |||
| return; | |||
| for (int i = 0; i < kNumVoices; ++i) | |||
| { | |||
| if (v[i]->getNote() == note) | |||
| v[i]->release(preroll); | |||
| } | |||
| } | |||
| void releaseAll(const int p) | |||
| { | |||
| for (int i = 0; i < kNumVoices; ++i) | |||
| { | |||
| vo1[i]->release(p); | |||
| vo2[i]->release(p); | |||
| vo3[i]->release(p); | |||
| } | |||
| } | |||
| void kill(const int what = 0) | |||
| { | |||
| switch (what) | |||
| { | |||
| case 0: | |||
| for (int i = 0; i < kNumVoices; ++i) | |||
| { | |||
| vo1[i]->kill(); | |||
| vo2[i]->kill(); | |||
| vo3[i]->kill(); | |||
| } | |||
| break; | |||
| case 1: | |||
| for (int i = 0; i < kNumVoices; ++i) | |||
| vo1[i]->kill(); | |||
| break; | |||
| case 2: | |||
| for (int i = 0; i < kNumVoices; ++i) | |||
| vo2[i]->kill(); | |||
| break; | |||
| case 3: | |||
| for (int i = 0; i < kNumVoices; ++i) | |||
| vo3[i]->kill(); | |||
| break; | |||
| } | |||
| } | |||
| void setWaveLater(const int part, const String& waveName) | |||
| { | |||
| switch (part) | |||
| { | |||
| case 1: | |||
| wr1.setWaveLater(waveName); | |||
| kill(1); | |||
| // REMOVE THIS | |||
| wr1.actuallySetWave(); | |||
| break; | |||
| case 2: | |||
| wr2.setWaveLater(waveName); | |||
| kill(2); | |||
| break; | |||
| case 3: | |||
| wr3.setWaveLater(waveName); | |||
| kill(3); | |||
| break; | |||
| } | |||
| } | |||
| void update(const int index) | |||
| { | |||
| if (index == 89) | |||
| { | |||
| part1 = (parameters[89] > 0.9f); | |||
| return; | |||
| } | |||
| if (index == 90) | |||
| { | |||
| part2 = (parameters[90] > 0.9f); | |||
| return; | |||
| } | |||
| if (index == 91) | |||
| { | |||
| part3 = (parameters[91] > 0.9f); | |||
| return; | |||
| } | |||
| for (int i = 0; i < kNumVoices; ++i) | |||
| { | |||
| vo1[i]->update(index); | |||
| vo2[i]->update(index); | |||
| vo3[i]->update(index); | |||
| } | |||
| } | |||
| private: | |||
| static const int kNumVoices = 8; | |||
| const float* parameters; | |||
| double sampleRate; | |||
| int benchwarmer; | |||
| VexVoice* vo1[kNumVoices]; | |||
| VexVoice* vo2[kNumVoices]; | |||
| VexVoice* vo3[kNumVoices]; | |||
| long playCount; | |||
| bool part1, part2, part3; | |||
| WaveRenderer wr1; | |||
| WaveRenderer wr2; | |||
| WaveRenderer wr3; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,265 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCETICE project - Copyright 2008 by Lucio Asnaghi. | |||
| JUCETICE is based around the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2008 by Julian Storer. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE and JUCETICE can be redistributed and/or modified under the terms of | |||
| the GNU Lesser General Public License, as published by the Free Software | |||
| Foundation; either version 2 of the License, or (at your option) any later | |||
| version. | |||
| JUCE and JUCETICE are distributed in the hope that they will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with JUCE and JUCETICE; if not, visit www.gnu.org/licenses or write to | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ============================================================================== | |||
| @author rockhardbuns | |||
| @tweaker Lucio Asnaghi | |||
| ============================================================================== | |||
| */ | |||
| #include "cVoice.h" | |||
| float convertPitch(float pitch) | |||
| { | |||
| long convert; | |||
| float *p = (float*)&convert; | |||
| float fl, fr, warp, out; | |||
| fl = std::floor(pitch); | |||
| fr = pitch - fl; | |||
| warp = fr*0.696f + fr*fr*0.225f + fr*fr*fr*0.079f; // chebychev approx | |||
| out = fl+warp; | |||
| out *= 8388608.0; //2^23; | |||
| out += 127.0 * 8388608.0; //2^23; | |||
| convert = (long)out; //magic | |||
| return *p; | |||
| } | |||
| float bipolar(const float in) | |||
| { | |||
| return in * 2.0f - 1.0f; | |||
| } | |||
| VexVoice::VexVoice(const float* const p, int po, WaveRenderer& w, float sr) | |||
| : wr(w), | |||
| parameters(p), | |||
| poff(po) | |||
| { | |||
| Ordinal = 1; | |||
| SampleRate = sr; | |||
| isOn = false; | |||
| note = 0; | |||
| lfoC = 2.f * (float)std::sin(float_Pi * 5.0f / SampleRate); | |||
| lfoS[0] = 0.3f; | |||
| lfoS[1] = 0.0f; | |||
| lowL = 0.0f; | |||
| bandL = 0.0f; | |||
| highL = 0.0f; | |||
| lowR = 0.0f; | |||
| bandR = 0.0f; | |||
| highR = 0.0f; | |||
| q = 0.0f; | |||
| cut = 0.0f; | |||
| } | |||
| void VexVoice::updateParameterPtr(const float* const p) | |||
| { | |||
| parameters = p; | |||
| } | |||
| void VexVoice::doProcess(float* outBufferL, float* outBufferR, int bufferSize) | |||
| { | |||
| //float resAmt = 0.0; | |||
| float A, B; | |||
| float amod; | |||
| wr.fillBuffer(outBufferL, bufferSize, oL); | |||
| wr.fillBuffer(outBufferR, bufferSize, oR); | |||
| for (int i = 0; i < bufferSize; i++) | |||
| { | |||
| //LFO | |||
| lfoS[0] = lfoS[0] - lfoC * lfoS[1]; | |||
| lfoS[1] = lfoS[1] + lfoC * lfoS[0]; | |||
| LFOA = lfoS[0] * parameters[20 + poff]; | |||
| LFOF = lfoS[0] * parameters[21 + poff]; | |||
| //Filter Mod | |||
| q = 1.1f - parameters[6 + poff]; | |||
| cut = jlimit(0.001f, 0.999f, parameters[5 + poff] | |||
| + (fadsr.getSample() * bipolar(parameters[8 + poff])) | |||
| + Fvelocity | |||
| + LFOF); | |||
| amod = LFOA + Avelocity; | |||
| //Filter | |||
| //Left | |||
| lowL = lowL + cut * bandL; | |||
| highL = outBufferL[i] - lowL - (q * bandL); | |||
| bandL = cut * highL + bandL; | |||
| B = (lowL * ((q * 0.5f) + 0.5f)); | |||
| A = (highL * ((q * 0.5f) + 0.5f)); | |||
| outBufferL[i] = A + parameters[7 + poff] * ( B - A ); | |||
| outBufferL[i] += outBufferL[i] * amod; | |||
| //Right | |||
| lowR = lowR + cut * bandR; | |||
| highR = outBufferR[i] - lowR - (q * bandR); | |||
| bandR = cut * highR + bandR; | |||
| B = (lowR * ((q * 0.5f) + 0.5f)); | |||
| A = (highR * ((q * 0.5f) + 0.5f)); | |||
| outBufferR[i] = A + parameters[7 + poff] * ( B - A ); | |||
| outBufferR[i] += outBufferR[i] * amod; | |||
| } | |||
| aadsr.doProcess(outBufferL, outBufferR, bufferSize); | |||
| isOn = aadsr.getState(); | |||
| } | |||
| void VexVoice::start(float f, float v, int n, int preroll, double s, long o) | |||
| { | |||
| Ordinal = o; | |||
| SampleRate = s; | |||
| float oct = (parameters[1 + poff] - 0.5f) * 4.0f; | |||
| float cent = (parameters[2 + poff] - 0.5f) * 0.1f; | |||
| BaseFrequency = f * convertPitch(cent + oct); | |||
| wr.reset(BaseFrequency, SampleRate, oL); | |||
| wr.reset(BaseFrequency, SampleRate, oR); | |||
| note = n; | |||
| lfoS[0] = 0.5f; | |||
| lfoS[1] = 0.0f; | |||
| isOn = true; | |||
| isReleased = false; | |||
| v = (v * v) - 1.0f; | |||
| Avelocity = (v * bipolar(parameters[18 + poff])); | |||
| Fvelocity = (1.0f + v) * bipolar(parameters[13 + poff]); | |||
| aadsr.reset(preroll); | |||
| fadsr.reset(preroll); | |||
| } | |||
| void VexVoice::release(const int p) | |||
| { | |||
| isReleased = true; | |||
| aadsr.release(p); | |||
| fadsr.release(p); | |||
| } | |||
| void VexVoice::quickRelease() | |||
| { | |||
| isReleased = true; | |||
| aadsr.quickRelease(); | |||
| } | |||
| void VexVoice::kill() | |||
| { | |||
| isOn = false; | |||
| } | |||
| /* | |||
| * params: | |||
| 1 = oct | |||
| 2 = cent | |||
| 3 = phaseOffset | |||
| 4 = phaseIncOffset | |||
| 5,6,7,8 = filter | |||
| 9,10,11,12 = F ADSR | |||
| 13 = F velocity | |||
| 14,15,16,17 = A ADSR | |||
| 18 = A velocity | |||
| 19 = lfoC | |||
| 20 = lfoA | |||
| 21 = lfoF | |||
| 22,23,24 = fx volumes | |||
| *3 | |||
| 83,84,85 = panning synths | |||
| 86,87,88 = volume synths | |||
| 89,90,91 = on/off synths | |||
| */ | |||
| void VexVoice::update(const int index) | |||
| { | |||
| float p; | |||
| switch (index-poff) | |||
| { | |||
| case 14: | |||
| case 15: | |||
| case 16: | |||
| case 17: | |||
| aadsr.setADSR(parameters[14+poff], parameters[15+poff], parameters[16+poff], parameters[17+poff], SampleRate); | |||
| break; | |||
| case 9: | |||
| case 10: | |||
| case 11: | |||
| case 12: | |||
| fadsr.setADSR(parameters[9+poff], parameters[10+poff], parameters[11+poff], parameters[12+poff], SampleRate); | |||
| break; | |||
| case 19: | |||
| lfoC = 2.f * (float)sin(float_Pi*(parameters[19 + poff] * 10.0f) / SampleRate); | |||
| break; | |||
| case 3: | |||
| p = bipolar(parameters[3 + poff]); | |||
| oL.phaseOffset = p > 0.0f ? p : 0.0f; | |||
| oR.phaseOffset = p < 0.0f ? fabs(p) : 0.0f; | |||
| break; | |||
| case 4: | |||
| p = bipolar(parameters[4 + poff]); | |||
| oL.phaseIncOffset = p > 0.0f ? p : 0.0f; | |||
| oR.phaseIncOffset = p < 0.0f ? fabs(p) : 0.0f; | |||
| break; | |||
| } | |||
| } | |||
| long VexVoice::getOrdinal() const | |||
| { | |||
| return Ordinal; | |||
| } | |||
| int VexVoice::getNote() const | |||
| { | |||
| return note; | |||
| } | |||
| bool VexVoice::getIsOn() const | |||
| { | |||
| return isOn; | |||
| } | |||
| bool VexVoice::getIsReleased() const | |||
| { | |||
| return isReleased; | |||
| } | |||
| @@ -0,0 +1,91 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCETICE project - Copyright 2008 by Lucio Asnaghi. | |||
| JUCETICE is based around the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2008 by Julian Storer. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE and JUCETICE can be redistributed and/or modified under the terms of | |||
| the GNU Lesser General Public License, as published by the Free Software | |||
| Foundation; either version 2 of the License, or (at your option) any later | |||
| version. | |||
| JUCE and JUCETICE are distributed in the hope that they will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with JUCE and JUCETICE; if not, visit www.gnu.org/licenses or write to | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ============================================================================== | |||
| @author rockhardbuns | |||
| @tweaker Lucio Asnaghi | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCETICE_VEXCVOICE_HEADER__ | |||
| #define __JUCETICE_VEXCVOICE_HEADER__ | |||
| #ifdef CARLA_EXPORT | |||
| #include "JuceHeader.h" | |||
| #else | |||
| #include "../StandardHeader.h" | |||
| #endif | |||
| #include "cADSR.h" | |||
| #include "cWaveRenderer.h" | |||
| class VexVoice | |||
| { | |||
| public: | |||
| VexVoice(const float* const p, int poff, WaveRenderer& w, float sr = 44100); | |||
| void updateParameterPtr(const float* const p); | |||
| void doProcess(float* outBufferL, float* outBufferR, int bufferSize); | |||
| void start(float f, float v, int n, int preroll, double s, long o); | |||
| void release(int p); | |||
| void quickRelease(); | |||
| void kill(); | |||
| void update(const int index); | |||
| long getOrdinal() const; | |||
| int getNote() const; | |||
| bool getIsOn() const; | |||
| bool getIsReleased() const; | |||
| private: | |||
| OscSet oL; | |||
| OscSet oR; | |||
| WaveRenderer& wr; | |||
| VexADSR aadsr; | |||
| VexADSR fadsr; | |||
| const float* parameters; | |||
| const int poff; | |||
| bool isOn, isReleased; | |||
| int note; | |||
| long Ordinal; | |||
| float Avelocity; | |||
| float Fvelocity; | |||
| double SampleRate; | |||
| float BaseFrequency; | |||
| float lfoC, LFOA, LFOP, LFOF; | |||
| float lfoS[2]; | |||
| float lowL, bandL, highL, lowR, bandR, highR, q, cut; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,91 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCETICE project - Copyright 2008 by Lucio Asnaghi. | |||
| JUCETICE is based around the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2008 by Julian Storer. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE and JUCETICE can be redistributed and/or modified under the terms of | |||
| the GNU Lesser General Public License, as published by the Free Software | |||
| Foundation; either version 2 of the License, or (at your option) any later | |||
| version. | |||
| JUCE and JUCETICE are distributed in the hope that they will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with JUCE and JUCETICE; if not, visit www.gnu.org/licenses or write to | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ============================================================================== | |||
| @author rockhardbuns | |||
| @tweaker Lucio Asnaghi | |||
| ============================================================================== | |||
| */ | |||
| #include "cWaveRenderer.h" | |||
| WaveTableNames WaveRenderer::waveTableNames[kWaveTableSize] = { | |||
| { "asym_saw", Wavetables::asym_saw }, | |||
| { "bass_tone", Wavetables::bass_tone }, | |||
| { "buzz_1", Wavetables::buzz_1 }, | |||
| { "buzz_2", Wavetables::buzz_2 }, | |||
| { "dark_strings", Wavetables::dark_strings }, | |||
| { "deep_ring_1", Wavetables::deep_ring_1 }, | |||
| { "deep_ring_2", Wavetables::deep_ring_2 }, | |||
| { "epiano_tone", Wavetables::epiano_tone }, | |||
| { "ghost_1", Wavetables::ghost_1 }, | |||
| { "ghost_2", Wavetables::ghost_2 }, | |||
| { "ghost_3", Wavetables::ghost_3 }, | |||
| { "ghost_4", Wavetables::ghost_4 }, | |||
| { "grind_1", Wavetables::grind_1 }, | |||
| { "grind_2", Wavetables::grind_2 }, | |||
| { "more_strings", Wavetables::more_strings }, | |||
| { "multi_pulse", Wavetables::multi_pulse }, | |||
| { "organ_1", Wavetables::organ_1 }, | |||
| { "organ_2", Wavetables::organ_2 }, | |||
| { "one_string", Wavetables::one_string }, | |||
| { "phasing_sqr", Wavetables::phasing_sqr }, | |||
| { "pulse", Wavetables::pulse }, | |||
| { "saw", Wavetables::saw }, | |||
| { "sharp_1", Wavetables::sharp_1 }, | |||
| { "sharp_2", Wavetables::sharp_2 }, | |||
| { "sine", Wavetables::sine }, | |||
| { "soft_1", Wavetables::soft_1 }, | |||
| { "soft_2", Wavetables::soft_2 }, | |||
| { "soft_3", Wavetables::soft_3 }, | |||
| { "soft_4", Wavetables::soft_4 }, | |||
| { "square", Wavetables::square }, | |||
| { "string_fuzz", Wavetables::string_fuzz }, | |||
| { "strings_1", Wavetables::strings_1 }, | |||
| { "strings_2", Wavetables::strings_2 }, | |||
| { "syn_choir_1", Wavetables::syn_choir_1 }, | |||
| { "syn_choir_2", Wavetables::syn_choir_2 }, | |||
| { "syn_choir_3", Wavetables::syn_choir_3 }, | |||
| { "thin_1", Wavetables::thin_1 }, | |||
| { "thin_2", Wavetables::thin_2 }, | |||
| { "two_strings", Wavetables::two_strings }, | |||
| { "voice_1", Wavetables::voice_1 }, | |||
| { "voice_2", Wavetables::voice_2 } | |||
| }; | |||
| int WaveRenderer::getWaveTableSize() | |||
| { | |||
| return kWaveTableSize; | |||
| } | |||
| String WaveRenderer::getWaveTableName(const int index) | |||
| { | |||
| jassert (index >= 0) | |||
| jassert (index < kWaveTableSize) | |||
| return String(WaveRenderer::waveTableNames[index].name); | |||
| } | |||
| @@ -0,0 +1,330 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCETICE project - Copyright 2008 by Lucio Asnaghi. | |||
| JUCETICE is based around the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2008 by Julian Storer. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE and JUCETICE can be redistributed and/or modified under the terms of | |||
| the GNU Lesser General Public License, as published by the Free Software | |||
| Foundation; either version 2 of the License, or (at your option) any later | |||
| version. | |||
| JUCE and JUCETICE are distributed in the hope that they will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with JUCE and JUCETICE; if not, visit www.gnu.org/licenses or write to | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ============================================================================== | |||
| @author rockhardbuns | |||
| @tweaker Lucio Asnaghi | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCETICE_VEXCWAVERENDERER_HEADER__ | |||
| #define __JUCETICE_VEXCWAVERENDERER_HEADER__ | |||
| #ifdef CARLA_EXPORT | |||
| #include "JuceHeader.h" | |||
| #include "ResourceFile.h" | |||
| #else | |||
| #include "../StandardHeader.h" | |||
| #include "../waverom/ResourceFile.h" | |||
| #endif | |||
| struct OscSet { | |||
| float phase; | |||
| float phaseOffset; | |||
| float phaseInc; | |||
| float phaseIncOffset; | |||
| float cut; | |||
| float buf[4]; | |||
| }; | |||
| struct WaveTableNames { | |||
| const char* name; | |||
| const char* data; | |||
| }; | |||
| class WaveRenderer | |||
| { | |||
| public: | |||
| WaveRenderer() | |||
| : cycle(256), //base pitch 86 Hz | |||
| tableSize(0), | |||
| daTable(nullptr), | |||
| sWave("sine"), | |||
| loadWave(true) | |||
| { | |||
| } | |||
| ~WaveRenderer() | |||
| { | |||
| //M.setSize(0); | |||
| daTable = nullptr; | |||
| } | |||
| void setWaveLater(const String& waveName) | |||
| { | |||
| sWave = waveName; | |||
| loadWave = true; | |||
| } | |||
| void actuallySetWave() | |||
| { | |||
| if (sWave == "asym_saw") { | |||
| daTable = (uint16*) Wavetables::asym_saw; | |||
| tableSize = Wavetables::asym_saw_size / 2; | |||
| } else if (sWave == "bass_tone") { | |||
| daTable = (uint16*) Wavetables::bass_tone; | |||
| tableSize = Wavetables::bass_tone_size / 2; | |||
| } else if (sWave == "buzz_1") { | |||
| daTable = (uint16*) Wavetables::buzz_1; | |||
| tableSize = Wavetables::buzz_1_size / 2; | |||
| } else if (sWave == "buzz_2") { | |||
| daTable = (uint16*) Wavetables::buzz_2; | |||
| tableSize = Wavetables::buzz_2_size / 2; | |||
| } else if (sWave == "dark_strings") { | |||
| daTable = (uint16*) Wavetables::dark_strings; | |||
| tableSize = Wavetables::dark_strings_size / 2; | |||
| } else if (sWave == "deep_ring_1") { | |||
| daTable = (uint16*) Wavetables::deep_ring_1; | |||
| tableSize = Wavetables::deep_ring_1_size / 2; | |||
| } else if (sWave == "deep_ring_2") { | |||
| daTable = (uint16*) Wavetables::deep_ring_2; | |||
| tableSize = Wavetables::deep_ring_2_size / 2; | |||
| } else if (sWave == "epiano_tone") { | |||
| daTable = (uint16*) Wavetables::epiano_tone; | |||
| tableSize = Wavetables::epiano_tone_size / 2; | |||
| } else if (sWave == "ghost_1") { | |||
| daTable = (uint16*) Wavetables::ghost_1; | |||
| tableSize = Wavetables::ghost_1_size / 2; | |||
| } else if (sWave == "ghost_2") { | |||
| daTable = (uint16*) Wavetables::ghost_2; | |||
| tableSize = Wavetables::ghost_2_size / 2; | |||
| } else if (sWave == "ghost_3") { | |||
| daTable = (uint16*) Wavetables::ghost_3; | |||
| tableSize = Wavetables::ghost_3_size / 2; | |||
| } else if (sWave == "ghost_4") { | |||
| daTable = (uint16*) Wavetables::ghost_4; | |||
| tableSize = Wavetables::ghost_4_size / 2; | |||
| } else if (sWave == "grind_1") { | |||
| daTable = (uint16*) Wavetables::grind_1; | |||
| tableSize = Wavetables::grind_1_size / 2; | |||
| } else if (sWave == "grind_2") { | |||
| daTable = (uint16*) Wavetables::grind_2; | |||
| tableSize = Wavetables::grind_2_size / 2; | |||
| } else if (sWave == "more_strings") { | |||
| daTable = (uint16*) Wavetables::more_strings; | |||
| tableSize = Wavetables::more_strings_size / 2; | |||
| } else if (sWave == "multi_pulse") { | |||
| daTable = (uint16*) Wavetables::multi_pulse; | |||
| tableSize = Wavetables::multi_pulse_size / 2; | |||
| } else if (sWave == "one_string") { | |||
| daTable = (uint16*) Wavetables::one_string; | |||
| tableSize = Wavetables::one_string_size / 2; | |||
| } else if (sWave == "organ_1") { | |||
| daTable = (uint16*) Wavetables::organ_1; | |||
| tableSize = Wavetables::organ_1_size / 2; | |||
| } else if (sWave == "organ_2") { | |||
| daTable = (uint16*) Wavetables::organ_2; | |||
| tableSize = Wavetables::organ_2_size / 2; | |||
| } else if (sWave == "phasing_sqr") { | |||
| daTable = (uint16*) Wavetables::phasing_sqr; | |||
| tableSize = Wavetables::phasing_sqr_size / 2; | |||
| } else if (sWave == "pulse") { | |||
| daTable = (uint16*) Wavetables::pulse; | |||
| tableSize = Wavetables::pulse_size / 2; | |||
| } else if (sWave == "saw") { | |||
| daTable = (uint16*) Wavetables::saw; | |||
| tableSize = Wavetables::saw_size / 2; | |||
| } else if (sWave == "sharp_1") { | |||
| daTable = (uint16*) Wavetables::sharp_1; | |||
| tableSize = Wavetables::sharp_1_size / 2; | |||
| } else if (sWave == "sharp_2") { | |||
| daTable = (uint16*) Wavetables::sharp_2; | |||
| tableSize = Wavetables::sharp_2_size / 2; | |||
| } else if (sWave == "sine") { | |||
| daTable = (uint16*) Wavetables::sine; | |||
| tableSize = Wavetables::sine_size / 2; | |||
| } else if (sWave == "soft_1") { | |||
| daTable = (uint16*) Wavetables::soft_1; | |||
| tableSize = Wavetables::soft_1_size / 2; | |||
| } else if (sWave == "soft_2") { | |||
| daTable = (uint16*) Wavetables::soft_2; | |||
| tableSize = Wavetables::soft_2_size / 2; | |||
| } else if (sWave == "soft_3") { | |||
| daTable = (uint16*) Wavetables::soft_3; | |||
| tableSize = Wavetables::soft_3_size / 2; | |||
| } else if (sWave == "soft_4") { | |||
| daTable = (uint16*) Wavetables::soft_4; | |||
| tableSize = Wavetables::soft_4_size / 2; | |||
| } else if (sWave == "square") { | |||
| daTable = (uint16*) Wavetables::square; | |||
| tableSize = Wavetables::square_size / 2; | |||
| } else if (sWave == "strings_1") { | |||
| daTable = (uint16*) Wavetables::strings_1; | |||
| tableSize = Wavetables::strings_1_size / 2; | |||
| } else if (sWave == "strings_2") { | |||
| daTable = (uint16*) Wavetables::strings_2; | |||
| tableSize = Wavetables::strings_2_size / 2; | |||
| } else if (sWave == "string_fuzz") { | |||
| daTable = (uint16*) Wavetables::string_fuzz; | |||
| tableSize = Wavetables::string_fuzz_size / 2; | |||
| } else if (sWave == "syn_choir_1") { | |||
| daTable = (uint16*) Wavetables::syn_choir_1; | |||
| tableSize = Wavetables::syn_choir_1_size / 2; | |||
| } else if (sWave == "syn_choir_2") { | |||
| daTable = (uint16*) Wavetables::syn_choir_2; | |||
| tableSize = Wavetables::syn_choir_2_size / 2; | |||
| } else if (sWave == "syn_choir_3") { | |||
| daTable = (uint16*) Wavetables::syn_choir_3; | |||
| tableSize = Wavetables::syn_choir_3_size / 2; | |||
| } else if (sWave == "thin_1") { | |||
| daTable = (uint16*) Wavetables::thin_1; | |||
| tableSize = Wavetables::thin_1_size / 2; | |||
| } else if (sWave == "thin_2") { | |||
| daTable = (uint16*) Wavetables::thin_2; | |||
| tableSize = Wavetables::thin_2_size / 2; | |||
| } else if (sWave == "two_strings") { | |||
| daTable = (uint16*) Wavetables::two_strings; | |||
| tableSize = Wavetables::two_strings_size / 2; | |||
| } else if (sWave == "voice_1") { | |||
| daTable = (uint16*) Wavetables::voice_1; | |||
| tableSize = Wavetables::voice_1_size / 2; | |||
| } else if (sWave == "voice_2") { | |||
| daTable = (uint16*) Wavetables::voice_2; | |||
| tableSize = Wavetables::voice_2_size / 2; | |||
| } | |||
| loadWave = false; | |||
| #if 0 | |||
| // TODO - this fails on linux (host directory not plugin one) | |||
| // String waveName = (File::getSpecialLocation(File::currentExecutableFile)).getParentDirectory().getFullPathName(); | |||
| File location = (File::getSpecialLocation(File::userHomeDirectory)).getChildFile(".vex"); | |||
| if (! location.exists ()) | |||
| location.createDirectory (); | |||
| String waveName; | |||
| waveName << location.getFullPathName() | |||
| << "/" | |||
| << sWave | |||
| << ".raw"; | |||
| DBG( waveName ); | |||
| File f(waveName); | |||
| if (f.existsAsFile ()) | |||
| { | |||
| tableSize = int(f.getSize() / 2); | |||
| if (tableSize > 0) | |||
| { | |||
| M.setSize(0); | |||
| f.loadFileAsData(M); | |||
| daTable = (uint16*) M.getData(); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| tableSize = int(Wavetables::sine_size / 2); | |||
| if (tableSize > 0) | |||
| { | |||
| M.setSize (0); | |||
| M.append (Wavetables::sine, Wavetables::sine_size); | |||
| daTable = (uint16*) M.getData(); | |||
| } | |||
| } | |||
| loadWave = false; | |||
| #endif | |||
| } | |||
| void reset(float f, double s, OscSet& o) | |||
| { | |||
| if (loadWave) actuallySetWave(); | |||
| s = s * 2.0; | |||
| f = f * 2.0f * (1.0f + o.phaseIncOffset * 0.01f); | |||
| o.cut = float(2.0 * double_Pi * 9000.0 / s); | |||
| o.phase = o.phaseOffset * tableSize * 0.5f; | |||
| o.phaseInc = float(cycle / (s/f)); | |||
| o.buf[0] = 0.0f; | |||
| o.buf[1] = 0.0f; | |||
| o.buf[2] = 0.0f; | |||
| o.buf[3] = 0.0f; | |||
| } | |||
| void setFrequency(float f, double s, OscSet& o) | |||
| { | |||
| s = s * 2.0; | |||
| f = f * 2.0f; | |||
| o.phaseInc = float((float)cycle / (s/f)); | |||
| } | |||
| void fillBuffer(float* buffer, int bufferSize, OscSet& o) | |||
| { | |||
| for (int i = 0; i < bufferSize; ++i) | |||
| { | |||
| buffer[i] = 0.0f; | |||
| float tmp = 0.0f; | |||
| int index = roundFloatToInt(o.phase - 0.5f); | |||
| float alpha = o.phase - (float)index; | |||
| const float conv = 1.0f / 65535.0f; | |||
| float sIndex = daTable[index] * conv - 0.5f; | |||
| float sIndexp1 = daTable[(index + 1) % tableSize] * conv - 0.5f; | |||
| tmp = sIndex + alpha * (sIndexp1 - sIndex); | |||
| o.buf[1] = ((tmp - o.buf[1]) * o.cut) + o.buf[1]; | |||
| o.buf[2] = ((o.buf[1] - o.buf[2]) * o.cut) + o.buf[2]; | |||
| o.buf[3] = ((o.buf[2] - o.buf[3]) * o.cut) + o.buf[3]; | |||
| o.buf[0] = ((o.buf[3] - o.buf[0]) * o.cut) + o.buf[0]; | |||
| tmp = o.buf[0]; | |||
| buffer[i] += tmp; | |||
| o.phase += o.phaseInc; | |||
| if (o.phase > (float)tableSize) | |||
| o.phase -= (float)tableSize; | |||
| tmp = 0.0f; | |||
| index = roundFloatToInt(o.phase - 0.5f); | |||
| alpha = o.phase - (float)index; | |||
| sIndex = daTable[index] * conv - 0.5f; | |||
| sIndexp1 = daTable[(index + 1) % tableSize] * conv - 0.5f; | |||
| tmp = sIndex + alpha * (sIndexp1 - sIndex); | |||
| o.buf[1] = ((tmp - o.buf[1]) * o.cut) + o.buf[1]; | |||
| o.buf[2] = ((o.buf[1] - o.buf[2]) * o.cut) + o.buf[2]; | |||
| o.buf[3] = ((o.buf[2] - o.buf[3]) * o.cut) + o.buf[3]; | |||
| o.buf[0] = ((o.buf[3] - o.buf[0]) * o.cut) + o.buf[0]; | |||
| tmp = o.buf[0]; | |||
| buffer[i] += tmp; | |||
| o.phase += o.phaseInc; | |||
| if (o.phase > (float)tableSize) | |||
| o.phase -= (float)tableSize; | |||
| } | |||
| } | |||
| static int getWaveTableSize(); | |||
| static String getWaveTableName(const int index); | |||
| private: | |||
| static const int kWaveTableSize = 41; | |||
| static WaveTableNames waveTableNames[kWaveTableSize]; | |||
| int cycle, tableSize; | |||
| uint16* daTable; | |||
| //MemoryBlock M; | |||
| String sWave; | |||
| bool loadWave; | |||
| }; | |||
| #endif | |||
| @@ -392,6 +392,8 @@ public: | |||
| const LV2_Program_Descriptor* lv2_get_program(const uint32_t index) const | |||
| { | |||
| if (fDescriptor->hints & PLUGIN_IS_SYNTH) | |||
| return nullptr; | |||
| if (fDescriptor->get_midi_program_count == nullptr) | |||
| return nullptr; | |||
| if (fDescriptor->get_midi_program_info == nullptr) | |||
| @@ -415,6 +417,8 @@ public: | |||
| void lv2_select_program(uint32_t bank, uint32_t program) | |||
| { | |||
| if (fDescriptor->hints & PLUGIN_IS_SYNTH) | |||
| return; | |||
| if (fDescriptor->set_midi_program == nullptr) | |||
| return; | |||
| @@ -523,6 +527,8 @@ public: | |||
| void lv2ui_select_program(uint32_t bank, uint32_t program) const | |||
| { | |||
| if (fDescriptor->hints & PLUGIN_IS_SYNTH) | |||
| return; | |||
| if (fDescriptor->ui_set_midi_program == nullptr) | |||
| return; | |||
| @@ -1189,6 +1195,8 @@ static const void* lv2_extension_data(const char* uri) | |||
| static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const char*, const char*, LV2UI_Write_Function writeFunction, | |||
| LV2UI_Controller controller, LV2UI_Widget* widget, const LV2_Feature* const* features) | |||
| { | |||
| carla_debug("lv2ui_instantiate(..., %p, %p, %p)", writeFunction, controller, widget, features); | |||
| NativePlugin* plugin = nullptr; | |||
| for (int i=0; features[i] != nullptr; ++i) | |||