| @@ -0,0 +1,501 @@ | |||
| /* | |||
| * Carla Backend | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or modify | |||
| * it under the terms of the GNU General Public License as published by | |||
| * the Free Software Foundation; either version 2 of the License, or | |||
| * any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the COPYING file | |||
| */ | |||
| #include "carla_engine.h" | |||
| #include "carla_plugin.h" | |||
| #include "DistrhoPlugin.h" | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| // ----------------------------------------- | |||
| // Parameters | |||
| static const unsigned char paramMap[] = { | |||
| 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, | |||
| 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, | |||
| 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, | |||
| 0x50, 0x51, 0x52, 0x53, 0x54, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F | |||
| }; | |||
| static const unsigned int paramVolume = 5; | |||
| static const unsigned int paramBalance = 6; | |||
| static const unsigned int paramPan = 8; | |||
| static const unsigned int paramCount = sizeof(paramMap); | |||
| static const unsigned int programCount = 128; | |||
| // ----------------------------------------- | |||
| class CarlaEnginePlugin : public CarlaEngine, | |||
| public DISTRHO::Plugin | |||
| { | |||
| public: | |||
| short idZyn; | |||
| CarlaEnginePlugin() | |||
| : CarlaEngine(), | |||
| DISTRHO::Plugin(paramCount, programCount, 0) | |||
| { | |||
| qDebug("CarlaEnginePlugin::CarlaEnginePlugin()"); | |||
| // init parameters | |||
| for (unsigned int i=0; i < paramCount; i++) | |||
| paramBuffers[i] = 0.0f; | |||
| paramBuffers[paramVolume] = 100.0f; | |||
| paramBuffers[paramBalance] = 63.5f; | |||
| paramBuffers[paramPan] = 63.5f; | |||
| memcpy(prevParamBuffers, paramBuffers, sizeof(float)*paramCount); | |||
| // set-up engine | |||
| carlaOptions.forceStereo = true; | |||
| carlaOptions.processMode = PROCESS_MODE_CONTINUOUS_RACK; | |||
| carlaOptions.preferPluginBridges = false; | |||
| carlaOptions.preferUiBridges = false; | |||
| init("Carla"); | |||
| // Force thread start so we get some OSC usage | |||
| // (liblo locks otherwise) | |||
| //startCheckThread(); | |||
| // testing | |||
| idZyn = addPlugin(PLUGIN_DSSI, "/usr/lib/dssi/sineshaper.so", nullptr, "ll-sineshaper"); | |||
| } | |||
| ~CarlaEnginePlugin() | |||
| { | |||
| qDebug("CarlaEnginePlugin::~CarlaEnginePlugin()"); | |||
| removeAllPlugins(); | |||
| close(); | |||
| } | |||
| // ------------------------------------- | |||
| // CarlaEngine virtual calls | |||
| bool init(const char* const clientName) | |||
| { | |||
| qDebug("CarlaEnginePlugin::init(\"%s\")", clientName); | |||
| bufferSize = d_bufferSize(); | |||
| sampleRate = d_sampleRate(); | |||
| name = strdup(clientName); | |||
| CarlaEngine::init(name); | |||
| return true; | |||
| } | |||
| bool close() | |||
| { | |||
| qDebug("CarlaEnginePlugin::close()"); | |||
| CarlaEngine::close(); | |||
| if (name) | |||
| { | |||
| free((void*)name); | |||
| name = nullptr; | |||
| } | |||
| return true; | |||
| } | |||
| bool isOffline() | |||
| { | |||
| return false; | |||
| } | |||
| bool isRunning() | |||
| { | |||
| return true; | |||
| } | |||
| CarlaEngineClient* addClient(CarlaPlugin* const plugin) | |||
| { | |||
| CarlaEngineClientNativeHandle handle; | |||
| handle.type = CarlaEngineTypeRtAudio; | |||
| return new CarlaEngineClient(handle); | |||
| Q_UNUSED(plugin); | |||
| } | |||
| protected: | |||
| // --------------------------------------------- | |||
| // DISTRHO Plugin Information | |||
| const char* d_label() | |||
| { | |||
| return "Carla"; | |||
| } | |||
| const char* d_maker() | |||
| { | |||
| return "falkTX"; | |||
| } | |||
| const char* d_license() | |||
| { | |||
| return "GPL v2+"; | |||
| } | |||
| uint32_t d_version() | |||
| { | |||
| return 0x0500; | |||
| } | |||
| long d_uniqueId() | |||
| { | |||
| return d_cconst('C', 'r', 'l', 'a'); | |||
| } | |||
| // --------------------------------------------- | |||
| // DISTRHO Plugin Init | |||
| void d_initParameter(uint32_t index, DISTRHO::Parameter& parameter) | |||
| { | |||
| if (index >= paramCount) | |||
| return; | |||
| parameter.hints = DISTRHO::PARAMETER_IS_AUTOMABLE; | |||
| parameter.ranges.def = 0.0f; | |||
| parameter.ranges.min = 0.0f; | |||
| parameter.ranges.max = 127.0f; | |||
| if (index == paramVolume) | |||
| parameter.ranges.def = 100.0f; | |||
| else if (index == paramBalance) | |||
| parameter.ranges.def = 63.5f; | |||
| else if (index == paramPan) | |||
| parameter.ranges.def = 63.5f; | |||
| switch (paramMap[index]) | |||
| { | |||
| case 0x01: | |||
| parameter.name = "0x01 Modulation"; | |||
| break; | |||
| case 0x02: | |||
| parameter.name = "0x02 Breath"; | |||
| break; | |||
| case 0x03: | |||
| parameter.name = "0x03 (Undefined)"; | |||
| break; | |||
| case 0x04: | |||
| parameter.name = "0x04 Foot"; | |||
| break; | |||
| case 0x05: | |||
| parameter.name = "0x05 Portamento"; | |||
| break; | |||
| case 0x07: | |||
| parameter.name = "0x07 Volume"; | |||
| break; | |||
| case 0x08: | |||
| parameter.name = "0x08 Balance"; | |||
| break; | |||
| case 0x09: | |||
| parameter.name = "0x09 (Undefined)"; | |||
| break; | |||
| case 0x0A: | |||
| parameter.name = "0x0A Pan"; | |||
| break; | |||
| case 0x0B: | |||
| parameter.name = "0x0B Expression"; | |||
| break; | |||
| case 0x0C: | |||
| parameter.name = "0x0C FX Control 1"; | |||
| break; | |||
| case 0x0D: | |||
| parameter.name = "0x0D FX Control 2"; | |||
| break; | |||
| case 0x0E: | |||
| parameter.name = "0x0E (Undefined)"; | |||
| break; | |||
| case 0x0F: | |||
| parameter.name = "0x0F (Undefined)"; | |||
| break; | |||
| case 0x10: | |||
| parameter.name = "0x10 General Purpose 1"; | |||
| break; | |||
| case 0x11: | |||
| parameter.name = "0x11 General Purpose 2"; | |||
| break; | |||
| case 0x12: | |||
| parameter.name = "0x12 General Purpose 3"; | |||
| break; | |||
| case 0x13: | |||
| parameter.name = "0x13 General Purpose 4"; | |||
| break; | |||
| case 0x14: | |||
| parameter.name = "0x14 (Undefined)"; | |||
| break; | |||
| case 0x15: | |||
| parameter.name = "0x15 (Undefined)"; | |||
| break; | |||
| case 0x16: | |||
| parameter.name = "0x16 (Undefined)"; | |||
| break; | |||
| case 0x17: | |||
| parameter.name = "0x17 (Undefined)"; | |||
| break; | |||
| case 0x18: | |||
| parameter.name = "0x18 (Undefined)"; | |||
| break; | |||
| case 0x19: | |||
| parameter.name = "0x19 (Undefined)"; | |||
| break; | |||
| case 0x1A: | |||
| parameter.name = "0x1A (Undefined)"; | |||
| break; | |||
| case 0x1B: | |||
| parameter.name = "0x1B (Undefined)"; | |||
| break; | |||
| case 0x1C: | |||
| parameter.name = "0x1C (Undefined)"; | |||
| break; | |||
| case 0x1D: | |||
| parameter.name = "0x1D (Undefined)"; | |||
| break; | |||
| case 0x1E: | |||
| parameter.name = "0x1E (Undefined)"; | |||
| break; | |||
| case 0x1F: | |||
| parameter.name = "0x1F (Undefined)"; | |||
| break; | |||
| case 0x46: | |||
| parameter.name = "0x46 Control 1 [Variation]"; | |||
| break; | |||
| case 0x47: | |||
| parameter.name = "0x47 Control 2 [Timbre]"; | |||
| break; | |||
| case 0x48: | |||
| parameter.name = "0x48 Control 3 [Release]"; | |||
| break; | |||
| case 0x49: | |||
| parameter.name = "0x49 Control 4 [Attack]"; | |||
| break; | |||
| case 0x4A: | |||
| parameter.name = "0x4A Control 5 [Brightness]"; | |||
| break; | |||
| case 0x4B: | |||
| parameter.name = "0x4B Control 6 [Decay]"; | |||
| break; | |||
| case 0x4C: | |||
| parameter.name = "0x4C Control 7 [Vib Rate]"; | |||
| break; | |||
| case 0x4D: | |||
| parameter.name = "0x4D Control 8 [Vib Depth]"; | |||
| break; | |||
| case 0x4E: | |||
| parameter.name = "0x4E Control 9 [Vib Delay]"; | |||
| break; | |||
| case 0x4F: | |||
| parameter.name = "0x4F Control 10 [Undefined]"; | |||
| break; | |||
| case 0x50: | |||
| parameter.name = "0x50 General Purpose 5"; | |||
| break; | |||
| case 0x51: | |||
| parameter.name = "0x51 General Purpose 6"; | |||
| break; | |||
| case 0x52: | |||
| parameter.name = "0x52 General Purpose 7"; | |||
| break; | |||
| case 0x53: | |||
| parameter.name = "0x53 General Purpose 8"; | |||
| break; | |||
| case 0x54: | |||
| parameter.name = "0x54 Portamento Control"; | |||
| break; | |||
| case 0x5B: | |||
| parameter.name = "0x5B FX 1 Depth [Reverb]"; | |||
| break; | |||
| case 0x5C: | |||
| parameter.name = "0x5C FX 2 Depth [Tremolo]"; | |||
| break; | |||
| case 0x5D: | |||
| parameter.name = "0x5D FX 3 Depth [Chorus]"; | |||
| break; | |||
| case 0x5E: | |||
| parameter.name = "0x5E FX 4 Depth [Detune]"; | |||
| break; | |||
| case 0x5F: | |||
| parameter.name = "0x5F FX 5 Depth [Phaser]"; | |||
| break; | |||
| } | |||
| } | |||
| void d_initProgramName(uint32_t index, d_string& programName) | |||
| { | |||
| programName = "Program #" + d_string(index); | |||
| } | |||
| void d_initStateKey(uint32_t index, d_string& stateKey) | |||
| { | |||
| Q_UNUSED(index); | |||
| Q_UNUSED(stateKey); | |||
| } | |||
| // --------------------------------------------- | |||
| // DISTRHO Plugin Internal data | |||
| float d_parameterValue(uint32_t index) | |||
| { | |||
| if (index >= paramCount) | |||
| return 0.0f; | |||
| return paramBuffers[index]; | |||
| } | |||
| void d_setParameterValue(uint32_t index, float value) | |||
| { | |||
| if (index >= paramCount) | |||
| return; | |||
| paramBuffers[index] = value; | |||
| } | |||
| void d_setProgram(uint32_t index) | |||
| { | |||
| if (index >= programCount) | |||
| return; | |||
| if (maxPluginNumber() == 0) | |||
| return; | |||
| if (CarlaPlugin* const plugin = getPlugin(0)) | |||
| { | |||
| if (index > plugin->programCount()) | |||
| plugin->setProgram(index, true, true, false, true); | |||
| } | |||
| } | |||
| void d_setState(const char* key, const char* value) | |||
| { | |||
| Q_UNUSED(key); | |||
| Q_UNUSED(value); | |||
| } | |||
| // --------------------------------------------- | |||
| // DISTRHO Plugin Process | |||
| void d_activate() | |||
| { | |||
| //#if 0 | |||
| for (unsigned short i=0, max=maxPluginNumber(); i < max; i++) | |||
| { | |||
| CarlaPlugin* const plugin = getPluginUnchecked(i); | |||
| if (plugin && plugin->enabled()) | |||
| plugin->setActive(true, true, false); | |||
| } | |||
| //#endif | |||
| memcpy(prevParamBuffers, paramBuffers, sizeof(float)*paramCount); | |||
| } | |||
| void d_deactivate() | |||
| { | |||
| //#if 0 | |||
| for (unsigned short i=0, max=maxPluginNumber(); i < max; i++) | |||
| { | |||
| CarlaPlugin* const plugin = getPluginUnchecked(i); | |||
| if (plugin && plugin->enabled()) | |||
| plugin->setActive(false, true, false); | |||
| } | |||
| //#endif | |||
| } | |||
| void d_run(const float** inputs, float** outputs, uint32_t frames, uint32_t midiEventCount, const DISTRHO::MidiEvent* midiEvents) | |||
| { | |||
| if (maxPluginNumber() == 0) | |||
| return; | |||
| // create audio buffers | |||
| float* inBuf[2] = { (float*)inputs[0], (float*)inputs[1] }; | |||
| float* outBuf[2] = { outputs[0], outputs[1] }; | |||
| // initialize control input | |||
| memset(rackControlEventsIn, 0, sizeof(CarlaEngineControlEvent)*MAX_ENGINE_CONTROL_EVENTS); | |||
| { | |||
| uint32_t carlaEventIndex = 0; | |||
| for (unsigned int i=0; i < paramCount; i++) | |||
| { | |||
| if (prevParamBuffers[i] == paramBuffers[i]) | |||
| continue; | |||
| CarlaEngineControlEvent* const carlaEvent = &rackControlEventsIn[carlaEventIndex++]; | |||
| carlaEvent->type = CarlaEngineEventControlChange; | |||
| carlaEvent->controller = paramMap[i]; | |||
| carlaEvent->value = paramBuffers[i]/127; | |||
| } | |||
| } | |||
| memcpy(prevParamBuffers, paramBuffers, sizeof(float)*paramCount); | |||
| // initialize midi input | |||
| memset(rackMidiEventsIn, 0, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS); | |||
| { | |||
| const DISTRHO::MidiEvent* event; | |||
| for (uint32_t i=0, j=0; j < midiEventCount; j++) | |||
| { | |||
| if (i == MAX_ENGINE_MIDI_EVENTS) | |||
| break; | |||
| event = &midiEvents[j]; | |||
| rackMidiEventsIn[i].time = event->frame; | |||
| rackMidiEventsIn[i].size = 3; | |||
| memcpy(rackMidiEventsIn[i].data, event->buffer, 3); | |||
| i += 1; | |||
| } | |||
| } | |||
| processRack(inBuf, outBuf, frames); | |||
| } | |||
| // --------------------------------------------- | |||
| // Callbacks | |||
| void d_bufferSizeChanged(uint32_t newBufferSize) | |||
| { | |||
| bufferSizeChanged(newBufferSize); | |||
| } | |||
| // --------------------------------------------- | |||
| private: | |||
| float paramBuffers[paramCount]; | |||
| float prevParamBuffers[paramCount]; | |||
| }; | |||
| CARLA_BACKEND_END_NAMESPACE | |||
| // ------------------------------------------------- | |||
| START_NAMESPACE_DISTRHO | |||
| Plugin* createPlugin() | |||
| { | |||
| return new CarlaBackend::CarlaEnginePlugin(); | |||
| } | |||
| END_NAMESPACE_DISTRHO | |||
| #include "DistrhoPluginMain.cpp" | |||