UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
SlidingWindow.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
6#pragma once
7
8#include "CoreMinimal.h"
9
10
11namespace Audio
12{
13 // Forward delcaration
14 template <typename InSampleType>
15 class TSlidingWindow;
16
17
26 template <typename InSampleType>
28 {
29 public:
30
35 : NumWindowSamples(InNumWindowSamples)
36 , NumHopSamples(InNumHopSamples)
37 , NumUnderflowSamples(0)
38 {
39 check(NumWindowSamples >= 1);
40 check(NumHopSamples >= 1);
41 }
42
44 : TSlidingBuffer(1, 1)
45 {
46 }
47
48 TSlidingBuffer(const TSlidingBuffer&) = default;
50
53
56 {
57 return NumWindowSamples;
58 }
59
62 {
63 return NumHopSamples;
64 }
65
68 {
69 return NumUnderflowSamples;
70 }
71
73 {
74 return StorageBuffer;
75 }
76
83 {
84 if (NumUnderflowSamples > 0)
85 {
86 // Consume some underflow samples from the storage buffer.
87 if (StorageBuffer.Num() > NumUnderflowSamples)
88 {
89 StorageBuffer.RemoveAt(0, NumUnderflowSamples);
90 NumUnderflowSamples = 0;
91 }
92 else
93 {
94 NumUnderflowSamples -= StorageBuffer.Num();
95 StorageBuffer.Reset();
96 }
97 }
98
99 // Total number of samples starting at beginning of first window generated from this buffer
100 int32 NumSamples = InBuffer.Num() + StorageBuffer.Num() - NumUnderflowSamples;
101
102 if (NumSamples < 0)
103 {
104 // No windows generated, but some underflow samples accounted for
105 NumUnderflowSamples -= InBuffer.Num();
106 }
107 else if (NumSamples < NumWindowSamples)
108 {
109 // No windows generated, but we should store data for future windows.
110 int32 NumToCopy = NumSamples - StorageBuffer.Num();
112 StorageBuffer.Append(&InBuffer.GetData()[InBufferIndex], NumToCopy);
113
114 // All underflow samples accounted for.
115 NumUnderflowSamples = 0;
116 }
117 else
118 {
119 // Calculate number of windows generated from samples in StorageBuffer and InBuffer.
120 int32 NumWindowsGenerated = (NumSamples - NumWindowSamples) / NumHopSamples + 1;
121
122 // Calculate number of samples to keep for future windows
123 int32 NumRemainingSamples = NumSamples - (NumWindowsGenerated * NumHopSamples);
124
125 if (NumRemainingSamples > InBuffer.Num())
126 {
127 // Need to keep some samples from storage buffer and from InBuffer
129 int32 NumToRemove = StorageBuffer.Num() - NumToKeep;
130
131 if (NumToRemove > 0)
132 {
133 // May need to remove soem from the storage buffer
134 StorageBuffer.RemoveAt(0, NumToRemove);
135 }
136
137 StorageBuffer.Append(InBuffer.GetData(), InBuffer.Num());
138 }
139 else if (NumRemainingSamples > 0)
140 {
141 // Only need to keep samples from InBuffer. Can discard samples in StorageBuffer
142 StorageBuffer.Reset(NumRemainingSamples);
144
147 }
148 else
149 {
150 // This occurs when HopSize > WindowSize. We have hopped to the next window, but don't have enough samples
151 // to account for the hop. We track the number of underflow samples to make sure they are consumed before
152 // the next window starts.
153 NumUnderflowSamples = -NumRemainingSamples;
154 StorageBuffer.Reset(0);
155 }
156 }
157 }
158
162 void Reset()
163 {
164 StorageBuffer.Reset();
165 NumUnderflowSamples = 0;
166 }
167
168 private:
169 // NumWindowSamples describes the number of samples in a window.
170 int32 NumWindowSamples;
171
172 // NumHopSamples describes the number of samples between adjacent windows.
173 int32 NumHopSamples;
174
175 // Stores samples from previous calls which are still needed for future buffers
176 TArray<InSampleType> StorageBuffer;
177
178 // When HopSize is greater than WindowSize a situation can occur where we need
179 // to account for hop samples that we have not yet ingested.
180 int32 NumUnderflowSamples;
181 };
182
188 template <typename InSampleType>
190 {
192
193 protected:
194 // Accessed from friendship with TSlidingBuffer
196
197 // New buffer passed in.
199
200 // Copied from TSlidingBuffer
202
203 // Copied from TSlidingBuffer
205
206 private:
207
208 int32 MaxReadIndex;
209 int32 NumUnderflowSamples;
210
211 public:
212
217 template<typename InAllocator = FDefaultAllocator>
219 {
220 const TSlidingWindow SlidingWindow;
221
222 // Samples in window will be copied into this array.
224
225 // Index into array for reading out data.
226 int32 ReadIndex;
227
228 public:
229
230 // Sentinel value marking that the last possible window has been generated.
232
237 : SlidingWindow(InSlidingWindow)
238 , WindowBuffer(OutWindowBuffer)
239 , ReadIndex(InReadIndex)
240 {
241 if (ReadIndex > SlidingWindow.MaxReadIndex)
242 {
243 ReadIndex = ReadIndexEnd;
244 }
245 }
246
251 {
252 if (ReadIndex != ReadIndexEnd)
253 {
254 ReadIndex += SlidingWindow.NumHopSamples;
255 if (ReadIndex > SlidingWindow.MaxReadIndex)
256 {
257 ReadIndex = ReadIndexEnd;
258 }
259 }
260
261 return *this;
262 }
263
269 {
270 return ReadIndex != Other.ReadIndex;
271 }
272
277 {
278 if (ReadIndex != ReadIndexEnd)
279 {
280 // Resize output window
281 WindowBuffer.Reset(SlidingWindow.NumWindowSamples);
282 WindowBuffer.AddUninitialized(SlidingWindow.NumWindowSamples);
283
285
286 if (ReadIndex < SlidingWindow.StorageBuffer.Num())
287 {
288 // The output window overlaps the storage buffer. Copy appropriate samples from the storage buffer.
289 int32 SamplesToCopy = SlidingWindow.StorageBuffer.Num() - ReadIndex;
290 FMemory::Memcpy(WindowBuffer.GetData(), &SlidingWindow.StorageBuffer.GetData()[ReadIndex], SamplesToCopy * sizeof(InSampleType));
292 }
293
294 if (SamplesFilled < SlidingWindow.NumWindowSamples)
295 {
296 // The output window overlaps the new buffer. Copy appropriate samples from the new buffer.
297 int32 NewBufferIndex = ReadIndex - SlidingWindow.StorageBuffer.Num() + SamplesFilled;
300
301 if (SamplesToCopy > 0)
302 {
303 FMemory::Memcpy(&WindowBuffer.GetData()[SamplesFilled], &SlidingWindow.NewBuffer.GetData()[NewBufferIndex], SamplesToCopy * sizeof(InSampleType));
304
306 }
307 }
308
309 if (SamplesFilled < SlidingWindow.NumWindowSamples)
310 {
311 // The output window still needs more samples (due to zeropadding & flushing), so set zeros.
313 FMemory::Memset(&WindowBuffer.GetData()[SamplesFilled], 0, sizeof(InSampleType) * SamplesToZeropad);
314 }
315 }
316 else
317 {
318 // Empty window if past end sliding window. ReadIndex == ReadIndexEnd
319 WindowBuffer.Reset();
320 }
321
322 return WindowBuffer;
323 }
324 };
325
334 : StorageBuffer(InSlidingBuffer.GetStorage())
336 , NumWindowSamples(InSlidingBuffer.GetNumWindowSamples())
337 , NumHopSamples(InSlidingBuffer.GetNumHopSamples())
338 , MaxReadIndex(0)
339 , NumUnderflowSamples(InSlidingBuffer.GetNumUnderflowSamples())
340 {
341 // Total samples to be slid over.
342 int32 NumSamples = NewBuffer.Num() + StorageBuffer.Num();
343
344 if (bDoFlush && (NumSamples > 0))
345 {
346 // If flushing, calculate the number of samples to zeropad
347 int32 NumZeroPad = 0;
348
349 if (NumSamples < NumWindowSamples)
350 {
351 NumZeroPad = NumWindowSamples - NumSamples;
352 }
353 else
354 {
355 // Determine number of windows
356 int32 NumWindowsGenerated = (NumSamples - NumWindowSamples - NumUnderflowSamples) / NumHopSamples + 1;
358 if (NumRemaining > 0)
359 {
361 }
362 }
363
364 NumSamples += NumZeroPad;
365 }
366
367 MaxReadIndex = NumSamples - NumWindowSamples;
368
369 if (MaxReadIndex < 0)
370 {
372 }
373 }
374
376 {
377 }
378
384 template<typename InAllocator = FDefaultAllocator>
386 {
387 if (MaxReadIndex == TSlidingWindowIterator<>::ReadIndexEnd)
388 {
390 }
391 // Set the starting read index to NumUnderflowSamples to account for samples that still need to be consumed.
392 return TSlidingWindowIterator<InAllocator>(*this, OutWindowBuffer, NumUnderflowSamples);
393 }
394
400 template<typename InAllocator = FDefaultAllocator>
405 };
406
413 template <class InSampleType>
414 class TScopedSlidingWindow : public TSlidingWindow<InSampleType>
415 {
416 // Do not allow copying or moving since that may cause the destructor to be called inadvertently.
418 void operator=(TScopedSlidingWindow const &) = delete;
420 TScopedSlidingWindow& operator=(TScopedSlidingWindow&&) = delete;
421
422 TSlidingBuffer<InSampleType>& SlidingBuffer;
423 public:
424
436
444 };
445
478 template <typename InSampleType, typename InAllocator = FDefaultAllocator>
479 class TAutoSlidingWindow : public TScopedSlidingWindow<InSampleType>
480 {
482
483 typedef typename TSlidingWindow<InSampleType>::template TSlidingWindowIterator<InAllocator> TAutoSlidingWindowIterator;
484
485 public:
498
504 TAutoSlidingWindowIterator begin()
505 {
507 }
508
514 TAutoSlidingWindowIterator end()
515 {
517 }
518 };
519}
#define check(expr)
Definition AssertionMacros.h:314
@ INDEX_NONE
Definition CoreMiscDefines.h:150
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
Definition SlidingWindow.h:480
TAutoSlidingWindow(TSlidingBuffer< InSampleType > &InBuffer, TArrayView< const InSampleType > InNewBuffer, TArray< InSampleType, InAllocator > &OutWindow, bool bDoFlush=false)
Definition SlidingWindow.h:494
TAutoSlidingWindowIterator end()
Definition SlidingWindow.h:514
TAutoSlidingWindowIterator begin()
Definition SlidingWindow.h:504
Definition SlidingWindow.h:415
TScopedSlidingWindow(TSlidingBuffer< InSampleType > &InSlidingBuffer, TArrayView< const InSampleType > InNewBuffer, bool bDoFlush=false)
Definition SlidingWindow.h:432
virtual ~TScopedSlidingWindow()
Definition SlidingWindow.h:440
Definition SlidingWindow.h:28
void Reset()
Definition SlidingWindow.h:162
void StoreForFutureWindows(TArrayView< const InSampleType > InBuffer)
Definition SlidingWindow.h:82
int32 GetNumUnderflowSamples() const
Definition SlidingWindow.h:67
int32 GetNumHopSamples() const
Definition SlidingWindow.h:61
TSlidingBuffer(const int32 InNumWindowSamples, const int32 InNumHopSamples)
Definition SlidingWindow.h:34
TSlidingBuffer(const TSlidingBuffer &)=default
int32 GetNumWindowSamples() const
Definition SlidingWindow.h:55
TSlidingBuffer(TSlidingBuffer &&)=default
TSlidingBuffer & operator=(TSlidingBuffer &&InOther)=default
TSlidingBuffer()
Definition SlidingWindow.h:43
TArrayView< const InSampleType > GetStorage() const
Definition SlidingWindow.h:72
TSlidingBuffer & operator=(const TSlidingBuffer &InOther)=default
Definition SlidingWindow.h:219
TArray< InSampleType, InAllocator > & operator*()
Definition SlidingWindow.h:276
static const int32 ReadIndexEnd
Definition SlidingWindow.h:231
TSlidingWindowIterator operator++()
Definition SlidingWindow.h:250
TSlidingWindowIterator(const TSlidingWindow &InSlidingWindow, TArray< InSampleType, InAllocator > &OutWindowBuffer, int32 InReadIndex)
Definition SlidingWindow.h:236
bool operator!=(const TSlidingWindowIterator &Other) const
Definition SlidingWindow.h:268
Definition SlidingWindow.h:190
TSlidingWindowIterator< InAllocator > begin(TArray< InSampleType, InAllocator > &OutWindowBuffer) const
Definition SlidingWindow.h:385
const int32 NumWindowSamples
Definition SlidingWindow.h:201
const int32 NumHopSamples
Definition SlidingWindow.h:204
virtual ~TSlidingWindow()
Definition SlidingWindow.h:375
TArrayView< const InSampleType > StorageBuffer
Definition SlidingWindow.h:195
TSlidingWindowIterator< InAllocator > end(TArray< InSampleType, InAllocator > &OutWindowBuffer) const
Definition SlidingWindow.h:401
TSlidingWindow(const TSlidingBuffer< InSampleType > &InSlidingBuffer, TArrayView< const InSampleType > InNewBuffer, bool bDoFlush)
Definition SlidingWindow.h:333
TArrayView< const InSampleType > NewBuffer
Definition SlidingWindow.h:198
Definition ArrayView.h:139
UE_FORCEINLINE_HINT constexpr ElementType * GetData() const
Definition ArrayView.h:295
UE_FORCEINLINE_HINT constexpr SizeType Num() const
Definition ArrayView.h:380
Definition Array.h:670
UE_FORCEINLINE_HINT SizeType AddUninitialized()
Definition Array.h:1664
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void RemoveAt(SizeType Index, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2083
void Reset(SizeType NewSize=0)
Definition Array.h:2246
UE_NODEBUG UE_FORCEINLINE_HINT ElementType * GetData() UE_LIFETIMEBOUND
Definition Array.h:1027
void Append(const TArray< OtherElementType, OtherAllocatorType > &Source)
Definition Array.h:2412
NO_LOGGING.
Definition AudioMixerPlatformAndroid.cpp:53
static UE_FORCEINLINE_HINT void * Memcpy(void *Dest, const void *Src, SIZE_T Count)
Definition UnrealMemory.h:160
static UE_FORCEINLINE_HINT void * Memset(void *Dest, uint8 Char, SIZE_T Count)
Definition UnrealMemory.h:119