static inline LV2_Atom_Event* lv2_atom_sequence_append_event(LV2_Atom_Sequence* seq, uint32_t capacity, const LV2_Atom_Event* event) { const uint32_t total_size = (uint32_t)sizeof(*event) + event->body.size; if (capacity - seq->atom.size < total_size) { return NULL; } LV2_Atom_Event* e = lv2_atom_sequence_end(&seq->body, seq->atom.size); memcpy(e, event, total_size); seq->atom.size += lv2_atom_pad_size(total_size); return e; }
void lv2_run(const uint32_t sampleCount) { // cache midi input and time position first #if DISTRHO_PLUGIN_WANT_MIDI_INPUT uint32_t midiEventCount = 0; #endif #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS LV2_ATOM_SEQUENCE_FOREACH(fPortEventsIn, event) { if (event == nullptr) break; # if DISTRHO_PLUGIN_WANT_MIDI_INPUT if (event->body.type == fURIDs.midiEvent) { if (midiEventCount >= kMaxMidiEvents) continue; const uint8_t* const data((const uint8_t*)(event + 1)); MidiEvent& midiEvent(fMidiEvents[midiEventCount++]); midiEvent.frame = event->time.frames; midiEvent.size = event->body.size; if (midiEvent.size > MidiEvent::kDataSize) { midiEvent.dataExt = data; std::memset(midiEvent.data, 0, MidiEvent::kDataSize); } else { midiEvent.dataExt = nullptr; std::memcpy(midiEvent.data, data, midiEvent.size); } continue; } # endif # if DISTRHO_PLUGIN_WANT_TIMEPOS if (event->body.type == fURIDs.atomBlank || event->body.type == fURIDs.atomObject) { const LV2_Atom_Object* const obj((const LV2_Atom_Object*)&event->body); if (obj->body.otype != fURIDs.timePosition) continue; LV2_Atom* bar = nullptr; LV2_Atom* barBeat = nullptr; LV2_Atom* beatUnit = nullptr; LV2_Atom* beatsPerBar = nullptr; LV2_Atom* beatsPerMinute = nullptr; LV2_Atom* frame = nullptr; LV2_Atom* speed = nullptr; LV2_Atom* ticksPerBeat = nullptr; lv2_atom_object_get(obj, fURIDs.timeBar, &bar, fURIDs.timeBarBeat, &barBeat, fURIDs.timeBeatUnit, &beatUnit, fURIDs.timeBeatsPerBar, &beatsPerBar, fURIDs.timeBeatsPerMinute, &beatsPerMinute, fURIDs.timeFrame, &frame, fURIDs.timeSpeed, &speed, fURIDs.timeTicksPerBeat, &ticksPerBeat, nullptr); // need to handle this first as other values depend on it if (ticksPerBeat != nullptr) { /**/ if (ticksPerBeat->type == fURIDs.atomDouble) fLastPositionData.ticksPerBeat = ((LV2_Atom_Double*)ticksPerBeat)->body; else if (ticksPerBeat->type == fURIDs.atomFloat) fLastPositionData.ticksPerBeat = ((LV2_Atom_Float*)ticksPerBeat)->body; else if (ticksPerBeat->type == fURIDs.atomInt) fLastPositionData.ticksPerBeat = ((LV2_Atom_Int*)ticksPerBeat)->body; else if (ticksPerBeat->type == fURIDs.atomLong) fLastPositionData.ticksPerBeat = ((LV2_Atom_Long*)ticksPerBeat)->body; else d_stderr("Unknown lv2 ticksPerBeat value type"); if (fLastPositionData.ticksPerBeat > 0) fTimePosition.bbt.ticksPerBeat = fLastPositionData.ticksPerBeat; } // same if (speed != nullptr) { /**/ if (speed->type == fURIDs.atomDouble) fLastPositionData.speed = ((LV2_Atom_Double*)speed)->body; else if (speed->type == fURIDs.atomFloat) fLastPositionData.speed = ((LV2_Atom_Float*)speed)->body; else if (speed->type == fURIDs.atomInt) fLastPositionData.speed = ((LV2_Atom_Int*)speed)->body; else if (speed->type == fURIDs.atomLong) fLastPositionData.speed = ((LV2_Atom_Long*)speed)->body; else d_stderr("Unknown lv2 speed value type"); fTimePosition.playing = d_isNotZero(fLastPositionData.speed); } if (bar != nullptr) { /**/ if (bar->type == fURIDs.atomDouble) fLastPositionData.bar = ((LV2_Atom_Double*)bar)->body; else if (bar->type == fURIDs.atomFloat) fLastPositionData.bar = ((LV2_Atom_Float*)bar)->body; else if (bar->type == fURIDs.atomInt) fLastPositionData.bar = ((LV2_Atom_Int*)bar)->body; else if (bar->type == fURIDs.atomLong) fLastPositionData.bar = ((LV2_Atom_Long*)bar)->body; else d_stderr("Unknown lv2 bar value type"); if (fLastPositionData.bar >= 0) fTimePosition.bbt.bar = fLastPositionData.bar + 1; } if (barBeat != nullptr) { /**/ if (barBeat->type == fURIDs.atomDouble) fLastPositionData.barBeat = ((LV2_Atom_Double*)barBeat)->body; else if (barBeat->type == fURIDs.atomFloat) fLastPositionData.barBeat = ((LV2_Atom_Float*)barBeat)->body; else if (barBeat->type == fURIDs.atomInt) fLastPositionData.barBeat = ((LV2_Atom_Int*)barBeat)->body; else if (barBeat->type == fURIDs.atomLong) fLastPositionData.barBeat = ((LV2_Atom_Long*)barBeat)->body; else d_stderr("Unknown lv2 barBeat value type"); if (fLastPositionData.barBeat >= 0.0f) { const double rest = std::fmod(fLastPositionData.barBeat, 1.0); fTimePosition.bbt.beat = fLastPositionData.barBeat-rest+1.0; fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; } } if (beatUnit != nullptr) { /**/ if (beatUnit->type == fURIDs.atomDouble) fLastPositionData.beatUnit = ((LV2_Atom_Double*)beatUnit)->body; else if (beatUnit->type == fURIDs.atomFloat) fLastPositionData.beatUnit = ((LV2_Atom_Float*)beatUnit)->body; else if (beatUnit->type == fURIDs.atomInt) fLastPositionData.beatUnit = ((LV2_Atom_Int*)beatUnit)->body; else if (beatUnit->type == fURIDs.atomLong) fLastPositionData.beatUnit = ((LV2_Atom_Long*)beatUnit)->body; else d_stderr("Unknown lv2 beatUnit value type"); if (fLastPositionData.beatUnit > 0) fTimePosition.bbt.beatType = fLastPositionData.beatUnit; } if (beatsPerBar != nullptr) { /**/ if (beatsPerBar->type == fURIDs.atomDouble) fLastPositionData.beatsPerBar = ((LV2_Atom_Double*)beatsPerBar)->body; else if (beatsPerBar->type == fURIDs.atomFloat) fLastPositionData.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body; else if (beatsPerBar->type == fURIDs.atomInt) fLastPositionData.beatsPerBar = ((LV2_Atom_Int*)beatsPerBar)->body; else if (beatsPerBar->type == fURIDs.atomLong) fLastPositionData.beatsPerBar = ((LV2_Atom_Long*)beatsPerBar)->body; else d_stderr("Unknown lv2 beatsPerBar value type"); if (fLastPositionData.beatsPerBar > 0.0f) fTimePosition.bbt.beatsPerBar = fLastPositionData.beatsPerBar; } if (beatsPerMinute != nullptr) { /**/ if (beatsPerMinute->type == fURIDs.atomDouble) fLastPositionData.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIDs.atomFloat) fLastPositionData.beatsPerMinute = ((LV2_Atom_Float*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIDs.atomInt) fLastPositionData.beatsPerMinute = ((LV2_Atom_Int*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIDs.atomLong) fLastPositionData.beatsPerMinute = ((LV2_Atom_Long*)beatsPerMinute)->body; else d_stderr("Unknown lv2 beatsPerMinute value type"); if (fLastPositionData.beatsPerMinute > 0.0f) { fTimePosition.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute; if (d_isNotZero(fLastPositionData.speed)) fTimePosition.bbt.beatsPerMinute *= std::abs(fLastPositionData.speed); } } if (frame != nullptr) { /**/ if (frame->type == fURIDs.atomDouble) fLastPositionData.frame = ((LV2_Atom_Double*)frame)->body; else if (frame->type == fURIDs.atomFloat) fLastPositionData.frame = ((LV2_Atom_Float*)frame)->body; else if (frame->type == fURIDs.atomInt) fLastPositionData.frame = ((LV2_Atom_Int*)frame)->body; else if (frame->type == fURIDs.atomLong) fLastPositionData.frame = ((LV2_Atom_Long*)frame)->body; else d_stderr("Unknown lv2 frame value type"); if (fLastPositionData.frame >= 0) fTimePosition.frame = fLastPositionData.frame; } fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat* fTimePosition.bbt.beatsPerBar* (fTimePosition.bbt.bar-1); fTimePosition.bbt.valid = (fLastPositionData.beatsPerMinute > 0.0 && fLastPositionData.beatUnit > 0 && fLastPositionData.beatsPerBar > 0.0f); fPlugin.setTimePosition(fTimePosition); continue; } # endif } #endif // check for messages from UI #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI LV2_ATOM_SEQUENCE_FOREACH(fPortEventsIn, event) { if (event == nullptr) break; if (event->body.type == fURIDs.distrhoState && fWorker != nullptr) { const void* const data((const void*)(event + 1)); // check if this is our special message if (std::strcmp((const char*)data, "__dpf_ui_data__") == 0) { for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) fNeededUiSends[i] = true; } else // no, send to DSP as usual { fWorker->schedule_work(fWorker->handle, event->body.size, data); } } } #endif // Check for updated parameters float curValue; for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) { if (fPortControls[i] == nullptr) continue; curValue = *fPortControls[i]; if (fLastControlValues[i] != curValue && ! fPlugin.isParameterOutput(i)) { fLastControlValues[i] = curValue; fPlugin.setParameterValue(i, curValue); } } // Run plugin if (sampleCount != 0) { #if DISTRHO_PLUGIN_WANT_MIDI_INPUT fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount, fMidiEvents, midiEventCount); #else fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount); #endif #if DISTRHO_PLUGIN_WANT_TIMEPOS // update timePos for next callback if (d_isNotZero(fLastPositionData.speed)) { if (fLastPositionData.speed > 0.0) { // playing forwards fLastPositionData.frame += sampleCount; } else { // playing backwards fLastPositionData.frame -= sampleCount; if (fLastPositionData.frame < 0) fLastPositionData.frame = 0; } fTimePosition.frame = fLastPositionData.frame; if (fTimePosition.bbt.valid) { const double beatsPerMinute = fLastPositionData.beatsPerMinute * fLastPositionData.speed; const double framesPerBeat = 60.0 * fSampleRate / beatsPerMinute; const double addedBarBeats = double(sampleCount) / framesPerBeat; if (fLastPositionData.barBeat >= 0.0f) { fLastPositionData.barBeat = std::fmod(fLastPositionData.barBeat+addedBarBeats, fLastPositionData.beatsPerBar); const double rest = std::fmod(fLastPositionData.barBeat, 1.0); fTimePosition.bbt.beat = fLastPositionData.barBeat-rest+1.0; fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; if (fLastPositionData.bar >= 0) { fLastPositionData.bar += std::floor((fLastPositionData.barBeat+addedBarBeats)/ fLastPositionData.beatsPerBar); if (fLastPositionData.bar < 0) fLastPositionData.bar = 0; fTimePosition.bbt.bar = fLastPositionData.bar + 1; fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat* fTimePosition.bbt.beatsPerBar* (fTimePosition.bbt.bar-1); } } fTimePosition.bbt.beatsPerMinute = std::abs(beatsPerMinute); } } #endif } updateParameterOutputs(); #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI const uint32_t capacity = fPortEventsOut->atom.size; bool needsInit = true; uint32_t size, offset = 0; LV2_Atom_Event* aev; // TODO - MIDI Output for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) { if (! fNeededUiSends[i]) continue; const String& key = fPlugin.getStateKey(i); for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) { const String& curKey = cit->first; if (curKey != key) continue; const String& value = cit->second; // set msg size (key + value + separator + 2x null terminator) const size_t msgSize(key.length()+value.length()+3); if (sizeof(LV2_Atom_Event) + msgSize > capacity - offset) break; if (needsInit) { fPortEventsOut->atom.size = 0; fPortEventsOut->atom.type = fURIDs.atomSequence; fPortEventsOut->body.unit = 0; fPortEventsOut->body.pad = 0; needsInit = false; } // reserve msg space char msgBuf[msgSize]; std::memset(msgBuf, 0, msgSize); // write key and value in atom bufer std::memcpy(msgBuf, key.buffer(), key.length()); std::memcpy(msgBuf+(key.length()+1), value.buffer(), value.length()); // put data aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fPortEventsOut) + offset); aev->time.frames = 0; aev->body.type = fURIDs.distrhoState; aev->body.size = msgSize; std::memcpy(LV2_ATOM_BODY(&aev->body), msgBuf, msgSize-1); size = lv2_atom_pad_size(sizeof(LV2_Atom_Event) + msgSize); offset += size; fPortEventsOut->atom.size += size; fNeededUiSends[i] = false; break; } } #endif }