Audacity 3.2.0
Public Member Functions | Static Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes | Static Private Attributes | List of all members
Sequence Class Referencefinal

A WaveTrack contains WaveClip(s). A WaveClip contains a Sequence. A Sequence is primarily an interface to an array of SeqBlock instances, corresponding to the audio sample blocks in the database. Contrast with RingBuffer. More...

#include <Sequence.h>

Inheritance diagram for Sequence:
[legend]
Collaboration diagram for Sequence:
[legend]

Public Member Functions

 Sequence (const SampleBlockFactoryPtr &pFactory, SampleFormats formats)
 
 Sequence (const Sequence &orig, const SampleBlockFactoryPtr &pFactory)
 
 Sequence (const Sequence &)=delete
 
Sequenceoperator= (const Sequence &) PROHIBITED
 
 ~Sequence ()
 
sampleCount GetNumSamples () const
 
bool Get (samplePtr buffer, sampleFormat format, sampleCount start, size_t len, bool mayThrow) const
 
void SetSamples (constSamplePtr buffer, sampleFormat format, sampleCount start, sampleCount len, sampleFormat effectiveFormat)
 Pass nullptr to set silence. More...
 
std::unique_ptr< SequenceCopy (const SampleBlockFactoryPtr &pFactory, sampleCount s0, sampleCount s1) const
 
void Paste (sampleCount s0, const Sequence *src)
 
size_t GetIdealAppendLen () const
 
bool Append (constSamplePtr buffer, sampleFormat format, size_t len, size_t stride, sampleFormat effectiveFormat)
 
void Flush ()
 
SeqBlock::SampleBlockPtr AppendNewBlock (constSamplePtr buffer, sampleFormat format, size_t len)
 
void AppendSharedBlock (const SeqBlock::SampleBlockPtr &pBlock)
 Append a complete block, not coalescing. More...
 
void Delete (sampleCount start, sampleCount len)
 
void SetSilence (sampleCount s0, sampleCount len)
 
void InsertSilence (sampleCount s0, sampleCount len)
 
const SampleBlockFactoryPtrGetFactory ()
 
bool HandleXMLTag (const std::string_view &tag, const AttributesList &attrs) override
 
void HandleXMLEndTag (const std::string_view &tag) override
 
XMLTagHandlerHandleXMLChild (const std::string_view &tag) override
 
void WriteXML (XMLWriter &xmlFile) const
 
bool GetErrorOpening ()
 
bool CloseLock ()
 
SampleFormats GetSampleFormats () const
 
bool ConvertToSampleFormat (sampleFormat format, const std::function< void(size_t)> &progressReport={})
 
std::pair< float, float > GetMinMax (sampleCount start, sampleCount len, bool mayThrow) const
 
float GetRMS (sampleCount start, sampleCount len, bool mayThrow) const
 
sampleCount GetBlockStart (sampleCount position) const
 
size_t GetBestBlockSize (sampleCount start) const
 
size_t GetMaxBlockSize () const
 
size_t GetIdealBlockSize () const
 
BlockArrayGetBlockArray ()
 
const BlockArrayGetBlockArray () const
 
size_t GetAppendBufferLen () const
 
constSamplePtr GetAppendBuffer () const
 
int FindBlock (sampleCount pos) const
 
void ConsistencyCheck (const wxChar *whereStr, bool mayThrow=true) const
 
- Public Member Functions inherited from XMLTagHandler
 XMLTagHandler ()
 
virtual ~XMLTagHandler ()
 
virtual bool HandleXMLTag (const std::string_view &tag, const AttributesList &attrs)=0
 
virtual void HandleXMLEndTag (const std::string_view &WXUNUSED(tag))
 
virtual void HandleXMLContent (const std::string_view &WXUNUSED(content))
 
virtual XMLTagHandlerHandleXMLChild (const std::string_view &tag)=0
 
void ReadXMLEndTag (const char *tag)
 
void ReadXMLContent (const char *s, int len)
 
XMLTagHandlerReadXMLChild (const char *tag)
 

Static Public Member Functions

static void SetMaxDiskBlockSize (size_t bytes)
 
static size_t GetMaxDiskBlockSize ()
 
static bool IsValidSampleFormat (const int nValue)
 true if nValue is one of the sampleFormat enum values More...
 
static bool Read (samplePtr buffer, sampleFormat format, const SeqBlock &b, size_t blockRelativeStart, size_t len, bool mayThrow)
 
static void DebugPrintf (const BlockArray &block, sampleCount numSamples, wxString *dest)
 

Private Member Functions

SeqBlock::SampleBlockPtr DoAppend (constSamplePtr buffer, sampleFormat format, size_t len, bool coalesce)
 Does not do any dithering. More...
 
bool Get (int b, samplePtr buffer, sampleFormat format, sampleCount start, size_t len, bool mayThrow) const
 
void CommitChangesIfConsistent (BlockArray &newBlock, sampleCount numSamples, const wxChar *whereStr)
 
void AppendBlocksIfConsistent (BlockArray &additionalBlocks, bool replaceLast, sampleCount numSamples, const wxChar *whereStr)
 

Static Private Member Functions

static void AppendBlock (SampleBlockFactory *pFactory, sampleFormat format, BlockArray &blocks, sampleCount &numSamples, const SeqBlock &b)
 
static void Blockify (SampleBlockFactory &factory, size_t maxSamples, sampleFormat format, BlockArray &list, sampleCount start, constSamplePtr buffer, size_t len)
 
static void ConsistencyCheck (const BlockArray &block, size_t maxSamples, size_t from, sampleCount numSamples, const wxChar *whereStr, bool mayThrow=true)
 

Private Attributes

SampleBlockFactoryPtr mpFactory
 
BlockArray mBlock
 
SampleFormats mSampleFormats
 
sampleCount mNumSamples { 0 }
 
size_t mMinSamples
 
size_t mMaxSamples
 
SampleBuffer mAppendBuffer {}
 
size_t mAppendBufferLen { 0 }
 
sampleFormat mAppendEffectiveFormat { narrowestSampleFormat }
 
bool mErrorOpening { false }
 

Static Private Attributes

static size_t sMaxDiskBlockSize = 1048576
 

Detailed Description

A WaveTrack contains WaveClip(s). A WaveClip contains a Sequence. A Sequence is primarily an interface to an array of SeqBlock instances, corresponding to the audio sample blocks in the database. Contrast with RingBuffer.

Definition at line 61 of file Sequence.h.

Constructor & Destructor Documentation

◆ Sequence() [1/3]

Sequence::Sequence ( const SampleBlockFactoryPtr pFactory,
SampleFormats  formats 
)

Definition at line 51 of file Sequence.cpp.

53: mpFactory(pFactory),
54 mSampleFormats{ formats },
57{
58}
#define SAMPLE_SIZE(SampleFormat)
Definition: SampleFormat.h:50
sampleFormat Stored() const
Definition: SampleFormat.h:89
SampleBlockFactoryPtr mpFactory
Definition: Sequence.h:235
static size_t sMaxDiskBlockSize
Definition: Sequence.h:229
size_t mMinSamples
Definition: Sequence.h:243
size_t mMaxSamples
Definition: Sequence.h:244
SampleFormats mSampleFormats
Definition: Sequence.h:238

◆ Sequence() [2/3]

Sequence::Sequence ( const Sequence orig,
const SampleBlockFactoryPtr pFactory 
)

Definition at line 63 of file Sequence.cpp.

65: mpFactory(pFactory),
69{
70 Paste(0, &orig);
71}
void Paste(sampleCount s0, const Sequence *src)
Definition: Sequence.cpp:494

References Paste().

Here is the call graph for this function:

◆ Sequence() [3/3]

Sequence::Sequence ( const Sequence )
delete

◆ ~Sequence()

Sequence::~Sequence ( )

Definition at line 73 of file Sequence.cpp.

74{
75}

Member Function Documentation

◆ Append()

bool Sequence::Append ( constSamplePtr  buffer,
sampleFormat  format,
size_t  len,
size_t  stride,
sampleFormat  effectiveFormat 
)

Samples may be retained in a memory buffer, pending Flush() If there are exceptions, an unspecified prefix of buffer may be appended

Returns
true if at least one sample block was added
Exception safety guarantee:
Weak
Exception safety guarantee:
Weak
Parameters
effectiveFormatMake the effective format of the data at least the minumum of this value and `format`. (Maybe wider, if merging with preexistent data.) If the data are later narrowed from stored format, but not narrower than the effective, then no dithering will occur.

Definition at line 1321 of file Sequence.cpp.

1324{
1325 effectiveFormat = std::min(effectiveFormat, format);
1326 const auto seqFormat = mSampleFormats.Stored();
1327 if (!mAppendBuffer.ptr())
1329
1330 bool result = false;
1331 auto blockSize = GetIdealAppendLen();
1332 for(;;) {
1333 if (mAppendBufferLen >= blockSize) {
1334 // flush some previously appended contents
1335 // use Strong-guarantee
1336 // Already dithered if needed when accumulated into mAppendBuffer
1337 DoAppend(mAppendBuffer.ptr(), seqFormat, blockSize, true);
1338 // Change our effective format now that DoAppend didn't throw
1340 result = true;
1341
1342 // use No-fail-guarantee for rest of this "if"
1343 memmove(mAppendBuffer.ptr(),
1344 mAppendBuffer.ptr() + blockSize * SAMPLE_SIZE(seqFormat),
1345 (mAppendBufferLen - blockSize) * SAMPLE_SIZE(seqFormat));
1346 mAppendBufferLen -= blockSize;
1347 blockSize = GetIdealAppendLen();
1348 }
1349
1350 if (len == 0)
1351 break;
1352
1353 // use No-fail-guarantee for rest of this "for"
1354 wxASSERT(mAppendBufferLen <= mMaxSamples);
1355 auto toCopy = std::min(len, mMaxSamples - mAppendBufferLen);
1356
1357 // If dithering of appended material is done at all, it happens here
1358 CopySamples(buffer, format,
1360 seqFormat,
1361 toCopy,
1362 (seqFormat < effectiveFormat ? gHighQualityDither : DitherType::none),
1363 stride);
1365 std::max(mAppendEffectiveFormat, effectiveFormat);
1366
1367 mAppendBufferLen += toCopy;
1368 buffer += toCopy * SAMPLE_SIZE(format) * stride;
1369 len -= toCopy;
1370 }
1371
1372 return result;
1373}
int min(int a, int b)
@ none
Definition: Dither.h:20
int format
Definition: ExportPCM.cpp:53
DitherType gHighQualityDither
void CopySamples(constSamplePtr src, sampleFormat srcFormat, samplePtr dst, sampleFormat dstFormat, size_t len, DitherType ditherType, unsigned int srcStride, unsigned int dstStride)
Copy samples from any format to any other format; apply dithering only if narrowing the format.
SampleBuffer & Allocate(size_t count, sampleFormat format)
Definition: SampleFormat.h:138
samplePtr ptr() const
Definition: SampleFormat.h:152
void UpdateEffective(sampleFormat effective)
Update the effective format, for insertion of more samples into the sequence.
Definition: SampleFormat.h:96
sampleFormat mAppendEffectiveFormat
Definition: Sequence.h:248
size_t mAppendBufferLen
Definition: Sequence.h:247
SeqBlock::SampleBlockPtr DoAppend(constSamplePtr buffer, sampleFormat format, size_t len, bool coalesce)
Does not do any dithering.
Definition: Sequence.cpp:1376
size_t GetIdealAppendLen() const
Definition: Sequence.cpp:1270
SampleBuffer mAppendBuffer
Definition: Sequence.h:246

