From c2de6b2af4c5b7ae75346b21783a973a52f7f847 Mon Sep 17 00:00:00 2001 From: falkTX Date: Sat, 4 Jul 2015 21:58:32 +0200 Subject: [PATCH] Rework carla-lv2 time info code similar to DPF, should work better --- source/plugin/carla-lv2.cpp | 303 +++++++++++++++++++++++------------- 1 file changed, 191 insertions(+), 112 deletions(-) diff --git a/source/plugin/carla-lv2.cpp b/source/plugin/carla-lv2.cpp index aced99da8..3b883d567 100644 --- a/source/plugin/carla-lv2.cpp +++ b/source/plugin/carla-lv2.cpp @@ -82,7 +82,6 @@ public: #endif fMidiEventCount(0), fTimeInfo(), - fLastTimeSpeed(0.0), fIsOffline(false), fBufferSize(0), fSampleRate(sampleRate), @@ -97,11 +96,7 @@ public: hide = extui_hide; CarlaString resourceDir(bundlePath); -#ifdef CARLA_OS_WIN - resourceDir += "\\resources\\"; -#else - resourceDir += "/resources/"; -#endif + resourceDir += CARLA_OS_SEP_STR "resources" CARLA_OS_SEP_STR; fHost.handle = this; fHost.resourceDir = resourceDir.dup(); @@ -164,16 +159,6 @@ public: } fUridMap = uridMap; - - if (fDescriptor->midiIns > 0) - fUI.portOffset += desc->midiIns; - else if (fDescriptor->hints & NATIVE_PLUGIN_USES_TIME) - fUI.portOffset += 1; - - fUI.portOffset += desc->midiOuts; - fUI.portOffset += 1; // freewheel - fUI.portOffset += desc->audioIns; - fUI.portOffset += desc->audioOuts; } ~NativePlugin() @@ -189,7 +174,7 @@ public: bool init() { - if (fUI.portOffset == 0) + if (fUridMap == nullptr) { // host is missing features return false; @@ -213,6 +198,26 @@ public: carla_zeroStructs(fMidiEvents, kMaxMidiEvents*2); carla_zeroStruct(fTimeInfo); + // hosts may not send all values, resulting on some invalid data + fTimeInfo.bbt.bar = 1; + fTimeInfo.bbt.beat = 1; + fTimeInfo.bbt.tick = 0; + fTimeInfo.bbt.barStartTick = 0; + fTimeInfo.bbt.beatsPerBar = 4; + fTimeInfo.bbt.beatType = 4; + fTimeInfo.bbt.ticksPerBeat = 960.0; + fTimeInfo.bbt.beatsPerMinute = 120.0; + + if (fDescriptor->midiIns > 0) + fUI.portOffset += fDescriptor->midiIns; + else if (fDescriptor->hints & NATIVE_PLUGIN_USES_TIME) + fUI.portOffset += 1; + + fUI.portOffset += fDescriptor->midiOuts; + fUI.portOffset += 1; // freewheel + fUI.portOffset += fDescriptor->audioIns; + fUI.portOffset += fDescriptor->audioOuts; + fPorts.init(fDescriptor, fHandle); fURIs.map(fUridMap); @@ -285,13 +290,11 @@ public: if (fDescriptor->hints & NATIVE_PLUGIN_USES_TIME) { - LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[0], iter) + LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[0], event) { - const LV2_Atom_Event* const event((const LV2_Atom_Event*)iter); - if (event == nullptr) continue; - if (event->body.type != fURIs.atomBlank) + if (event->body.type != fURIs.atomBlank && event->body.type != fURIs.atomObject) continue; const LV2_Atom_Object* const obj((const LV2_Atom_Object*)&event->body); @@ -299,153 +302,186 @@ public: if (obj->body.otype != fURIs.timePos) continue; - LV2_Atom* bar = nullptr; - LV2_Atom* barBeat = nullptr; - LV2_Atom* beat = nullptr; + LV2_Atom* bar = nullptr; + LV2_Atom* barBeat = nullptr; LV2_Atom* beatUnit = nullptr; LV2_Atom* beatsPerBar = nullptr; LV2_Atom* beatsPerMinute = nullptr; - LV2_Atom* ticksPerBeat = nullptr; LV2_Atom* frame = nullptr; LV2_Atom* speed = nullptr; + LV2_Atom* ticksPerBeat = nullptr; lv2_atom_object_get(obj, fURIs.timeBar, &bar, fURIs.timeBarBeat, &barBeat, - fURIs.timeBeat, &beat, fURIs.timeBeatUnit, &beatUnit, fURIs.timeBeatsPerBar, &beatsPerBar, fURIs.timeBeatsPerMinute, &beatsPerMinute, - fURIs.timeTicksPerBeat, &ticksPerBeat, fURIs.timeFrame, &frame, fURIs.timeSpeed, &speed, + fURIs.timeTicksPerBeat, &ticksPerBeat, nullptr); + // need to handle this first as other values depend on it + if (ticksPerBeat != nullptr) + { + /**/ if (ticksPerBeat->type == fURIs.atomDouble) + fLastPositionData.ticksPerBeat = ((LV2_Atom_Double*)ticksPerBeat)->body; + else if (ticksPerBeat->type == fURIs.atomFloat) + fLastPositionData.ticksPerBeat = ((LV2_Atom_Float*)ticksPerBeat)->body; + else if (ticksPerBeat->type == fURIs.atomInt) + fLastPositionData.ticksPerBeat = ((LV2_Atom_Int*)ticksPerBeat)->body; + else if (ticksPerBeat->type == fURIs.atomLong) + fLastPositionData.ticksPerBeat = ((LV2_Atom_Long*)ticksPerBeat)->body; + else + carla_stderr("Unknown lv2 ticksPerBeat value type"); + + if (fLastPositionData.ticksPerBeat > 0) + fTimeInfo.bbt.ticksPerBeat = fLastPositionData.ticksPerBeat; + } + + // same + if (speed != nullptr) + { + /**/ if (speed->type == fURIs.atomDouble) + fLastPositionData.speed = ((LV2_Atom_Double*)speed)->body; + else if (speed->type == fURIs.atomFloat) + fLastPositionData.speed = ((LV2_Atom_Float*)speed)->body; + else if (speed->type == fURIs.atomInt) + fLastPositionData.speed = ((LV2_Atom_Int*)speed)->body; + else if (speed->type == fURIs.atomLong) + fLastPositionData.speed = ((LV2_Atom_Long*)speed)->body; + else + carla_stderr("Unknown lv2 speed value type"); + + fTimeInfo.playing = carla_isNotZero(fLastPositionData.speed); + } + if (bar != nullptr) { /**/ if (bar->type == fURIs.atomDouble) - fTimeInfo.bbt.bar = static_cast(((LV2_Atom_Double*)bar)->body + 1.0); + fLastPositionData.bar = ((LV2_Atom_Double*)bar)->body; else if (bar->type == fURIs.atomFloat) - fTimeInfo.bbt.bar = static_cast(((LV2_Atom_Float*)bar)->body + 1.0f); + fLastPositionData.bar = ((LV2_Atom_Float*)bar)->body; else if (bar->type == fURIs.atomInt) - fTimeInfo.bbt.bar = static_cast(((LV2_Atom_Int*)bar)->body + 1); + fLastPositionData.bar = ((LV2_Atom_Int*)bar)->body; else if (bar->type == fURIs.atomLong) - fTimeInfo.bbt.bar = static_cast(((LV2_Atom_Long*)bar)->body + 1); + fLastPositionData.bar = ((LV2_Atom_Long*)bar)->body; else carla_stderr("Unknown lv2 bar value type"); - } - if (ticksPerBeat != nullptr) - { - /**/ if (ticksPerBeat->type == fURIs.atomDouble) - fTimeInfo.bbt.ticksPerBeat = ((LV2_Atom_Double*)ticksPerBeat)->body; - else if (ticksPerBeat->type == fURIs.atomFloat) - fTimeInfo.bbt.ticksPerBeat = static_cast(((LV2_Atom_Float*)ticksPerBeat)->body); - else if (ticksPerBeat->type == fURIs.atomInt) - fTimeInfo.bbt.ticksPerBeat = static_cast(((LV2_Atom_Int*)ticksPerBeat)->body); - else if (ticksPerBeat->type == fURIs.atomLong) - fTimeInfo.bbt.ticksPerBeat = static_cast(((LV2_Atom_Long*)ticksPerBeat)->body); - else - carla_stderr("Unknown lv2 ticksPerBeat value type"); + if (fLastPositionData.bar >= 0) + fTimeInfo.bbt.bar = fLastPositionData.bar + 1; } if (barBeat != nullptr) { - double barBeatValue = 0.0; - /**/ if (barBeat->type == fURIs.atomDouble) - barBeatValue = ((LV2_Atom_Double*)barBeat)->body; + fLastPositionData.barBeat = ((LV2_Atom_Double*)barBeat)->body; else if (barBeat->type == fURIs.atomFloat) - barBeatValue = static_cast(((LV2_Atom_Float*)barBeat)->body); + fLastPositionData.barBeat = ((LV2_Atom_Float*)barBeat)->body; else if (barBeat->type == fURIs.atomInt) - barBeatValue = static_cast(((LV2_Atom_Int*)barBeat)->body); + fLastPositionData.barBeat = ((LV2_Atom_Int*)barBeat)->body; else if (barBeat->type == fURIs.atomLong) - barBeatValue = static_cast(((LV2_Atom_Long*)barBeat)->body); + fLastPositionData.barBeat = ((LV2_Atom_Long*)barBeat)->body; else carla_stderr("Unknown lv2 barBeat value type"); - const double rest = std::fmod(barBeatValue, 1.0); - fTimeInfo.bbt.beat = static_cast(barBeatValue-rest+1.0); - fTimeInfo.bbt.tick = static_cast(rest*fTimeInfo.bbt.ticksPerBeat+0.5); - } - // barBeat includes beat - else if (beat != nullptr) - { - /**/ if (beat->type == fURIs.atomDouble) - fTimeInfo.bbt.beat = static_cast(((LV2_Atom_Double*)beat)->body + 1.0); - else if (beat->type == fURIs.atomFloat) - fTimeInfo.bbt.beat = static_cast(((LV2_Atom_Float*)beat)->body + 1.0f); - else if (beat->type == fURIs.atomInt) - fTimeInfo.bbt.beat = static_cast(((LV2_Atom_Int*)beat)->body + 1); - else if (beat->type == fURIs.atomLong) - fTimeInfo.bbt.beat = static_cast(((LV2_Atom_Long*)beat)->body + 1); - else - carla_stderr("Unknown lv2 beat value type"); + if (fLastPositionData.barBeat >= 0.0f) + { + const double rest = std::fmod(fLastPositionData.barBeat, 1.0); + fTimeInfo.bbt.beat = fLastPositionData.barBeat-rest+1.0; + fTimeInfo.bbt.tick = rest*fTimeInfo.bbt.ticksPerBeat+0.5; + } } if (beatUnit != nullptr) { /**/ if (beatUnit->type == fURIs.atomDouble) - fTimeInfo.bbt.beatType = static_cast(((LV2_Atom_Double*)beatUnit)->body); + fLastPositionData.beatUnit = ((LV2_Atom_Double*)beatUnit)->body; else if (beatUnit->type == fURIs.atomFloat) - fTimeInfo.bbt.beatType = ((LV2_Atom_Float*)beatUnit)->body; + fLastPositionData.beatUnit = ((LV2_Atom_Float*)beatUnit)->body; else if (beatUnit->type == fURIs.atomInt) - fTimeInfo.bbt.beatType = static_cast(((LV2_Atom_Int*)beatUnit)->body); + fLastPositionData.beatUnit = ((LV2_Atom_Int*)beatUnit)->body; else if (beatUnit->type == fURIs.atomLong) - fTimeInfo.bbt.beatType = static_cast(((LV2_Atom_Long*)beatUnit)->body); + fLastPositionData.beatUnit = ((LV2_Atom_Long*)beatUnit)->body; else carla_stderr("Unknown lv2 beatUnit value type"); + + if (fLastPositionData.beatUnit > 0) + fTimeInfo.bbt.beatType = fLastPositionData.beatUnit; } if (beatsPerBar != nullptr) { /**/ if (beatsPerBar->type == fURIs.atomDouble) - fTimeInfo.bbt.beatsPerBar = static_cast(((LV2_Atom_Double*)beatsPerBar)->body); + fLastPositionData.beatsPerBar = ((LV2_Atom_Double*)beatsPerBar)->body; else if (beatsPerBar->type == fURIs.atomFloat) - fTimeInfo.bbt.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body; + fLastPositionData.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body; else if (beatsPerBar->type == fURIs.atomInt) - fTimeInfo.bbt.beatsPerBar = static_cast(((LV2_Atom_Int*)beatsPerBar)->body); + fLastPositionData.beatsPerBar = ((LV2_Atom_Int*)beatsPerBar)->body; else if (beatsPerBar->type == fURIs.atomLong) - fTimeInfo.bbt.beatsPerBar = static_cast(((LV2_Atom_Long*)beatsPerBar)->body); + fLastPositionData.beatsPerBar = ((LV2_Atom_Long*)beatsPerBar)->body; else carla_stderr("Unknown lv2 beatsPerBar value type"); + + if (fLastPositionData.beatsPerBar > 0.0f) + fTimeInfo.bbt.beatsPerBar = fLastPositionData.beatsPerBar; } if (beatsPerMinute != nullptr) { /**/ if (beatsPerMinute->type == fURIs.atomDouble) - fTimeInfo.bbt.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body; + fLastPositionData.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIs.atomFloat) - fTimeInfo.bbt.beatsPerMinute = static_cast(((LV2_Atom_Float*)beatsPerMinute)->body); + fLastPositionData.beatsPerMinute = ((LV2_Atom_Float*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIs.atomInt) - fTimeInfo.bbt.beatsPerMinute = static_cast(((LV2_Atom_Int*)beatsPerMinute)->body); + fLastPositionData.beatsPerMinute = ((LV2_Atom_Int*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIs.atomLong) - fTimeInfo.bbt.beatsPerMinute = static_cast(((LV2_Atom_Long*)beatsPerMinute)->body); + fLastPositionData.beatsPerMinute = ((LV2_Atom_Long*)beatsPerMinute)->body; else carla_stderr("Unknown lv2 beatsPerMinute value type"); - } - fTimeInfo.bbt.barStartTick = fTimeInfo.bbt.ticksPerBeat*fTimeInfo.bbt.beatsPerBar*(fTimeInfo.bbt.bar-1); + if (fLastPositionData.beatsPerMinute > 0.0f) + { + fTimeInfo.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute; - if (frame != nullptr && frame->type == fURIs.atomLong) - fTimeInfo.frame = static_cast(((LV2_Atom_Long*)frame)->body); + if (carla_isNotZero(fLastPositionData.speed)) + fTimeInfo.bbt.beatsPerMinute *= std::abs(fLastPositionData.speed); + } + } - if (speed != nullptr && speed->type == fURIs.atomFloat) + if (frame != nullptr) { - fLastTimeSpeed = ((LV2_Atom_Float*)speed)->body; - fTimeInfo.playing = carla_isEqual(fLastTimeSpeed, 1.0); + /**/ if (frame->type == fURIs.atomDouble) + fLastPositionData.frame = ((LV2_Atom_Double*)frame)->body; + else if (frame->type == fURIs.atomFloat) + fLastPositionData.frame = ((LV2_Atom_Float*)frame)->body; + else if (frame->type == fURIs.atomInt) + fLastPositionData.frame = ((LV2_Atom_Int*)frame)->body; + else if (frame->type == fURIs.atomLong) + fLastPositionData.frame = ((LV2_Atom_Long*)frame)->body; + else + carla_stderr("Unknown lv2 frame value type"); + + if (fLastPositionData.frame >= 0) + fTimeInfo.frame = fLastPositionData.frame; } - fTimeInfo.bbt.valid = (beatsPerMinute != nullptr && beatsPerBar != nullptr && beatUnit != nullptr); + fTimeInfo.bbt.barStartTick = fTimeInfo.bbt.ticksPerBeat* + fTimeInfo.bbt.beatsPerBar* + (fTimeInfo.bbt.bar-1); + + fTimeInfo.bbt.valid = (fLastPositionData.beatsPerMinute > 0.0 && + fLastPositionData.beatUnit > 0 && + fLastPositionData.beatsPerBar > 0.0f); } } for (uint32_t i=0; i < fDescriptor->midiIns; ++i) { - LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[i], iter) + LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[i], event) { - const LV2_Atom_Event* const event((const LV2_Atom_Event*)iter); - if (event == nullptr) continue; if (event->body.type != fURIs.midiEvent) @@ -476,37 +512,56 @@ public: fDescriptor->process(fHandle, const_cast(fPorts.audioIns), fPorts.audioOuts, frames, fMidiEvents, fMidiEventCount); // update timePos for next callback - if (carla_isNotEqual(fLastTimeSpeed, 0.0)) + if (carla_isNotZero(fLastPositionData.speed)) { - const double newFrames = fLastTimeSpeed*frames; + if (fLastPositionData.speed > 0.0) + { + // playing forwards + fLastPositionData.frame += frames; + } + else + { + // playing backwards + fLastPositionData.frame -= frames; + + if (fLastPositionData.frame < 0) + fLastPositionData.frame = 0; + } - fTimeInfo.frame += static_cast(newFrames); + fTimeInfo.frame = fLastPositionData.frame; if (fTimeInfo.bbt.valid) { - const double samplesPerBeat = 60.0 / fTimeInfo.bbt.beatsPerMinute * fSampleRate; - const double ticksPerSample = fTimeInfo.bbt.ticksPerBeat / samplesPerBeat; - - double newTickPos = double(fTimeInfo.bbt.tick) + ticksPerSample*newFrames; - double newBeatPos = double(fTimeInfo.bbt.beat)-1.0; - double newBarPos = double(fTimeInfo.bbt.bar)-1.0; + const double beatsPerMinute = fLastPositionData.beatsPerMinute * fLastPositionData.speed; + const double framesPerBeat = 60.0 * fSampleRate / beatsPerMinute; + const double addedBarBeats = double(frames) / framesPerBeat; - for (; newTickPos >= fTimeInfo.bbt.ticksPerBeat;) + if (fLastPositionData.barBeat >= 0.0f) { - ++newBeatPos; - newTickPos -= fTimeInfo.bbt.ticksPerBeat; - } + fLastPositionData.barBeat = std::fmod(fLastPositionData.barBeat+addedBarBeats, + fLastPositionData.beatsPerBar); - for (; newBeatPos >= fTimeInfo.bbt.beatsPerBar;) - { - ++newBarPos; - newBeatPos -= fTimeInfo.bbt.beatsPerBar; + const double rest = std::fmod(fLastPositionData.barBeat, 1.0); + fTimeInfo.bbt.beat = fLastPositionData.barBeat-rest+1.0; + fTimeInfo.bbt.tick = rest*fTimeInfo.bbt.ticksPerBeat+0.5; + + if (fLastPositionData.bar >= 0) + { + fLastPositionData.bar += std::floor((fLastPositionData.barBeat+addedBarBeats)/ + fLastPositionData.beatsPerBar); + + if (fLastPositionData.bar < 0) + fLastPositionData.bar = 0; + + fTimeInfo.bbt.bar = fLastPositionData.bar + 1; + + fTimeInfo.bbt.barStartTick = fTimeInfo.bbt.ticksPerBeat* + fTimeInfo.bbt.beatsPerBar* + (fTimeInfo.bbt.bar-1); + } } - fTimeInfo.bbt.bar = static_cast(newBarPos+1.0); - fTimeInfo.bbt.beat = static_cast(newBeatPos+1.0); - fTimeInfo.bbt.tick = static_cast(newTickPos); - fTimeInfo.bbt.barStartTick = fTimeInfo.bbt.ticksPerBeat*fTimeInfo.bbt.beatsPerBar*(fTimeInfo.bbt.bar-1); + fTimeInfo.bbt.beatsPerMinute = std::abs(beatsPerMinute); } } @@ -988,7 +1043,6 @@ private: uint32_t fMidiEventCount; NativeMidiEvent fMidiEvents[kMaxMidiEvents*2]; NativeTimeInfo fTimeInfo; - double fLastTimeSpeed; // Lv2 host data bool fIsOffline; @@ -997,8 +1051,31 @@ private: const LV2_URID_Map* fUridMap; + struct Lv2PositionData { + int64_t bar; + float barBeat; + uint32_t beatUnit; + float beatsPerBar; + float beatsPerMinute; + int64_t frame; + double speed; + int64_t ticksPerBeat; + + Lv2PositionData() + : bar(-1), + barBeat(-1.0f), + beatUnit(0), + beatsPerBar(0.0f), + beatsPerMinute(0.0f), + frame(-1), + speed(0.0), + ticksPerBeat(-1) {} + + } fLastPositionData; + struct URIDs { LV2_URID atomBlank; + LV2_URID atomObject; LV2_URID atomDouble; LV2_URID atomFloat; LV2_URID atomInt; @@ -1019,6 +1096,7 @@ private: URIDs() : atomBlank(0), + atomObject(0), atomDouble(0), atomFloat(0), atomInt(0), @@ -1040,6 +1118,7 @@ private: void map(const LV2_URID_Map* const uridMap) { atomBlank = uridMap->map(uridMap->handle, LV2_ATOM__Blank); + atomObject = uridMap->map(uridMap->handle, LV2_ATOM__Object); atomDouble = uridMap->map(uridMap->handle, LV2_ATOM__Double); atomFloat = uridMap->map(uridMap->handle, LV2_ATOM__Float); atomInt = uridMap->map(uridMap->handle, LV2_ATOM__Int);