Audacity 3.2.0
Classes | Public Member Functions | Private Member Functions | Private Attributes | List of all members
SampleTrackCache Class Reference

A short-lived object, during whose lifetime, the contents of the WaveTrack are assumed not to change. More...

#include <SampleTrackCache.h>

Collaboration diagram for SampleTrackCache:
[legend]

Classes

struct  Buffer
 

Public Member Functions

 SampleTrackCache ()
 
 SampleTrackCache (const std::shared_ptr< const WideSampleSequence > &pSequence)
 
 ~SampleTrackCache ()
 
const std::shared_ptr< const WideSampleSequence > & GetSequence () const
 
void SetSequence (const std::shared_ptr< const WideSampleSequence > &pSequence)
 
std::pair< const float *, const float * > GetFloatsWide (size_t nChannels, sampleCount start, size_t len, bool mayThrow)
 Retrieve samples as floats from the track or from the memory cache. More...
 
const float * GetFloats (sampleCount start, size_t len, bool mayThrow)
 fetch first channel only More...
 

Private Member Functions

void Free ()
 

Private Attributes

std::shared_ptr< const WideSampleSequencempSequence
 
size_t mBufferSize
 
Buffer mBuffers [2]
 
GrowableSampleBuffer mOverlapBuffers [2]
 
int mNValidBuffers
 

Detailed Description

A short-lived object, during whose lifetime, the contents of the WaveTrack are assumed not to change.

It can replace repeated calls to WaveTrack::Get() (each of which opens and closes at least one block).

Definition at line 24 of file SampleTrackCache.h.

Constructor & Destructor Documentation

◆ SampleTrackCache() [1/2]

SampleTrackCache::SampleTrackCache ( )
inline

Definition at line 26 of file SampleTrackCache.h.

27 : mBufferSize(0)
29 {
30 }

◆ SampleTrackCache() [2/2]

SampleTrackCache::SampleTrackCache ( const std::shared_ptr< const WideSampleSequence > &  pSequence)
inlineexplicit

Definition at line 32 of file SampleTrackCache.h.

34 : mBufferSize(0)
36 {
37 SetSequence(pSequence);
38 }
void SetSequence(const std::shared_ptr< const WideSampleSequence > &pSequence)

◆ ~SampleTrackCache()

SampleTrackCache::~SampleTrackCache ( )

Definition at line 15 of file SampleTrackCache.cpp.

16{
17}

Member Function Documentation

◆ Free()

void SampleTrackCache::Free ( )
private

Definition at line 238 of file SampleTrackCache.cpp.

239{
240 mBuffers[0].Free();
241 mBuffers[1].Free();
244 mNValidBuffers = 0;
245}
GrowableSampleBuffer mOverlapBuffers[2]

References GrowableSampleBuffer::Free(), SampleTrackCache::Buffer::Free(), mBuffers, mNValidBuffers, and mOverlapBuffers.

Referenced by SetSequence().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetFloats()

const float * SampleTrackCache::GetFloats ( sampleCount  start,
size_t  len,
bool  mayThrow 
)
inline

fetch first channel only

Definition at line 60 of file SampleTrackCache.h.

61 {
62 return GetFloatsWide(1, start, len, mayThrow).first;
63 }
std::pair< const float *, const float * > GetFloatsWide(size_t nChannels, sampleCount start, size_t len, bool mayThrow)
Retrieve samples as floats from the track or from the memory cache.

Referenced by SpecCache::CalculateOneSpectrum().

Here is the caller graph for this function:

◆ GetFloatsWide()

std::pair< const float *, const float * > SampleTrackCache::GetFloatsWide ( size_t  nChannels,
sampleCount  start,
size_t  len,
bool  mayThrow 
)

Retrieve samples as floats from the track or from the memory cache.

Uses fillZero always

Returns
both null on failure; this object owns the memory; may be invalidated if GetFloats() is called again
Precondition
nChannels <= GetSequence()->NChannels()
nChannels <= 2