References SampleBuffer::Allocate(), CopySamples(), DoAppend(), format, GetIdealAppendLen(), gHighQualityDither, mAppendBuffer, mAppendBufferLen, mAppendEffectiveFormat, min(), mMaxSamples, mSampleFormats, none, SampleBuffer::ptr(), SAMPLE_SIZE, SampleFormats::Stored(), and SampleFormats::UpdateEffective().

Here is the call graph for this function:

◆ AppendBlock()

void Sequence::AppendBlock ( SampleBlockFactory pFactory,
sampleFormat  format,
BlockArray blocks,
sampleCount numSamples,
const SeqBlock b 
)
staticprivate

Definition at line 757 of file Sequence.cpp.

759{
760 // Quick check to make sure that it doesn't overflow
761 if (Overflows((mNumSamples.as_double()) + ((double)b.sb->GetSampleCount())))
763
764 auto sb = ShareOrCopySampleBlock( pFactory, format, b.sb );
765 SeqBlock newBlock(sb, mNumSamples);
766
767 // We can assume newBlock.sb is not null
768
769 mBlock.push_back(newBlock);
770 mNumSamples += newBlock.sb->GetSampleCount();
771
772 // Don't do a consistency check here because this
773 // function gets called in an inner loop.
774}
#define THROW_INCONSISTENCY_EXCEPTION
Throw InconsistencyException, using C++ preprocessor to identify the source code location.
Data structure containing pointer to a sample block and a start time. Element of a BlockArray.
Definition: Sequence.h:28
SampleBlockPtr sb
Definition: Sequence.h:31
BlockArray mBlock
Definition: Sequence.h:237
sampleCount mNumSamples
Definition: Sequence.h:241
double as_double() const
Definition: SampleCount.h:46
bool Overflows(double numSamples)
Definition: Sequence.cpp:471
SampleBlockPtr ShareOrCopySampleBlock(SampleBlockFactory *pFactory, sampleFormat format, SampleBlockPtr sb)
Definition: Sequence.cpp:476

References sampleCount::as_double(), format, mBlock, mNumSamples, anonymous_namespace{Sequence.cpp}::Overflows(), SeqBlock::sb, anonymous_namespace{Sequence.cpp}::ShareOrCopySampleBlock(), and THROW_INCONSISTENCY_EXCEPTION.

Referenced by Copy(), and Paste().

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

◆ AppendBlocksIfConsistent()

void Sequence::AppendBlocksIfConsistent ( BlockArray additionalBlocks,
bool  replaceLast,
sampleCount  numSamples,
const wxChar *  whereStr 
)
private

Definition at line 1767 of file Sequence.cpp.

1770{
1771 // Any additional blocks are meant to be appended,
1772 // replacing the final block if there was one.
1773
1774 if (additionalBlocks.empty())
1775 return;
1776
1777 bool tmpValid = false;
1778 SeqBlock tmp;
1779
1780 if ( replaceLast && ! mBlock.empty() ) {
1781 tmp = mBlock.back(), tmpValid = true;
1782 mBlock.pop_back();
1783 }
1784
1785 auto prevSize = mBlock.size();
1786
1787 bool consistent = false;
1788 auto cleanup = finally( [&] {
1789 if ( !consistent ) {
1790 mBlock.resize( prevSize );
1791 if ( tmpValid )
1792 mBlock.push_back( tmp );
1793 }
1794 } );
1795
1796 std::copy( additionalBlocks.begin(), additionalBlocks.end(),
1797 std::back_inserter( mBlock ) );
1798
1799 // Check consistency only of the blocks that were added,
1800 // avoiding quadratic time for repeated checking of repeating appends
1801 ConsistencyCheck( mBlock, mMaxSamples, prevSize, numSamples, whereStr ); // may throw
1802
1803 // now commit
1804 // use No-fail-guarantee
1805
1806 mNumSamples = numSamples;
1807 consistent = true;
1808}
void ConsistencyCheck(const wxChar *whereStr, bool mayThrow=true) const
Definition: Sequence.cpp:1699

References ConsistencyCheck(), mBlock, mMaxSamples, and mNumSamples.

Referenced by AppendSharedBlock(), and DoAppend().

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

◆ AppendNewBlock()

SeqBlock::SampleBlockPtr Sequence::AppendNewBlock ( constSamplePtr  buffer,
sampleFormat  format,
size_t  len 
)

Append data, not coalescing blocks, returning a pointer to the new block. No dithering applied.

Exception safety guarantee:
Strong
Exception safety guarantee:
Strong

Definition at line 1286 of file Sequence.cpp.

1288{
1289 // Come here only when importing old .aup projects
1290 auto result = DoAppend( buffer, format, len, false );
1291 // Change our effective format now that DoAppend didn't throw
1293 return result;
1294}

References DoAppend(), format, mSampleFormats, and SampleFormats::UpdateEffective().

Here is the call graph for this function:

◆ AppendSharedBlock()

void Sequence::AppendSharedBlock ( const SeqBlock::SampleBlockPtr pBlock)

Append a complete block, not coalescing.

Exception safety guarantee:
Strong

Definition at line 1297 of file Sequence.cpp.

1298{
1299 auto len = pBlock->GetSampleCount();
1300
1301 // Quick check to make sure that it doesn't overflow
1302 if (Overflows(mNumSamples.as_double() + ((double)len)))
1304
1305 BlockArray newBlock;
1306 newBlock.emplace_back( pBlock, mNumSamples );
1307 auto newNumSamples = mNumSamples + len;
1308
1309 AppendBlocksIfConsistent(newBlock, false,
1310 newNumSamples, wxT("Append"));
1311
1312// JKC: During generate we use Append again and again.
1313// If generating a long sequence this test would give O(n^2)
1314// performance - not good!
1315#ifdef VERY_SLOW_CHECKING
1316 ConsistencyCheck(wxT("Append"));
1317#endif
1318}
wxT("CloseDown"))
void AppendBlocksIfConsistent(BlockArray &additionalBlocks, bool replaceLast, sampleCount numSamples, const wxChar *whereStr)
Definition: Sequence.cpp:1768

References AppendBlocksIfConsistent(), sampleCount::as_double(), ConsistencyCheck(), mNumSamples, anonymous_namespace{Sequence.cpp}::Overflows(), THROW_INCONSISTENCY_EXCEPTION, and wxT().

Here is the call graph for this function:

◆ Blockify()

void Sequence::Blockify ( SampleBlockFactory factory,
size_t  maxSamples,
sampleFormat  format,
BlockArray list,
sampleCount  start,
constSamplePtr  buffer,
size_t  len 
)
staticprivate

Definition at line 1498 of file Sequence.cpp.

1502{
1503 if (len <= 0)
1504 return;
1505
1506 auto num = (len + (mMaxSamples - 1)) / mMaxSamples;
1507 list.reserve(list.size() + num);
1508
1509 for (decltype(num) i = 0; i < num; i++) {
1510 SeqBlock b;
1511
1512 const auto offset = i * len / num;
1513 b.start = start + offset;
1514 int newLen = ((i + 1) * len / num) - offset;
1515 auto bufStart = buffer + (offset * SAMPLE_SIZE(mSampleFormat));
1516
1517 b.sb = factory.Create(bufStart, newLen, mSampleFormat);
1518
1519 list.push_back(b);
1520 }
1521}
sampleCount start
the sample in the global wavetrack that this block starts at.
Definition: Sequence.h:33
static RegisteredToolbarFactory factory

References cloud::factory, mMaxSamples, SAMPLE_SIZE, SeqBlock::sb, and SeqBlock::start.

Referenced by ConvertToSampleFormat(), Delete(), and Paste().

Here is the caller graph for this function:

◆ CloseLock()

bool Sequence::CloseLock ( )

Definition at line 87 of file Sequence.cpp.

88{
89 for (unsigned int i = 0; i < mBlock.size(); i++)
90 mBlock[i].sb->CloseLock();
91
92 return true;
93}

References mBlock.

Referenced by WaveClip::CloseLock().

Here is the caller graph for this function:

◆ CommitChangesIfConsistent()

void Sequence::CommitChangesIfConsistent ( BlockArray newBlock,
sampleCount  numSamples,
const wxChar *  whereStr 
)
private

Definition at line 1755 of file Sequence.cpp.

1757{
1758 ConsistencyCheck( newBlock, mMaxSamples, 0, numSamples, whereStr ); // may throw
1759
1760 // now commit
1761 // use No-fail-guarantee
1762
1763 mBlock.swap(newBlock);
1764 mNumSamples = numSamples;
1765}

References ConsistencyCheck(), mBlock, mMaxSamples, and mNumSamples.

Referenced by ConvertToSampleFormat(), Delete(), Paste(), and SetSamples().

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

◆ ConsistencyCheck() [1/2]

static void Sequence::ConsistencyCheck ( const BlockArray block,
size_t  maxSamples,
size_t  from,
sampleCount  numSamples,
const wxChar *  whereStr,
bool  mayThrow = true 
)
staticprivate

◆ ConsistencyCheck() [2/2]

void Sequence::ConsistencyCheck ( const wxChar *  whereStr,
bool  mayThrow = true 
) const

Definition at line 1699 of file Sequence.cpp.

1700{
1701 ConsistencyCheck(mBlock, mMaxSamples, 0, mNumSamples, whereStr, mayThrow);
1702}

References ConsistencyCheck(), mBlock, mMaxSamples, and mNumSamples.

Referenced by AppendBlocksIfConsistent(), AppendSharedBlock(), CommitChangesIfConsistent(), ConsistencyCheck(), Delete(), DoAppend(), and Paste().

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

◆ ConvertToSampleFormat()

bool Sequence::ConvertToSampleFormat ( sampleFormat  format,
const std::function< void(size_t)> &  progressReport = {} 
)
Returns
whether there was a change
Exception safety guarantee:
Strong
Exception safety guarantee:
Strong

Definition at line 137 of file Sequence.cpp.

