diff --git a/source/backend/CarlaNative.h b/source/backend/CarlaNative.h index ade525107..52d2f2281 100644 --- a/source/backend/CarlaNative.h +++ b/source/backend/CarlaNative.h @@ -98,7 +98,7 @@ typedef struct _Parameter { } Parameter; typedef struct _MidiEvent { - uint32_t port; + uint8_t port; uint32_t time; uint8_t data[3]; } MidiEvent; diff --git a/source/backend/engine/CarlaEngineRtAudio.cpp b/source/backend/engine/CarlaEngineRtAudio.cpp index 979b5e539..96a114f16 100644 --- a/source/backend/engine/CarlaEngineRtAudio.cpp +++ b/source/backend/engine/CarlaEngineRtAudio.cpp @@ -270,7 +270,7 @@ protected: { for (unsigned int i=0; i < nframes*2; i++) { - if (i % 2) + if (i % 2 == 0) fAudioInBuf1[i/2] = insPtr[i]; else fAudioInBuf2[i/2] = insPtr[i]; @@ -308,7 +308,7 @@ protected: { for (unsigned int i=0; i < nframes*2; i++) { - if (i % 2) + if (i % 2 == 0) outsPtr[i] = fAudioOutBuf1[i/2]; else outsPtr[i] = fAudioOutBuf2[i/2]; diff --git a/source/backend/plugin/CarlaPluginInternal.hpp b/source/backend/plugin/CarlaPluginInternal.hpp index 43e4d66d7..559159ad0 100644 --- a/source/backend/plugin/CarlaPluginInternal.hpp +++ b/source/backend/plugin/CarlaPluginInternal.hpp @@ -247,10 +247,12 @@ struct PluginProgramData { CARLA_ASSERT(names == nullptr); if (names == nullptr) + { names = new ProgramName[count]; - for (uint32_t i=0; i < count; i++) - names[i] = nullptr; + for (uint32_t i=0; i < count; i++) + names[i] = nullptr; + } this->count = count; } diff --git a/source/backend/plugin/DssiPlugin.cpp b/source/backend/plugin/DssiPlugin.cpp index 820e0070c..84dea59a0 100644 --- a/source/backend/plugin/DssiPlugin.cpp +++ b/source/backend/plugin/DssiPlugin.cpp @@ -30,7 +30,7 @@ public: DssiPlugin(CarlaEngine* const engine, const unsigned int id) : CarlaPlugin(engine, id) { - carla_debug("DssiPlugin::DssiPlugin()"); + carla_debug("DssiPlugin::DssiPlugin(%p, %i)", engine, id); fHandle = nullptr; fHandle2 = nullptr; @@ -277,6 +277,8 @@ public: void setMidiProgram(int32_t index, const bool sendGui, const bool sendOsc, const bool sendCallback, const bool block) { + CARLA_ASSERT(fDssiDescriptor != nullptr); + CARLA_ASSERT(fHandle != nullptr); CARLA_ASSERT(index >= -1 && index < static_cast(kData->midiprog.count)); if (index < -1) @@ -285,7 +287,7 @@ public: return; // FIXME - if (index >= 0) + if (fDssiDescriptor != nullptr && fHandle != nullptr && index >= 0) { const uint32_t bank = kData->midiprog.data[index].bank; const uint32_t program = kData->midiprog.data[index].program; @@ -295,7 +297,7 @@ public: //const CarlaEngine::ScopedLocker m(x_engine, block); fDssiDescriptor->select_program(fHandle, bank, program); - if (fHandle) + if (fHandle2 != nullptr) fDssiDescriptor->select_program(fHandle2, bank, program); } else @@ -304,7 +306,7 @@ public: fDssiDescriptor->select_program(fHandle, bank, program); - if (fHandle2) + if (fHandle2 != nullptr) fDssiDescriptor->select_program(fHandle2, bank, program); } } @@ -419,6 +421,7 @@ public: { kData->audioOut.createNew(aOuts); fAudioOutBuffers = new float*[aOuts]; + needsCtrlIn = true; for (uint32_t i=0; i < aOuts; i++) fAudioOutBuffers[i] = nullptr; @@ -469,7 +472,6 @@ public: j = iAudioOut++; kData->audioOut.ports[j].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, false); kData->audioOut.ports[j].rindex = i; - needsCtrlIn = true; if (forcedStereoOut) { @@ -681,7 +683,7 @@ public: if (kData->engine->getOptions().useDssiVstChunks && QString(fFilename).endsWith("dssi-vst.so", Qt::CaseInsensitive)) { - if (fDssiDescriptor->get_custom_data && fDssiDescriptor->set_custom_data) + if (fDssiDescriptor->get_custom_data != nullptr && fDssiDescriptor->set_custom_data != nullptr) fHints |= PLUGIN_USES_CHUNKS; } @@ -845,7 +847,6 @@ public: void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t framesOffset) { uint32_t i, k; - unsigned long midiEventCount = 0; // -------------------------------------------------------------------------------------------------------- // Check if active @@ -871,8 +872,10 @@ public: return; } + unsigned long midiEventCount = 0; + // -------------------------------------------------------------------------------------------------------- - // Check if active before + // Check if not active before if (! kData->activeBefore) { @@ -1123,6 +1126,9 @@ public: allNotesOffSent = true; } + if (midiEventCount >= MAX_MIDI_EVENTS) + continue; + carla_zeroStruct(fMidiEvents[midiEventCount]); if (! sampleAccurate) @@ -1132,7 +1138,7 @@ public: fMidiEvents[midiEventCount].data.control.channel = event.channel; fMidiEvents[midiEventCount].data.control.param = MIDI_CONTROL_ALL_SOUND_OFF; - midiEventCount++; + midiEventCount += 1; break; @@ -1145,6 +1151,9 @@ public: allNotesOffSent = true; } + if (midiEventCount >= MAX_MIDI_EVENTS) + continue; + carla_zeroStruct(fMidiEvents[midiEventCount]); if (! sampleAccurate) @@ -1154,7 +1163,7 @@ public: fMidiEvents[midiEventCount].data.control.channel = event.channel; fMidiEvents[midiEventCount].data.control.param = MIDI_CONTROL_ALL_NOTES_OFF; - midiEventCount++; + midiEventCount += 1; break; } @@ -1178,8 +1187,8 @@ public: carla_zeroStruct(fMidiEvents[midiEventCount]); - //if (! sampleAccurate) - fMidiEvents[midiEventCount].time.tick = time - timeOffset; + if (! sampleAccurate) + fMidiEvents[midiEventCount].time.tick = time - timeOffset; if (MIDI_IS_STATUS_NOTE_OFF(status)) { @@ -1394,8 +1403,6 @@ public: } // End of Control Output - CARLA_PROCESS_CONTINUE_CHECK; - // -------------------------------------------------------------------------------------------------------- kData->activeBefore = kData->active; diff --git a/source/backend/plugin/LadspaPlugin.cpp b/source/backend/plugin/LadspaPlugin.cpp index 6ca92792b..1452d6585 100644 --- a/source/backend/plugin/LadspaPlugin.cpp +++ b/source/backend/plugin/LadspaPlugin.cpp @@ -416,6 +416,7 @@ public: { kData->audioOut.createNew(aOuts); fAudioOutBuffers = new float*[aOuts]; + needsCtrlIn = true; for (uint32_t i=0; i < aOuts; i++) fAudioOutBuffers[i] = nullptr; @@ -467,7 +468,6 @@ public: j = iAudioOut++; kData->audioOut.ports[j].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, false); kData->audioOut.ports[j].rindex = i; - needsCtrlIn = true; if (forcedStereoOut) { @@ -770,7 +770,7 @@ public: } // -------------------------------------------------------------------------------------------------------- - // Check if active before + // Check if not active before if (! kData->activeBefore) { @@ -1094,8 +1094,6 @@ public: } // End of Control Output - CARLA_PROCESS_CONTINUE_CHECK; - // -------------------------------------------------------------------------------------------------------- kData->activeBefore = kData->active; diff --git a/source/backend/plugin/Lv2Plugin.cpp b/source/backend/plugin/Lv2Plugin.cpp index c0500c68c..61bb93c3e 100644 --- a/source/backend/plugin/Lv2Plugin.cpp +++ b/source/backend/plugin/Lv2Plugin.cpp @@ -199,7 +199,7 @@ public: Lv2Plugin(CarlaEngine* const engine, const unsigned short id) : CarlaPlugin(engine, id) { - carla_debug("Lv2Plugin::Lv2Plugin()"); + carla_debug("Lv2Plugin::Lv2Plugin(%p, %i)", engine, id); m_type = PLUGIN_LV2; m_count += 1; diff --git a/source/backend/plugin/NativePlugin.cpp b/source/backend/plugin/NativePlugin.cpp index e3d8bcc42..669b4e14e 100644 --- a/source/backend/plugin/NativePlugin.cpp +++ b/source/backend/plugin/NativePlugin.cpp @@ -19,18 +19,77 @@ CARLA_BACKEND_START_NAMESPACE -#if 0 struct NativePluginMidiData { uint32_t count; uint32_t* indexes; - CarlaEngineMidiPort** ports; + CarlaEngineEventPort** ports; NativePluginMidiData() : count(0), indexes(nullptr), ports(nullptr) {} + + void createNew(const uint32_t count) + { + CARLA_ASSERT(ports == nullptr); + CARLA_ASSERT(indexes == nullptr); + + if (ports == nullptr) + { + ports = new CarlaEngineEventPort*[count]; + + for (uint32_t i=0; i < count; i++) + ports[i] = nullptr; + } + + if (indexes == nullptr) + { + indexes = new uint32_t[count]; + + for (uint32_t i=0; i < count; i++) + indexes[i] = 0; + } + + this->count = count; + } + + void clear() + { + if (ports != nullptr) + { + for (uint32_t i=0; i < count; i++) + { + if (ports[i] != nullptr) + { + delete ports[i]; + ports[i] = nullptr; + } + } + + delete[] ports; + ports = nullptr; + } + + if (indexes != nullptr) + { + delete[] indexes; + indexes = nullptr; + } + + count = 0; + } + + void initBuffers(CarlaEngine* const engine) + { + for (uint32_t i=0; i < count; i++) + { + if (ports[i] != nullptr) + ports[i]->initBuffer(engine); + } + } + + CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(NativePluginMidiData) }; -#endif class NativePlugin : public CarlaPlugin { @@ -55,8 +114,10 @@ public: fIsProcessing = false; - //midiEventCount = 0; - //memset(midiEvents, 0, sizeof(::MidiEvent) * MAX_MIDI_EVENTS * 2); + fAudioInBuffers = nullptr; + fAudioOutBuffers = nullptr; + fMidiEventCount = 0; + carla_zeroMem(fMidiEvents, sizeof(::MidiEvent)*MAX_MIDI_EVENTS*2); } ~NativePlugin() @@ -85,12 +146,14 @@ public: fHandle2 = nullptr; fDescriptor = nullptr; } + + deleteBuffers(); } // ------------------------------------------------------------------- // Information (base) - virtual PluginType type() const + PluginType type() const { return PLUGIN_INTERNAL; } @@ -108,17 +171,15 @@ public: // ------------------------------------------------------------------- // Information (count) -#if 0 uint32_t midiInCount() { - return mIn.count; + return fMidiIn.count; } uint32_t midiOutCount() { - return mOut.count; + return fMidiOut.count; } -#endif uint32_t parameterScalePointCount(const uint32_t parameterId) const { @@ -314,35 +375,38 @@ public: CarlaPlugin::setParameterValue(parameterId, fixedValue, sendGui, sendOsc, sendCallback); } -#if 0 void setCustomData(const char* const type, const char* const key, const char* const value, const bool sendGui) { - CARLA_ASSERT(descriptor); - CARLA_ASSERT(handle); - CARLA_ASSERT(type); - CARLA_ASSERT(key); - CARLA_ASSERT(value); + CARLA_ASSERT(fDescriptor != nullptr); + CARLA_ASSERT(fHandle != nullptr); + CARLA_ASSERT(type != nullptr); + CARLA_ASSERT(key != nullptr); + CARLA_ASSERT(value != nullptr); - if (! type) + if (type == nullptr) return carla_stderr2("NativePlugin::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is not string", type, key, value, bool2str(sendGui)); - if (! key) + if (std::strcmp(type, CUSTOM_DATA_STRING) != 0) + return carla_stderr2("NativePlugin::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is not string", type, key, value, bool2str(sendGui)); + + if (key == nullptr) return carla_stderr2("NativePlugin::setCustomData(\"%s\", \"%s\", \"%s\", %s) - key is null", type, key, value, bool2str(sendGui)); - if (! value) + if (value == nullptr) return carla_stderr2("Nativelugin::setCustomData(\"%s\", \"%s\", \"%s\", %s) - value is null", type, key, value, bool2str(sendGui)); - if (descriptor && handle) + if (fDescriptor != nullptr && fHandle != nullptr) { - if (descriptor->set_custom_data) + if (fDescriptor->set_custom_data != nullptr) { - descriptor->set_custom_data(handle, key, value); - if (h2) descriptor->set_custom_data(h2, key, value); + fDescriptor->set_custom_data(fHandle, key, value); + + if (fHandle2) + fDescriptor->set_custom_data(fHandle2, key, value); } - // FIXME - only if gui was started before - if (sendGui && descriptor->ui_set_custom_data) - descriptor->ui_set_custom_data(handle, key, value); + if (sendGui && fDescriptor->ui_set_custom_data != nullptr) + fDescriptor->ui_set_custom_data(fHandle, key, value); } CarlaPlugin::setCustomData(type, key, value, sendGui); @@ -352,32 +416,39 @@ public: { CARLA_ASSERT(fDescriptor != nullptr); CARLA_ASSERT(fHandle != nullptr); - CARLA_ASSERT(index >= -1 && index < (int32_t)midiprog.count); + CARLA_ASSERT(index >= -1 && index < static_cast(kData->midiprog.count)); if (index < -1) index = -1; - else if (index > (int32_t)midiprog.count) + else if (index > static_cast(kData->midiprog.count)) return; - if (descriptor && handle && index >= 0) + // FIXME + if (fDescriptor != nullptr && fHandle != nullptr && index >= 0) { - if (x_engine->isOffline()) + const uint32_t bank = kData->midiprog.data[index].bank; + const uint32_t program = kData->midiprog.data[index].program; + + if (kData->engine->isOffline()) { - const CarlaEngine::ScopedLocker m(x_engine, block); - descriptor->set_midi_program(handle, midiprog.data[index].bank, midiprog.data[index].program); - if (h2) descriptor->set_midi_program(h2, midiprog.data[index].bank, midiprog.data[index].program); + //const CarlaEngine::ScopedLocker m(x_engine, block); + fDescriptor->set_midi_program(fHandle, bank, program); + + if (fHandle2 != nullptr) + fDescriptor->set_midi_program(fHandle2, bank, program); } else { - const ScopedDisabler m(this, block); - descriptor->set_midi_program(handle, midiprog.data[index].bank, midiprog.data[index].program); - if (h2) descriptor->set_midi_program(h2, midiprog.data[index].bank, midiprog.data[index].program); + //const ScopedDisabler m(this, block); + fDescriptor->set_midi_program(fHandle, bank, program); + + if (fHandle2 != nullptr) + fDescriptor->set_midi_program(fHandle2, bank, program); } } CarlaPlugin::setMidiProgram(index, sendGui, sendOsc, sendCallback, block); } -#endif // ------------------------------------------------------------------- // Set gui stuff @@ -406,40 +477,41 @@ public: void reload() { carla_debug("NativePlugin::reload() - start"); + CARLA_ASSERT(kData->engine != nullptr); CARLA_ASSERT(fDescriptor != nullptr); + CARLA_ASSERT(fHandle != nullptr); -#if 0 - const ProcessMode processMode(x_engine->getOptions().processMode); + const ProcessMode processMode(kData->engine->getProccessMode()); // Safely disable plugin for reload - const ScopedDisabler m(this); + const ScopedDisabler sd(this); - if (x_client->isActive()) - x_client->deactivate(); + if (kData->client->isActive()) + kData->client->deactivate(); - // Remove client ports - removeClientPorts(); - - // Delete old data deleteBuffers(); + const double sampleRate = kData->engine->getSampleRate(); + uint32_t aIns, aOuts, mIns, mOuts, params, j; aIns = aOuts = mIns = mOuts = params = 0; - const double sampleRate = x_engine->getSampleRate(); - - aIns = descriptor->audioIns; - aOuts = descriptor->audioOuts; - mIns = descriptor->midiIns; - mOuts = descriptor->midiOuts; - params = descriptor->get_parameter_count ? descriptor->get_parameter_count(handle) : 0; - bool forcedStereoIn, forcedStereoOut; forcedStereoIn = forcedStereoOut = false; - if (x_engine->getOptions().forceStereo && (aIns == 1 || aOuts == 1) && mIns <= 1 && mOuts <= 1 && ! h2) + bool needsCtrlIn, needsCtrlOut; + needsCtrlIn = needsCtrlOut = false; + + aIns = fDescriptor->audioIns; + aOuts = fDescriptor->audioOuts; + mIns = fDescriptor->midiIns; + mOuts = fDescriptor->midiOuts; + params = (fDescriptor->get_parameter_count != nullptr && fDescriptor->get_parameter_info != nullptr) ? fDescriptor->get_parameter_count(fHandle) : 0; + + if ((fOptions & PLUGIN_OPTION_FORCE_STEREO) != 0 && (aIns == 1 || aOuts == 1) && mIns <= 1 && mOuts <= 1) { - h2 = descriptor->instantiate(descriptor, &host); + if (fHandle2 == nullptr) + fHandle2 = fDescriptor->instantiate(fDescriptor, &fHost); if (aIns == 1) { @@ -456,120 +528,164 @@ public: if (aIns > 0) { - aIn.ports = new CarlaEngineAudioPort*[aIns]; - aIn.rindexes = new uint32_t[aIns]; + kData->audioIn.createNew(aIns); + fAudioInBuffers = new float*[aIns]; + + for (uint32_t i=0; i < aIns; i++) + fAudioInBuffers[i] = nullptr; } if (aOuts > 0) { - aOut.ports = new CarlaEngineAudioPort*[aOuts]; - aOut.rindexes = new uint32_t[aOuts]; + kData->audioOut.createNew(aOuts); + fAudioOutBuffers = new float*[aOuts]; + needsCtrlIn = true; + + for (uint32_t i=0; i < aOuts; i++) + fAudioOutBuffers[i] = nullptr; } if (mIns > 0) { - mIn.ports = new CarlaEngineMidiPort*[mIns]; - mIn.indexes = new uint32_t[mIns]; + fMidiIn.createNew(mIns); + needsCtrlIn = (mIns == 1); } if (mOuts > 0) { - mOut.ports = new CarlaEngineMidiPort*[mOuts]; - mOut.indexes = new uint32_t[mOuts]; + fMidiOut.createNew(mOuts); + needsCtrlOut = (mOuts == 1); } if (params > 0) { - param.data = new ParameterData[params]; - param.ranges = new ParameterRanges[params]; + kData->param.createNew(params); } - const int portNameSize = x_engine->maxPortNameSize() - 2; - char portName[portNameSize]; - bool needsCtrlIn = false; - bool needsCtrlOut = false; + const int portNameSize = kData->engine->maxPortNameSize(); + CarlaString portName; // Audio Ins - for (j=0; j < descriptor->audioIns; j++) + for (j=0; j < aIns; j++) { + portName.clear(); + if (processMode == PROCESS_MODE_SINGLE_CLIENT) - sprintf(portName, "%s:input_%02i", m_name, j+1); + { + portName = fName; + portName += ":"; + } + + if (aIns > 1) + { + portName += "input_"; + portName += CarlaString(j+1); + } else - sprintf(portName, "input_%02i", j+1); + portName += "input"; + + portName.truncate(portNameSize); - aIn.ports[j] = (CarlaEngineAudioPort*)x_client->addPort(CarlaEnginePortTypeAudio, portName, true); - aIn.rindexes[j] = j; + kData->audioIn.ports[j].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, true); + kData->audioIn.ports[j].rindex = j; if (forcedStereoIn) { - strcat(portName, "_"); - aIn.ports[1] = (CarlaEngineAudioPort*)x_client->addPort(CarlaEnginePortTypeAudio, portName, true); - aIn.rindexes[1] = j; + portName += "_2"; + kData->audioIn.ports[1].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, true); + kData->audioIn.ports[1].rindex = j; + break; } } // Audio Outs - for (j=0; j < descriptor->audioOuts; j++) + for (j=0; j < aOuts; j++) { + portName.clear(); + if (processMode == PROCESS_MODE_SINGLE_CLIENT) - sprintf(portName, "%s:output_%02i", m_name, j+1); + { + portName = fName; + portName += ":"; + } + + if (aOuts > 1) + { + portName += "output_"; + portName += CarlaString(j+1); + } else - sprintf(portName, "output_%02i", j+1); + portName += "output"; - carla_debug("Audio Out #%i", j); - aOut.ports[j] = (CarlaEngineAudioPort*)x_client->addPort(CarlaEnginePortTypeAudio, portName, false); - aOut.rindexes[j] = j; - needsCtrlIn = true; + portName.truncate(portNameSize); + + kData->audioOut.ports[j].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, false); + kData->audioOut.ports[j].rindex = j; if (forcedStereoOut) { - strcat(portName, "_"); - aOut.ports[1] = (CarlaEngineAudioPort*)x_client->addPort(CarlaEnginePortTypeAudio, portName, false); - aOut.rindexes[1] = j; + portName += "_2"; + kData->audioOut.ports[1].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, false); + kData->audioOut.ports[1].rindex = j; + break; } } - // MIDI Input - for (j=0; j < mIns; j++) + // MIDI Input (only if multiple) + if (mIns > 1) { - if (processMode == PROCESS_MODE_SINGLE_CLIENT) - sprintf(portName, "%s:midi-in_%02i", m_name, j+1); - else - sprintf(portName, "midi-in_%02i", j+1); + for (j=0; j < mIns; j++) + { + portName.clear(); - mIn.ports[j] = (CarlaEngineMidiPort*)x_client->addPort(CarlaEnginePortTypeMIDI, portName, true); - mIn.indexes[j] = j; + if (processMode == PROCESS_MODE_SINGLE_CLIENT) + { + portName = fName; + portName += ":"; + } + + portName += "midi-in_"; + portName += CarlaString(j+1); + portName.truncate(portNameSize); + + fMidiIn.ports[j] = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, true); + fMidiIn.indexes[j] = j; + } } - // MIDI Output - for (j=0; j < mOuts; j++) + // MIDI Output (only if multiple) + if (mOuts > 1) { - if (processMode == PROCESS_MODE_SINGLE_CLIENT) - sprintf(portName, "%s:midi-out_%02i", m_name, j+1); - else - sprintf(portName, "midi-out_%02i", j+1); + for (j=0; j < mOuts; j++) + { + portName.clear(); + + if (processMode == PROCESS_MODE_SINGLE_CLIENT) + { + portName = fName; + portName += ":"; + } - mOut.ports[j] = (CarlaEngineMidiPort*)x_client->addPort(CarlaEnginePortTypeMIDI, portName, false); - mOut.indexes[j] = j; + portName += "midi-out_"; + portName += CarlaString(j+1); + portName.truncate(portNameSize); + + fMidiOut.ports[j] = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, false); + fMidiOut.indexes[j] = j; + } } for (j=0; j < params; j++) { - if (! descriptor->get_parameter_info) - break; - - const ::Parameter* const paramInfo = descriptor->get_parameter_info(handle, j); - - //const uint32_t paramHints = param->hints; - //const bool paramOutput = paramHins; + const ::Parameter* const paramInfo = fDescriptor->get_parameter_info(fHandle, j); - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].hints = 0; - param.data[j].midiChannel = 0; - param.data[j].midiCC = -1; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].hints = 0x0; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; - double min, max, def, step, stepSmall, stepLarge; + float min, max, def, step, stepSmall, stepLarge; // min value min = paramInfo->ranges.min; @@ -582,10 +698,10 @@ public: else if (max < min) min = max; - if (max - min == 0.0) + if (max - min == 0.0f) { - carla_stderr("Broken plugin parameter: max - min == 0"); - max = min + 0.1; + carla_stderr2("WARNING - Broken plugin parameter '%s': max - min == 0.0f", paramInfo->name); + max = min + 0.1f; } // default value @@ -601,7 +717,7 @@ public: min *= sampleRate; max *= sampleRate; def *= sampleRate; - param.data[j].hints |= PARAMETER_USES_SAMPLERATE; + kData->param.data[j].hints |= PARAMETER_USES_SAMPLERATE; } if (paramInfo->hints & ::PARAMETER_IS_BOOLEAN) @@ -609,89 +725,89 @@ public: step = max - min; stepSmall = step; stepLarge = step; - param.data[j].hints |= PARAMETER_IS_BOOLEAN; + kData->param.data[j].hints |= PARAMETER_IS_BOOLEAN; } else if (paramInfo->hints & ::PARAMETER_IS_INTEGER) { - step = 1.0; - stepSmall = 1.0; - stepLarge = 10.0; - param.data[j].hints |= PARAMETER_IS_INTEGER; + step = 1.0f; + stepSmall = 1.0f; + stepLarge = 10.0f; + kData->param.data[j].hints |= PARAMETER_IS_INTEGER; } else { - double range = max - min; - step = range/100.0; - stepSmall = range/1000.0; - stepLarge = range/10.0; + float range = max - min; + step = range/100.0f; + stepSmall = range/1000.0f; + stepLarge = range/10.0f; } if (paramInfo->hints & ::PARAMETER_IS_OUTPUT) { - param.data[j].type = PARAMETER_OUTPUT; + kData->param.data[j].type = PARAMETER_OUTPUT; needsCtrlOut = true; } else { - param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].type = PARAMETER_INPUT; needsCtrlIn = true; } // extra parameter hints if (paramInfo->hints & ::PARAMETER_IS_ENABLED) - param.data[j].hints |= PARAMETER_IS_ENABLED; + kData->param.data[j].hints |= PARAMETER_IS_ENABLED; if (paramInfo->hints & ::PARAMETER_IS_AUTOMABLE) - param.data[j].hints |= PARAMETER_IS_AUTOMABLE; + kData->param.data[j].hints |= PARAMETER_IS_AUTOMABLE; if (paramInfo->hints & ::PARAMETER_IS_LOGARITHMIC) - param.data[j].hints |= PARAMETER_IS_LOGARITHMIC; + kData->param.data[j].hints |= PARAMETER_IS_LOGARITHMIC; if (paramInfo->hints & ::PARAMETER_USES_SCALEPOINTS) - param.data[j].hints |= PARAMETER_USES_SCALEPOINTS; + kData->param.data[j].hints |= PARAMETER_USES_SCALEPOINTS; if (paramInfo->hints & ::PARAMETER_USES_CUSTOM_TEXT) - param.data[j].hints |= PARAMETER_USES_CUSTOM_TEXT; - - param.ranges[j].min = min; - param.ranges[j].max = max; - param.ranges[j].def = def; - param.ranges[j].step = step; - param.ranges[j].stepSmall = stepSmall; - param.ranges[j].stepLarge = stepLarge; + kData->param.data[j].hints |= PARAMETER_USES_CUSTOM_TEXT; + + kData->param.ranges[j].min = min; + kData->param.ranges[j].max = max; + kData->param.ranges[j].def = def; + kData->param.ranges[j].step = step; + kData->param.ranges[j].stepSmall = stepSmall; + kData->param.ranges[j].stepLarge = stepLarge; } if (needsCtrlIn) { + portName.clear(); + if (processMode == PROCESS_MODE_SINGLE_CLIENT) { - strcpy(portName, m_name); - strcat(portName, ":control-in"); + portName = fName; + portName += ":"; } - else - strcpy(portName, "control-in"); - param.portCin = (CarlaEngineControlPort*)x_client->addPort(CarlaEnginePortTypeControl, portName, true); + portName += "event-in"; + portName.truncate(portNameSize); + + kData->event.portIn = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, true); } if (needsCtrlOut) { + portName.clear(); + if (processMode == PROCESS_MODE_SINGLE_CLIENT) { - strcpy(portName, m_name); - strcat(portName, ":control-out"); + portName = fName; + portName += ":"; } - else - strcpy(portName, "control-out"); - param.portCout = (CarlaEngineControlPort*)x_client->addPort(CarlaEnginePortTypeControl, portName, false); - } + portName += "event-out"; + portName.truncate(portNameSize); - aIn.count = aIns; - aOut.count = aOuts; - mIn.count = mIns; - mOut.count = mOuts; - param.count = params; + kData->event.portOut = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, false); + } // plugin checks fHints &= ~(PLUGIN_IS_SYNTH | PLUGIN_USES_CHUNKS | PLUGIN_CAN_DRYWET | PLUGIN_CAN_VOLUME | PLUGIN_CAN_BALANCE | PLUGIN_CAN_FORCE_STEREO); @@ -707,7 +823,6 @@ public: if (aIns <= 2 && aOuts <= 2 && (aIns == aOuts || aIns == 0 || aOuts == 0) && mIns <= 1 && mOuts <= 1) fHints |= PLUGIN_CAN_FORCE_STEREO; -#endif // native plugin hints if (fDescriptor->hints & ::PLUGIN_IS_RTSAFE) @@ -719,6 +834,7 @@ public: if (fDescriptor->hints & ::PLUGIN_USES_SINGLE_THREAD) fHints |= PLUGIN_USES_SINGLE_THREAD; + bufferSizeChanged(kData->engine->getBufferSize()); reloadPrograms(true); kData->client->activate(); @@ -726,90 +842,84 @@ public: carla_debug("NativePlugin::reload() - end"); } -#if 0 void reloadPrograms(const bool init) { carla_debug("NativePlugin::reloadPrograms(%s)", bool2str(init)); - uint32_t i, oldCount = midiprog.count; + uint32_t i, oldCount = kData->midiprog.count; // Delete old programs - if (midiprog.count > 0) - { - for (i=0; i < midiprog.count; i++) - { - if (midiprog.data[i].name) - free((void*)midiprog.data[i].name); - } - - delete[] midiprog.data; - } + kData->midiprog.clear(); - midiprog.count = (descriptor->get_midi_program_count && descriptor->get_midi_program_info) ? descriptor->get_midi_program_count(handle) : 0; - midiprog.data = nullptr; + // Query new programs + uint32_t count = 0; + if (fDescriptor->get_midi_program_count != nullptr && fDescriptor->get_midi_program_info != nullptr) + count = fDescriptor->get_midi_program_count(fHandle); - if (midiprog.count > 0) - midiprog.data = new MidiProgramData[midiprog.count]; + if (count > 0) + kData->midiprog.createNew(count); // Update data - for (i=0; i < midiprog.count; i++) + for (i=0; i < kData->midiprog.count; i++) { - const ::MidiProgram* const mpDesc = descriptor->get_midi_program_info(handle, i); - CARLA_ASSERT(mpDesc); - CARLA_ASSERT(mpDesc->name); + const ::MidiProgram* const mpDesc = fDescriptor->get_midi_program_info(fHandle, i); + CARLA_ASSERT(mpDesc != nullptr); + CARLA_ASSERT(mpDesc->name != nullptr); - midiprog.data[i].bank = mpDesc->bank; - midiprog.data[i].program = mpDesc->program; - midiprog.data[i].name = strdup(mpDesc->name); + kData->midiprog.data[i].bank = mpDesc->bank; + kData->midiprog.data[i].program = mpDesc->program; + kData->midiprog.data[i].name = carla_strdup(mpDesc->name); } +#ifndef BUILD_BRIDGE // Update OSC Names - if (x_engine->isOscControlRegistered()) + if (kData->engine->isOscControlRegistered()) { - x_engine->osc_send_control_set_midi_program_count(m_id, midiprog.count); + kData->engine->osc_send_control_set_midi_program_count(fId, kData->midiprog.count); - for (i=0; i < midiprog.count; i++) - x_engine->osc_send_control_set_midi_program_data(m_id, i, midiprog.data[i].bank, midiprog.data[i].program, midiprog.data[i].name); + for (i=0; i < kData->midiprog.count; i++) + kData->engine->osc_send_control_set_midi_program_data(fId, i, kData->midiprog.data[i].bank, kData->midiprog.data[i].program, kData->midiprog.data[i].name); } +#endif if (init) { - if (midiprog.count > 0) + if (kData->midiprog.count > 0) setMidiProgram(0, false, false, false, true); } else { - x_engine->callback(CALLBACK_RELOAD_PROGRAMS, m_id, 0, 0, 0.0, nullptr); + kData->engine->callback(CALLBACK_RELOAD_PROGRAMS, fId, 0, 0, 0.0f, nullptr); // Check if current program is invalid bool programChanged = false; - if (midiprog.count == oldCount+1) + if (kData->midiprog.count == oldCount+1) { // one midi program added, probably created by user - midiprog.current = oldCount; - programChanged = true; + kData->midiprog.current = oldCount; + programChanged = true; } - else if (midiprog.current >= (int32_t)midiprog.count) + else if (kData->midiprog.current >= static_cast(kData->midiprog.count)) { // current midi program > count - midiprog.current = 0; - programChanged = true; + kData->midiprog.current = 0; + programChanged = true; } - else if (midiprog.current < 0 && midiprog.count > 0) + else if (kData->midiprog.current < 0 && kData->midiprog.count > 0) { // programs exist now, but not before - midiprog.current = 0; - programChanged = true; + kData->midiprog.current = 0; + programChanged = true; } - else if (midiprog.current >= 0 && midiprog.count == 0) + else if (kData->midiprog.current >= 0 && kData->midiprog.count == 0) { // programs existed before, but not anymore - midiprog.current = -1; - programChanged = true; + kData->midiprog.current = -1; + programChanged = true; } if (programChanged) - setMidiProgram(midiprog.current, true, true, true, true); + setMidiProgram(kData->midiprog.current, true, true, true, true); } } @@ -820,481 +930,423 @@ public: { uint32_t i, k; - double aInsPeak[2] = { 0.0 }; - double aOutsPeak[2] = { 0.0 }; + // -------------------------------------------------------------------------------------------------------- + // Check if active - // reset MIDI - midiEventCount = 0; - memset(midiEvents, 0, sizeof(::MidiEvent) * MAX_MIDI_EVENTS * 2); + if (! kData->active) + { + // disable any output sound + for (i=0; i < kData->audioOut.count; i++) + carla_zeroFloat(outBuffer[i], frames); - CARLA_PROCESS_CONTINUE_CHECK; + if (kData->activeBefore) + { + if (fDescriptor->deactivate != nullptr) + { + fDescriptor->deactivate(fHandle); + + if (fHandle2 != nullptr) + fDescriptor->deactivate(fHandle2); + } + } + + kData->activeBefore = kData->active; + return; + } + + fMidiEventCount = 0; + carla_zeroMem(fMidiEvents, sizeof(::MidiEvent)*MAX_MIDI_EVENTS*2); // -------------------------------------------------------------------------------------------------------- - // Input VU + // Check if not active before - if (aIn.count > 0 && x_engine->getOptions().processMode != PROCESS_MODE_CONTINUOUS_RACK) + if (! kData->activeBefore) { - if (aIn.count == 1) + if (kData->event.portIn != nullptr) { - for (k=0; k < frames; k++) + for (k=0, i=MAX_MIDI_CHANNELS; k < MAX_MIDI_CHANNELS; k++) { - if (std::abs(inBuffer[0][k]) > aInsPeak[0]) - aInsPeak[0] = std::abs(inBuffer[0][k]); + fMidiEvents[k].data[0] = MIDI_STATUS_CONTROL_CHANGE + k; + fMidiEvents[k].data[1] = MIDI_CONTROL_ALL_SOUND_OFF; + + fMidiEvents[k+i].data[0] = MIDI_STATUS_CONTROL_CHANGE + k; + fMidiEvents[k+i].data[1] = MIDI_CONTROL_ALL_NOTES_OFF; } + + fMidiEventCount = MAX_MIDI_CHANNELS*2; } - else if (aIn.count > 1) + + if (fDescriptor->activate != nullptr) { - for (k=0; k < frames; k++) - { - if (std::abs(inBuffer[0][k]) > aInsPeak[0]) - aInsPeak[0] = std::abs(inBuffer[0][k]); + fDescriptor->activate(fHandle); - if (std::abs(inBuffer[1][k]) > aInsPeak[1]) - aInsPeak[1] = std::abs(inBuffer[1][k]); - } + if (fHandle2 != nullptr) + fDescriptor->activate(fHandle2); } } - CARLA_PROCESS_CONTINUE_CHECK; - // -------------------------------------------------------------------------------------------------------- - // Parameters Input [Automation] + // Event Input and Processing - if (param.portCin && m_active && m_activeBefore) + else if (kData->event.portIn != nullptr) { + // ---------------------------------------------------------------------------------------------------- + // MIDI Input (External) + + if (kData->extNotes.mutex.tryLock()) + { + while (fMidiEventCount < MAX_MIDI_EVENTS*2 && ! kData->extNotes.data.isEmpty()) + { + const ExternalMidiNote& note = kData->extNotes.data.getLast(true); // FIXME, should be first + + CARLA_ASSERT(note.channel >= 0); + + fMidiEvents[fMidiEventCount].port = 0; + fMidiEvents[fMidiEventCount].time = 0; + fMidiEvents[fMidiEventCount].data[0] = (note.velo > 0) ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF; + fMidiEvents[fMidiEventCount].data[0] += note.channel; + fMidiEvents[fMidiEventCount].data[1] = note.note; + fMidiEvents[fMidiEventCount].data[2] = note.velo; + + fMidiEventCount += 1; + } + + kData->extNotes.mutex.unlock(); + + } // End of MIDI Input (External) + + // ---------------------------------------------------------------------------------------------------- + // Event Input (System) + bool allNotesOffSent = false; + bool sampleAccurate = (fHints & PLUGIN_OPTION_FIXED_BUFFER) == 0; - const CarlaEngineControlEvent* cinEvent; - uint32_t time, nEvents = param.portCin->getEventCount(); + uint32_t time, nEvents = kData->event.portIn->getEventCount(); + uint32_t timeOffset = 0; uint32_t nextBankId = 0; - if (midiprog.current >= 0 && midiprog.count > 0) - nextBankId = midiprog.data[midiprog.current].bank; + if (kData->midiprog.current >= 0 && kData->midiprog.count > 0) + nextBankId = kData->midiprog.data[kData->midiprog.current].bank; for (i=0; i < nEvents; i++) { - cinEvent = param.portCin->getEvent(i); + const EngineEvent& event = kData->event.portIn->getEvent(i); - if (! cinEvent) - continue; - - time = cinEvent->time - framesOffset; + time = event.time - framesOffset; if (time >= frames) continue; + CARLA_ASSERT_INT2(time >= timeOffset, time, timeOffset); + + if (time > timeOffset && sampleAccurate) + { + processSingle(inBuffer, outBuffer, time - timeOffset, timeOffset); + + if (fMidiEventCount > 0) + { + carla_zeroMem(fMidiEvents, sizeof(::MidiEvent)*fMidiEventCount); + fMidiEventCount = 0; + } + + nextBankId = 0; + timeOffset = time; + } + // Control change - switch (cinEvent->type) + switch (event.type) { - case CarlaEngineNullEvent: + case kEngineEventTypeNull: break; - case CarlaEngineParameterChangeEvent: + case kEngineEventTypeControl: { - double value; + const EngineControlEvent& ctrlEvent = event.ctrl; - // Control backend stuff - if (cinEvent->channel == m_ctrlInChannel) + switch (ctrlEvent.type) { - if (MIDI_IS_CONTROL_BREATH_CONTROLLER(cinEvent->parameter) && (m_hints & PLUGIN_CAN_DRYWET) > 0) - { - value = cinEvent->value; - setDryWet(value, false, false); - postponeEvent(PluginPostEventParameterChange, PARAMETER_DRYWET, 0, value); - continue; - } - - if (MIDI_IS_CONTROL_CHANNEL_VOLUME(cinEvent->parameter) && (m_hints & PLUGIN_CAN_VOLUME) > 0) - { - value = cinEvent->value*127/100; - setVolume(value, false, false); - postponeEvent(PluginPostEventParameterChange, PARAMETER_VOLUME, 0, value); - continue; - } + case kEngineControlEventTypeNull: + break; - if (MIDI_IS_CONTROL_BALANCE(cinEvent->parameter) && (m_hints & PLUGIN_CAN_BALANCE) > 0) + case kEngineControlEventTypeParameter: + { + // Control backend stuff + if (event.channel == kData->ctrlInChannel) { - double left, right; - value = cinEvent->value/0.5 - 1.0; + double value; - if (value < 0.0) + if (MIDI_IS_CONTROL_BREATH_CONTROLLER(ctrlEvent.param) && (fHints & PLUGIN_CAN_DRYWET) > 0) { - left = -1.0; - right = (value*2)+1.0; + value = ctrlEvent.value; + setDryWet(value, false, false); + postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_DRYWET, 0, value); + continue; } - else if (value > 0.0) + + if (MIDI_IS_CONTROL_CHANNEL_VOLUME(ctrlEvent.param) && (fHints & PLUGIN_CAN_VOLUME) > 0) { - left = (value*2)-1.0; - right = 1.0; + value = ctrlEvent.value*127/100; + setVolume(value, false, false); + postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_VOLUME, 0, value); + continue; } - else + + if (MIDI_IS_CONTROL_BALANCE(ctrlEvent.param) && (fHints & PLUGIN_CAN_BALANCE) > 0) { - left = -1.0; - right = 1.0; + double left, right; + value = ctrlEvent.value/0.5 - 1.0; + + if (value < 0.0) + { + left = -1.0; + right = (value*2)+1.0; + } + else if (value > 0.0) + { + left = (value*2)-1.0; + right = 1.0; + } + else + { + left = -1.0; + right = 1.0; + } + + setBalanceLeft(left, false, false); + setBalanceRight(right, false, false); + postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_BALANCE_LEFT, 0, left); + postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_BALANCE_RIGHT, 0, right); + continue; } - - setBalanceLeft(left, false, false); - setBalanceRight(right, false, false); - postponeEvent(PluginPostEventParameterChange, PARAMETER_BALANCE_LEFT, 0, left); - postponeEvent(PluginPostEventParameterChange, PARAMETER_BALANCE_RIGHT, 0, right); - continue; } - } - // Control plugin parameters - for (k=0; k < param.count; k++) - { - if (param.data[k].midiChannel != cinEvent->channel) - continue; - if (param.data[k].midiCC != cinEvent->parameter) - continue; - if (param.data[k].type != PARAMETER_INPUT) - continue; - - if (param.data[k].hints & PARAMETER_IS_AUTOMABLE) + // Control plugin parameters + for (k=0; k < kData->param.count; k++) { - if (param.data[k].hints & PARAMETER_IS_BOOLEAN) + if (kData->param.data[k].midiChannel != event.channel) + continue; + if (kData->param.data[k].midiCC != ctrlEvent.param) + continue; + if (kData->param.data[k].type != PARAMETER_INPUT) + continue; + if ((kData->param.data[k].hints & PARAMETER_IS_AUTOMABLE) == 0) + continue; + + double value; + + if (kData->param.data[k].hints & PARAMETER_IS_BOOLEAN) { - value = cinEvent->value < 0.5 ? param.ranges[k].min : param.ranges[k].max; + value = (ctrlEvent.value < 0.5) ? kData->param.ranges[k].min : kData->param.ranges[k].max; } else { - value = cinEvent->value * (param.ranges[k].max - param.ranges[k].min) + param.ranges[k].min; + // FIXME - ranges call for this + value = ctrlEvent.value * (kData->param.ranges[k].max - kData->param.ranges[k].min) + kData->param.ranges[k].min; - if (param.data[k].hints & PARAMETER_IS_INTEGER) - value = rint(value); + if (kData->param.data[k].hints & PARAMETER_IS_INTEGER) + value = std::rint(value); } setParameterValue(k, value, false, false, false); - postponeEvent(PluginPostEventParameterChange, k, 0, value); + postponeRtEvent(kPluginPostRtEventParameterChange, k, 0, value); } - } - break; - } - - case CarlaEngineMidiBankChangeEvent: - if (cinEvent->channel == m_ctrlInChannel) - nextBankId = rint(cinEvent->value); - break; + break; + } - case CarlaEngineMidiProgramChangeEvent: - if (cinEvent->channel == m_ctrlInChannel) - { - uint32_t nextProgramId = rint(cinEvent->value); + case kEngineControlEventTypeMidiBank: + if (event.channel == kData->ctrlInChannel) + nextBankId = ctrlEvent.param; + break; - for (k=0; k < midiprog.count; k++) + case kEngineControlEventTypeMidiProgram: + if (event.channel == kData->ctrlInChannel) { - if (midiprog.data[k].bank == nextBankId && midiprog.data[k].program == nextProgramId) + const uint32_t nextProgramId = ctrlEvent.param; + + for (k=0; k < kData->midiprog.count; k++) { - setMidiProgram(k, false, false, false, false); - postponeEvent(PluginPostEventMidiProgramChange, k, 0, 0.0); - break; + if (kData->midiprog.data[k].bank == nextBankId && kData->midiprog.data[k].program == nextProgramId) + { + setMidiProgram(k, false, false, false, false); + postponeRtEvent(kPluginPostRtEventMidiProgramChange, k, 0, 0.0); + break; + } } } - } - break; - - case CarlaEngineAllSoundOffEvent: - if (cinEvent->channel == m_ctrlInChannel) - { - if (mIn.count > 0 && ! allNotesOffSent) - sendMidiAllNotesOff(); + break; - if (descriptor->deactivate) + case kEngineControlEventTypeAllSoundOff: + if (event.channel == kData->ctrlInChannel) { - descriptor->deactivate(handle); - if (h2) descriptor->deactivate(h2); - } + if (! allNotesOffSent) + sendMidiAllNotesOff(); - if (descriptor->activate) - { - descriptor->activate(handle); - if (h2) descriptor->activate(h2); - } + if (fDescriptor->deactivate != nullptr) + { + fDescriptor->deactivate(fHandle); - postponeEvent(PluginPostEventParameterChange, PARAMETER_ACTIVE, 0, 0.0); - postponeEvent(PluginPostEventParameterChange, PARAMETER_ACTIVE, 0, 1.0); + if (fHandle2 != nullptr) + fDescriptor->deactivate(fHandle2); + } - allNotesOffSent = true; - } - break; + if (fDescriptor->activate != nullptr) + { + fDescriptor->activate(fHandle); - case CarlaEngineAllNotesOffEvent: - if (cinEvent->channel == m_ctrlInChannel) - { - if (mIn.count > 0 && ! allNotesOffSent) - sendMidiAllNotesOff(); + if (fHandle2 != nullptr) + fDescriptor->activate(fHandle2); + } - allNotesOffSent = true; - } - break; - } - } - } // End of Parameters Input + postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_ACTIVE, 0, 0.0); + postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_ACTIVE, 0, 1.0); - CARLA_PROCESS_CONTINUE_CHECK; + allNotesOffSent = true; + } - // -------------------------------------------------------------------------------------------------------- - // MIDI Input + if (fMidiEventCount >= MAX_MIDI_EVENTS*2) + continue; - if (mIn.count > 0 && m_active && m_activeBefore) - { - // ---------------------------------------------------------------------------------------------------- - // MIDI Input (External) + fMidiEvents[fMidiEventCount].port = 0; + fMidiEvents[fMidiEventCount].time = sampleAccurate ? 0 : time; + fMidiEvents[fMidiEventCount].data[0] = MIDI_STATUS_CONTROL_CHANGE + event.channel; + fMidiEvents[fMidiEventCount].data[1] = MIDI_CONTROL_ALL_SOUND_OFF; + fMidiEvents[fMidiEventCount].data[2] = 0; - { - engineMidiLock(); + fMidiEventCount += 1; - for (i=0; i < MAX_MIDI_EVENTS && midiEventCount < MAX_MIDI_EVENTS; i++) - { - if (extMidiNotes[i].channel < 0) break; - ::MidiEvent* const midiEvent = &midiEvents[midiEventCount]; - memset(midiEvent, 0, sizeof(::MidiEvent)); - - midiEvent->data[0] = uint8_t(extMidiNotes[i].velo ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) + extMidiNotes[i].channel; - midiEvent->data[1] = extMidiNotes[i].note; - midiEvent->data[2] = extMidiNotes[i].velo; + case kEngineControlEventTypeAllNotesOff: + if (event.channel == kData->ctrlInChannel) + { + if (! allNotesOffSent) + sendMidiAllNotesOff(); - extMidiNotes[i].channel = -1; // mark as invalid - midiEventCount += 1; - } + allNotesOffSent = true; + } - engineMidiUnlock(); + if (fMidiEventCount >= MAX_MIDI_EVENTS*2) + continue; - } // End of MIDI Input (External) + fMidiEvents[fMidiEventCount].port = 0; + fMidiEvents[fMidiEventCount].time = sampleAccurate ? 0: time; + fMidiEvents[fMidiEventCount].data[0] = MIDI_STATUS_CONTROL_CHANGE + event.channel; + fMidiEvents[fMidiEventCount].data[1] = MIDI_CONTROL_ALL_NOTES_OFF; + fMidiEvents[fMidiEventCount].data[2] = 0; - CARLA_PROCESS_CONTINUE_CHECK; + fMidiEventCount += 1; - // ---------------------------------------------------------------------------------------------------- - // MIDI Input (System) - - for (i=0; i < mIn.count; i++) - { - if (! mIn.ports[i]) - continue; + break; + } - const CarlaEngineMidiEvent* minEvent; - uint32_t time, nEvents = mIn.ports[i]->getEventCount(); + break; + } - for (k=0; k < nEvents && midiEventCount < MAX_MIDI_EVENTS; k++) + case kEngineEventTypeMidi: { - minEvent = mIn.ports[i]->getEvent(k); - - if (! minEvent) - continue; - - time = minEvent->time - framesOffset; - - if (time >= frames) + if (fMidiEventCount >= MAX_MIDI_EVENTS*2) continue; - uint8_t status = minEvent->data[0]; - uint8_t channel = status & 0x0F; - - // Fix bad note-off - if (MIDI_IS_STATUS_NOTE_ON(status) && minEvent->data[2] == 0) - status -= 0x10; - - ::MidiEvent* const midiEvent = &midiEvents[midiEventCount]; - memset(midiEvent, 0, sizeof(::MidiEvent)); - - midiEvent->port = i; - midiEvent->time = minEvent->time; - - if (MIDI_IS_STATUS_NOTE_OFF(status)) - { - uint8_t note = minEvent->data[1]; - - midiEvent->data[0] = status; - midiEvent->data[1] = note; - - postponeEvent(PluginPostEventNoteOff, channel, note, 0.0); - } - else if (MIDI_IS_STATUS_NOTE_ON(status)) - { - uint8_t note = minEvent->data[1]; - uint8_t velo = minEvent->data[2]; - - midiEvent->data[0] = status; - midiEvent->data[1] = note; - midiEvent->data[2] = velo; - - postponeEvent(PluginPostEventNoteOn, channel, note, velo); - } - else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status)) - { - uint8_t note = minEvent->data[1]; - uint8_t pressure = minEvent->data[2]; - - midiEvent->data[0] = status; - midiEvent->data[1] = note; - midiEvent->data[2] = pressure; - } - else if (MIDI_IS_STATUS_AFTERTOUCH(status)) - { - uint8_t pressure = minEvent->data[1]; + const EngineMidiEvent& midiEvent = event.midi; - midiEvent->data[0] = status; - midiEvent->data[1] = pressure; - } - else if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status)) - { - uint8_t lsb = minEvent->data[1]; - uint8_t msb = minEvent->data[2]; + uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent.data); + uint8_t channel = event.channel; - midiEvent->data[0] = status; - midiEvent->data[1] = lsb; - midiEvent->data[2] = msb; - } - else + if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (fHints & PLUGIN_OPTION_SELF_AUTOMATION) == 0) continue; - midiEventCount += 1; - } - } // End of MIDI Input (System) - - } // End of MIDI Input - - CARLA_PROCESS_CONTINUE_CHECK; - - // -------------------------------------------------------------------------------------------------------- - // Plugin processing + // Fix bad note-off (per DSSI spec) + if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0) + status -= 0x10; - uint32_t midiEventCountBefore = midiEventCount; + fMidiEvents[fMidiEventCount].port = 0; + fMidiEvents[fMidiEventCount].time = sampleAccurate ? 0 : time - timeOffset; - if (m_active) - { - if (! m_activeBefore) - { - if (mIn.count > 0) - { - for (k=0; k < MAX_MIDI_CHANNELS; k++) - { - memset(&midiEvents[k], 0, sizeof(::MidiEvent)); - midiEvents[k].data[0] = MIDI_STATUS_CONTROL_CHANGE + k; - midiEvents[k].data[1] = MIDI_CONTROL_ALL_SOUND_OFF; + fMidiEvents[fMidiEventCount].data[0] = status + channel; + fMidiEvents[fMidiEventCount].data[1] = midiEvent.data[1]; + fMidiEvents[fMidiEventCount].data[2] = midiEvent.data[2]; - memset(&midiEvents[k*2], 0, sizeof(::MidiEvent)); - midiEvents[k*2].data[0] = MIDI_STATUS_CONTROL_CHANGE + k; - midiEvents[k*2].data[1] = MIDI_CONTROL_ALL_NOTES_OFF; - } + fMidiEventCount += 1; - midiEventCount = MAX_MIDI_CHANNELS*2; + break; } - - if (descriptor->activate) - { - descriptor->activate(handle); - if (h2) descriptor->activate(h2); } } - isProcessing = true; + kData->postRtEvents.trySplice(); - if (h2) - { - descriptor->process(handle, inBuffer? &inBuffer[0] : nullptr, outBuffer? &outBuffer[0] : nullptr, frames, midiEventCountBefore, midiEvents); - descriptor->process(h2, inBuffer? &inBuffer[1] : nullptr, outBuffer? &outBuffer[1] : nullptr, frames, midiEventCountBefore, midiEvents); - } - else - descriptor->process(handle, inBuffer, outBuffer, frames, midiEventCountBefore, midiEvents); + if (frames > timeOffset) + processSingle(inBuffer, outBuffer, frames - timeOffset, timeOffset); + + } // End of Event Input and Processing + + // -------------------------------------------------------------------------------------------------------- + // Plugin processing (no events) - isProcessing = false; - } else { - if (m_activeBefore) - { - if (descriptor->deactivate) - { - descriptor->deactivate(handle); - if (h2) descriptor->deactivate(h2); - } - } - } + processSingle(inBuffer, outBuffer, frames, 0); + + } // End of Plugin processing (no events) CARLA_PROCESS_CONTINUE_CHECK; // -------------------------------------------------------------------------------------------------------- // Post-processing (dry/wet, volume and balance) - if (m_active) { - bool do_drywet = (m_hints & PLUGIN_CAN_DRYWET) > 0 && x_dryWet != 1.0; - bool do_volume = (m_hints & PLUGIN_CAN_VOLUME) > 0 && x_volume != 1.0; - bool do_balance = (m_hints & PLUGIN_CAN_BALANCE) > 0 && (x_balanceLeft != -1.0 || x_balanceRight != 1.0); + const bool doDryWet = (fHints & PLUGIN_CAN_DRYWET) > 0 && kData->postProc.dryWet != 1.0f; + const bool doVolume = (fHints & PLUGIN_CAN_VOLUME) > 0 && kData->postProc.volume != 1.0f; + const bool doBalance = (fHints & PLUGIN_CAN_BALANCE) > 0 && (kData->postProc.balanceLeft != -1.0f || kData->postProc.balanceRight != 1.0f); - double bal_rangeL, bal_rangeR; - float bufValue, oldBufLeft[do_balance ? frames : 0]; + float bufValue, oldBufLeft[doBalance ? frames : 1]; - for (i=0; i < aOut.count; i++) + for (i=0; i < kData->audioOut.count; i++) { // Dry/Wet - if (do_drywet) + if (doDryWet) { for (k=0; k < frames; k++) { - bufValue = (aIn.count == 1) ? inBuffer[0][k] : inBuffer[i][k]; - - outBuffer[i][k] = (outBuffer[i][k]*x_dryWet)+(bufValue*(1.0-x_dryWet)); + bufValue = inBuffer[(kData->audioIn.count == 1) ? 0 : i][k]; + outBuffer[i][k] = (outBuffer[i][k] * kData->postProc.dryWet) + (bufValue * (1.0f - kData->postProc.dryWet)); } } // Balance - if (do_balance) + if (doBalance) { - if (i%2 == 0) - memcpy(&oldBufLeft, outBuffer[i], sizeof(float)*frames); + if (i % 2 == 0) + std::memcpy(oldBufLeft, outBuffer[i], sizeof(float)*frames); - bal_rangeL = (x_balanceLeft+1.0)/2; - bal_rangeR = (x_balanceRight+1.0)/2; + float balRangeL = (kData->postProc.balanceLeft + 1.0f)/2.0f; + float balRangeR = (kData->postProc.balanceRight + 1.0f)/2.0f; for (k=0; k < frames; k++) { - if (i%2 == 0) + if (i % 2 == 0) { - // left output - outBuffer[i][k] = oldBufLeft[k]*(1.0-bal_rangeL); - outBuffer[i][k] += outBuffer[i+1][k]*(1.0-bal_rangeR); + // left + outBuffer[i][k] = oldBufLeft[k] * (1.0f - balRangeL); + outBuffer[i][k] += outBuffer[i+1][k] * (1.0f - balRangeR); } else { // right - outBuffer[i][k] = outBuffer[i][k]*bal_rangeR; - outBuffer[i][k] += oldBufLeft[k]*bal_rangeL; + outBuffer[i][k] = outBuffer[i][k] * balRangeR; + outBuffer[i][k] += oldBufLeft[k] * balRangeL; } } } // Volume - if (do_volume) + if (doVolume) { for (k=0; k < frames; k++) - outBuffer[i][k] *= x_volume; - } - - // Output VU - if (x_engine->getOptions().processMode != PROCESS_MODE_CONTINUOUS_RACK) - { - for (k=0; i < 2 && k < frames; k++) - { - if (std::abs(outBuffer[i][k]) > aOutsPeak[i]) - aOutsPeak[i] = std::abs(outBuffer[i][k]); - } + outBuffer[i][k] *= kData->postProc.volume; } } - } - else - { - // disable any output sound if not active - for (i=0; i < aOut.count; i++) - carla_zeroF(outBuffer[i], frames); - - aOutsPeak[0] = 0.0; - aOutsPeak[1] = 0.0; } // End of Post-processing @@ -1303,100 +1355,101 @@ public: // -------------------------------------------------------------------------------------------------------- // MIDI Output - if (mOut.count > 0 && m_active) + if (fMidiOut.count > 0) { - uint8_t data[3] = { 0 }; - - for (uint32_t i = midiEventCountBefore; i < midiEventCount; i++) + // reverse lookup + for (uint32_t i=fMidiEventCount-1; i >= fMidiEventCount; i--) { - data[0] = midiEvents[i].data[0]; - data[1] = midiEvents[i].data[1]; - data[2] = midiEvents[i].data[2]; - - // Fix bad note-off - if (MIDI_IS_STATUS_NOTE_ON(data[0]) && data[2] == 0) - data[0] -= 0x10; + if (fMidiEvents[i].data[0] == 0) + break; - const uint32_t port = midiEvents[i].port; + const uint8_t channel = MIDI_GET_CHANNEL_FROM_DATA(fMidiEvents[i].data); + const uint8_t port = fMidiEvents[i].port; - if (port < mOut.count) - mOut.ports[port]->writeEvent(midiEvents[i].time, data, 3); + if (port < fMidiOut.count) + fMidiOut.ports[port]->writeMidiEvent(fMidiEvents[i].time, channel, port, fMidiEvents[i].data, 3); } } // End of MIDI Output + CARLA_PROCESS_CONTINUE_CHECK; + // -------------------------------------------------------------------------------------------------------- // Control Output - if (param.portCout && m_active) + if (kData->event.portOut != nullptr) { - double value, valueControl; + float value, curValue; - for (k=0; k < param.count; k++) + for (k=0; k < kData->param.count; k++) { - if (param.data[k].type == PARAMETER_OUTPUT) - { - value = descriptor->get_parameter_value(handle, param.data[k].rindex); + if (kData->param.data[k].type != PARAMETER_OUTPUT) + continue; - if (param.data[k].midiCC > 0) - { - valueControl = (value - param.ranges[k].min) / (param.ranges[k].max - param.ranges[k].min); - param.portCout->writeEvent(CarlaEngineParameterChangeEvent, framesOffset, param.data[k].midiChannel, param.data[k].midiCC, valueControl); - } + curValue = fDescriptor->get_parameter_value(fHandle, k); + kData->param.ranges[k].fixValue(curValue); + + if (kData->param.data[k].midiCC > 0) + { + value = kData->param.ranges[k].normalizeValue(curValue); + kData->event.portOut->writeControlEvent(framesOffset, kData->param.data[k].midiChannel, kEngineControlEventTypeParameter, kData->param.data[k].midiCC, value); } } - } // End of Control Output - CARLA_PROCESS_CONTINUE_CHECK; + } // End of Control Output // -------------------------------------------------------------------------------------------------------- - // Peak Values - - x_engine->setInputPeak(m_id, 0, aInsPeak[0]); - x_engine->setInputPeak(m_id, 1, aInsPeak[1]); - x_engine->setOutputPeak(m_id, 0, aOutsPeak[0]); - x_engine->setOutputPeak(m_id, 1, aOutsPeak[1]); - m_activeBefore = m_active; + kData->activeBefore = kData->active; } - // ------------------------------------------------------------------- - // Cleanup - - void removeClientPorts() + void processSingle(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t timeOffset) { - carla_debug("NativePlugin::removeClientPorts() - start"); + for (uint32_t i=0; i < kData->audioIn.count; i++) + std::memcpy(fAudioInBuffers[i], inBuffer[i]+timeOffset, sizeof(float)*frames); + for (uint32_t i=0; i < kData->audioOut.count; i++) + carla_zeroFloat(fAudioOutBuffers[i], frames); - for (uint32_t i=0; i < mIn.count; i++) - { - delete mIn.ports[i]; - mIn.ports[i] = nullptr; - } + fIsProcessing = true; - for (uint32_t i=0; i < mOut.count; i++) - { - delete mOut.ports[i]; - mOut.ports[i] = nullptr; - } + fDescriptor->process(fHandle, fAudioInBuffers, fAudioOutBuffers, frames, 0, nullptr); - CarlaPlugin::removeClientPorts(); + if (fHandle2 != nullptr) + fDescriptor->process(fHandle2, fAudioInBuffers, fAudioOutBuffers, frames, 0, nullptr); + + fIsProcessing = false; - carla_debug("NativePlugin::removeClientPorts() - end"); + for (uint32_t i=0, k; i < kData->audioOut.count; i++) + { + for (k=0; k < frames; k++) + outBuffer[i][k+timeOffset] = fAudioOutBuffers[i][k]; + } } - void initBuffers() + void bufferSizeChanged(const uint32_t newBufferSize) { - for (uint32_t i=0; i < mIn.count; i++) + for (uint32_t i=0; i < kData->audioIn.count; i++) { - if (mIn.ports[i]) - mIn.ports[i]->initBuffer(x_engine); + if (fAudioInBuffers[i] != nullptr) + delete[] fAudioInBuffers[i]; + fAudioInBuffers[i] = new float[newBufferSize]; } - for (uint32_t i=0; i < mOut.count; i++) + for (uint32_t i=0; i < kData->audioOut.count; i++) { - if (mOut.ports[i]) - mOut.ports[i]->initBuffer(x_engine); + if (fAudioOutBuffers[i] != nullptr) + delete[] fAudioOutBuffers[i]; + fAudioOutBuffers[i] = new float[newBufferSize]; } + } + + // ------------------------------------------------------------------- + // Cleanup + + void initBuffers() + { + fMidiIn.initBuffers(kData->engine); + fMidiOut.initBuffers(kData->engine); CarlaPlugin::initBuffers(); } @@ -1405,25 +1458,38 @@ public: { carla_debug("NativePlugin::deleteBuffers() - start"); - if (mIn.count > 0) + if (fAudioInBuffers != nullptr) { - delete[] mIn.ports; - delete[] mIn.indexes; + for (uint32_t i=0; i < kData->audioIn.count; i++) + { + if (fAudioInBuffers[i] != nullptr) + { + delete[] fAudioInBuffers[i]; + fAudioInBuffers[i] = nullptr; + } + } + + delete[] fAudioInBuffers; + fAudioInBuffers = nullptr; } - if (mOut.count > 0) + if (fAudioOutBuffers != nullptr) { - delete[] mOut.ports; - delete[] mOut.indexes; - } + for (uint32_t i=0; i < kData->audioOut.count; i++) + { + if (fAudioOutBuffers[i] != nullptr) + { + delete[] fAudioOutBuffers[i]; + fAudioOutBuffers[i] = nullptr; + } + } - mIn.count = 0; - mIn.ports = nullptr; - mIn.indexes = nullptr; + delete[] fAudioOutBuffers; + fAudioOutBuffers = nullptr; + } - mOut.count = 0; - mOut.ports = nullptr; - mOut.indexes = nullptr; + fMidiIn.clear(); + fMidiOut.clear(); CarlaPlugin::deleteBuffers(); @@ -1431,7 +1497,6 @@ public: } // ------------------------------------------------------------------- -#endif protected: uint32_t handleGetBufferSize() @@ -1444,7 +1509,7 @@ protected: return kData->engine->getSampleRate(); } - const TimeInfo* handleGetTimeInfo() + const ::TimeInfo* handleGetTimeInfo() { // TODO return nullptr; @@ -1453,27 +1518,32 @@ protected: bool handleWriteMidiEvent(const MidiEvent* const event) { CARLA_ASSERT(fEnabled); - //CARLA_ASSERT(mOut.count > 0); + CARLA_ASSERT(fMidiOut.count > 0); CARLA_ASSERT(fIsProcessing); CARLA_ASSERT(event != nullptr); if (! fEnabled) return false; - - //if (mOut.count == 0) - // return false; - + if (fMidiOut.count == 0) + return false; if (! fIsProcessing) { carla_stderr2("NativePlugin::handleWriteMidiEvent(%p) - received MIDI out events outside audio thread, ignoring", event); return false; } - //if (midiEventCount >= MAX_MIDI_EVENTS*2) - // return false; + if (fMidiEventCount >= MAX_MIDI_EVENTS*2) + return false; - //memcpy(&midiEvents[midiEventCount], event, sizeof(::MidiEvent)); - //midiEventCount += 1; + // reverse-find first free event, and put it there + for (uint32_t i=fMidiEventCount-1; i >= fMidiEventCount; i--) + { + if (fMidiEvents[i].data[0] == 0) + { + std::memcpy(&fMidiEvents[i], event, sizeof(::MidiEvent)); + break; + } + } return true; } @@ -1617,13 +1687,13 @@ private: bool fIsProcessing; -#if 0 - NativePluginMidiData mIn; - NativePluginMidiData mOut; + float** fAudioInBuffers; + float** fAudioOutBuffers; + uint32_t fMidiEventCount; + ::MidiEvent fMidiEvents[MAX_MIDI_EVENTS*2]; - uint32_t midiEventCount; - ::MidiEvent midiEvents[MAX_MIDI_EVENTS*2]; -#endif + NativePluginMidiData fMidiIn; + NativePluginMidiData fMidiOut; static bool sFirstInit; static std::vector sPluginDescriptors; @@ -1642,7 +1712,7 @@ private: return handlePtr->handleGetSampleRate(); } - static const TimeInfo* carla_host_get_time_info(HostHandle handle) + static const ::TimeInfo* carla_host_get_time_info(HostHandle handle) { return handlePtr->handleGetTimeInfo(); } diff --git a/source/backend/plugin/VstPlugin.cpp b/source/backend/plugin/VstPlugin.cpp index dcafe44c0..c3db2c9ad 100644 --- a/source/backend/plugin/VstPlugin.cpp +++ b/source/backend/plugin/VstPlugin.cpp @@ -50,7 +50,7 @@ public: VstPlugin(CarlaEngine* const engine, const unsigned short id) : CarlaPlugin(engine, id) { - carla_debug("VstPlugin::VstPlugin()"); + carla_debug("VstPlugin::VstPlugin(%p, %i)", engine, id); m_type = PLUGIN_VST;