Audacity 3.2.0
Public Types | Public Member Functions | Private Types | Private Member Functions | Private Attributes | List of all members
SqliteSampleBlock Class Referencefinal

Implementation of SampleBlock using Sqlite database. More...

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

Public Types

using Sizes = std::pair< size_t, size_t >
 Numbers of bytes needed for 256 and for 64k summaries. More...
 
- Public Types inherited from SampleBlock
using DeletionCallback = std::function< void(const SampleBlock &)>
 

Public Member Functions

BlockSampleView GetFloatSampleView (bool mayThrow) override
 
 SqliteSampleBlock (const std::shared_ptr< SqliteSampleBlockFactory > &pFactory)
 
 ~SqliteSampleBlock () override
 
void CloseLock () noexcept override
 
void SetSamples (constSamplePtr src, size_t numsamples, sampleFormat srcformat)
 
void Commit (Sizes sizes)
 
void Delete ()
 
SampleBlockID GetBlockID () const override
 
size_t DoGetSamples (samplePtr dest, sampleFormat destformat, size_t sampleoffset, size_t numsamples) override
 
sampleFormat GetSampleFormat () const override
 
size_t GetSampleCount () const override
 
bool GetSummary256 (float *dest, size_t frameoffset, size_t numframes) override
 Non-throwing, should fill with zeroes on failure. More...
 
bool GetSummary64k (float *dest, size_t frameoffset, size_t numframes) override
 Non-throwing, should fill with zeroes on failure. More...
 
double GetSumMin () const
 
double GetSumMax () const
 
double GetSumRms () const
 
MinMaxRMS DoGetMinMaxRMS (size_t start, size_t len) override
 Gets extreme values for the specified region. More...
 
MinMaxRMS DoGetMinMaxRMS () const override
 Gets extreme values for the entire block. More...
 
size_t GetSpaceUsage () const override
 
void SaveXML (XMLWriter &xmlFile) override
 
- Public Member Functions inherited from SampleBlock
virtual ~SampleBlock ()
 
virtual void CloseLock () noexcept=0
 
virtual SampleBlockID GetBlockID () const =0
 
size_t GetSamples (samplePtr dest, sampleFormat destformat, size_t sampleoffset, size_t numsamples, bool mayThrow=true)
 
virtual BlockSampleView GetFloatSampleView (bool mayThrow)=0
 
virtual sampleFormat GetSampleFormat () const =0
 
virtual size_t GetSampleCount () const =0
 
virtual bool GetSummary256 (float *dest, size_t frameoffset, size_t numframes)=0
 Non-throwing, should fill with zeroes on failure. More...
 
virtual bool GetSummary64k (float *dest, size_t frameoffset, size_t numframes)=0
 Non-throwing, should fill with zeroes on failure. More...
 
MinMaxRMS GetMinMaxRMS (size_t start, size_t len, bool mayThrow=true)
 Gets extreme values for the specified region. More...
 
MinMaxRMS GetMinMaxRMS (bool mayThrow=true) const
 Gets extreme values for the entire block. More...
 
virtual size_t GetSpaceUsage () const =0
 
virtual void SaveXML (XMLWriter &xmlFile)=0
 

Private Types

enum  { fields = 3 , bytesPerFrame = fields * sizeof(float) }
 

Private Member Functions

bool IsSilent () const
 
void Load (SampleBlockID sbid)
 
bool GetSummary (float *dest, size_t frameoffset, size_t numframes, DBConnection::StatementID id, const char *sql)
 
size_t GetBlob (void *dest, sampleFormat destformat, sqlite3_stmt *stmt, sampleFormat srcformat, size_t srcoffset, size_t srcbytes)
 
Sizes SetSizes (size_t numsamples, sampleFormat srcformat)
 
void CalcSummary (Sizes sizes)
 
DBConnectionConn () const
 This must never be called for silent blocks. More...
 
sqlite3 * DB () const
 

Private Attributes

std::weak_ptr< std::vector< float > > mCache
 
std::mutex mCacheMutex
 
friend SqliteSampleBlockFactory
 
const std::shared_ptr< SqliteSampleBlockFactorympFactory
 
bool mValid { false }
 
bool mLocked = false
 
SampleBlockID mBlockID { 0 }
 
ArrayOf< char > mSamples
 
size_t mSampleBytes
 
size_t mSampleCount
 
sampleFormat mSampleFormat
 
ArrayOf< char > mSummary256
 
ArrayOf< char > mSummary64k
 
double mSumMin
 
double mSumMax
 
double mSumRms
 

Additional Inherited Members

virtual size_t DoGetSamples (samplePtr dest, sampleFormat destformat, size_t sampleoffset, size_t numsamples)=0
 
virtual MinMaxRMS DoGetMinMaxRMS (size_t start, size_t len)=0
 
virtual MinMaxRMS DoGetMinMaxRMS () const =0
 

Detailed Description

Implementation of SampleBlock using Sqlite database.

Definition at line 35 of file SqliteSampleBlock.cpp.

Member Typedef Documentation

◆ Sizes

using SqliteSampleBlock::Sizes = std::pair< size_t, size_t >

Numbers of bytes needed for 256 and for 64k summaries.

Definition at line 55 of file SqliteSampleBlock.cpp.

Member Enumeration Documentation

◆ anonymous enum

anonymous enum
private
Enumerator
fields 
bytesPerFrame 

Definition at line 99 of file SqliteSampleBlock.cpp.