139{
141 // no change
142 return false;
143
144 if (mBlock.size() == 0)
145 {
146 // Effective format can be made narrowest when there is no content
148 return true;
149 }
150
151 // Decide the new pair of formats. If becoming narrower than the effective,
152 // this will change the effective.
154
155 const auto oldFormats = mSampleFormats;
156 mSampleFormats = newFormats;
157
158 const auto oldMinSamples = mMinSamples, oldMaxSamples = mMaxSamples;
159 // These are the same calculations as in the constructor.
162
163 bool bSuccess = false;
164 auto cleanup = finally( [&] {
165 if (!bSuccess) {
166 // Conversion failed. Revert these member vars.
167 mSampleFormats = oldFormats;
168 mMaxSamples = oldMaxSamples;
169 mMinSamples = oldMinSamples;
170 }
171 } );
172
173 BlockArray newBlockArray;
174 // Use the ratio of old to NEW mMaxSamples to make a reasonable guess
175 // at allocation.
176 newBlockArray.reserve
177 (1 + mBlock.size() * ((float)oldMaxSamples / (float)mMaxSamples));
178
179 {
180 size_t oldSize = oldMaxSamples;
181 SampleBuffer bufferOld(oldSize, oldFormats.Stored());
182 size_t newSize = oldMaxSamples;
183 SampleBuffer bufferNew(newSize, format);
184
185 for (size_t i = 0, nn = mBlock.size(); i < nn; i++)
186 {
187 SeqBlock &oldSeqBlock = mBlock[i];
188 const auto &oldBlockFile = oldSeqBlock.sb;
189 const auto len = oldBlockFile->GetSampleCount();
190 ensureSampleBufferSize(bufferOld, oldFormats.Stored(), oldSize, len);
191
192 // Dither won't happen here, reading back the same as-saved format
193 Read(bufferOld.ptr(), oldFormats.Stored(), oldSeqBlock, 0, len, true);
194
195 ensureSampleBufferSize(bufferNew, format, newSize, len);
196
198 bufferOld.ptr(), oldFormats.Stored(), bufferNew.ptr(), format, len,
199 // Do not dither to reformat samples if format is at least as wide
200 // as the old effective (though format might be narrower than the
201 // old stored).
202 format < oldFormats.Effective()
205
206 // Note this fix for http://bugzilla.audacityteam.org/show_bug.cgi?id=451,
207 // using Blockify, allows (len < mMinSamples).
208 // This will happen consistently when going from more bytes per sample to fewer...
209 // This will create a block that's smaller than mMinSamples, which
210 // shouldn't be allowed, but we agreed it's okay for now.
211 //vvv ANSWER-ME: Does this cause any bugs, or failures on write, elsewhere?
212 // If so, need to special-case (len < mMinSamples) and start combining data
213 // from the old blocks... Oh no!
214
215 // Using Blockify will handle the cases where len > the NEW mMaxSamples. Previous code did not.
216 const auto blockstart = oldSeqBlock.start;
218 newBlockArray, blockstart, bufferNew.ptr(), len);
219
220 if (progressReport)
221 progressReport(len);
222 }
223 }
224
225 // Invalidate all the old, non-aliased block files.
226 // Aliased files will be converted at save, per comment above.
227
228 // Commit the changes to block file array
230 (newBlockArray, mNumSamples, wxT("Sequence::ConvertToSampleFormat()"));
231
232 // Commit the other changes
233 bSuccess = true;
234
235 return true;
236}
@ narrowestSampleFormat
Two synonyms for previous values that might change if more values were added.
Two sample formats, remembering format of original source and describing stored format.
Definition: SampleFormat.h:77
sampleFormat Effective() const
Definition: SampleFormat.h:88
void CommitChangesIfConsistent(BlockArray &newBlock, sampleCount numSamples, const wxChar *whereStr)
Definition: Sequence.cpp:1756
static bool Read(samplePtr buffer, sampleFormat format, const SeqBlock &b, size_t blockRelativeStart, size_t len, bool mayThrow)
Definition: Sequence.cpp:1091
static void Blockify(SampleBlockFactory &factory, size_t maxSamples, sampleFormat format, BlockArray &list, sampleCount start, constSamplePtr buffer, size_t len)
Definition: Sequence.cpp:1498
void ensureSampleBufferSize(SampleBuffer &buffer, sampleFormat format, size_t &size, size_t required, SampleBuffer *pSecondBuffer=nullptr)
Definition: Sequence.cpp:112

References Blockify(), CommitChangesIfConsistent(), CopySamples(), SampleFormats::Effective(), anonymous_namespace{Sequence.cpp}::ensureSampleBufferSize(), format, gHighQualityDither, mBlock, mMaxSamples, mMinSamples, mNumSamples, mpFactory, mSampleFormats, narrowestSampleFormat, none, SampleBuffer::ptr(), Read(), SAMPLE_SIZE, SeqBlock::sb, sMaxDiskBlockSize, SeqBlock::start, SampleFormats::Stored(), and wxT().

Referenced by AUPImportFileHandle::HandleSequence().

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

◆ Copy()

std::unique_ptr< Sequence > Sequence::Copy ( const SampleBlockFactoryPtr pFactory,
sampleCount  s0,
sampleCount  s1 
) const

Definition at line 389 of file Sequence.cpp.

391{
392 // Make a new Sequence object for the specified factory:
393 auto dest = std::make_unique<Sequence>(pFactory, mSampleFormats);
394 if (s0 >= s1 || s0 >= mNumSamples || s1 < 0) {
395 return dest;
396 }
397
398 // Decide whether to share sample blocks or make new copies, when whole block
399 // contents are used -- must copy if factories are different:
400 auto pUseFactory = (pFactory == mpFactory) ? nullptr : pFactory.get();
401
402 int numBlocks = mBlock.size();
403
404 int b0 = FindBlock(s0);
405 const int b1 = FindBlock(s1 - 1);
406 wxASSERT(b0 >= 0);
407 wxASSERT(b0 < numBlocks);
408 wxASSERT(b1 < numBlocks);
409 wxUnusedVar(numBlocks);
410 wxASSERT(b0 <= b1);
411
412 dest->mBlock.reserve(b1 - b0 + 1);
413
414 auto bufferSize = mMaxSamples;
415 const auto format = mSampleFormats.Stored();
416 SampleBuffer buffer(bufferSize, format);
417
418 int blocklen;
419
420 // Do any initial partial block
421
422 const SeqBlock &block0 = mBlock[b0];
423 if (s0 != block0.start) {
424 const auto &sb = block0.sb;
425 // Nonnegative result is length of block0 or less:
426 blocklen =
427 ( std::min(s1, block0.start + sb->GetSampleCount()) - s0 ).as_size_t();
428 wxASSERT(blocklen <= (int)mMaxSamples); // Vaughan, 2012-02-29
429 ensureSampleBufferSize(buffer, format, bufferSize, blocklen);
430 Get(b0, buffer.ptr(), format, s0, blocklen, true);
431
432 dest->Append(
433 buffer.ptr(), format, blocklen, 1, mSampleFormats.Effective());
434 }
435 else
436 --b0;
437
438 // If there are blocks in the middle, use the blocks whole
439 for (int bb = b0 + 1; bb < b1; ++bb)
440 AppendBlock(pUseFactory, format,
441 dest->mBlock, dest->mNumSamples, mBlock[bb]);
442 // Increase ref count or duplicate file
443
444 // Do the last block
445 if (b1 > b0) {
446 // Probable case of a partial block
447 const SeqBlock &block = mBlock[b1];
448 const auto &sb = block.sb;
449 // s1 is within block:
450 blocklen = (s1 - block.start).as_size_t();
451 wxASSERT(blocklen <= (int)mMaxSamples); // Vaughan, 2012-02-29
452 if (blocklen < (int)sb->GetSampleCount()) {
453 ensureSampleBufferSize(buffer, format, bufferSize, blocklen);
454 Get(b1, buffer.ptr(), format, block.start, blocklen, true);
455 dest->Append(
456 buffer.ptr(), format, blocklen, 1, mSampleFormats.Effective());
457 }
458 else
459 // Special case of a whole block
460 AppendBlock(pUseFactory, format,
461 dest->mBlock, dest->mNumSamples, block);
462 // Increase ref count or duplicate file
463 }
464
465 dest->ConsistencyCheck(wxT("Sequence::Copy()"));
466
467 return dest;
468}
bool Get(samplePtr buffer, sampleFormat format, sampleCount start, size_t len, bool mayThrow) const
Definition: Sequence.cpp:1112
static void AppendBlock(SampleBlockFactory *pFactory, sampleFormat format, BlockArray &blocks, sampleCount &numSamples, const SeqBlock &b)
Definition: Sequence.cpp:757
int FindBlock(sampleCount pos) const
Definition: Sequence.cpp:1041

References AppendBlock(), SampleFormats::Effective(), anonymous_namespace{Sequence.cpp}::ensureSampleBufferSize(), FindBlock(), format, Get(), mBlock, min(), mMaxSamples, mNumSamples, mpFactory, mSampleFormats, SampleBuffer::ptr(), SeqBlock::sb, SeqBlock::start, SampleFormats::Stored(), and wxT().

Here is the call graph for this function:

◆ DebugPrintf()

void Sequence::DebugPrintf ( const BlockArray block,
sampleCount  numSamples,
wxString *  dest 
)
static

Definition at line 1810 of file Sequence.cpp.

1812{
1813 unsigned int i;
1814 decltype(mNumSamples) pos = 0;
1815
1816 for (i = 0; i < mBlock.size(); i++) {
1817 const SeqBlock &seqBlock = mBlock[i];
1818 *dest += wxString::Format
1819 (wxT(" Block %3u: start %8lld, len %8lld, refs %ld, id %lld"),
1820 i,
1821 seqBlock.start.as_long_long(),
1822 seqBlock.sb ? (long long) seqBlock.sb->GetSampleCount() : 0,
1823 seqBlock.sb ? seqBlock.sb.use_count() : 0,
1824 seqBlock.sb ? (long long) seqBlock.sb->GetBlockID() : 0);
1825
1826 if ((pos != seqBlock.start) || !seqBlock.sb)
1827 *dest += wxT(" ERROR\n");
1828 else
1829 *dest += wxT("\n");
1830
1831 if (seqBlock.sb)
1832 pos += seqBlock.sb->GetSampleCount();
1833 }
1834 if (pos != mNumSamples)
1835 *dest += wxString::Format
1836 (wxT("ERROR mNumSamples = %lld\n"), mNumSamples.as_long_long());
1837}
long long as_long_long() const
Definition: SampleCount.h:48

References sampleCount::as_long_long(), mBlock, mNumSamples, SeqBlock::sb, SeqBlock::start, and wxT().

Here is the call graph for this function:

◆ Delete()

void Sequence::Delete ( sampleCount  start,
sampleCount  len 
)
Exception safety guarantee:
Strong

Definition at line 1524 of file Sequence.cpp.

