37 int channelIndex)
noexcept
40 mFirstClipSampleID != clip.GetSequence(0)->GetNumSamples() ||
41 mSampleType != outBlock.DataType)
43 mFirstClipSampleID = clip.GetSequence(0)->GetNumSamples();
44 mLastProcessedSample = 0;
45 mSampleType = outBlock.DataType;
55 const size_t appendedSamples = clip.GetAppendBufferLen(channelIndex);
57 if (appendedSamples == 0)
60 const auto appendBuffer = GetAppendBufferPointer(clip, channelIndex);
66 float* outBuffer = outBlock.GetWritePointer(appendedSamples);
68 std::copy(appendBuffer, appendBuffer + appendedSamples, outBuffer);
72 FillBlocksFromAppendBuffer<256>(
73 appendBuffer, appendedSamples, outBlock);
76 FillBlocksFromAppendBuffer<64 * 1024>(
77 appendBuffer, appendedSamples, outBlock);
90 const auto appendBuffer =
94 return static_cast<const float*
>(appendBuffer);
97 mConvertedAppendBufferData.resize(samplesCount);
101 const auto int16Buffer =
static_cast<const int16_t*
>(appendBuffer);
103 for (
size_t i = 0; i < samplesCount; ++i)
104 mConvertedAppendBufferData[i] =
float(int16Buffer[i]) / (1 << 15);
108 const auto int24Buffer =
static_cast<const int32_t*
>(appendBuffer);
110 for (
size_t i = 0; i < samplesCount; ++i)
111 mConvertedAppendBufferData[i] =
float(int24Buffer[i]) / (1 << 23);
114 return mConvertedAppendBufferData.data();
117 template<
size_t blockSize>
119 const float* bufferSamples,
size_t samplesCount,
122 const size_t startingBlock = mLastProcessedSample / blockSize;
123 const size_t blocksCount =
RoundUpUnsafe(samplesCount, blockSize);
125 for (
size_t blockIndex = startingBlock; blockIndex < blocksCount;
128 const size_t samplesInBlock =
129 std::min(blockSize, samplesCount - blockIndex * blockSize);
131 float min = std::numeric_limits<float>::infinity();
132 float max = -std::numeric_limits<float>::infinity();
136 auto samples = bufferSamples + blockIndex * blockSize;
138 for (
size_t sampleIndex = 0; sampleIndex < samplesInBlock;
141 const float sample = *samples++;
144 max = std::max(max, sample);
146 const double dbl = sample;
151 const auto rms =
static_cast<float>(
std::sqrt(sqSum / samplesInBlock));
153 mCachedData[blockIndex] = {
min, max, rms };
156 mLastProcessedSample = samplesCount;
158 sizeof(
CacheItem) * blocksCount /
sizeof(float));
160 std::memmove(ptr, mCachedData.data(),
sizeof(
CacheItem) * blocksCount);
177 size_t mLastProcessedSample { 0 };
183 return [sequence = clip.
GetSequence(channelIndex), clip = &clip,
188 if (requiredSample < 0)
191 if (requiredSample >= sequence->GetNumSamples())
193 requiredSample -= sequence->GetNumSamples().as_long_long();
198 outBlock.DataType = dataType;
199 outBlock.FirstSample = sequence->GetNumSamples().as_long_long();
202 return appendBufferHelper.FillBuffer(*clip, outBlock, channelIndex);
205 const auto blockIndex = sequence->FindBlock(requiredSample);
206 const auto& inputBlock = sequence->GetBlockArray()[blockIndex];
208 outBlock.FirstSample = inputBlock.start.as_long_long();
209 outBlock.NumSamples = inputBlock.sb->GetSampleCount();
216 static_cast<void*
>(outBlock.GetWritePointer(outBlock.NumSamples)));
218 inputBlock.sb->GetSamples(
224 size_t framesCount =
RoundUpUnsafe(outBlock.NumSamples, 256);
227 static_cast<float*
>(outBlock.GetWritePointer(framesCount * 3));
229 inputBlock.sb->GetSummary256(ptr, 0, framesCount);
234 size_t framesCount =
RoundUpUnsafe(outBlock.NumSamples, 64 * 1024);
237 static_cast<float*
>(outBlock.GetWritePointer(framesCount * 3));
239 inputBlock.sb->GetSummary64k(ptr, 0, framesCount);
246 outBlock.DataType = dataType;
256 waveClip.
GetRate() / waveClip.GetStretchRatio(),
257 [] {
return std::make_unique<WaveCacheElement>(); })
259 , mWaveClip { waveClip }
260 , mStretchChangedSubscription {
265 mWaveClip.GetRate() / mWaveClip.GetStretchRatio());
279 int64_t firstSample =
key.FirstSample;
281 const size_t samplesPerColumn =
284 const size_t elementSamplesCount =
286 size_t processedSamples = 0;
289 samplesPerColumn >= 64 * 1024 ?
297 size_t columnIndex = 0;
302 size_t samplesLeft = samplesPerColumn;
304 while (samplesLeft != 0)
319 auto& column = element.
Data[columnIndex];
321 column.min = summary.
Min;
322 column.max = summary.
Max;
329 const auto prevColumn = element.
Data[columnIndex - 1];
330 auto& column = element.
Data[columnIndex];
332 bool updated =
false;
334 if (prevColumn.min > column.max)
336 column.max = prevColumn.min;
340 if (prevColumn.max < column.min)
342 column.min = prevColumn.max;
347 column.rms = std::clamp(column.rms, column.min, column.max);
350 if (samplesLeft != 0)
358 element.
IsComplete = processedSamples == elementSamplesCount;
360 return processedSamples != 0;
365 return sampleIndex >= FirstSample &&
366 (sampleIndex < (FirstSample + NumSamples));
371 mData.resize(floatsCount);
383template<
size_t blockSize>
385 const float* input, int64_t from,
size_t count,
388 input = input + 3 * (from / blockSize);
392 float max = summary.
Max;
395 for (
size_t idx = 0; idx < count; ++idx)
398 max = std::max(max, *input++);
400 const double rms = *input++;
402 squareSum += rms * rms * blockSize;
418 from = from - FirstSample;
420 std::min<size_t>(samplesCount, std::max<int64_t>(0, NumSamples - from));
422 const auto to = from + samplesCount;
425 static_cast<const float*
>(
static_cast<const void*
>(mData.data()));
436 for (
auto sampleIndex = from; sampleIndex < to; ++sampleIndex)
438 const float sample = data[sampleIndex];
441 summary.
Max = std::max(summary.
Max, sample);
443 summary.
SquaresSum += double(sample) * double(sample);
446 assert(summary.
Min <= summary.
Max);
450 processBlock<256>(data, from, samplesCount, summary);
453 processBlock<64 * 1024>(data, from, samplesCount, summary);
469 if (prev->AvailableColumns == 0)
472 const auto prevLastColumn = prev->
Data[prev->AvailableColumns - 1];
473 auto& firstColumn =
Data[0];
475 bool updated =
false;
477 if (prevLastColumn.min > firstColumn.max)
479 firstColumn.max = prevLastColumn.min;
483 if (prevLastColumn.max < firstColumn.min)
485 firstColumn.min = prevLastColumn.max;
491 std::clamp(firstColumn.rms, firstColumn.min, firstColumn.max);
auto RoundUpUnsafe(LType numerator, RType denominator) noexcept
Returns a rounded up integer result for numerator / denominator.
@ WaveDataCache
Time required to access the data cache.
static Stopwatch CreateStopwatch(SectionID section) noexcept
Create a Stopwatch for the section specified.
static constexpr uint32_t CacheElementWidth
double GetScaledSampleRate() const noexcept
Returns the sample rate associated with cache.
An object that sends messages to an open-ended list of subscribed callbacks.
This allows multiple clips to be a part of one WaveTrack.
constSamplePtr GetAppendBuffer(size_t ii) const
Get one channel of the append buffer.
SampleFormats GetSampleFormats() const
size_t GetAppendBufferLen(size_t ii) const
Sequence * GetSequence(size_t ii)
std::function< bool(int64_t requiredSample, WaveCacheSampleBlock::Type dataType, WaveCacheSampleBlock &block)> DataProvider
WaveCacheSampleBlock mCachedBlock
WaveDataCache(const WaveClip &waveClip, int channelIndex)
bool InitializeElement(const GraphicsDataCacheKey &key, WaveCacheElement &element) override
std::vector< float > mConvertedAppendBufferData
const float * GetAppendBufferPointer(const WaveClip &clip, int channelIndex)
void FillBlocksFromAppendBuffer(const float *bufferSamples, size_t samplesCount, WaveCacheSampleBlock &outBlock)
bool FillBuffer(const WaveClip &clip, WaveCacheSampleBlock &outBlock, int channelIndex) noexcept
std::vector< CacheItem > mCachedData
Positions or offsets within audio files need a wide type.
RegisteredInitializer initializer
double GetRate(const Track &track)
WaveDataCache::DataProvider MakeDefaultDataProvider(const WaveClip &clip, int channelIndex)
void processBlock(const float *input, int64_t from, size_t count, WaveCacheSampleBlock::Summary &summary)
__finl float_x4 __vecc sqrt(const float_x4 &a)
void copy(const T *src, T *dst, int32_t n)
A base class for the for cache elements.
bool AwaitsEviction
This flag is used to simplify the eviction algorithm.
bool IsComplete
Cache implementation is responsible to set this flag when all the data of the item is filled.
A key into the graphics data cache.
An element of a cache that contains the waveform data.
void Smooth(GraphicsDataCacheElementBase *prevElement) override
This method is called during the lookup when new items are inserted. prevElement can be nullptr....
Summary calculated over the requested range.
Helper structure used to transfer the data between the data and graphics layers.
Summary GetSummary(int64_t from, size_t samplesCount, const Summary &initializer) const noexcept
std::vector< float > mData
float * GetWritePointer(size_t floatsCount)
Gets a pointer to a data buffer enough to store floatsCount floats.
Type
Type of the data of the request.
@ Samples
Each element of the resulting array is a sample.
bool ContainsSample(int64_t sampleIndex) const noexcept
Checks if sample is in the range represented by this block.