DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

commit 4e067e7ae3ed4367eebad1c6ac0997ab6c0f8d9a
parent a02cdf7ace1bb95d6b6e5ad34a5363f3c5ffd931
Author: falkTX <falktx@gmail.com>
Date:   Sat, 13 Jun 2015 02:58:28 +0200

Rework LV2 time position, seems to work nicely now

Diffstat:
Mdistrho/src/DistrhoPluginLV2.cpp | 258++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
1 file changed, 163 insertions(+), 95 deletions(-)

diff --git a/distrho/src/DistrhoPluginLV2.cpp b/distrho/src/DistrhoPluginLV2.cpp @@ -40,10 +40,6 @@ # error DISTRHO_PLUGIN_URI undefined! #endif -#if DISTRHO_PLUGIN_WANT_TIMEPOS -# warning LV2 TimePos still TODO -#endif - #define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) #define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) @@ -61,9 +57,6 @@ public: fLastControlValues(nullptr), fSampleRate(sampleRate), #if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT -# if DISTRHO_PLUGIN_WANT_TIMEPOS - fLastTimeSpeed(0.0), -# endif fURIDs(uridMap), #endif fUridMap(uridMap), @@ -133,8 +126,7 @@ public: #endif #if DISTRHO_PLUGIN_WANT_TIMEPOS - // hosts may not send all values, resulting on some invalid ones - fTimePosition.bbt.valid = false; + // hosts may not send all values, resulting on some invalid data fTimePosition.bbt.bar = 1; fTimePosition.bbt.beat = 1; fTimePosition.bbt.tick = 0; @@ -311,142 +303,178 @@ public: LV2_Atom* bar = nullptr; LV2_Atom* barBeat = nullptr; - LV2_Atom* beat = 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, fURIDs.timeBar, &bar, fURIDs.timeBarBeat, &barBeat, - fURIDs.timeBeat, &beat, fURIDs.timeBeatUnit, &beatUnit, fURIDs.timeBeatsPerBar, &beatsPerBar, fURIDs.timeBeatsPerMinute, &beatsPerMinute, - fURIDs.timeTicksPerBeat, &ticksPerBeat, 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) - fTimePosition.bbt.bar = ((LV2_Atom_Double*)bar)->body + 1.0; + fLastPositionData.bar = ((LV2_Atom_Double*)bar)->body; else if (bar->type == fURIDs.atomFloat) - fTimePosition.bbt.bar = ((LV2_Atom_Float*)bar)->body + 1.0f; + fLastPositionData.bar = ((LV2_Atom_Float*)bar)->body; else if (bar->type == fURIDs.atomInt) - fTimePosition.bbt.bar = ((LV2_Atom_Int*)bar)->body + 1; + fLastPositionData.bar = ((LV2_Atom_Int*)bar)->body; else if (bar->type == fURIDs.atomLong) - fTimePosition.bbt.bar = ((LV2_Atom_Long*)bar)->body + 1; + fLastPositionData.bar = ((LV2_Atom_Long*)bar)->body; else d_stderr("Unknown lv2 bar value type"); - } - if (ticksPerBeat != nullptr) - { - /**/ if (ticksPerBeat->type == fURIDs.atomDouble) - fTimePosition.bbt.ticksPerBeat = ((LV2_Atom_Double*)ticksPerBeat)->body; - else if (ticksPerBeat->type == fURIDs.atomFloat) - fTimePosition.bbt.ticksPerBeat = ((LV2_Atom_Float*)ticksPerBeat)->body; - else if (ticksPerBeat->type == fURIDs.atomInt) - fTimePosition.bbt.ticksPerBeat = ((LV2_Atom_Int*)ticksPerBeat)->body; - else if (ticksPerBeat->type == fURIDs.atomLong) - fTimePosition.bbt.ticksPerBeat = ((LV2_Atom_Long*)ticksPerBeat)->body; - else - d_stderr("Unknown lv2 ticksPerBeat value type"); + if (fLastPositionData.bar >= 0) + fTimePosition.bbt.bar = fLastPositionData.bar + 1; } if (barBeat != nullptr) { - double barBeatValue = 0.0; - /**/ if (barBeat->type == fURIDs.atomDouble) - barBeatValue = ((LV2_Atom_Double*)barBeat)->body; + fLastPositionData.barBeat = ((LV2_Atom_Double*)barBeat)->body; else if (barBeat->type == fURIDs.atomFloat) - barBeatValue = ((LV2_Atom_Float*)barBeat)->body; + fLastPositionData.barBeat = ((LV2_Atom_Float*)barBeat)->body; else if (barBeat->type == fURIDs.atomInt) - barBeatValue = ((LV2_Atom_Int*)barBeat)->body; + fLastPositionData.barBeat = ((LV2_Atom_Int*)barBeat)->body; else if (barBeat->type == fURIDs.atomLong) - barBeatValue = ((LV2_Atom_Long*)barBeat)->body; + fLastPositionData.barBeat = ((LV2_Atom_Long*)barBeat)->body; else d_stderr("Unknown lv2 barBeat value type"); - const double rest = std::fmod(barBeatValue, 1.0); - fTimePosition.bbt.beat = barBeatValue-rest+1.0; - fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; - } - // barBeat includes beat - else if (beat != nullptr) - { - /**/ if (beat->type == fURIDs.atomDouble) - fTimePosition.bbt.beat = ((LV2_Atom_Double*)beat)->body + 1.0; - else if (beat->type == fURIDs.atomFloat) - fTimePosition.bbt.beat = ((LV2_Atom_Float*)beat)->body + 1.0f; - else if (beat->type == fURIDs.atomInt) - fTimePosition.bbt.beat = ((LV2_Atom_Int*)beat)->body + 1; - else if (beat->type == fURIDs.atomLong) - fTimePosition.bbt.beat = ((LV2_Atom_Long*)beat)->body + 1; - else - d_stderr("Unknown lv2 beat 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) - fTimePosition.bbt.beatType = ((LV2_Atom_Double*)beatUnit)->body; + fLastPositionData.beatUnit = ((LV2_Atom_Double*)beatUnit)->body; else if (beatUnit->type == fURIDs.atomFloat) - fTimePosition.bbt.beatType = ((LV2_Atom_Float*)beatUnit)->body; + fLastPositionData.beatUnit = ((LV2_Atom_Float*)beatUnit)->body; else if (beatUnit->type == fURIDs.atomInt) - fTimePosition.bbt.beatType = ((LV2_Atom_Int*)beatUnit)->body; + fLastPositionData.beatUnit = ((LV2_Atom_Int*)beatUnit)->body; else if (beatUnit->type == fURIDs.atomLong) - fTimePosition.bbt.beatType = ((LV2_Atom_Long*)beatUnit)->body; + 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) - fTimePosition.bbt.beatsPerBar = ((LV2_Atom_Double*)beatsPerBar)->body; + fLastPositionData.beatsPerBar = ((LV2_Atom_Double*)beatsPerBar)->body; else if (beatsPerBar->type == fURIDs.atomFloat) - fTimePosition.bbt.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body; + fLastPositionData.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body; else if (beatsPerBar->type == fURIDs.atomInt) - fTimePosition.bbt.beatsPerBar = ((LV2_Atom_Int*)beatsPerBar)->body; + fLastPositionData.beatsPerBar = ((LV2_Atom_Int*)beatsPerBar)->body; else if (beatsPerBar->type == fURIDs.atomLong) - fTimePosition.bbt.beatsPerBar = ((LV2_Atom_Long*)beatsPerBar)->body; + 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) - fTimePosition.bbt.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body; + fLastPositionData.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIDs.atomFloat) - fTimePosition.bbt.beatsPerMinute = ((LV2_Atom_Float*)beatsPerMinute)->body; + fLastPositionData.beatsPerMinute = ((LV2_Atom_Float*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIDs.atomInt) - fTimePosition.bbt.beatsPerMinute = ((LV2_Atom_Int*)beatsPerMinute)->body; + fLastPositionData.beatsPerMinute = ((LV2_Atom_Int*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIDs.atomLong) - fTimePosition.bbt.beatsPerMinute = ((LV2_Atom_Long*)beatsPerMinute)->body; + fLastPositionData.beatsPerMinute = ((LV2_Atom_Long*)beatsPerMinute)->body; else d_stderr("Unknown lv2 beatsPerMinute value type"); - } - fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*fTimePosition.bbt.beatsPerBar*(fTimePosition.bbt.bar-1); + if (fLastPositionData.beatsPerMinute > 0.0f) + { + fTimePosition.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute; - if (frame != nullptr && frame->type == fURIDs.atomLong) - fTimePosition.frame = ((LV2_Atom_Long*)frame)->body; + if (d_isNotZero(fLastPositionData.speed)) + fTimePosition.bbt.beatsPerMinute *= std::abs(fLastPositionData.speed); + } + } - if (speed != nullptr && speed->type == fURIDs.atomFloat) + if (frame != nullptr) { - fLastTimeSpeed = ((LV2_Atom_Float*)speed)->body; - fTimePosition.playing = (fLastTimeSpeed == 1.0); + /**/ 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.valid = (beatsPerMinute != nullptr && beatsPerBar != nullptr && beatUnit != nullptr); + 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); + continue; } # endif @@ -485,37 +513,56 @@ public: # if DISTRHO_PLUGIN_WANT_TIMEPOS // update timePos for next callback - if (fLastTimeSpeed != 0.0) + if (d_isNotZero(fLastPositionData.speed)) { - const double newFrames = fLastTimeSpeed*sampleCount; + 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 += newFrames; + fTimePosition.frame = fLastPositionData.frame; if (fTimePosition.bbt.valid) { - const double samplesPerBeat = 60.0 / fTimePosition.bbt.beatsPerMinute * fSampleRate; - const double ticksPerSample = fTimePosition.bbt.ticksPerBeat / samplesPerBeat; + const double beatsPerMinute = fLastPositionData.beatsPerMinute * fLastPositionData.speed; + const double framesPerBeat = 60.0 * fSampleRate / beatsPerMinute; + const double addedBarBeats = double(sampleCount) / framesPerBeat; - double newTickPos = double(fTimePosition.bbt.tick) + ticksPerSample*newFrames; - double newBeatPos = double(fTimePosition.bbt.beat)-1.0; - double newBarPos = double(fTimePosition.bbt.bar)-1.0; - - for (; newTickPos >= fTimePosition.bbt.ticksPerBeat;) + if (fLastPositionData.bar >= 0) { - ++newBeatPos; - newTickPos -= fTimePosition.bbt.ticksPerBeat; + 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); } - for (; newBeatPos >= fTimePosition.bbt.beatsPerBar;) + if (fLastPositionData.barBeat >= 0.0f) { - ++newBarPos; - newBeatPos -= fTimePosition.bbt.beatsPerBar; + fLastPositionData.barBeat = std::fmod(fLastPositionData.barBeat+addedBarBeats, + fTimePosition.bbt.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; } - fTimePosition.bbt.bar = newBarPos+1.0; - fTimePosition.bbt.beat = newBeatPos+1.0; - fTimePosition.bbt.tick = newTickPos; - fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*fTimePosition.bbt.beatsPerBar*(fTimePosition.bbt.bar-1); + fTimePosition.bbt.beatsPerMinute = std::abs(beatsPerMinute); } } # endif @@ -788,7 +835,30 @@ private: #endif #if DISTRHO_PLUGIN_WANT_TIMEPOS TimePosition fTimePosition; - double fLastTimeSpeed; + + struct Lv2PositionData { + int64_t bar; + float barBeat; + double beat; + uint32_t beatUnit; + float beatsPerBar; + float beatsPerMinute; + int64_t frame; + double speed; + int64_t ticksPerBeat; + + Lv2PositionData() + : bar(-1), + barBeat(-1.0f), + beat(-1.0), + beatUnit(0), + beatsPerBar(0.0f), + beatsPerMinute(0.0f), + frame(-1), + speed(0.0), + ticksPerBeat(-1) {} + + } fLastPositionData; #endif // LV2 URIDs @@ -807,7 +877,6 @@ private: LV2_URID timePosition; LV2_URID timeBar; LV2_URID timeBarBeat; - LV2_URID timeBeat; LV2_URID timeBeatUnit; LV2_URID timeBeatsPerBar; LV2_URID timeBeatsPerMinute; @@ -829,7 +898,6 @@ private: timePosition(uridMap->map(uridMap->handle, LV2_TIME__Position)), timeBar(uridMap->map(uridMap->handle, LV2_TIME__bar)), timeBarBeat(uridMap->map(uridMap->handle, LV2_TIME__barBeat)), - timeBeat(uridMap->map(uridMap->handle, LV2_TIME__beat)), timeBeatUnit(uridMap->map(uridMap->handle, LV2_TIME__beatUnit)), timeBeatsPerBar(uridMap->map(uridMap->handle, LV2_TIME__beatsPerBar)), timeBeatsPerMinute(uridMap->map(uridMap->handle, LV2_TIME__beatsPerMinute)),