1525{
1526 if (len == 0)
1527 return;
1528
1529 if (len < 0 || start < 0 || start + len > mNumSamples)
1531
1532 auto &factory = *mpFactory;
1533
1534 const unsigned int numBlocks = mBlock.size();
1535
1536 const unsigned int b0 = FindBlock(start);
1537 unsigned int b1 = FindBlock(start + len - 1);
1538
1539 const auto format = mSampleFormats.Stored();
1540 auto sampleSize = SAMPLE_SIZE(format);
1541
1542 SeqBlock *pBlock;
1543 decltype(pBlock->sb->GetSampleCount()) length;
1544
1545 // One buffer for reuse in various branches here
1546 SampleBuffer scratch;
1547 // The maximum size that should ever be needed
1548 auto scratchSize = mMaxSamples + mMinSamples;
1549
1550 // Special case: if the samples to DELETE are all within a single
1551 // block and the resulting length is not too small, perform the
1552 // deletion within this block:
1553 if (b0 == b1 &&
1554 (length = (pBlock = &mBlock[b0])->sb->GetSampleCount()) - len >= mMinSamples) {
1555 SeqBlock &b = *pBlock;
1556 // start is within block
1557 auto pos = ( start - b.start ).as_size_t();
1558
1559 // Guard against failure of this anyway below with limitSampleBufferSize
1560 wxASSERT(len < length);
1561
1562 // len must be less than length
1563 // because start + len - 1 is also in the block...
1564 auto newLen = ( length - limitSampleBufferSize( length, len ) );
1565
1566 scratch.Allocate(scratchSize, format);
1567 ensureSampleBufferSize(scratch, format, scratchSize, newLen);
1568
1569 Read(scratch.ptr(), format, b, 0, pos, true);
1570 Read(scratch.ptr() + (pos * sampleSize), format,
1571 b,
1572 // ... and therefore pos + len
1573 // is not more than the length of the block
1574 ( pos + len ).as_size_t(), newLen - pos, true);
1575
1576 b.sb = factory.Create(scratch.ptr(), newLen, format);
1577
1578 // Don't make a duplicate array. We can still give Strong-guarantee
1579 // if we modify only one block in place.
1580
1581 // use No-fail-guarantee in remaining steps
1582
1583 for (unsigned int j = b0 + 1; j < numBlocks; j++)
1584 mBlock[j].start -= len;
1585
1586 mNumSamples -= len;
1587
1588 // This consistency check won't throw, it asserts.
1589 // Proof that we kept consistency is not hard.
1590 ConsistencyCheck(wxT("Delete - branch one"), false);
1591 return;
1592 }
1593
1594 // Create a NEW array of blocks
1595 BlockArray newBlock;
1596 newBlock.reserve(numBlocks - (b1 - b0) + 2);
1597
1598 // Copy the blocks before the deletion point over to
1599 // the NEW array
1600 newBlock.insert(newBlock.end(), mBlock.begin(), mBlock.begin() + b0);
1601 unsigned int i;
1602
1603 // First grab the samples in block b0 before the deletion point
1604 // into preBuffer. If this is enough samples for its own block,
1605 // or if this would be the first block in the array, write it out.
1606 // Otherwise combine it with the previous block (splitting them
1607 // 50/50 if necessary).
1608 const SeqBlock &preBlock = mBlock[b0];
1609 // start is within preBlock
1610 auto preBufferLen = ( start - preBlock.start ).as_size_t();
1611 if (preBufferLen) {
1612 if (preBufferLen >= mMinSamples || b0 == 0) {
1613 if (!scratch.ptr())
1614 scratch.Allocate(scratchSize, format);
1615 ensureSampleBufferSize(scratch, format, scratchSize, preBufferLen);
1616 Read(scratch.ptr(), format, preBlock, 0, preBufferLen, true);
1617 auto pFile =
1618 factory.Create(scratch.ptr(), preBufferLen, format);
1619
1620 newBlock.push_back(SeqBlock(pFile, preBlock.start));
1621 } else {
1622 const SeqBlock &prepreBlock = mBlock[b0 - 1];
1623 const auto prepreLen = prepreBlock.sb->GetSampleCount();
1624 const auto sum = prepreLen + preBufferLen;
1625
1626 if (!scratch.ptr())
1627 scratch.Allocate(scratchSize, format);
1628 ensureSampleBufferSize(scratch, format, scratchSize,
1629 sum);
1630
1631 Read(scratch.ptr(), format, prepreBlock, 0, prepreLen, true);
1632 Read(scratch.ptr() + prepreLen*sampleSize, format,
1633 preBlock, 0, preBufferLen, true);
1634
1635 newBlock.pop_back();
1637 newBlock, prepreBlock.start, scratch.ptr(), sum);
1638 }
1639 }
1640 else {
1641 // The sample where we begin deletion happens to fall
1642 // right on the beginning of a block.
1643 }
1644
1645 // Now, symmetrically, grab the samples in block b1 after the
1646 // deletion point into postBuffer. If this is enough samples
1647 // for its own block, or if this would be the last block in
1648 // the array, write it out. Otherwise combine it with the
1649 // subsequent block (splitting them 50/50 if necessary).
1650 const SeqBlock &postBlock = mBlock[b1];
1651 // start + len - 1 lies within postBlock
1652 const auto postBufferLen = (
1653 (postBlock.start + postBlock.sb->GetSampleCount()) - (start + len)
1654 ).as_size_t();
1655 if (postBufferLen) {
1656 if (postBufferLen >= mMinSamples || b1 == numBlocks - 1) {
1657 if (!scratch.ptr())
1658 // Last use of scratch, can ask for smaller
1659 scratch.Allocate(postBufferLen, format);
1660 // start + len - 1 lies within postBlock
1661 auto pos = (start + len - postBlock.start).as_size_t();
1662 Read(scratch.ptr(), format, postBlock, pos, postBufferLen, true);
1663 auto file =
1664 factory.Create(scratch.ptr(), postBufferLen, format);
1665
1666 newBlock.push_back(SeqBlock(file, start));
1667 } else {
1668 SeqBlock &postpostBlock = mBlock[b1 + 1];
1669 const auto postpostLen = postpostBlock.sb->GetSampleCount();
1670 const auto sum = postpostLen + postBufferLen;
1671
1672 if (!scratch.ptr())
1673 // Last use of scratch, can ask for smaller
1674 scratch.Allocate(sum, format);
1675 // start + len - 1 lies within postBlock
1676 auto pos = (start + len - postBlock.start).as_size_t();
1677 Read(scratch.ptr(), format, postBlock, pos, postBufferLen, true);
1678 Read(scratch.ptr() + (postBufferLen * sampleSize), format,
1679 postpostBlock, 0, postpostLen, true);
1680
1682 newBlock, start, scratch.ptr(), sum);
1683 b1++;
1684 }
1685 }
1686 else {
1687 // The sample where we begin deletion happens to fall
1688 // right on the end of a block.
1689 }
1690
1691 // Copy the remaining blocks over from the old array
1692 for (i = b1 + 1; i < numBlocks; i++)
1693 newBlock.push_back(mBlock[i].Plus(-len));
1694
1696 (newBlock, mNumSamples - len, wxT("Delete - branch two"));
1697}
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: SampleCount.cpp:22

References SampleBuffer::Allocate(), Blockify(), CommitChangesIfConsistent(), ConsistencyCheck(), anonymous_namespace{Sequence.cpp}::ensureSampleBufferSize(), cloud::factory, FindBlock(), format, limitSampleBufferSize(), mBlock, mMaxSamples, mMinSamples, mNumSamples, mpFactory, mSampleFormats, SampleBuffer::ptr(), Read(), SAMPLE_SIZE, SeqBlock::sb, SeqBlock::start, SampleFormats::Stored(), THROW_INCONSISTENCY_EXCEPTION, and wxT().

Referenced by WaveClip::ClearAndAddCutLine(), and WaveClip::ClearSequence().

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

◆ DoAppend()

SeqBlock::SampleBlockPtr Sequence::DoAppend ( constSamplePtr  buffer,
sampleFormat  format,
size_t  len,
bool  coalesce 
)
private

Does not do any dithering.

Exception safety guarantee:
Strong

Definition at line 1376 of file Sequence.cpp.

1378{
1380
1381 if (len == 0)
1382 return result;
1383
1384 auto &factory = *mpFactory;
1385
1386 // Quick check to make sure that it doesn't overflow
1387 if (Overflows(mNumSamples.as_double() + ((double)len)))
1389
1390 BlockArray newBlock;
1391 sampleCount newNumSamples = mNumSamples;
1392
1393 // If the last block is not full, we need to add samples to it
1394 int numBlocks = mBlock.size();
1395 SeqBlock *pLastBlock;
1396 decltype(pLastBlock->sb->GetSampleCount()) length;
1397 size_t bufferSize = mMaxSamples;
1398 const auto dstFormat = mSampleFormats.Stored();
1399 SampleBuffer buffer2(bufferSize, dstFormat);
1400 bool replaceLast = false;
1401 if (coalesce &&
1402 numBlocks > 0 &&
1403 (length =
1404 (pLastBlock = &mBlock.back())->sb->GetSampleCount()) < mMinSamples) {
1405 // Enlarge a sub-minimum block at the end
1406 const SeqBlock &lastBlock = *pLastBlock;
1407 const auto addLen = std::min(mMaxSamples - length, len);
1408
1409 // Reading same format as was saved before causes no dithering
1410 Read(buffer2.ptr(), dstFormat, lastBlock, 0, length, true);
1411
1412 CopySamples(buffer,
1413 format,
1414 buffer2.ptr() + length * SAMPLE_SIZE(dstFormat),
1415 dstFormat,
1416 addLen, DitherType::none);
1417
1418 const auto newLastBlockLen = length + addLen;
1419 SampleBlockPtr pBlock = factory.Create(
1420 buffer2.ptr(),
1421 newLastBlockLen,
1422 dstFormat);
1423 SeqBlock newLastBlock(pBlock, lastBlock.start);
1424
1425 newBlock.push_back( newLastBlock );
1426
1427 len -= addLen;
1428 newNumSamples += addLen;
1429 buffer += addLen * SAMPLE_SIZE(format);
1430
1431 replaceLast = true;
1432 }
1433 // Append the rest as NEW blocks
1434 while (len) {
1435 const auto idealSamples = GetIdealBlockSize();
1436 const auto addedLen = std::min(idealSamples, len);
1437 SampleBlockPtr pBlock;
1438 if (format == dstFormat) {
1439 pBlock = factory.Create(buffer, addedLen, dstFormat);
1440 // It's expected that when not requesting coalescence, the
1441 // data should fit in one block
1442 wxASSERT( coalesce || !result );
1443 result = pBlock;
1444 }
1445 else {
1446 CopySamples(buffer, format, buffer2.ptr(), dstFormat,
1447 addedLen, DitherType::none);
1448 pBlock = factory.Create(buffer2.ptr(), addedLen, dstFormat);
1449 }
1450
1451 newBlock.push_back(SeqBlock(pBlock, newNumSamples));
1452
1453 buffer += addedLen * SAMPLE_SIZE(format);
1454 newNumSamples += addedLen;
1455 len -= addedLen;
1456 }
1457
1458 AppendBlocksIfConsistent(newBlock, replaceLast,
1459 newNumSamples, wxT("Append"));
1460
1461// JKC: During generate we use Append again and again.
1462// If generating a long sequence this test would give O(n^2)
1463// performance - not good!
1464#ifdef VERY_SLOW_CHECKING
1465 ConsistencyCheck(wxT("Append"));
1466#endif
1467
1468 return result;
1469}
std::shared_ptr< SampleBlock > SampleBlockPtr
Definition: SampleBlock.h:27
std::shared_ptr< SampleBlock > SampleBlockPtr
Definition: Sequence.h:30
size_t GetIdealBlockSize() const
Definition: Sequence.cpp:82
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19

References AppendBlocksIfConsistent(), sampleCount::as_double(), ConsistencyCheck(), CopySamples(), cloud::factory, format, GetIdealBlockSize(), mBlock, min(), mMaxSamples, mMinSamples, mNumSamples, mpFactory, mSampleFormats, none, anonymous_namespace{Sequence.cpp}::Overflows(), SampleBuffer::ptr(), Read(), SAMPLE_SIZE, SeqBlock::sb, SeqBlock::start, SampleFormats::Stored(), THROW_INCONSISTENCY_EXCEPTION, and wxT().

Referenced by Append(), AppendNewBlock(), and Flush().

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

◆ FindBlock()

int Sequence::FindBlock ( sampleCount  pos) const

Definition at line 1041 of file Sequence.cpp.

1042{
1043 wxASSERT(pos >= 0 && pos < mNumSamples);
1044
1045 if (pos == 0)
1046 return 0;
1047
1048 int numBlocks = mBlock.size();
1049
1050 size_t lo = 0, hi = numBlocks, guess;
1051 sampleCount loSamples = 0, hiSamples = mNumSamples;
1052
1053 while (true) {
1054 //this is not a binary search, but a
1055 //dictionary search where we guess something smarter than the binary division
1056 //of the unsearched area, since samples are usually proportional to block file number.
1057 const double frac = (pos - loSamples).as_double() /
1058 (hiSamples - loSamples).as_double();
1059 guess = std::min(hi - 1, lo + size_t(frac * (hi - lo)));
1060 const SeqBlock &block = mBlock[guess];
1061
1062 wxASSERT(block.sb->GetSampleCount() > 0);
1063 wxASSERT(lo <= guess && guess < hi && lo < hi);
1064
1065 if (pos < block.start) {
1066 wxASSERT(lo != guess);
1067 hi = guess;
1068 hiSamples = block.start;
1069 }
1070 else {
1071 const sampleCount nextStart = block.start + block.sb->GetSampleCount();
1072 if (pos < nextStart)
1073 break;
1074 else {
1075 wxASSERT(guess < hi - 1);
1076 lo = guess + 1;
1077 loSamples = nextStart;
1078 }
1079 }
1080 }
1081
1082 const int rval = guess;
1083 wxASSERT(rval >= 0 && rval < numBlocks &&
1084 pos >= mBlock[rval].start &&
1085 pos < mBlock[rval].start + mBlock[rval].sb->GetSampleCount());
1086
1087 return rval;
1088}

