diff --git a/source/plugin/carla-lv2.cpp b/source/plugin/carla-lv2.cpp index 3b883d567..20bbfe17b 100644 --- a/source/plugin/carla-lv2.cpp +++ b/source/plugin/carla-lv2.cpp @@ -195,7 +195,7 @@ public: fHandle = fDescriptor->instantiate(&fHost); CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false); - carla_zeroStructs(fMidiEvents, kMaxMidiEvents*2); + carla_zeroStructs(fMidiEvents, kMaxMidiEvents); carla_zeroStruct(fTimeInfo); // hosts may not send all values, resulting on some invalid data @@ -259,34 +259,13 @@ public: fIsOffline = (fPorts.freewheel != nullptr && *fPorts.freewheel >= 0.5f); if (frames == 0) - { - updateParameterOutputs(); - return; - } - - // Check for updated parameters - float curValue; + return updateParameterOutputs(); - for (uint32_t i=0; i < fPorts.paramCount; ++i) - { - if (fPorts.paramsOut[i]) - continue; - - CARLA_SAFE_ASSERT_CONTINUE(fPorts.paramsPtr[i] != nullptr) - - curValue = *fPorts.paramsPtr[i]; - - if (carla_isEqual(fPorts.paramsLast[i], curValue)) - continue; - - fPorts.paramsLast[i] = curValue; - fDescriptor->set_parameter_value(fHandle, i, curValue); - } - - if (fDescriptor->midiIns > 0 || fDescriptor->midiOuts > 0 || (fDescriptor->hints & NATIVE_PLUGIN_USES_TIME) != 0) + // cache midi events and time information + if (fDescriptor->midiIns > 0 || (fDescriptor->hints & NATIVE_PLUGIN_USES_TIME) != 0) { fMidiEventCount = 0; - carla_zeroStructs(fMidiEvents, kMaxMidiEvents*2); + carla_zeroStructs(fMidiEvents, kMaxMidiEvents); if (fDescriptor->hints & NATIVE_PLUGIN_USES_TIME) { @@ -490,24 +469,59 @@ public: continue; if (event->time.frames >= frames) break; - if (fMidiEventCount >= kMaxMidiEvents*2) + if (fMidiEventCount >= kMaxMidiEvents) break; const uint8_t* const data((const uint8_t*)(event + 1)); NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]); - carla_zeroStruct(nativeEvent); nativeEvent.port = (uint8_t)i; nativeEvent.size = (uint8_t)event->body.size; nativeEvent.time = (uint32_t)event->time.frames; - for (uint32_t j=0; j < event->body.size; ++j) + uint32_t j=0; + for (uint32_t size=event->body.size; jmidiOuts > 0) + { + for (uint32_t i=0, size=fDescriptor->midiOuts; iatom.size; + mData.offset = 0; + } + } + + // Check for updated parameters + float curValue; + + for (uint32_t i=0; i < fPorts.paramCount; ++i) + { + if (fPorts.paramsOut[i]) + continue; + + CARLA_SAFE_ASSERT_CONTINUE(fPorts.paramsPtr[i] != nullptr) + + curValue = *fPorts.paramsPtr[i]; + + if (carla_isEqual(fPorts.paramsLast[i], curValue)) + continue; + + fPorts.paramsLast[i] = curValue; + fDescriptor->set_parameter_value(fHandle, i, curValue); + } + // FIXME fDescriptor->process(fHandle, const_cast(fPorts.audioIns), fPorts.audioOuts, frames, fMidiEvents, fMidiEventCount); @@ -566,60 +580,6 @@ public: } updateParameterOutputs(); - - if (fDescriptor->midiOuts > 0) - { - uint32_t capacities[fDescriptor->midiOuts]; - uint32_t offsets [fDescriptor->midiOuts]; - - for (uint32_t i=0, size=fDescriptor->midiOuts; iatom.size; - offsets [i] = 0; - } - - LV2_Atom_Event* aev; - uint32_t size; - - // reverse lookup MIDI events - for (uint32_t i = (kMaxMidiEvents*2)-1; i >= fMidiEventCount; --i) - { - if (fMidiEvents[i].data[0] == 0) - break; - - NativeMidiEvent& nativeEvent(fMidiEvents[i]); - - const uint8_t port(nativeEvent.port); - CARLA_SAFE_ASSERT_CONTINUE(nativeEvent.port < fDescriptor->midiOuts); - - LV2_Atom_Sequence* const seq(fPorts.midiOuts[port]); - CARLA_SAFE_ASSERT_CONTINUE(seq != nullptr); - - if (sizeof(LV2_Atom_Event) + nativeEvent.size > capacities[port] - offsets[port]) - continue; - - if (offsets[port] == 0) - { - seq->atom.size = 0; - seq->atom.type = fURIs.atomSequence; - seq->body.unit = 0; - seq->body.pad = 0; - } - - aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, seq) + offsets[port]); - aev->time.frames = nativeEvent.time; - aev->body.size = nativeEvent.size; - aev->body.type = fURIs.midiEvent; - std::memcpy(LV2_ATOM_BODY(&aev->body), nativeEvent.data, nativeEvent.size); - - size = lv2_atom_pad_size(sizeof(LV2_Atom_Event) + nativeEvent.size); - offsets[port] += size; - seq->atom.size += size; - } - } } // ------------------------------------------------------------------- @@ -936,20 +896,39 @@ protected: { CARLA_SAFE_ASSERT_RETURN(fDescriptor->midiOuts > 0, false); CARLA_SAFE_ASSERT_RETURN(event != nullptr, false); - CARLA_SAFE_ASSERT_RETURN(event->data[0] != 0, false); + CARLA_SAFE_ASSERT_RETURN(event->size > 0, false); - // reverse-find first free event, and put it there - for (uint32_t i=(kMaxMidiEvents*2)-1; i > fMidiEventCount; --i) - { - if (fMidiEvents[i].data[0] != 0) - continue; + const uint8_t port(event->port); + CARLA_SAFE_ASSERT_RETURN(port < fDescriptor->midiOuts, false); - std::memcpy(&fMidiEvents[i], event, sizeof(NativeMidiEvent)); - return true; + LV2_Atom_Sequence* const seq(fPorts.midiOuts[port]); + CARLA_SAFE_ASSERT_RETURN(seq != nullptr, false); + + Ports::MidiOutData& mData(fPorts.midiOutData[port]); + + if (sizeof(LV2_Atom_Event) + event->size > mData.capacity - mData.offset) + return false; + + if (mData.offset == 0) + { + seq->atom.size = 0; + seq->atom.type = fURIs.atomSequence; + seq->body.unit = 0; + seq->body.pad = 0; } - carla_stdout("NativePlugin::handleWriteMidiEvent(%p) - buffer full", event); - return false; + LV2_Atom_Event* const aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, seq) + mData.offset); + + aev->time.frames = event->time; + aev->body.size = event->size; + aev->body.type = fURIs.midiEvent; + std::memcpy(LV2_ATOM_BODY(&aev->body), event->data, event->size); + + const uint32_t size = lv2_atom_pad_size(sizeof(LV2_Atom_Event) + event->size); + mData.offset += size; + seq->atom.size += size; + + return true; } void handleUiParameterChanged(const uint32_t index, const float value) const @@ -1041,7 +1020,7 @@ private: LV2_Program_Descriptor fProgramDesc; uint32_t fMidiEventCount; - NativeMidiEvent fMidiEvents[kMaxMidiEvents*2]; + NativeMidiEvent fMidiEvents[kMaxMidiEvents]; NativeTimeInfo fTimeInfo; // Lv2 host data @@ -1157,8 +1136,19 @@ private: } fUI; struct Ports { + // need to save current state + struct MidiOutData { + uint32_t capacity; + uint32_t offset; + + MidiOutData() + : capacity(0), + offset(0) {} + }; + const LV2_Atom_Sequence** eventsIn; /* */ LV2_Atom_Sequence** midiOuts; + /* */ MidiOutData* midiOutData; const float** audioIns; /* */ float** audioOuts; float* freewheel; @@ -1192,6 +1182,12 @@ private: midiOuts = nullptr; } + if (midiOutData != nullptr) + { + delete[] midiOutData; + midiOutData = nullptr; + } + if (audioIns != nullptr) { delete[] audioIns; @@ -1243,6 +1239,7 @@ private: if (desc->midiOuts > 0) { midiOuts = new LV2_Atom_Sequence*[desc->midiOuts]; + midiOutData = new MidiOutData[desc->midiOuts]; for (uint32_t i=0; i < desc->midiOuts; ++i) midiOuts[i] = nullptr;