Definition at line 44 of file SampleTrackCache.cpp.

46{
47 float *overlaps[2]{};
48 assert(nChannels <= GetSequence()->NChannels());
49 assert(nChannels <= 2);
50
51 constexpr auto format = floatSample;
52 if (format == floatSample && len > 0) {
53 const auto end = start + len;
54
55 bool fillFirst = (mNValidBuffers < 1);
56 bool fillSecond = (mNValidBuffers < 2);
57
58 // Discard cached results that we no longer need
59 if (mNValidBuffers > 0 &&
60 (end <= mBuffers[0].start ||
61 start >= mBuffers[mNValidBuffers - 1].end())) {
62 // Complete miss
63 fillFirst = true;
64 fillSecond = true;
65 }
66 else if (mNValidBuffers == 2 &&
67 start >= mBuffers[1].start &&
68 end > mBuffers[1].end()) {
69 // Request starts in the second buffer and extends past it.
70 // Discard the first buffer.
71 // (But don't deallocate the buffer space.)
72 mBuffers[0] .swap ( mBuffers[1] );
73 fillSecond = true;
75 }
76 else if (mNValidBuffers > 0 &&
77 start < mBuffers[0].start &&
78 0 <= mpSequence->GetBlockStart(start)) {
79 // Request is not a total miss but starts before the cache,
80 // and there is a clip to fetch from.
81 // Not the access pattern for drawing spectrogram or playback,
82 // but maybe scrubbing causes this.
83 // Move the first buffer into second place, and later
84 // refill the first.
85 // (This case might be useful when marching backwards through
86 // the sequence, as with scrubbing.)
87 mBuffers[0] .swap ( mBuffers[1] );
88 fillFirst = true;
89 fillSecond = false;
90 // Cache is not in a consistent state yet
92 }
93
94 // Refill buffers as needed
95 if (fillFirst) {
96 const auto start0 = mpSequence->GetBlockStart(start);
97 if (start0 >= 0) {
98 const auto len0 = mpSequence->GetBestBlockSize(start0);
99 assert(len0 <= mBufferSize);
100 if (!mpSequence->GetFloats(0, nChannels,
101 mBuffers[0].GetBuffers(), start0, len0,
102 fillZero, mayThrow))
103 return { nullptr, nullptr };
104 mBuffers[0].start = start0;
105 mBuffers[0].len = len0;
106 if (!fillSecond &&
107 mBuffers[0].end() != mBuffers[1].start)
108 fillSecond = true;
109 // Keep the partially updated state consistent:
110 mNValidBuffers = fillSecond ? 1 : 2;
111 }
112 else {
113 // Request may fall between the clips of a sequence.
114 // Invalidate all. WaveTrack::Get() will return zeroes.
115 mNValidBuffers = 0;
116 fillSecond = false;
117 }
118 }
119 assert(!fillSecond || mNValidBuffers > 0);
120 if (fillSecond) {
121 mNValidBuffers = 1;
122 const auto end0 = mBuffers[0].end();
123 if (end > end0) {
124 const auto start1 = mpSequence->GetBlockStart(end0);
125 if (start1 == end0) {
126 const auto len1 = mpSequence->GetBestBlockSize(start1);
127 assert(len1 <= mBufferSize);
128 if (!mpSequence->GetFloats(0, nChannels,
129 mBuffers[1].GetBuffers(), start1, len1, fillZero, mayThrow))
130 return { nullptr, nullptr };
131 mBuffers[1].start = start1;
132 mBuffers[1].len = len1;
133 mNValidBuffers = 2;
134 }
135 }
136 }
137 assert(mNValidBuffers < 2 || mBuffers[0].end() == mBuffers[1].start);
138
139 samplePtr buffers[2]{}; // will point into mOverlapBuffers
140 auto remaining = len;
141 const auto resizeOverlapBuffers = [&]{
142 for (size_t iChannel = 0; iChannel < nChannels; ++iChannel) {
143 auto &overlapBuffer = mOverlapBuffers[iChannel];
144 overlapBuffer.Resize(len, format);
145 // See comment below about casting
146 overlaps[iChannel] = reinterpret_cast<float*>(overlapBuffer.ptr());
147 }
148 };
149 const auto assignBuffers = [&]{
150 size_t iChannel = 0;
151 for (; iChannel < nChannels; ++iChannel)
152 buffers[iChannel] = reinterpret_cast<samplePtr>(overlaps[iChannel]);
153 for (; iChannel < 2; ++iChannel)
154 buffers[iChannel] = nullptr;
155 };
156
157 // Possibly get an initial portion that is uncached
158
159 // This may be negative
160 const auto initLen =
161 mNValidBuffers < 1 ? sampleCount( len )
162 : std::min(sampleCount( len ), mBuffers[0].start - start);
163
164 if (initLen > 0) {
165 // This might be fetching zeroes between clips
166 resizeOverlapBuffers();
167 // initLen is not more than len:
168 auto sinitLen = initLen.as_size_t();
169 if (!mpSequence->GetFloats(0, nChannels, overlaps,
170 start, sinitLen, fillZero, mayThrow))
171 return { nullptr, nullptr };
172 assert(sinitLen <= remaining);
173 remaining -= sinitLen;
174 start += initLen;
175 for (size_t iChannel = 0; iChannel < nChannels; ++iChannel)
176 buffers[iChannel] =
177 reinterpret_cast<samplePtr>(overlaps[iChannel] + sinitLen);
178 }
179
180 // Now satisfy the request from the buffers
181 for (int ii = 0; ii < mNValidBuffers && remaining > 0; ++ii) {
182 const auto starti = start - mBuffers[ii].start;
183 // Treatment of initLen above establishes this loop invariant,
184 // and statements below preserve it:
185 assert(starti >= 0);
186
187 // This may be negative
188 const auto leni =
189 std::min( sampleCount( remaining ), mBuffers[ii].len - starti );
190 if (initLen <= 0 && leni == len) {
191 // All is contiguous already. We can completely avoid copying
192 // leni is nonnegative, therefore start falls within mBuffers[ii],
193 // so starti is bounded between 0 and buffer length
194 return mBuffers[ii].GetResults(nChannels, starti.as_size_t());
195 }
196 else if (leni > 0) {
197 // leni is nonnegative, therefore start falls within mBuffers[ii]
198 // But we can't satisfy all from one buffer, so copy
199 if (!buffers[0]) {
200 resizeOverlapBuffers();
201 assignBuffers();
202 }
203 // leni is positive and not more than remaining
204 const size_t size = sizeof(float) * leni.as_size_t();
205 // starti is less than mBuffers[ii].len and nonnegative
206 for (size_t iChannel = 0; iChannel < nChannels; ++iChannel)
207 memcpy(buffers[iChannel],
208 mBuffers[ii].areas[iChannel].get() + starti.as_size_t(),
209 size);
210 assert(leni <= remaining);
211 remaining -= leni.as_size_t();
212 start += leni;
213 for (size_t iChannel = 0; iChannel < nChannels; ++iChannel)
214 buffers[iChannel] += size;
215 }
216 }
217
218 if (remaining > 0) {
219 // Very big request!
220 // Fall back to direct fetch
221 if (!buffers[0])
222 resizeOverlapBuffers();
223 // See comment below about casting
224 if (!mpSequence->GetFloats(0, nChannels,
225 reinterpret_cast<float**>(buffers),
226 start, remaining, fillZero, mayThrow))
227 return { nullptr, nullptr };
228 }
229
230 return { overlaps[0], overlaps[1] };
231 }
232 else {
233 // No longer handling other than float format. Therefore len is 0.
234 return { nullptr, nullptr };
235 }
236}
int min(int a, int b)
int format
Definition: ExportPCM.cpp:53
char * samplePtr
Definition: SampleFormat.h:55
@ fillZero
Definition: SampleFormat.h:60
GrowableSampleBuffer & Resize(size_t count, sampleFormat format)
Definition: SampleFormat.h:183
const std::shared_ptr< const WideSampleSequence > & GetSequence() const
std::shared_ptr< const WideSampleSequence > mpSequence
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
STL namespace.
void swap(Buffer &other)
sampleCount end() const
std::pair< const float *, const float * > GetResults(size_t nChannels, size_t offset) const