References mBlock, min(), mNumSamples, SeqBlock::sb, and SeqBlock::start.

Referenced by Copy(), Delete(), Get(), GetBestBlockSize(), GetBlockStart(), GetMinMax(), GetRMS(), GetWaveDisplay(), Paste(), and SetSamples().

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

◆ Flush()

void Sequence::Flush ( )
Exception safety guarantee:
Mixed
Exception safety guarantee:
No-fail – The Sequence will be in a flushed state.
Exception safety guarantee:
Partial – Some initial portion (maybe none) of the append buffer of the Sequence gets appended; no previously flushed contents are lost.

Definition at line 1476 of file Sequence.cpp.

1477{
1478 if (mAppendBufferLen > 0) {
1479
1480 auto cleanup = finally( [&] {
1481 // Blow away the append buffer even in case of failure. May lose some
1482 // data but don't leave the sequence in an un-flushed state.
1483
1484 // Use No-fail-guarantee of these steps.
1485 mAppendBufferLen = 0;
1487 mAppendEffectiveFormat = narrowestSampleFormat; // defaulted again
1488 } );
1489
1490 // Already dithered if needed when accumulated into mAppendBuffer:
1492 mAppendBufferLen, true);
1493 // Change our effective format now that DoAppend didn't throw
1495 }
1496}

References DoAppend(), SampleBuffer::Free(), mAppendBuffer, mAppendBufferLen, mAppendEffectiveFormat, mSampleFormats, narrowestSampleFormat, SampleBuffer::ptr(), SampleFormats::Stored(), and SampleFormats::UpdateEffective().

Here is the call graph for this function:

◆ Get() [1/2]

bool Sequence::Get ( int  b,
samplePtr  buffer,
sampleFormat  format,
sampleCount  start,
size_t  len,
bool  mayThrow 
) const
private

Definition at line 1130 of file Sequence.cpp.

1132{
1133 bool result = true;
1134 while (len) {
1135 const SeqBlock &block = mBlock[b];
1136 // start is in block
1137 const auto bstart = (start - block.start).as_size_t();
1138 // bstart is not more than block length
1139 const auto blen = std::min(len, block.sb->GetSampleCount() - bstart);
1140
1141 if (! Read(buffer, format, block, bstart, blen, mayThrow) )
1142 result = false;
1143
1144 len -= blen;
1145 buffer += (blen * SAMPLE_SIZE(format));
1146 b++;
1147 start += blen;
1148 }
1149 return result;
1150}

References format, mBlock, min(), Read(), SAMPLE_SIZE, SeqBlock::sb, and SeqBlock::start.

Here is the call graph for this function:

◆ Get() [2/2]

bool Sequence::Get ( samplePtr  buffer,
sampleFormat  format,
sampleCount  start,
size_t  len,
bool  mayThrow 
) const

Definition at line 1112 of file Sequence.cpp.

1114{
1115 if (start == mNumSamples) {
1116 return len == 0;
1117 }
1118
1119 if (start < 0 || start + len > mNumSamples) {
1120 if (mayThrow)
1122 ClearSamples( buffer, floatSample, 0, len );
1123 return false;
1124 }
1125 int b = FindBlock(start);
1126
1127 return Get(b, buffer, format, start, len, mayThrow);
1128}
void ClearSamples(samplePtr dst, sampleFormat format, size_t start, size_t len)

References ClearSamples(), FindBlock(), floatSample, format, Get(), mNumSamples, and THROW_INCONSISTENCY_EXCEPTION.

Referenced by Copy(), Get(), and Paste().

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

◆ GetAppendBuffer()

constSamplePtr Sequence::GetAppendBuffer ( ) const
inline

Definition at line 221 of file Sequence.h.

221{ return mAppendBuffer.ptr(); }

Referenced by WaveClip::GetAppendBuffer().

Here is the caller graph for this function:

◆ GetAppendBufferLen()

size_t Sequence::GetAppendBufferLen ( ) const
inline

Definition at line 220 of file Sequence.h.

220{ return mAppendBufferLen; }

Referenced by WaveClip::GetAppendBufferLen().

Here is the caller graph for this function:

◆ GetBestBlockSize()

size_t Sequence::GetBestBlockSize ( sampleCount  start) const

Definition at line 782 of file Sequence.cpp.

783{
784 // This method returns a nice number of samples you should try to grab in
785 // one big chunk in order to land on a block boundary, based on the starting
786 // sample. The value returned will always be nonzero and will be no larger
787 // than the value of GetMaxBlockSize()
788
789 if (start < 0 || start >= mNumSamples)
790 return mMaxSamples;
791
792 int b = FindBlock(start);
793 int numBlocks = mBlock.size();
794
795 const SeqBlock &block = mBlock[b];
796 // start is in block:
797 auto result = (block.start + block.sb->GetSampleCount() - start).as_size_t();
798
799 decltype(result) length;
800 while(result < mMinSamples && b+1<numBlocks &&
801 ((length = mBlock[b+1].sb->GetSampleCount()) + result) <= mMaxSamples) {
802 b++;
803 result += length;
804 }
805
806 wxASSERT(result > 0 && result <= mMaxSamples);
807
808 return result;
809}

References FindBlock(), mBlock, mMaxSamples, mMinSamples, mNumSamples, SeqBlock::sb, and SeqBlock::start.

Here is the call graph for this function:

◆ GetBlockArray() [1/2]

BlockArray & Sequence::GetBlockArray ( )
inline

Definition at line 217 of file Sequence.h.

217{ return mBlock; }

Referenced by GetAllSeqBlocks(), and GetWaveDisplay().

Here is the caller graph for this function:

◆ GetBlockArray() [2/2]

const BlockArray & Sequence::GetBlockArray ( ) const
inline

Definition at line 218 of file Sequence.h.

218{ return mBlock; }

◆ GetBlockStart()

sampleCount Sequence::GetBlockStart ( sampleCount  position) const
Returns
possibly a large or negative value

Definition at line 776 of file Sequence.cpp.

777{
778 int b = FindBlock(position);
779 return mBlock[b].start;
780}

References FindBlock(), and mBlock.

Here is the call graph for this function:

◆ GetErrorOpening()

bool Sequence::GetErrorOpening ( )
inline

Definition at line 172 of file Sequence.h.

172{ return mErrorOpening; }
bool mErrorOpening
Definition: Sequence.h:250

◆ GetFactory()

const SampleBlockFactoryPtr & Sequence::GetFactory ( )
inline

Definition at line 161 of file Sequence.h.

161{ return mpFactory; }

◆ GetIdealAppendLen()

size_t Sequence::GetIdealAppendLen ( ) const

Definition at line 1270 of file Sequence.cpp.

1271{
1272 int numBlocks = mBlock.size();
1273 const auto max = GetMaxBlockSize();
1274
1275 if (numBlocks == 0)
1276 return max;
1277
1278 const auto lastBlockLen = mBlock.back().sb->GetSampleCount();
1279 if (lastBlockLen >= max)
1280 return max;
1281 else
1282 return max - lastBlockLen;
1283}
size_t GetMaxBlockSize() const
Definition: Sequence.cpp:77

References GetMaxBlockSize(), and mBlock.

Referenced by Append().

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

◆ GetIdealBlockSize()

size_t Sequence::GetIdealBlockSize ( ) const

Definition at line 82 of file Sequence.cpp.

83{
84 return mMaxSamples;
85}

References mMaxSamples.

Referenced by DoAppend(), WaveTrack::GetIdealBlockSize(), and InsertSilence().

Here is the caller graph for this function:

◆ GetMaxBlockSize()

size_t Sequence::GetMaxBlockSize ( ) const

Definition at line 77 of file Sequence.cpp.

78{
79 return mMaxSamples;
80}

References mMaxSamples.

Referenced by GetIdealAppendLen(), and GetWaveDisplay().

Here is the caller graph for this function:

◆ GetMaxDiskBlockSize()

size_t Sequence::GetMaxDiskBlockSize ( )
static

Definition at line 1845 of file Sequence.cpp.

1846{
1847 return sMaxDiskBlockSize;
1848}

References sMaxDiskBlockSize.

Referenced by BenchmarkDialog::OnRun().

Here is the caller graph for this function:

◆ GetMinMax()

std::pair< float, float > Sequence::GetMinMax ( sampleCount  start,
sampleCount  len,
bool  mayThrow 
) const

Definition at line 238 of file Sequence.cpp.

240{
241 if (len == 0 || mBlock.size() == 0) {
242 return {
243 0.f,
244 // FLT_MAX? So it doesn't look like a spurious '0' to a caller?
245
246 0.f
247 // -FLT_MAX? So it doesn't look like a spurious '0' to a caller?
248 };
249 }
250
251 float min = FLT_MAX;
252 float max = -FLT_MAX;
253
254 unsigned int block0 = FindBlock(start);
255 unsigned int block1 = FindBlock(start + len - 1);
256
257 // First calculate the min/max of the blocks in the middle of this region;
258 // this is very fast because we have the min/max of every entire block
259 // already in memory.
260
261 for (unsigned b = block0 + 1; b < block1; ++b) {
262 auto results = mBlock[b].sb->GetMinMaxRMS(mayThrow);
263
264 if (results.min < min)
265 min = results.min;
266 if (results.max > max)
267 max = results.max;
268 }
269
270 // Now we take the first and last blocks into account, noting that the
271 // selection may only partly overlap these blocks. If the overall min/max
272 // of either of these blocks is within min...max, then we can ignore them.
273 // If not, we need read some samples and summaries from disk.
274 {
275 const SeqBlock &theBlock = mBlock[block0];
276 const auto &theFile = theBlock.sb;
277 auto results = theFile->GetMinMaxRMS(mayThrow);
278
279 if (results.min < min || results.max > max) {
280 // start lies within theBlock:
281 auto s0 = ( start - theBlock.start ).as_size_t();
282 const auto maxl0 = (
283 // start lies within theBlock:
284 theBlock.start + theFile->GetSampleCount() - start
285 ).as_size_t();
286 wxASSERT(maxl0 <= mMaxSamples); // Vaughan, 2011-10-19
287 const auto l0 = limitSampleBufferSize ( maxl0, len );
288
289 results = theFile->GetMinMaxRMS(s0, l0, mayThrow);
290 if (results.min < min)
291 min = results.min;
292 if (results.max > max)
293 max = results.max;
294 }
295 }
296
297 if (block1 > block0)
298 {
299 const SeqBlock &theBlock = mBlock[block1];
300 const auto &theFile = theBlock.sb;
301 auto results = theFile->GetMinMaxRMS(mayThrow);
302
303 if (results.min < min || results.max > max) {
304
305 // start + len - 1 lies in theBlock:
306 const auto l0 = ( start + len - theBlock.start ).as_size_t();
307 wxASSERT(l0 <= mMaxSamples); // Vaughan, 2011-10-19
308
309 results = theFile->GetMinMaxRMS(0, l0, mayThrow);
310 if (results.min < min)
311 min = results.min;
312 if (results.max > max)
313 max = results.max;
314 }
315 }
316
317 return { min, max };
318}