99 {
100 fields = 3, /* min, max, rms */
101 bytesPerFrame = fields * sizeof(float),
102 };

Constructor & Destructor Documentation

◆ SqliteSampleBlock()

SqliteSampleBlock::SqliteSampleBlock ( const std::shared_ptr< SqliteSampleBlockFactory > &  pFactory)
explicit

Definition at line 333 of file SqliteSampleBlock.cpp.

335: mpFactory(pFactory)
336{
338 mSampleBytes = 0;
339 mSampleCount = 0;
340
341 mSumMin = 0.0;
342 mSumMax = 0.0;
343 mSumRms = 0.0;
344}
sampleFormat mSampleFormat
const std::shared_ptr< SqliteSampleBlockFactory > mpFactory

References floatSample, mSampleBytes, mSampleCount, mSampleFormat, mSumMax, mSumMin, and mSumRms.

◆ ~SqliteSampleBlock()

SqliteSampleBlock::~SqliteSampleBlock ( )
override

Definition at line 346 of file SqliteSampleBlock.cpp.

347{
348 if (
349 const auto cb = mpFactory ? mpFactory->GetSampleBlockDeletionCallback() :
351 {
352 cb(*this);
353 }
354
355 if (IsSilent()) {
356 // The block object was constructed but failed to Load() or Commit().
357 // Or it's a silent block with no row in the database.
358 // Just let the stack unwind. Don't violate the assertion in
359 // Delete(), which may do odd recursive things in debug builds when it
360 // yields to the UI to put up a dialog, but then dispatches timer
361 // events that try again to finish recording.
362 return;
363 }
364
365 // See ProjectFileIO::Bypass() for a description of mIO.mBypass
366 GuardedCall( [this]{
367 if (!mLocked && !Conn()->ShouldBypass())
368 {
369 // In case Delete throws, don't let an exception escape a destructor,
370 // but we can still enqueue the delayed handler so that an error message
371 // is presented to the user.
372 // The failure in this case may be a less harmful waste of space in the
373 // database, which should not cause aborting of the attempted edit.
374 Delete();
375 }
376 } );
377}
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), F3 delayedHandler=DefaultDelayedHandlerAction) noexcept(noexcept(handler(std::declval< AudacityException * >())) &&noexcept(handler(nullptr)) &&noexcept(std::function< void(AudacityException *)>{std::move(delayedHandler)}))
Execute some code on any thread; catch any AudacityException; enqueue error report on the main thread...
std::function< void(const SampleBlock &)> DeletionCallback
Definition: SampleBlock.h:49
DBConnection * Conn() const
This must never be called for silent blocks.

References Conn(), Delete(), GuardedCall(), IsSilent(), mLocked, and mpFactory.

Here is the call graph for this function:

Member Function Documentation

◆ CalcSummary()

void SqliteSampleBlock::CalcSummary ( Sizes  sizes)
private

Calculates summary block data describing this sample data.

This method also has the side effect of setting the mSumMin, mSumMax, and mSumRms members of this class.

Definition at line 911 of file SqliteSampleBlock.cpp.