References SampleTrackCache::Buffer::end(), PackedArray::end(), fillZero, floatSample, format, SampleTrackCache::Buffer::GetBuffers(), SampleTrackCache::Buffer::GetResults(), GetSequence(), SampleTrackCache::Buffer::len, mBuffers, mBufferSize, min(), mNValidBuffers, mOverlapBuffers, mpSequence, GrowableSampleBuffer::Resize(), size, SampleTrackCache::Buffer::start, and SampleTrackCache::Buffer::swap().

Here is the call graph for this function:

◆ GetSequence()

const std::shared_ptr< const WideSampleSequence > & SampleTrackCache::GetSequence ( ) const
inline

Definition at line 41 of file SampleTrackCache.h.

41 {
42 return mpSequence;
43 }

Referenced by anonymous_namespace{SpectrumView.cpp}::DrawClipSpectrum(), GetFloatsWide(), and WaveClipSpectrumCache::GetSpectrogram().

Here is the caller graph for this function:

◆ SetSequence()

void SampleTrackCache::SetSequence ( const std::shared_ptr< const WideSampleSequence > &  pSequence)

Definition at line 19 of file SampleTrackCache.cpp.

21{
22 if (mpSequence != pSequence) {
23 if (pSequence) {
24 mBufferSize = pSequence->GetMaxBlockSize();
25 if (!mpSequence ||
26 mpSequence->GetMaxBlockSize() != mBufferSize) {
27 Free();
28 const auto nChannels = pSequence->NChannels();
29 for (size_t ii : {0, 1}) {
30 mBuffers[ii].areas.reinit(nChannels, true);
31 for (size_t iChannel = 0; iChannel < nChannels; ++iChannel)
32 mBuffers[ii].areas[iChannel] = Floats{ mBufferSize };
33 }
34 }
35 }
36 else
37 Free();
38 mpSequence = pSequence;
40 }
41}
void reinit(Integral count)
Definition: MemoryX.h:109