References FindBlock(), limitSampleBufferSize(), mBlock, min(), mMaxSamples, SeqBlock::sb, and SeqBlock::start.

Here is the call graph for this function:

◆ GetNumSamples()

sampleCount Sequence::GetNumSamples ( ) const
inline

Definition at line 91 of file Sequence.h.

91{ return mNumSamples; }

Referenced by GetWaveDisplay(), and WaveClipWaveformCache::GetWaveDisplay().

Here is the caller graph for this function:

◆ GetRMS()

float Sequence::GetRMS ( sampleCount  start,
sampleCount  len,
bool  mayThrow 
) const

Definition at line 320 of file Sequence.cpp.

321{
322 // len is the number of samples that we want the rms of.
323 // it may be longer than a block, and the code is carefully set up to handle that.
324 if (len == 0 || mBlock.size() == 0)
325 return 0.f;
326
327 double sumsq = 0.0;
328 sampleCount length = 0; // this is the cumulative length of the bits we have the ms of so far, and should end up == len
329
330 unsigned int block0 = FindBlock(start);
331 unsigned int block1 = FindBlock(start + len - 1);
332
333 // First calculate the rms of the blocks in the middle of this region;
334 // this is very fast because we have the rms of every entire block
335 // already in memory.
336 for (unsigned b = block0 + 1; b < block1; b++) {
337 const SeqBlock &theBlock = mBlock[b];
338 const auto &sb = theBlock.sb;
339 auto results = sb->GetMinMaxRMS(mayThrow);
340
341 const auto fileLen = sb->GetSampleCount();
342 const auto blockRMS = results.RMS;
343 sumsq += blockRMS * blockRMS * fileLen;
344 length += fileLen;
345 }
346
347 // Now we take the first and last blocks into account, noting that the
348 // selection may only partly overlap these blocks.
349 // If not, we need read some samples and summaries from disk.
350 {
351 const SeqBlock &theBlock = mBlock[block0];
352 const auto &sb = theBlock.sb;
353 // start lies within theBlock
354 auto s0 = ( start - theBlock.start ).as_size_t();
355 // start lies within theBlock
356 const auto maxl0 =
357 (theBlock.start + sb->GetSampleCount() - start).as_size_t();
358 wxASSERT(maxl0 <= mMaxSamples); // Vaughan, 2011-10-19
359 const auto l0 = limitSampleBufferSize( maxl0, len );
360
361 auto results = sb->GetMinMaxRMS(s0, l0, mayThrow);
362 const auto partialRMS = results.RMS;
363 sumsq += partialRMS * partialRMS * l0;
364 length += l0;
365 }
366
367 if (block1 > block0) {
368 const SeqBlock &theBlock = mBlock[block1];
369 const auto &sb = theBlock.sb;
370
371 // start + len - 1 lies within theBlock
372 const auto l0 = ( start + len - theBlock.start ).as_size_t();
373 wxASSERT(l0 <= mMaxSamples); // PRL: I think Vaughan missed this
374
375 auto results = sb->GetMinMaxRMS(0, l0, mayThrow);
376 const auto partialRMS = results.RMS;
377 sumsq += partialRMS * partialRMS * l0;
378 length += l0;
379 }
380
381 // PRL: catch bugs like 1320:
382 wxASSERT(length == len);
383
384 return sqrt(sumsq / length.as_double() );
385}

References sampleCount::as_double(), FindBlock(), limitSampleBufferSize(), mBlock, mMaxSamples, SeqBlock::sb, and SeqBlock::start.

Here is the call graph for this function:

◆ GetSampleFormats()

SampleFormats Sequence::GetSampleFormats ( ) const

Definition at line 95 of file Sequence.cpp.

96{
97 return mSampleFormats;
98}

References mSampleFormats.

◆ HandleXMLChild()

XMLTagHandler * Sequence::HandleXMLChild ( const std::string_view &  tag)
overridevirtual

Implements XMLTagHandler.

Definition at line 979 of file Sequence.cpp.

980{
981 if (tag == "waveblock")
982 {
983 return this;
984 }
985
986 return nullptr;
987}

◆ HandleXMLEndTag()

void Sequence::HandleXMLEndTag ( const std::string_view &  tag)
override

Definition at line 937 of file Sequence.cpp.

938{
939 if (tag != "sequence" != 0)
940 {
941 return;
942 }
943
944 // Make sure that the sequence is valid.
945
946 // Make sure that start times and lengths are consistent
947 sampleCount numSamples = 0;
948 for (unsigned b = 0, nn = mBlock.size(); b < nn; b++)
949 {
950 SeqBlock &block = mBlock[b];
951 if (block.start != numSamples)
952 {
953 wxLogWarning(
954 wxT("Gap detected in project file.\n")
955 wxT(" Start (%s) for block file %lld is not one sample past end of previous block (%s).\n")
956 wxT(" Moving start so blocks are contiguous."),
957 // PRL: Why bother with Internat when the above is just wxT?
959 block.sb->GetBlockID(),
960 Internat::ToString(numSamples.as_double(), 0));
961 block.start = numSamples;
962 mErrorOpening = true;
963 }
964 numSamples += block.sb->GetSampleCount();
965 }
966
967 if (mNumSamples != numSamples)
968 {
969 wxLogWarning(
970 wxT("Gap detected in project file. Correcting sequence sample count from %s to %s."),
971 // PRL: Why bother with Internat when the above is just wxT?
973 Internat::ToString(numSamples.as_double(), 0));
974 mNumSamples = numSamples;
975 mErrorOpening = true;
976 }
977}
static wxString ToString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, always uses the dot as decimal separator.
Definition: Internat.cpp:150

References sampleCount::as_double(), mBlock, mErrorOpening, mNumSamples, SeqBlock::sb, SeqBlock::start, Internat::ToString(), and wxT().

Here is the call graph for this function:

◆ HandleXMLTag()

bool Sequence::HandleXMLTag ( const std::string_view &  tag,
const AttributesList attrs 
)
overridevirtual

Implements XMLTagHandler.

Definition at line 811 of file Sequence.cpp.

812{
813 auto &factory = *mpFactory;
814
815 /* handle waveblock tag and its attributes */
816 if (tag == "waveblock")
817 {
818 SeqBlock wb;
819
820 // Give SampleBlock a go at the attributes first
821 wb.sb = factory.CreateFromXML(mSampleFormats.Stored(), attrs);
822 if (wb.sb == nullptr)
823 {
824 mErrorOpening = true;
825 return false;
826 }
827
828 // loop through attrs, which is a null-terminated list of attribute-value pairs
829 for (auto pair : attrs)
830 {
831 auto attr = pair.first;
832 auto value = pair.second;
833
834 if (attr == "start")
835 {
836 // This attribute is a sample offset, so can be 64bit
837 sampleCount::type start;
838
839 if (!value.TryGet(start))
840 {
841 mErrorOpening = true;
842 return false;
843 }
844
845 wb.start = start;
846 }
847 }
848
849 mBlock.push_back(wb);
850
851 return true;
852 }
853
854 /* handle sequence tag and its attributes */
855 if (tag == "sequence")
856 {
857 sampleFormat effective = floatSample, stored = floatSample;
858 for (auto pair : attrs)
859 {
860 auto attr = pair.first;
861 auto value = pair.second;
862
863 long long nValue = 0;
864
865 if (attr == "maxsamples")
866 {
867 // This attribute is a sample count, so can be 64bit
868 if (!value.TryGet(nValue))
869 {
870 mErrorOpening = true;
871 return false;
872 }
873
874 // Dominic, 12/10/2006:
875 // Let's check that maxsamples is >= 1024 and <= 64 * 1024 * 1024
876 // - that's a pretty wide range of reasonable values.
877 if ((nValue < 1024) || (nValue > 64 * 1024 * 1024))
878 {
879 mErrorOpening = true;
880 return false;
881 }
882
883 // nValue is now safe for size_t
884 mMaxSamples = nValue;
885 }
886 else if (attr == "sampleformat")
887 {
888 // This attribute is a sample format, normal int
889 long fValue;
890
891 if (!value.TryGet(fValue) || !IsValidSampleFormat(fValue))
892 {
893 mErrorOpening = true;
894 return false;
895 }
896 stored = static_cast<sampleFormat>( fValue );
897 }
898 else if (attr == "effectivesampleformat")
899 {
900 // This attribute is a sample format, normal int
901 long fValue;
902
903 if (!value.TryGet(fValue) || !IsValidSampleFormat(fValue))
904 {
905 mErrorOpening = true;
906 return false;
907 }
908 effective = static_cast<sampleFormat>( fValue );
909 }
910 else if (attr == "numsamples")
911 {
912 // This attribute is a sample count, so can be 64bit
913 if (!value.TryGet(nValue) || (nValue < 0))
914 {
915 mErrorOpening = true;
916 return false;
917 }
918 mNumSamples = nValue;
919 }
920 } // for
921
922 // Set at least the stored format as it was saved
923 mSampleFormats = SampleFormats{ effective, stored };
924
925 // Check whether the invariant of SampleFormats changed the value
926 if (mSampleFormats.Effective() != effective) {
927 mErrorOpening = true;
928 return false;
929 }
930
931 return true;
932 }
933
934 return false;
935}
sampleFormat
The ordering of these values with operator < agrees with the order of increasing bit width.
Definition: SampleFormat.h:30
static bool IsValidSampleFormat(const int nValue)
true if nValue is one of the sampleFormat enum values
Definition: Sequence.cpp:1850
long long type
Definition: SampleCount.h:21

References SampleFormats::Effective(), cloud::factory, floatSample, IsValidSampleFormat(), mBlock, mErrorOpening, mMaxSamples, mNumSamples, mpFactory, mSampleFormats, SeqBlock::sb, SeqBlock::start, and SampleFormats::Stored().

Here is the call graph for this function:

◆ InsertSilence()

void Sequence::InsertSilence ( sampleCount  s0,
sampleCount  len 
)
Exception safety guarantee:
Strong

Definition at line 707 of file Sequence.cpp.

708{
709 auto &factory = *mpFactory;
710
711 // Quick check to make sure that it doesn't overflow
712 if (Overflows((mNumSamples.as_double()) + (len.as_double())))
714
715 if (len <= 0)
716 return;
717
718 // Create a NEW track containing as much silence as we
719 // need to insert, and then call Paste to do the insertion.
720
722
723 auto idealSamples = GetIdealBlockSize();
724
725 sampleCount pos = 0;
726
727 // Could nBlocks overflow a size_t? Not very likely. You need perhaps
728 // 2 ^ 52 samples which is over 3000 years at 44.1 kHz.
729 auto nBlocks = (len + idealSamples - 1) / idealSamples;
730 sTrack.mBlock.reserve(nBlocks.as_size_t());
731
732 const auto format = mSampleFormats.Stored();
733 if (len >= idealSamples) {
734 auto silentFile = factory.CreateSilent(
735 idealSamples,
736 format);
737 while (len >= idealSamples) {
738 sTrack.mBlock.push_back(SeqBlock(silentFile, pos));
739
740 pos += idealSamples;
741 len -= idealSamples;
742 }
743 }
744 if (len != 0) {
745 // len is not more than idealSamples:
746 sTrack.mBlock.push_back(SeqBlock(
747 factory.CreateSilent(len.as_size_t(), format), pos));
748 pos += len;
749 }
750
751 sTrack.mNumSamples = pos;
752
753 // use Strong-guarantee
754 Paste(s0, &sTrack);
755}
A WaveTrack contains WaveClip(s). A WaveClip contains a Sequence. A Sequence is primarily an interfac...
Definition: Sequence.h:61
size_t as_size_t() const
Definition: SampleCount.cpp:16

References sampleCount::as_double(), sampleCount::as_size_t(), cloud::factory, format, GetIdealBlockSize(), mNumSamples, mpFactory, mSampleFormats, anonymous_namespace{Sequence.cpp}::Overflows(), Paste(), SampleFormats::Stored(), and THROW_INCONSISTENCY_EXCEPTION.

Referenced by WaveClip::InsertSilence().

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

◆ IsValidSampleFormat()

bool Sequence::IsValidSampleFormat ( const int  nValue)
static

true if nValue is one of the sampleFormat enum values

Definition at line 1850 of file Sequence.cpp.

1851{
1852 auto nValue = static_cast<sampleFormat>(iValue);
1853 return (nValue == int16Sample) || (nValue == int24Sample) || (nValue == floatSample);
1854}

References floatSample, int16Sample, and int24Sample.

Referenced by AUPImportFileHandle::HandleSequence(), HandleXMLTag(), and WaveTrack::HandleXMLTag().

Here is the caller graph for this function:

◆ operator=()

Sequence & Sequence::operator= ( const Sequence )

◆ Paste()

void Sequence::Paste ( sampleCount  s,
const Sequence src 
)
Exception safety guarantee:
Strong

Definition at line 494 of file Sequence.cpp.

495{
496 if ((s < 0) || (s > mNumSamples))
497 {
498 wxLogError(
499 wxT("Sequence::Paste: sampleCount s %s is < 0 or > mNumSamples %s)."),
500 // PRL: Why bother with Internat when the above is just wxT?
504 }
505
506 // Quick check to make sure that it doesn't overflow
508 {
509 wxLogError(
510 wxT("Sequence::Paste: mNumSamples %s + src->mNumSamples %s would overflow."),
511 // PRL: Why bother with Internat when the above is just wxT?
515 }
516
517 const auto format = mSampleFormats.Stored();
518 if (src->mSampleFormats.Stored() != format)
519 {
520 wxLogError(
521 wxT("Sequence::Paste: Sample format to be pasted, %s, does not match destination format, %s."),
523 GetSampleFormatStr(format).Debug());
525 }
526
527 const BlockArray &srcBlock = src->mBlock;
528 auto addedLen = src->mNumSamples;
529 const unsigned int srcNumBlocks = srcBlock.size();
530 auto sampleSize = SAMPLE_SIZE(format);
531
532 if (addedLen == 0 || srcNumBlocks == 0)
533 return;
534
535 const size_t numBlocks = mBlock.size();
536
537 // Decide whether to share sample blocks or make new copies, when whole block
538 // contents are used -- must copy if factories are different:
539 auto pUseFactory =
540 (src->mpFactory == mpFactory) ? nullptr : mpFactory.get();
541
542 if (numBlocks == 0 ||
543 (s == mNumSamples && mBlock.back().sb->GetSampleCount() >= mMinSamples)) {
544 // Special case: this track is currently empty, or it's safe to append
545 // onto the end because the current last block is longer than the
546 // minimum size
547
548 // Build and swap a copy so there is a strong exception safety guarantee
549 BlockArray newBlock{ mBlock };
550 sampleCount samples = mNumSamples;
551 for (unsigned int i = 0; i < srcNumBlocks; i++)
552 // AppendBlock may throw for limited disk space, if pasting from
553 // one project into another.
554 AppendBlock(pUseFactory, format,
555 newBlock, samples, srcBlock[i]);
556
558 (newBlock, samples, wxT("Paste branch one"));
560 return;
561 }
562
563 const int b = (s == mNumSamples) ? mBlock.size() - 1 : FindBlock(s);
564 wxASSERT((b >= 0) && (b < (int)numBlocks));
565 SeqBlock *const pBlock = &mBlock[b];
566 const auto length = pBlock->sb->GetSampleCount();
567 const auto largerBlockLen = addedLen + length;
568 // PRL: when insertion point is the first sample of a block,
569 // and the following test fails, perhaps we could test
570 // whether coalescence with the previous block is possible.
571 if (largerBlockLen <= mMaxSamples) {
572 // Special case: we can fit all of the NEW samples inside of
573 // one block!
574
575 SeqBlock &block = *pBlock;
576 // largerBlockLen is not more than mMaxSamples...
577 SampleBuffer buffer(largerBlockLen.as_size_t(), format);
578
579 // ...and addedLen is not more than largerBlockLen
580 auto sAddedLen = addedLen.as_size_t();
581 // s lies within block:
582 auto splitPoint = ( s - block.start ).as_size_t();
583 Read(buffer.ptr(), format, block, 0, splitPoint, true);
584 src->Get(0, buffer.ptr() + splitPoint*sampleSize,
585 format, 0, sAddedLen, true);
586 Read(buffer.ptr() + (splitPoint + sAddedLen) * sampleSize,
587 format, block,
588 splitPoint, length - splitPoint, true);
589
590 // largerBlockLen is not more than mMaxSamples...
591 block.sb = mpFactory->Create(
592 buffer.ptr(),
593 largerBlockLen.as_size_t(),
594 format);
595
596 // Don't make a duplicate array. We can still give Strong-guarantee
597 // if we modify only one block in place.
598
599 // use No-fail-guarantee in remaining steps
600 for (unsigned int i = b + 1; i < numBlocks; i++)
601 mBlock[i].start += addedLen;
602
603 mNumSamples += addedLen;
604
605 // This consistency check won't throw, it asserts.
606 // Proof that we kept consistency is not hard.
607 ConsistencyCheck(wxT("Paste branch two"), false);
609 return;
610 }
611
612 // Case three: if we are inserting four or fewer blocks,
613 // it's simplest to just lump all the data together
614 // into one big block along with the split block,
615 // then resplit it all
616 BlockArray newBlock;
617 newBlock.reserve(numBlocks + srcNumBlocks + 2);
618 newBlock.insert(newBlock.end(), mBlock.begin(), mBlock.begin() + b);
619
620 SeqBlock &splitBlock = mBlock[b];
621 auto splitLen = splitBlock.sb->GetSampleCount();
622 // s lies within splitBlock
623 auto splitPoint = ( s - splitBlock.start ).as_size_t();
624
625 unsigned int i;
626 if (srcNumBlocks <= 4) {
627
628 // addedLen is at most four times maximum block size
629 auto sAddedLen = addedLen.as_size_t();
630 const auto sum = splitLen + sAddedLen;
631
632 SampleBuffer sumBuffer(sum, format);
633 Read(sumBuffer.ptr(), format, splitBlock, 0, splitPoint, true);
634 src->Get(0, sumBuffer.ptr() + splitPoint * sampleSize,
635 format,
636 0, sAddedLen, true);
637 Read(sumBuffer.ptr() + (splitPoint + sAddedLen) * sampleSize, format,
638 splitBlock, splitPoint,
639 splitLen - splitPoint, true);
640
642 newBlock, splitBlock.start, sumBuffer.ptr(), sum);
643 } else {
644
645 // The final case is that we're inserting at least five blocks.
646 // We divide these into three groups: the first two get merged
647 // with the first half of the split block, the middle ones get
648 // used whole, and the last two get merged with the last
649 // half of the split block.
650
651 const auto srcFirstTwoLen =
652 srcBlock[0].sb->GetSampleCount() + srcBlock[1].sb->GetSampleCount();
653 const auto leftLen = splitPoint + srcFirstTwoLen;
654
655 const SeqBlock &penultimate = srcBlock[srcNumBlocks - 2];
656 const auto srcLastTwoLen =
657 penultimate.sb->GetSampleCount() +
658 srcBlock[srcNumBlocks - 1].sb->GetSampleCount();
659 const auto rightSplit = splitBlock.sb->GetSampleCount() - splitPoint;
660 const auto rightLen = rightSplit + srcLastTwoLen;
661
662 SampleBuffer sampleBuffer(std::max(leftLen, rightLen), format);
663
664 Read(sampleBuffer.ptr(), format, splitBlock, 0, splitPoint, true);
665 src->Get(0, sampleBuffer.ptr() + splitPoint*sampleSize,
666 format, 0, srcFirstTwoLen, true);
667
669 newBlock, splitBlock.start, sampleBuffer.ptr(), leftLen);
670
671 for (i = 2; i < srcNumBlocks - 2; i++) {
672 const SeqBlock &block = srcBlock[i];
673 auto sb = ShareOrCopySampleBlock(
674 pUseFactory, format, block.sb );
675 newBlock.push_back(SeqBlock(sb, block.start + s));
676 }
677
678 auto lastStart = penultimate.start;
679 src->Get(srcNumBlocks - 2, sampleBuffer.ptr(), format,
680 lastStart, srcLastTwoLen, true);
681 Read(sampleBuffer.ptr() + srcLastTwoLen * sampleSize, format,
682 splitBlock, splitPoint, rightSplit, true);
683
685 newBlock, s + lastStart, sampleBuffer.ptr(), rightLen);
686 }
687
688 // Copy remaining blocks to NEW block array and
689 // swap the NEW block array in for the old
690 for (i = b + 1; i < numBlocks; i++)
691 newBlock.push_back(mBlock[i].Plus(addedLen));
692
694 (newBlock, mNumSamples + addedLen, wxT("Paste branch three"));
695
697}
TranslatableString GetSampleFormatStr(sampleFormat format)
wxString Debug() const
Format as an English string for debugging logs and developers' eyes, not for end users.

References AppendBlock(), sampleCount::as_double(), Blockify(), CommitChangesIfConsistent(), ConsistencyCheck(), TranslatableString::Debug(), SampleFormats::Effective(), FindBlock(), format, Get(), GetSampleFormatStr(), mBlock, mMaxSamples, mMinSamples, mNumSamples, mpFactory, mSampleFormats, anonymous_namespace{Sequence.cpp}::Overflows(), SampleBuffer::ptr(), Read(), SAMPLE_SIZE, SeqBlock::sb, anonymous_namespace{Sequence.cpp}::ShareOrCopySampleBlock(), SeqBlock::start, SampleFormats::Stored(), THROW_INCONSISTENCY_EXCEPTION, Internat::ToString(), SampleFormats::UpdateEffective(), and wxT().

Referenced by InsertSilence(), and Sequence().

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

◆ Read()

bool Sequence::Read ( samplePtr  buffer,
sampleFormat  format,
const SeqBlock b,
size_t  blockRelativeStart,
size_t  len,
bool  mayThrow 
)
static

Definition at line 1091 of file Sequence.cpp.

1094{
1095 const auto &sb = b.sb;
1096
1097 wxASSERT(blockRelativeStart + len <= sb->GetSampleCount());
1098
1099 // Either throws, or of !mayThrow, tells how many were really read
1100 auto result = sb->GetSamples(buffer, format, blockRelativeStart, len, mayThrow);
1101
1102 if (result != len)
1103 {
1104 wxLogWarning(wxT("Expected to read %ld samples, got %ld samples."),
1105 len, result);
1106 return false;
1107 }
1108
1109 return true;
1110}