912{
913 const auto mSummary256Bytes = sizes.first;
914 const auto mSummary64kBytes = sizes.second;
915
916 Floats samplebuffer;
917 float *samples;
918
920 {
921 samples = (float *) mSamples.get();
922 }
923 else
924 {
925 samplebuffer.reinit((unsigned) mSampleCount);
927 samplebuffer.get(), mSampleCount);
928 samples = samplebuffer.get();
929 }
930
931 mSummary256.reinit(mSummary256Bytes);
932 mSummary64k.reinit(mSummary64kBytes);
933
934 float *summary256 = (float *) mSummary256.get();
935 float *summary64k = (float *) mSummary64k.get();
936
937 float min;
938 float max;
939 float sumsq;
940 double totalSquares = 0.0;
941 double fraction = 0.0;
942
943 // Recalc 256 summaries
944 int sumLen = (mSampleCount + 255) / 256;
945 int summaries = 256;
946
947 for (int i = 0; i < sumLen; ++i)
948 {
949 min = samples[i * 256];
950 max = samples[i * 256];
951 sumsq = min * min;
952
953 int jcount = 256;
954 if (jcount > mSampleCount - i * 256)
955 {
956 jcount = mSampleCount - i * 256;
957 fraction = 1.0 - (jcount / 256.0);
958 }
959
960 for (int j = 1; j < jcount; ++j)
961 {
962 float f1 = samples[i * 256 + j];
963 sumsq += f1 * f1;
964
965 if (f1 < min)
966 {
967 min = f1;
968 }
969 else if (f1 > max)
970 {
971 max = f1;
972 }
973 }
974
975 totalSquares += sumsq;
976
977 summary256[i * fields] = min;
978 summary256[i * fields + 1] = max;
979 // The rms is correct, but this may be for less than 256 samples in last loop.
980 summary256[i * fields + 2] = (float) sqrt(sumsq / jcount);
981 }
982
983 for (int i = sumLen, frames256 = mSummary256Bytes / bytesPerFrame;
984 i < frames256; ++i)
985 {
986 // filling in the remaining bits with non-harming/contributing values
987 // rms values are not "non-harming", so keep count of them:
988 summaries--;
989 summary256[i * fields] = FLT_MAX; // min
990 summary256[i * fields + 1] = -FLT_MAX; // max
991 summary256[i * fields + 2] = 0.0f; // rms
992 }
993
994 // Calculate now while we can do it accurately
995 mSumRms = sqrt(totalSquares / mSampleCount);
996
997 // Recalc 64K summaries
998 sumLen = (mSampleCount + 65535) / 65536;
999
1000 for (int i = 0; i < sumLen; ++i)
1001 {
1002 min = summary256[3 * i * 256];
1003 max = summary256[3 * i * 256 + 1];
1004 sumsq = summary256[3 * i * 256 + 2];
1005 sumsq *= sumsq;
1006
1007 for (int j = 1; j < 256; ++j)
1008 {
1009 // we can overflow the useful summary256 values here, but have put
1010 // non-harmful values in them
1011 if (summary256[3 * (i * 256 + j)] < min)
1012 {
1013 min = summary256[3 * (i * 256 + j)];
1014 }
1015
1016 if (summary256[3 * (i * 256 + j) + 1] > max)
1017 {
1018 max = summary256[3 * (i * 256 + j) + 1];
1019 }
1020
1021 float r1 = summary256[3 * (i * 256 + j) + 2];
1022 sumsq += r1 * r1;
1023 }
1024
1025 double denom = (i < sumLen - 1) ? 256.0 : summaries - fraction;
1026 float rms = (float) sqrt(sumsq / denom);
1027
1028 summary64k[i * fields] = min;
1029 summary64k[i * fields + 1] = max;
1030 summary64k[i * fields + 2] = rms;
1031 }
1032
1033 for (int i = sumLen, frames64k = mSummary64kBytes / bytesPerFrame;
1034 i < frames64k; ++i)
1035 {
1036 wxASSERT_MSG(false, wxT("Out of data for mSummaryInfo")); // Do we ever get here?
1037
1038 summary64k[i * fields] = 0.0f; // probably should be FLT_MAX, need a test case
1039 summary64k[i * fields + 1] = 0.0f; // probably should be -FLT_MAX, need a test case
1040 summary64k[i * fields + 2] = 0.0f; // just padding
1041 }
1042
1043 // Recalc block-level summary (mRMS already calculated)
1044 min = summary64k[0];
1045 max = summary64k[1];
1046
1047 for (int i = 1; i < sumLen; ++i)
1048 {
1049 if (summary64k[i * fields] < min)
1050 {
1051 min = summary64k[i * fields];
1052 }
1053
1054 if (summary64k[i * fields + 1] > max)
1055 {
1056 max = summary64k[i * fields + 1];
1057 }
1058 }
1059
1060 mSumMin = min;
1061 mSumMax = max;
1062}
wxT("CloseDown"))
int min(int a, int b)
void SamplesToFloats(constSamplePtr src, sampleFormat srcFormat, float *dst, size_t len, size_t srcStride, size_t dstStride)
Copy samples from any format into the widest format, which is 32 bit float, with no dithering.
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:59
ArrayOf< char > mSummary256
ArrayOf< char > mSummary64k
ArrayOf< char > mSamples
__finl float_x4 __vecc sqrt(const float_x4 &a)

References bytesPerFrame, fields, floatSample, min(), mSampleCount, mSampleFormat, mSamples, mSummary256, mSummary64k, mSumMax, mSumMin, mSumRms, ArrayOf< X >::reinit(), SamplesToFloats(), staffpad::audio::simd::sqrt(), and wxT().

Referenced by SetSamples().

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

◆ CloseLock()

void SqliteSampleBlock::CloseLock ( )
overridevirtualnoexcept

Implements SampleBlock.

Definition at line 397 of file SqliteSampleBlock.cpp.

398{
399 mLocked = true;
400}

References mLocked.

◆ Commit()

void SqliteSampleBlock::Commit ( Sizes  sizes)

Definition at line 772 of file SqliteSampleBlock.cpp.

773{
774 const auto mSummary256Bytes = sizes.first;
775 const auto mSummary64kBytes = sizes.second;
776
777 auto db = DB();
778 int rc;
779
780 // Prepare and cache statement...automatically finalized at DB close
781 sqlite3_stmt *stmt = Conn()->Prepare(DBConnection::InsertSampleBlock,
782 "INSERT INTO sampleblocks (sampleformat, summin, summax, sumrms,"
783 " summary256, summary64k, samples)"
784 " VALUES(?1,?2,?3,?4,?5,?6,?7);");
785
786 // Bind statement parameters
787 // Might return SQLITE_MISUSE which means it's our mistake that we violated
788 // preconditions; should return SQL_OK which is 0
789 if (sqlite3_bind_int(stmt, 1, static_cast<int>(mSampleFormat)) ||
790 sqlite3_bind_double(stmt, 2, mSumMin) ||
791 sqlite3_bind_double(stmt, 3, mSumMax) ||
792 sqlite3_bind_double(stmt, 4, mSumRms) ||
793 sqlite3_bind_blob(stmt, 5, mSummary256.get(), mSummary256Bytes, SQLITE_STATIC) ||
794 sqlite3_bind_blob(stmt, 6, mSummary64k.get(), mSummary64kBytes, SQLITE_STATIC) ||
795 sqlite3_bind_blob(stmt, 7, mSamples.get(), mSampleBytes, SQLITE_STATIC))
796 {
797
799 "sqlite3.rc", std::to_string(sqlite3_errcode(Conn()->DB())));
800 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Commit::bind");
801
802
803 wxASSERT_MSG(false, wxT("Binding failed...bug!!!"));
804 }
805
806 // Execute the statement
807 rc = sqlite3_step(stmt);
808 if (rc != SQLITE_DONE)
809 {
810 ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
811 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Commit::step");
812
813 wxLogDebug(wxT("SqliteSampleBlock::Commit - SQLITE error %s"), sqlite3_errmsg(db));
814
815 // Clear statement bindings and rewind statement
816 sqlite3_clear_bindings(stmt);
817 sqlite3_reset(stmt);
818
819 // Just showing the user a simple message, not the library error too
820 // which isn't internationalized
821 Conn()->ThrowException( true );
822 }
823
824 // Retrieve returned data
825 mBlockID = sqlite3_last_insert_rowid(db);
826
827 // Reset local arrays
828 mSamples.reset();
829 mSummary256.reset();
830 mSummary64k.reset();
831 {
832 std::lock_guard<std::mutex> lock(mCacheMutex);
833 mCache.reset();
834 }
835
836 // Clear statement bindings and rewind statement
837 sqlite3_clear_bindings(stmt);
838 sqlite3_reset(stmt);
839
840 mValid = true;
841}
#define ADD_EXCEPTION_CONTEXT(name, value)
Definition: SentryHelper.h:21
void ThrowException(bool write) const
throw and show appropriate message box
sqlite3_stmt * Prepare(enum StatementID id, const char *sql)
std::weak_ptr< std::vector< float > > mCache
sqlite3 * DB() const