References SampleTrackCache::Buffer::areas, Free(), mBuffers, mBufferSize, mNValidBuffers, mpSequence, and ArraysOf< X >::reinit().

Here is the call graph for this function:

Member Data Documentation

◆ mBuffers

Buffer SampleTrackCache::mBuffers[2]
private

Definition at line 101 of file SampleTrackCache.h.

Referenced by Free(), GetFloatsWide(), and SetSequence().

◆ mBufferSize

size_t SampleTrackCache::mBufferSize
private

Definition at line 100 of file SampleTrackCache.h.

Referenced by GetFloatsWide(), and SetSequence().

◆ mNValidBuffers

int SampleTrackCache::mNValidBuffers
private

Definition at line 103 of file SampleTrackCache.h.

Referenced by Free(), GetFloatsWide(), and SetSequence().

◆ mOverlapBuffers

GrowableSampleBuffer SampleTrackCache::mOverlapBuffers[2]
private

Definition at line 102 of file SampleTrackCache.h.

Referenced by Free(), and GetFloatsWide().

◆ mpSequence

std::shared_ptr<const WideSampleSequence> SampleTrackCache::mpSequence
private

Definition at line 99 of file SampleTrackCache.h.

Referenced by GetFloatsWide(), and SetSequence().


The documentation for this class was generated from the following files: