From 3f0401ac03b0652fc101263180ae9279cee07fd9 Mon Sep 17 00:00:00 2001 From: Dmitry Vedenko Date: Fri, 26 Apr 2024 17:46:37 +0300 Subject: [PATCH] Fixes the stretched tracks painting --- .../GraphicsDataCache.cpp | 29 +++++++++++++------ .../lib-wave-track-paint/GraphicsDataCache.h | 12 ++++---- .../waveform/WaveBitmapCache.cpp | 27 ++++++++++++----- .../waveform/WaveBitmapCache.h | 10 +++++-- .../waveform/WaveDataCache.cpp | 15 ++++++++-- .../waveform/WaveDataCache.h | 4 +++ .../wavetrack/ui/WaveformView.cpp | 8 +++-- 7 files changed, 74 insertions(+), 31 deletions(-) diff --git a/libraries/lib-wave-track-paint/GraphicsDataCache.cpp b/libraries/lib-wave-track-paint/GraphicsDataCache.cpp index 0a604b954eb4..e1ba5e0b8161 100644 --- a/libraries/lib-wave-track-paint/GraphicsDataCache.cpp +++ b/libraries/lib-wave-track-paint/GraphicsDataCache.cpp @@ -79,9 +79,9 @@ void GraphicsDataCacheBase::Invalidate() mLookup.clear(); } -double GraphicsDataCacheBase::GetSampleRate() const noexcept +double GraphicsDataCacheBase::GetScaledSampleRate() const noexcept { - return mSampleRate; + return mScaledSampleRate; } void GraphicsDataCacheBase::UpdateViewportWidth(int64_t width) noexcept @@ -95,10 +95,21 @@ int64_t GraphicsDataCacheBase::GetMaxViewportWidth() const noexcept } GraphicsDataCacheBase::GraphicsDataCacheBase(double sampleRate) - : mSampleRate(sampleRate) + : mScaledSampleRate { sampleRate } { } +void GraphicsDataCacheBase::SetScaledSampleRate(double scaledSampleRate) +{ + if ( + std::abs(mScaledSampleRate - scaledSampleRate) <= + std::numeric_limits::epsilon()) + return; + + mScaledSampleRate = scaledSampleRate; + Invalidate(); +} + void GraphicsDataCacheElementBase::Dispose() { } @@ -112,7 +123,7 @@ GraphicsDataCacheBase::BaseLookupResult GraphicsDataCacheBase::PerformBaseLookup( const ZoomInfo& zoomInfo, double t0, double t1) { - if (bool(t0 > t1) || IsSameSample(mSampleRate, t0, t1)) + if (bool(t0 > t1) || IsSameSample(mScaledSampleRate, t0, t1)) return {}; const double pixelsPerSecond = zoomInfo.GetZoom(); @@ -129,7 +140,7 @@ GraphicsDataCacheBase::PerformBaseLookup( const int64_t cacheLeftColumn = cacheLeft * CacheElementWidth; const int64_t cacheRightColumn = cacheRight * CacheElementWidth; - const double samplesPerPixel = mSampleRate / pixelsPerSecond; + const double samplesPerPixel = mScaledSampleRate / pixelsPerSecond; UpdateViewportWidth(width); @@ -137,7 +148,7 @@ GraphicsDataCacheBase::PerformBaseLookup( mNewLookupItems.reserve(cacheItemsCount); const auto ppsMatchRange = - GetPPSMatchRange(mLookup, pixelsPerSecond, mSampleRate); + GetPPSMatchRange(mLookup, pixelsPerSecond, mScaledSampleRate); for (int64_t itemIndex = 0; itemIndex < cacheItemsCount; ++itemIndex) { @@ -170,7 +181,7 @@ GraphicsDataCacheBase::PerformBaseLookup( std::merge( mLookup.begin(), mLookup.end(), mNewLookupItems.begin(), mNewLookupItems.end(), std::back_inserter(mLookupHelper), - [sampleRate = mSampleRate](auto lhs, auto rhs) + [sampleRate = mScaledSampleRate](auto lhs, auto rhs) { return IsKeyLess(sampleRate, lhs.Key, rhs.Key); }); std::swap(mLookup, mLookupHelper); @@ -265,7 +276,7 @@ GraphicsDataCacheBase::PerformBaseLookup(GraphicsDataCacheKey key) auto insertedPosition = mLookup.insert( std::upper_bound( mLookup.begin(), mLookup.end(), key, - [sampleRate = mSampleRate](auto lhs, auto rhs) + [sampleRate = mScaledSampleRate](auto lhs, auto rhs) { if constexpr (std::is_same_v< std::decay_t, GraphicsDataCacheKey>) @@ -315,7 +326,7 @@ GraphicsDataCacheBase::FindKey(GraphicsDataCacheKey key) { return std::find_if( mLookup.begin(), mLookup.end(), - [sampleRate = mSampleRate, key](auto lhs) + [sampleRate = mScaledSampleRate, key](auto lhs) { return IsSameKey(sampleRate, lhs.Key, key); }); } diff --git a/libraries/lib-wave-track-paint/GraphicsDataCache.h b/libraries/lib-wave-track-paint/GraphicsDataCache.h index 11db670959bd..74d3b5c0941b 100644 --- a/libraries/lib-wave-track-paint/GraphicsDataCache.h +++ b/libraries/lib-wave-track-paint/GraphicsDataCache.h @@ -63,13 +63,15 @@ class WAVE_TRACK_PAINT_API GraphicsDataCacheBase /* not final */ void Invalidate(); //! Returns the sample rate associated with cache - double GetSampleRate() const noexcept; + double GetScaledSampleRate() const noexcept; void UpdateViewportWidth(int64_t width) noexcept; int64_t GetMaxViewportWidth() const noexcept; protected: - explicit GraphicsDataCacheBase(double sampleRate); + explicit GraphicsDataCacheBase(double scaledSampleRate); + + void SetScaledSampleRate(double scaledSampleRate); //! Element of the cache lookup struct WAVE_TRACK_PAINT_API LookupElement final @@ -128,7 +130,7 @@ class WAVE_TRACK_PAINT_API GraphicsDataCacheBase /* not final */ std::vector mLRUHelper; // Sample rate associated with this cache - double mSampleRate {}; // DV: Why do we use double for sample rate? I don't know + double mScaledSampleRate {}; // DV: Why do we use double for sample rate? I don't know // The max width of the request processed in pixels int64_t mMaxWidth { 1600 }; @@ -236,8 +238,8 @@ class GraphicsDataCache /* not final */ : public GraphicsDataCacheBase using Initializer = std::function; - explicit GraphicsDataCache(double sampleRate, ElementFactory elementFactory) - : GraphicsDataCacheBase(sampleRate), mElementFactory(std::move(elementFactory)) + explicit GraphicsDataCache(double scaledSampleRate, ElementFactory elementFactory) + : GraphicsDataCacheBase(scaledSampleRate), mElementFactory(std::move(elementFactory)) { } diff --git a/libraries/lib-wave-track-paint/waveform/WaveBitmapCache.cpp b/libraries/lib-wave-track-paint/waveform/WaveBitmapCache.cpp index 07f301fe2b21..e9836da95fae 100644 --- a/libraries/lib-wave-track-paint/waveform/WaveBitmapCache.cpp +++ b/libraries/lib-wave-track-paint/waveform/WaveBitmapCache.cpp @@ -21,6 +21,8 @@ #include "Envelope.h" #include "FrameStatistics.h" +#include "WaveClip.h" + // The worst case scenario is: // blank -> background -> min -> rms -> max -> backgroud -> blank // So we have 7 stops @@ -153,7 +155,7 @@ struct WaveBitmapCache::LookupHelper final { envelope->GetValues( EnvelopeValues.data(), static_cast(EnvelopeValues.size()), - key.FirstSample / cache->GetSampleRate(), + key.FirstSample / cache->GetScaledSampleRate(), 1.0 / key.PixelsPerSecond); for (size_t column = 0; column < columnsCount; ++column) @@ -183,7 +185,7 @@ struct WaveBitmapCache::LookupHelper final const auto clipColors = cache->mPaintParamters.ClippingColors; const auto showRMS = cache->mPaintParamters.ShowRMS; - auto firstPixel = int64_t(key.FirstSample / cache->GetSampleRate() * key.PixelsPerSecond + 0.5); + auto firstPixel = int64_t(key.FirstSample / cache->GetScaledSampleRate() * key.PixelsPerSecond + 0.5); const auto selFirst = cache->mSelection.FirstPixel; const auto selLast = cache->mSelection.LastPixel; @@ -293,12 +295,21 @@ struct WaveBitmapCache::LookupHelper final bool IsComplete { 0 }; }; -WaveBitmapCache::WaveBitmapCache(std::shared_ptr dataCache, - ElementFactory elementFactory, - double sampleRate) - : GraphicsDataCache(sampleRate, std::move(elementFactory)) - - , mLookupHelper(std::make_unique(std::move(dataCache))) +WaveBitmapCache::WaveBitmapCache( + const WaveClip& waveClip, std::shared_ptr dataCache, + ElementFactory elementFactory) + : GraphicsDataCache { waveClip.GetRate() / waveClip.GetStretchRatio(), + std::move(elementFactory) } + , mLookupHelper { std::make_unique(std::move(dataCache)) } + , mWaveClip { waveClip } + , mStretchChangedSubscription { + const_cast(waveClip) + .Observer::Publisher::Subscribe( + [this](const StretchRatioChange&) { + SetScaledSampleRate( + mWaveClip.GetRate() / mWaveClip.GetStretchRatio()); + }) + } { } diff --git a/libraries/lib-wave-track-paint/waveform/WaveBitmapCache.h b/libraries/lib-wave-track-paint/waveform/WaveBitmapCache.h index 4b5aac4fbf8b..eb7cbb2c954f 100644 --- a/libraries/lib-wave-track-paint/waveform/WaveBitmapCache.h +++ b/libraries/lib-wave-track-paint/waveform/WaveBitmapCache.h @@ -13,12 +13,14 @@ #include #include "GraphicsDataCache.h" +#include "Observer.h" #include "waveform/WavePaintParameters.h" class wxBitmap; class wxImage; class WaveDataCache; class Envelope; +class WaveClip; //! An element, that contains a rasterized bitmap matching the WaveDataCacheElement class WAVE_TRACK_PAINT_API WaveBitmapCacheElement : @@ -40,9 +42,8 @@ class WAVE_TRACK_PAINT_API WaveBitmapCache final : public GraphicsDataCache { public: - WaveBitmapCache(std::shared_ptr dataCache, - ElementFactory elementFactory, - double sampleRate); + WaveBitmapCache(const WaveClip& waveClip, std::shared_ptr dataCache, + ElementFactory elementFactory); ~WaveBitmapCache() override; WaveBitmapCache& SetPaintParameters(const WavePaintParameters& params); @@ -73,4 +74,7 @@ class WAVE_TRACK_PAINT_API WaveBitmapCache final : const Envelope* mEnvelope { nullptr }; size_t mEnvelopeVersion { 0 }; + + const WaveClip& mWaveClip; + Observer::Subscription mStretchChangedSubscription; }; diff --git a/libraries/lib-wave-track-paint/waveform/WaveDataCache.cpp b/libraries/lib-wave-track-paint/waveform/WaveDataCache.cpp index db753f155e64..248b6aa00bfa 100644 --- a/libraries/lib-wave-track-paint/waveform/WaveDataCache.cpp +++ b/libraries/lib-wave-track-paint/waveform/WaveDataCache.cpp @@ -253,9 +253,18 @@ MakeDefaultDataProvider(const WaveClip& clip, int channelIndex) WaveDataCache::WaveDataCache(const WaveClip& waveClip, int channelIndex) : GraphicsDataCache( - waveClip.GetRate(), + waveClip.GetRate() / waveClip.GetStretchRatio(), [] { return std::make_unique(); }) - , mProvider(MakeDefaultDataProvider(waveClip, channelIndex)) + , mProvider { MakeDefaultDataProvider(waveClip, channelIndex) } + , mWaveClip { waveClip } + , mStretchChangedSubscription { + const_cast(waveClip) + .Observer::Publisher::Subscribe( + [this](const StretchRatioChange&) { + SetScaledSampleRate( + mWaveClip.GetRate() / mWaveClip.GetStretchRatio()); + }) + } { } @@ -270,7 +279,7 @@ bool WaveDataCache::InitializeElement( int64_t firstSample = key.FirstSample; const size_t samplesPerColumn = - static_cast(std::max(0.0, GetSampleRate() / key.PixelsPerSecond)); + static_cast(std::max(0.0, GetScaledSampleRate() / key.PixelsPerSecond)); const size_t elementSamplesCount = samplesPerColumn * WaveDataCache::CacheElementWidth; diff --git a/libraries/lib-wave-track-paint/waveform/WaveDataCache.h b/libraries/lib-wave-track-paint/waveform/WaveDataCache.h index 845e5e158686..60e23d37b2b5 100644 --- a/libraries/lib-wave-track-paint/waveform/WaveDataCache.h +++ b/libraries/lib-wave-track-paint/waveform/WaveDataCache.h @@ -18,6 +18,7 @@ #include "GraphicsDataCache.h" #include "WaveData.h" +#include "Observer.h" class WaveClip; @@ -103,4 +104,7 @@ class WAVE_TRACK_PAINT_API WaveDataCache final : DataProvider mProvider; WaveCacheSampleBlock mCachedBlock; + + const WaveClip& mWaveClip; + Observer::Subscription mStretchChangedSubscription; }; diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveformView.cpp b/src/tracks/playabletrack/wavetrack/ui/WaveformView.cpp index 8142f8166a12..3cd6b2d8a045 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveformView.cpp +++ b/src/tracks/playabletrack/wavetrack/ui/WaveformView.cpp @@ -233,9 +233,8 @@ class WaveformPainter final auto dataCache = std::make_shared(clip, channelIndex); auto bitmapCache = std::make_unique( - dataCache, - [] { return std::make_unique(); }, - dataCache->GetSampleRate()); + clip, dataCache, + [] { return std::make_unique(); }); mChannelCaches.push_back( { std::move(dataCache), std::move(bitmapCache) }); @@ -290,7 +289,10 @@ class WaveformPainter final void Invalidate() override { for (auto& channelCache : mChannelCaches) + { channelCache.DataCache->Invalidate(); + channelCache.BitmapCache->Invalidate(); + } } std::unique_ptr Clone() const override