References ADD_EXCEPTION_CONTEXT, Conn(), DB(), DBConnection::InsertSampleBlock, mBlockID, mCache, mCacheMutex, mSampleBytes, mSampleFormat, mSamples, mSummary256, mSummary64k, mSumMax, mSumMin, mSumRms, mValid, DBConnection::Prepare(), DBConnection::ThrowException(), and wxT().

Referenced by SetSamples().

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

◆ Conn()

DBConnection * SqliteSampleBlock::Conn ( ) const
private

This must never be called for silent blocks.

Postcondition
return value is not null

Definition at line 379 of file SqliteSampleBlock.cpp.

380{
381 if (!mpFactory)
382 return nullptr;
383
384 auto &pConnection = mpFactory->mppConnection->mpConnection;
385 if (!pConnection) {
387 {
389 XO("Connection to project file is null"),
390 XO("Warning"),
391 "Error:_Disk_full_or_not_writable"
392 };
393 }
394 return pConnection.get();
395}
@ Internal
Indicates internal failure from Audacity.
XO("Cut/Copy/Paste")
A MessageBoxException that shows a given, unvarying string.

References Internal, mpFactory, and XO().

Referenced by Commit(), DB(), Delete(), DoGetSamples(), GetBlob(), GetSpaceUsage(), GetSummary(), Load(), and ~SqliteSampleBlock().

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

◆ DB()

sqlite3 * SqliteSampleBlock::DB ( ) const
inlineprivate

Definition at line 110 of file SqliteSampleBlock.cpp.

111 {
112 return Conn()->DB();
113 }
sqlite3 * DB()

References Conn(), and DBConnection::DB().

Referenced by Commit(), Delete(), GetBlob(), and Load().

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

◆ Delete()

void SqliteSampleBlock::Delete ( )

Definition at line 843 of file SqliteSampleBlock.cpp.

844{
845 auto db = DB();
846 int rc;
847
848 wxASSERT(!IsSilent());
849
850 // Prepare and cache statement...automatically finalized at DB close
851 sqlite3_stmt *stmt = Conn()->Prepare(DBConnection::DeleteSampleBlock,
852 "DELETE FROM sampleblocks WHERE blockid = ?1;");
853
854 // Bind statement parameters
855 // Might return SQLITE_MISUSE which means it's our mistake that we violated
856 // preconditions; should return SQL_OK which is 0
857 if (sqlite3_bind_int64(stmt, 1, mBlockID))
858 {
860 "sqlite3.rc", std::to_string(sqlite3_errcode(Conn()->DB())));
861 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Delete::bind");
862
863 wxASSERT_MSG(false, wxT("Binding failed...bug!!!"));
864 }
865
866 // Execute the statement
867 rc = sqlite3_step(stmt);
868 if (rc != SQLITE_DONE)
869 {
870 ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
871 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Delete::step");
872
873 wxLogDebug(wxT("SqliteSampleBlock::Load - SQLITE error %s"), sqlite3_errmsg(db));
874
875 // Clear statement bindings and rewind statement
876 sqlite3_clear_bindings(stmt);
877 sqlite3_reset(stmt);
878
879 // Just showing the user a simple message, not the library error too
880 // which isn't internationalized
881 Conn()->ThrowException( true );
882 }
883
884 // Clear statement bindings and rewind statement
885 sqlite3_clear_bindings(stmt);
886 sqlite3_reset(stmt);
887}

References ADD_EXCEPTION_CONTEXT, Conn(), DB(), DBConnection::DeleteSampleBlock, IsSilent(), mBlockID, DBConnection::Prepare(), DBConnection::ThrowException(), and wxT().

Referenced by ~SqliteSampleBlock().

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

◆ DoGetMinMaxRMS() [1/2]

MinMaxRMS SqliteSampleBlock::DoGetMinMaxRMS ( ) const
overridevirtual

Gets extreme values for the entire block.

Retrieves the minimum, maximum, and maximum RMS of this entire block. This is faster than the other GetMinMax function since these values are already computed.

Implements SampleBlock.

Definition at line 567 of file SqliteSampleBlock.cpp.

568{
569 return { (float) mSumMin, (float) mSumMax, (float) mSumRms };
570}

References mSumMax, mSumMin, and mSumRms.

◆ DoGetMinMaxRMS() [2/2]

MinMaxRMS SqliteSampleBlock::DoGetMinMaxRMS ( size_t  start,
size_t  len 
)
overridevirtual

Gets extreme values for the specified region.

Retrieves the minimum, maximum, and maximum RMS of the specified sample data in this block.

Parameters
startThe offset in this block where the region should begin
lenThe number of samples to include in the region

Implements SampleBlock.

Definition at line 520 of file SqliteSampleBlock.cpp.

521{
522 if (IsSilent())
523 return {};
524
525 float min = FLT_MAX;
526 float max = -FLT_MAX;
527 float sumsq = 0;
528
529 if (!mValid)
530 {
531 Load(mBlockID);
532 }
533
534 if (start < mSampleCount)
535 {
536 len = std::min(len, mSampleCount - start);
537
538 // TODO: actually use summaries
539 SampleBuffer blockData(len, floatSample);
540 float *samples = (float *) blockData.ptr();
541
542 size_t copied = DoGetSamples((samplePtr) samples, floatSample, start, len);
543 for (size_t i = 0; i < copied; ++i, ++samples)
544 {
545 float sample = *samples;
546
547 if (sample > max)
548 {
549 max = sample;
550 }
551
552 if (sample < min)
553 {
554 min = sample;
555 }
556
557 sumsq += (sample * sample);
558 }
559 }
560
561 return { min, max, (float) sqrt(sumsq / len) };
562}
char * samplePtr
Definition: SampleFormat.h:57
size_t DoGetSamples(samplePtr dest, sampleFormat destformat, size_t sampleoffset, size_t numsamples) override
void Load(SampleBlockID sbid)

References DoGetSamples(), floatSample, IsSilent(), Load(), mBlockID, min(), mSampleCount, mValid, SampleBuffer::ptr(), and staffpad::audio::simd::sqrt().

Here is the call graph for this function:

◆ DoGetSamples()

size_t SqliteSampleBlock::DoGetSamples ( samplePtr  dest,
sampleFormat  destformat,
size_t  sampleoffset,
size_t  numsamples 
)
overridevirtual

Implements SampleBlock.

Definition at line 417 of file SqliteSampleBlock.cpp.

421{
422 if (IsSilent()) {
423 auto size = SAMPLE_SIZE(destformat);
424 memset(dest, 0, numsamples * size);
425 return numsamples;
426 }
427
428 // Prepare and cache statement...automatically finalized at DB close
429 sqlite3_stmt *stmt = Conn()->Prepare(DBConnection::GetSamples,
430 "SELECT samples FROM sampleblocks WHERE blockid = ?1;");
431
432 return GetBlob(dest,
433 destformat,
434 stmt,
436 sampleoffset * SAMPLE_SIZE(mSampleFormat),
438}
#define SAMPLE_SIZE(SampleFormat)
Definition: SampleFormat.h:52
size_t GetBlob(void *dest, sampleFormat destformat, sqlite3_stmt *stmt, sampleFormat srcformat, size_t srcoffset, size_t srcbytes)

References Conn(), GetBlob(), DBConnection::GetSamples, IsSilent(), mSampleFormat, DBConnection::Prepare(), SAMPLE_SIZE, and size.

Referenced by DoGetMinMaxRMS(), and GetFloatSampleView().

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

◆ GetBlob()

size_t SqliteSampleBlock::GetBlob ( void *  dest,
sampleFormat  destformat,
sqlite3_stmt *  stmt,
sampleFormat  srcformat,
size_t  srcoffset,
size_t  srcbytes 
)
private

Definition at line 580 of file SqliteSampleBlock.cpp.

586{
587 auto db = DB();
588
589 wxASSERT(!IsSilent());
590
591 if (!mValid)
592 {
593 Load(mBlockID);
594 }
595
596 int rc;
597 size_t minbytes = 0;
598
599 // Bind statement parameters
600 // Might return SQLITE_MISUSE which means it's our mistake that we violated
601 // preconditions; should return SQL_OK which is 0
602 if (sqlite3_bind_int64(stmt, 1, mBlockID))
603 {
605 "sqlite3.rc", std::to_string(sqlite3_errcode(Conn()->DB())));
606 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::GetBlob::bind");
607
608 wxASSERT_MSG(false, wxT("Binding failed...bug!!!"));
609 }
610
611 // Execute the statement
612 rc = sqlite3_step(stmt);
613 if (rc != SQLITE_ROW)
614 {
615 ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
616 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::GetBlob::step");
617
618 wxLogDebug(wxT("SqliteSampleBlock::GetBlob - SQLITE error %s"), sqlite3_errmsg(db));
619
620 // Clear statement bindings and rewind statement
621 sqlite3_clear_bindings(stmt);
622 sqlite3_reset(stmt);
623
624 // Just showing the user a simple message, not the library error too
625 // which isn't internationalized
626 // Actually this can lead to 'Could not read from file' error message
627 // but it can also lead to no error message at all and a flat line,
628 // depending on where GetBlob is called from.
629 // The latter can happen when repainting the screen.
630 // That possibly happens on a very slow machine. Possibly that's the
631 // right trade off when a machine can't keep up?
632 // ANSWER-ME: Do we always report an error when we should here?
633 Conn()->ThrowException( false );
634 }
635
636 // Retrieve returned data
637 samplePtr src = (samplePtr) sqlite3_column_blob(stmt, 0);
638 size_t blobbytes = (size_t) sqlite3_column_bytes(stmt, 0);
639
640 srcoffset = std::min(srcoffset, blobbytes);
641 minbytes = std::min(srcbytes, blobbytes - srcoffset);
642
643 if (srcoffset != 0)
644 {
645 srcoffset += 0;
646 }
647
648 /*
649 Will dithering happen in CopySamples? Answering this as of 3.0.3 by
650 examining all uses.
651
652 As this function is called from GetSummary, no, because destination format
653 is float.
654
655 There is only one other call to this function, in DoGetSamples. At one
656 call to that function, in DoGetMinMaxRMS, again format is float always.
657
658 There is only one other call to DoGetSamples, in SampleBlock::GetSamples().
659 In one call to that function, in WaveformView.cpp, again format is float.
660
661 That leaves two calls in Sequence.cpp. One of those can be proved to be
662 used only in copy and paste operations, always supplying the same sample
663 format as the samples were stored in, therefore no dither.
664
665 That leaves uses of Sequence::Read(). There are uses of Read() in internal
666 operations also easily shown to use only the saved format, and
667 GetWaveDisplay() always reads as float.
668
669 The remaining use of Sequence::Read() is in Sequence::Get(). That is used
670 by WaveClip::Resample(), always fetching float. It is also used in
671 WaveClip::GetSamples().
672
673 There is only one use of that function not always fetching float, in
674 WaveTrack::Get().
675
676 It can be shown that the only paths to WaveTrack::Get() not specifying
677 floatSample are in Benchmark, which is only a diagnostic test, and there
678 the sample format is the same as what the track was constructed with.
679
680 Therefore, no dithering even there!
681 */
682 wxASSERT(destformat == floatSample || destformat == srcformat);
683
684 CopySamples(src + srcoffset,
685 srcformat,
686 (samplePtr) dest,
687 destformat,
688 minbytes / SAMPLE_SIZE(srcformat));
689
690 dest = ((samplePtr) dest) + minbytes;
691
692 if (srcbytes - minbytes)
693 {
694 memset(dest, 0, srcbytes - minbytes);
695 }
696
697 // Clear statement bindings and rewind statement
698 sqlite3_clear_bindings(stmt);
699 sqlite3_reset(stmt);
700
701 return srcbytes;
702}
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.

References ADD_EXCEPTION_CONTEXT, Conn(), CopySamples(), DB(), floatSample, IsSilent(), Load(), mBlockID, min(), mValid, SAMPLE_SIZE, DBConnection::ThrowException(), and wxT().

Referenced by DoGetSamples(), and GetSummary().

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

◆ GetBlockID()

SampleBlockID SqliteSampleBlock::GetBlockID ( ) const
overridevirtual

Implements SampleBlock.

Definition at line 402 of file SqliteSampleBlock.cpp.

403{
404 return mBlockID;
405}

References mBlockID.

◆ GetFloatSampleView()

BlockSampleView SqliteSampleBlock::GetFloatSampleView ( bool  mayThrow)
overridevirtual

Implements SampleBlock.

Definition at line 300 of file SqliteSampleBlock.cpp.

301{
302 assert(mSampleCount > 0);
303
304 // Double-checked locking.
305 // `weak_ptr::lock()` guarantees atomicity, which is important to make this
306 // work without races.
307 auto cache = mCache.lock();
308 if (cache)
309 return cache;
310 std::lock_guard<std::mutex> lock(mCacheMutex);
311 cache = mCache.lock();
312 if (cache)
313 return cache;
314
315 const auto newCache =
316 std::make_shared<std::vector<float>>(mSampleCount);
317 try {
318 const auto cachedSize = DoGetSamples(
319 reinterpret_cast<samplePtr>(newCache->data()), floatSample, 0,
321 assert(cachedSize == mSampleCount);
322 }
323 catch (...)
324 {
325 if (mayThrow)
326 std::rethrow_exception(std::current_exception());
327 std::fill(newCache->begin(), newCache->end(), 0.f);
328 }
329 mCache = newCache;
330 return newCache;
331}

References DoGetSamples(), floatSample, mCache, mCacheMutex, and mSampleCount.

Here is the call graph for this function:

◆ GetSampleCount()

size_t SqliteSampleBlock::GetSampleCount ( ) const
overridevirtual

Implements SampleBlock.

Definition at line 412 of file SqliteSampleBlock.cpp.

413{
414 return mSampleCount;
415}

References mSampleCount.

◆ GetSampleFormat()

sampleFormat SqliteSampleBlock::GetSampleFormat ( ) const
overridevirtual

Implements SampleBlock.

Definition at line 407 of file SqliteSampleBlock.cpp.

408{
409 return mSampleFormat;
410}

References mSampleFormat.

◆ GetSpaceUsage()

size_t SqliteSampleBlock::GetSpaceUsage ( ) const
overridevirtual

Implements SampleBlock.

Definition at line 572 of file SqliteSampleBlock.cpp.

573{
574 if (IsSilent())
575 return 0;
576 else
578}
static int64_t GetDiskUsage(DBConnection &conn, SampleBlockID blockid)

References Conn(), ProjectFileIO::GetDiskUsage(), IsSilent(), and mBlockID.

Here is the call graph for this function:

◆ GetSummary()

bool SqliteSampleBlock::GetSummary ( float *  dest,
size_t  frameoffset,
size_t  numframes,
DBConnection::StatementID  id,
const char *  sql 
)
private

Definition at line 469 of file SqliteSampleBlock.cpp.

474{
475 // Non-throwing, it returns true for success
476 bool silent = IsSilent();
477 if (!silent) {
478 // Not a silent block
479 try {
480 // Prepare and cache statement...automatically finalized at DB close
481 auto stmt = Conn()->Prepare(id, sql);
482 // Note GetBlob returns a size_t, not a bool
483 // REVIEW: An error in GetBlob() will throw an exception.
484 GetBlob(dest,
486 stmt,
488 frameoffset * fields * SAMPLE_SIZE(floatSample),
489 numframes * fields * SAMPLE_SIZE(floatSample));
490 return true;
491 }
492 catch ( const AudacityException & ) {
493 }
494 }
495 memset(dest, 0, 3 * numframes * sizeof( float ));
496 // Return true for success only if we didn't catch
497 return silent;
498}
Base class for exceptions specially processed by the application.

References Conn(), fields, floatSample, GetBlob(), IsSilent(), DBConnection::Prepare(), and SAMPLE_SIZE.

Referenced by GetSummary256(), and GetSummary64k().

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

◆ GetSummary256()

bool SqliteSampleBlock::GetSummary256 ( float *  dest,
size_t  frameoffset,
size_t  numframes 
)
overridevirtual

Non-throwing, should fill with zeroes on failure.

Implements SampleBlock.

Definition at line 453 of file SqliteSampleBlock.cpp.

456{
457 return GetSummary(dest, frameoffset, numframes, DBConnection::GetSummary256,
458 "SELECT summary256 FROM sampleblocks WHERE blockid = ?1;");
459}
bool GetSummary(float *dest, size_t frameoffset, size_t numframes, DBConnection::StatementID id, const char *sql)

References GetSummary(), and DBConnection::GetSummary256.

Here is the call graph for this function:

◆ GetSummary64k()

bool SqliteSampleBlock::GetSummary64k ( float *  dest,
size_t  frameoffset,
size_t  numframes 
)
overridevirtual

Non-throwing, should fill with zeroes on failure.

Implements SampleBlock.

Definition at line 461 of file SqliteSampleBlock.cpp.

464{
465 return GetSummary(dest, frameoffset, numframes, DBConnection::GetSummary64k,
466 "SELECT summary64k FROM sampleblocks WHERE blockid = ?1;");
467}

References GetSummary(), and DBConnection::GetSummary64k.

Here is the call graph for this function:

◆ GetSumMax()

double SqliteSampleBlock::GetSumMax ( ) const

Definition at line 505 of file SqliteSampleBlock.cpp.

506{
507 return mSumMax;
508}

References mSumMax.

◆ GetSumMin()

double SqliteSampleBlock::GetSumMin ( ) const

Definition at line 500 of file SqliteSampleBlock.cpp.

501{
502 return mSumMin;
503}

References mSumMin.

◆ GetSumRms()

double SqliteSampleBlock::GetSumRms ( ) const

Definition at line 510 of file SqliteSampleBlock.cpp.

511{
512 return mSumRms;
513}

References mSumRms.

◆ IsSilent()

bool SqliteSampleBlock::IsSilent ( ) const
inlineprivate

Definition at line 85 of file SqliteSampleBlock.cpp.

85{ return mBlockID <= 0; }

References mBlockID.

Referenced by Delete(), DoGetMinMaxRMS(), DoGetSamples(), GetBlob(), GetSpaceUsage(), GetSummary(), and ~SqliteSampleBlock().

Here is the caller graph for this function:

◆ Load()

void SqliteSampleBlock::Load ( SampleBlockID  sbid)
private

Definition at line 704 of file SqliteSampleBlock.cpp.

705{
706 auto db = DB();
707 int rc;
708
709 wxASSERT(sbid > 0);
710
711 mValid = false;
712 mSampleCount = 0;
713 mSampleBytes = 0;
714 mSumMin = FLT_MAX;
715 mSumMax = -FLT_MAX;
716 mSumMin = 0.0;
717
718 // Prepare and cache statement...automatically finalized at DB close
719 sqlite3_stmt *stmt = Conn()->Prepare(DBConnection::LoadSampleBlock,
720 "SELECT sampleformat, summin, summax, sumrms,"
721 " length(samples)"
722 " FROM sampleblocks WHERE blockid = ?1;");
723
724 // Bind statement parameters
725 // Might return SQLITE_MISUSE which means it's our mistake that we violated
726 // preconditions; should return SQL_OK which is 0
727 if (sqlite3_bind_int64(stmt, 1, sbid))
728 {
729
730 ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(sqlite3_errcode(Conn()->DB())));
731 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Load::bind");
732
733 wxASSERT_MSG(false, wxT("Binding failed...bug!!!"));
734 }
735
736 // Execute the statement
737 rc = sqlite3_step(stmt);
738 if (rc != SQLITE_ROW)
739 {
740
741 ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
742 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Load::step");
743
744
745 wxLogDebug(wxT("SqliteSampleBlock::Load - SQLITE error %s"), sqlite3_errmsg(db));
746
747 // Clear statement bindings and rewind statement
748 sqlite3_clear_bindings(stmt);
749 sqlite3_reset(stmt);
750
751 // Just showing the user a simple message, not the library error too
752 // which isn't internationalized
753 Conn()->ThrowException( false );
754 }
755
756 // Retrieve returned data
757 mBlockID = sbid;
758 mSampleFormat = (sampleFormat) sqlite3_column_int(stmt, 0);
759 mSumMin = sqlite3_column_double(stmt, 1);
760 mSumMax = sqlite3_column_double(stmt, 2);
761 mSumRms = sqlite3_column_double(stmt, 3);
762 mSampleBytes = sqlite3_column_int(stmt, 4);
764
765 // Clear statement bindings and rewind statement
766 sqlite3_clear_bindings(stmt);
767 sqlite3_reset(stmt);
768
769 mValid = true;
770}
sampleFormat
The ordering of these values with operator < agrees with the order of increasing bit width.
Definition: SampleFormat.h:30