References format, SeqBlock::sb, and wxT().

Referenced by ConvertToSampleFormat(), Delete(), DoAppend(), Get(), GetWaveDisplay(), Paste(), and SetSamples().

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

◆ SetMaxDiskBlockSize()

void Sequence::SetMaxDiskBlockSize ( size_t  bytes)
static

Definition at line 1840 of file Sequence.cpp.

1841{
1842 sMaxDiskBlockSize = bytes;
1843}

References sMaxDiskBlockSize.

Referenced by AudacityApp::InitPart2(), and BenchmarkDialog::OnRun().

Here is the caller graph for this function:

◆ SetSamples()

void Sequence::SetSamples ( constSamplePtr  buffer,
sampleFormat  format,
sampleCount  start,
sampleCount  len,
sampleFormat  effectiveFormat 
)

Pass nullptr to set silence.

Note that len is not size_t, because nullptr may be passed for buffer, in which case, silence is inserted, possibly a large amount.

Exception safety guarantee:
Strong
Exception safety guarantee:
Strong
Parameters
effectiveFormatMake the effective format of the data at least the minumum of this value and `format`. (Maybe wider, if merging with preexistent data.) If the data are later narrowed from stored format, but not narrower than the effective, then no dithering will occur.

Definition at line 1154 of file Sequence.cpp.

1156{
1157 effectiveFormat = std::min(effectiveFormat, format);
1158 auto &factory = *mpFactory;
1159
1160 const auto size = mBlock.size();
1161
1162 if (start < 0 || start + len > mNumSamples)
1164
1165 size_t tempSize = mMaxSamples;
1166 const auto dstFormat = mSampleFormats.Stored();
1167 // to do: allocate this only on demand
1168 SampleBuffer scratch(tempSize, dstFormat);
1169
1170 SampleBuffer temp;
1171 if (buffer && format != dstFormat) {
1172 temp.Allocate(tempSize, dstFormat);
1173 }
1174
1175 int b = FindBlock(start);
1176 BlockArray newBlock;
1177 std::copy( mBlock.begin(), mBlock.begin() + b, std::back_inserter(newBlock) );
1178
1179 while (len > 0
1180 // Redundant termination condition,
1181 // but it guards against infinite loop in case of inconsistencies
1182 // (too-small files, not yet seen?)
1183 // that cause the loop to make no progress because blen == 0
1184 && b < (int)size
1185 ) {
1186 newBlock.push_back( mBlock[b] );
1187 SeqBlock &block = newBlock.back();
1188 // start is within block
1189 const auto bstart = ( start - block.start ).as_size_t();
1190 const auto fileLength = block.sb->GetSampleCount();
1191
1192 // the std::min is a guard against inconsistent Sequence
1193 const auto blen =
1194 limitSampleBufferSize( fileLength - std::min( bstart, fileLength ),
1195 len );
1196 wxASSERT(blen == 0 || bstart + blen <= fileLength);
1197
1198#if 0
1199 // PRL: This inconsistency (too-big file) has been seen in "the wild"
1200 // in 2.2.0. It is the least problematic kind of inconsistency.
1201 // We will tolerate it for 2.2.1.
1202 // Not known whether it is only in projects saved in earlier versions.
1203 // After 2.2.1, we should detect and correct it at file loading time.
1204 if (fileLength > mMaxSamples) {
1206 }
1207#endif
1208
1209 ensureSampleBufferSize(scratch, dstFormat, tempSize, fileLength,
1210 &temp);
1211
1212 auto useBuffer = buffer;
1213 if (buffer && format != dstFormat)
1214 {
1215 // To do: remove the extra movement.
1216 // Note: we ensured temp can hold fileLength. blen is not more
1217 CopySamples(buffer, format, temp.ptr(), dstFormat, blen,
1218 (dstFormat < effectiveFormat
1220 useBuffer = temp.ptr();
1221 }
1222
1223 // We don't ever write to an existing block; to support Undo,
1224 // we copy the old block entirely into memory, dereference it,
1225 // make the change, and then write the NEW block to disk.
1226
1227 if ( bstart > 0 || blen < fileLength ) {
1228 // First or last block is only partially overwritten
1229 Read(scratch.ptr(), dstFormat, block, 0, fileLength, true);
1230
1231 if (useBuffer) {
1232 auto sampleSize = SAMPLE_SIZE(dstFormat);
1233 memcpy(scratch.ptr() +
1234 bstart * sampleSize, useBuffer, blen * sampleSize);
1235 }
1236 else
1237 ClearSamples(scratch.ptr(), dstFormat, bstart, blen);
1238
1239 block.sb = factory.Create(
1240 scratch.ptr(),
1241 fileLength,
1242 dstFormat);
1243 }
1244 else {
1245 // Avoid reading the disk when the replacement is total
1246 if (useBuffer)
1247 block.sb = factory.Create(useBuffer, fileLength, dstFormat);
1248 else
1249 block.sb = factory.CreateSilent(fileLength, dstFormat);
1250 }
1251
1252 // blen might be zero for inconsistent Sequence...
1253 if( buffer )
1254 buffer += (blen * SAMPLE_SIZE(format));
1255
1256 len -= blen;
1257 start += blen;
1258
1259 // ... but this, at least, always guarantees some loop progress:
1260 b++;
1261 }
1262
1263 std::copy( mBlock.begin() + b, mBlock.end(), std::back_inserter(newBlock) );
1264
1265 CommitChangesIfConsistent( newBlock, mNumSamples, wxT("SetSamples") );
1266
1267 mSampleFormats.UpdateEffective(effectiveFormat);
1268}

References SampleBuffer::Allocate(), ClearSamples(), CommitChangesIfConsistent(), CopySamples(), anonymous_namespace{Sequence.cpp}::ensureSampleBufferSize(), cloud::factory, FindBlock(), format, gHighQualityDither, limitSampleBufferSize(), mBlock, min(), mMaxSamples, mNumSamples, mpFactory, mSampleFormats, none, SampleBuffer::ptr(), Read(), SAMPLE_SIZE, SeqBlock::sb, size, SeqBlock::start, SampleFormats::Stored(), THROW_INCONSISTENCY_EXCEPTION, SampleFormats::UpdateEffective(), and wxT().

Referenced by SetSilence().

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

◆ SetSilence()

void Sequence::SetSilence ( sampleCount  s0,
sampleCount  len 
)
Exception safety guarantee:
Strong

Definition at line 700 of file Sequence.cpp.

701{
702 // Exact zeroes won't need dithering
704}
void SetSamples(constSamplePtr buffer, sampleFormat format, sampleCount start, sampleCount len, sampleFormat effectiveFormat)
Pass nullptr to set silence.
Definition: Sequence.cpp:1154

References mSampleFormats, narrowestSampleFormat, SetSamples(), and SampleFormats::Stored().

Referenced by WaveClip::SetSilence().

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

◆ WriteXML()

void Sequence::WriteXML ( XMLWriter xmlFile) const

Definition at line 990 of file Sequence.cpp.

992{
993 unsigned int b;
994
995 xmlFile.StartTag(wxT("sequence"));
996
997 xmlFile.WriteAttr(wxT("maxsamples"), mMaxSamples);
998 xmlFile.WriteAttr(wxT("sampleformat"),
999 static_cast<size_t>( mSampleFormats.Stored() ) );
1000 // This attribute was added in 3.0.3:
1001 xmlFile.WriteAttr( wxT("effectivesampleformat"),
1002 static_cast<size_t>( mSampleFormats.Effective() ));
1003 xmlFile.WriteAttr(wxT("numsamples"), mNumSamples.as_long_long() );
1004
1005 for (b = 0; b < mBlock.size(); b++) {
1006 const SeqBlock &bb = mBlock[b];
1007
1008 // See http://bugzilla.audacityteam.org/show_bug.cgi?id=451.
1009 if (bb.sb->GetSampleCount() > mMaxSamples)
1010 {
1011 // PRL: Bill observed this error. Not sure how it was caused.
1012 // I have added code in ConsistencyCheck that should abort the
1013 // editing operation that caused this, not fixing
1014 // the problem but moving the point of detection earlier if we
1015 // find a reproducible case.
1016 using namespace BasicUI;
1017 auto sMsg =
1018 XO("Sequence has block file exceeding maximum %s samples per block.\nTruncating to this maximum length.")
1019 .Format( Internat::ToString(((wxLongLong)mMaxSamples).ToDouble(), 0) );
1021 sMsg,
1023 .Caption(XO("Warning - Truncating Overlong Block File"))
1024 .IconStyle(Icon::Warning)
1025 .ButtonStyle(Button::Ok));
1026 wxLogWarning(sMsg.Translation()); //Debug?
1027// bb.sb->SetLength(mMaxSamples);
1028 }
1029
1030 xmlFile.StartTag(wxT("waveblock"));
1031 xmlFile.WriteAttr(wxT("start"), bb.start.as_long_long() );
1032
1033 bb.sb->SaveXML(xmlFile);
1034
1035 xmlFile.EndTag(wxT("waveblock"));
1036 }
1037
1038 xmlFile.EndTag(wxT("sequence"));
1039}
XO("Cut/Copy/Paste")
virtual void StartTag(const wxString &name)
Definition: XMLWriter.cpp:79
void WriteAttr(const wxString &name, const Identifier &value)
Definition: XMLWriter.h:36
virtual void EndTag(const wxString &name)
Definition: XMLWriter.cpp:102
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
Definition: BasicUI.h:274
MessageBoxOptions && Caption(TranslatableString caption_) &&
Definition: BasicUI.h:100

References sampleCount::as_long_long(), BasicUI::MessageBoxOptions::Caption(), SeqBlock::sb, BasicUI::ShowMessageBox(), SeqBlock::start, Internat::ToString(), wxT(), and XO().

Here is the call graph for this function:

Member Data Documentation

◆ mAppendBuffer

SampleBuffer Sequence::mAppendBuffer {}
private

Definition at line 246 of file Sequence.h.

Referenced by Append(), and Flush().

◆ mAppendBufferLen

size_t Sequence::mAppendBufferLen { 0 }
private

Definition at line 247 of file Sequence.h.

Referenced by Append(), and Flush().

◆ mAppendEffectiveFormat

sampleFormat Sequence::mAppendEffectiveFormat { narrowestSampleFormat }
private

Definition at line 248 of file Sequence.h.

Referenced by Append(), and Flush().

◆ mBlock

BlockArray Sequence::mBlock
private

◆ mErrorOpening

bool Sequence::mErrorOpening { false }
private

Definition at line 250 of file Sequence.h.

Referenced by HandleXMLEndTag(), and HandleXMLTag().

◆ mMaxSamples

size_t Sequence::mMaxSamples
private

◆ mMinSamples

size_t Sequence::mMinSamples
private

Definition at line 243 of file Sequence.h.

Referenced by ConvertToSampleFormat(), Delete(), DoAppend(), GetBestBlockSize(), and Paste().

◆ mNumSamples

sampleCount Sequence::mNumSamples { 0 }
private

◆ mpFactory

SampleBlockFactoryPtr Sequence::mpFactory
private

◆ mSampleFormats

SampleFormats Sequence::mSampleFormats
private

◆ sMaxDiskBlockSize

size_t Sequence::sMaxDiskBlockSize = 1048576
staticprivate

Definition at line 229 of file Sequence.h.

Referenced by ConvertToSampleFormat(), GetMaxDiskBlockSize(), and SetMaxDiskBlockSize().


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