References ADD_EXCEPTION_CONTEXT, Conn(), DB(), DBConnection::LoadSampleBlock, mBlockID, mSampleBytes, mSampleCount, mSampleFormat, mSumMax, mSumMin, mSumRms, mValid, DBConnection::Prepare(), SAMPLE_SIZE, DBConnection::ThrowException(), and wxT().

Referenced by DoGetMinMaxRMS(), and GetBlob().

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

◆ SaveXML()

void SqliteSampleBlock::SaveXML ( XMLWriter xmlFile)
overridevirtual

Implements SampleBlock.

Definition at line 889 of file SqliteSampleBlock.cpp.

890{
891 xmlFile.WriteAttr(wxT("blockid"), mBlockID);
892}
void WriteAttr(const wxString &name, const Identifier &value)
Definition: XMLWriter.h:36

References mBlockID, XMLWriter::WriteAttr(), and wxT().

Here is the call graph for this function:

◆ SetSamples()

void SqliteSampleBlock::SetSamples ( constSamplePtr  src,
size_t  numsamples,
sampleFormat  srcformat 
)

Definition at line 440 of file SqliteSampleBlock.cpp.

443{
444 auto sizes = SetSizes(numsamples, srcformat);
446 memcpy(mSamples.get(), src, mSampleBytes);
447
448 CalcSummary( sizes );
449
450 Commit( sizes );
451}
Sizes SetSizes(size_t numsamples, sampleFormat srcformat)
void CalcSummary(Sizes sizes)
void Commit(Sizes sizes)

References CalcSummary(), Commit(), mSampleBytes, mSamples, ArrayOf< X >::reinit(), and SetSizes().

Here is the call graph for this function:

◆ SetSizes()

auto SqliteSampleBlock::SetSizes ( size_t  numsamples,
sampleFormat  srcformat 
)
private

Definition at line 894 of file SqliteSampleBlock.cpp.

896{
897 mSampleFormat = srcformat;
898 mSampleCount = numsamples;
900
901 int frames64k = (mSampleCount + 65535) / 65536;
902 int frames256 = frames64k * 256;
903 return { frames256 * bytesPerFrame, frames64k * bytesPerFrame };
904}

References SAMPLE_SIZE.

Referenced by SetSamples().

Here is the caller graph for this function:

Member Data Documentation

◆ mBlockID

SampleBlockID SqliteSampleBlock::mBlockID { 0 }
private

◆ mCache

std::weak_ptr<std::vector<float> > SqliteSampleBlock::mCache
private

Definition at line 41 of file SqliteSampleBlock.cpp.

Referenced by Commit(), and GetFloatSampleView().

◆ mCacheMutex

std::mutex SqliteSampleBlock::mCacheMutex
private

Definition at line 42 of file SqliteSampleBlock.cpp.

Referenced by Commit(), and GetFloatSampleView().

◆ mLocked

bool SqliteSampleBlock::mLocked = false
private

Definition at line 119 of file SqliteSampleBlock.cpp.

Referenced by CloseLock(), and ~SqliteSampleBlock().

◆ mpFactory

const std::shared_ptr<SqliteSampleBlockFactory> SqliteSampleBlock::mpFactory
private

Definition at line 117 of file SqliteSampleBlock.cpp.

Referenced by Conn(), and ~SqliteSampleBlock().

◆ mSampleBytes

size_t SqliteSampleBlock::mSampleBytes
private

Definition at line 124 of file SqliteSampleBlock.cpp.

Referenced by Commit(), Load(), SetSamples(), and SqliteSampleBlock().

◆ mSampleCount

size_t SqliteSampleBlock::mSampleCount
private

◆ mSampleFormat

sampleFormat SqliteSampleBlock::mSampleFormat
private

◆ mSamples

ArrayOf<char> SqliteSampleBlock::mSamples
private

Definition at line 123 of file SqliteSampleBlock.cpp.

Referenced by CalcSummary(), Commit(), and SetSamples().

◆ mSummary256

ArrayOf<char> SqliteSampleBlock::mSummary256
private

Definition at line 128 of file SqliteSampleBlock.cpp.

Referenced by CalcSummary(), and Commit().

◆ mSummary64k

ArrayOf<char> SqliteSampleBlock::mSummary64k
private

Definition at line 129 of file SqliteSampleBlock.cpp.

Referenced by CalcSummary(), and Commit().

◆ mSumMax

double SqliteSampleBlock::mSumMax
private

◆ mSumMin

double SqliteSampleBlock::mSumMin
private

◆ mSumRms

double SqliteSampleBlock::mSumRms
private

◆ mValid

bool SqliteSampleBlock::mValid { false }
private

Definition at line 118 of file SqliteSampleBlock.cpp.

Referenced by Commit(), DoGetMinMaxRMS(), GetBlob(), and Load().

◆ SqliteSampleBlockFactory

friend SqliteSampleBlock::SqliteSampleBlockFactory
private

Definition at line 115 of file SqliteSampleBlock.cpp.


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