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 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
 
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 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 33 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 53 of file SqliteSampleBlock.cpp.

Member Enumeration Documentation

◆ anonymous enum

anonymous enum
private
Enumerator
fields 
bytesPerFrame 

Definition at line 97 of file SqliteSampleBlock.cpp.

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

Constructor & Destructor Documentation

◆ SqliteSampleBlock()

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

Definition at line 334 of file SqliteSampleBlock.cpp.

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

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

◆ ~SqliteSampleBlock()

SqliteSampleBlock::~SqliteSampleBlock ( )
override

Definition at line 347 of file SqliteSampleBlock.cpp.

348{
350
351 if (IsSilent()) {
352 // The block object was constructed but failed to Load() or Commit().
353 // Or it's a silent block with no row in the database.
354 // Just let the stack unwind. Don't violate the assertion in
355 // Delete(), which may do odd recursive things in debug builds when it
356 // yields to the UI to put up a dialog, but then dispatches timer
357 // events that try again to finish recording.
358 return;
359 }
360
361 // See ProjectFileIO::Bypass() for a description of mIO.mBypass
362 GuardedCall( [this]{
363 if (!mLocked && !Conn()->ShouldBypass())
364 {
365 // In case Delete throws, don't let an exception escape a destructor,
366 // but we can still enqueue the delayed handler so that an error message
367 // is presented to the user.
368 // The failure in this case may be a less harmful waste of space in the
369 // database, which should not cause aborting of the attempted edit.
370 Delete();
371 }
372 } );
373}
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...
static result_type Call(Arguments &&...arguments)
Null check of the installed function is done for you.
DBConnection * Conn() const
This must never be called for silent blocks.

References GlobalHook< DeletionCallback, void(const SampleBlock &) >::Call(), Conn(), Delete(), GuardedCall(), IsSilent(), and mLocked.

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 907 of file SqliteSampleBlock.cpp.

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

394{
395 mLocked = true;
396}

References mLocked.

◆ Commit()

void SqliteSampleBlock::Commit ( Sizes  sizes)

Definition at line 768 of file SqliteSampleBlock.cpp.

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

376{
377 if (!mpFactory)
378 return nullptr;
379
380 auto &pConnection = mpFactory->mppConnection->mpConnection;
381 if (!pConnection) {
383 {
385 XO("Connection to project file is null"),
386 XO("Warning"),
387 "Error:_Disk_full_or_not_writable"
388 };
389 }
390 return pConnection.get();
391}
@ 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 108 of file SqliteSampleBlock.cpp.

109 {
110 return Conn()->DB();
111 }
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 839 of file SqliteSampleBlock.cpp.

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

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 563 of file SqliteSampleBlock.cpp.

564{
565 return { (float) mSumMin, (float) mSumMax, (float) mSumRms };
566}

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 516 of file SqliteSampleBlock.cpp.

517{
518 if (IsSilent())
519 return {};
520
521 float min = FLT_MAX;
522 float max = -FLT_MAX;
523 float sumsq = 0;
524
525 if (!mValid)
526 {
527 Load(mBlockID);
528 }
529
530 if (start < mSampleCount)
531 {
532 len = std::min(len, mSampleCount - start);
533
534 // TODO: actually use summaries
535 SampleBuffer blockData(len, floatSample);
536 float *samples = (float *) blockData.ptr();
537
538 size_t copied = DoGetSamples((samplePtr) samples, floatSample, start, len);
539 for (size_t i = 0; i < copied; ++i, ++samples)
540 {
541 float sample = *samples;
542
543 if (sample > max)
544 {
545 max = sample;
546 }
547
548 if (sample < min)
549 {
550 min = sample;
551 }
552
553 sumsq += (sample * sample);
554 }
555 }
556
557 return { min, max, (float) sqrt(sumsq / len) };
558}
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 413 of file SqliteSampleBlock.cpp.

417{
418 if (IsSilent()) {
419 auto size = SAMPLE_SIZE(destformat);
420 memset(dest, 0, numsamples * size);
421 return numsamples;
422 }
423
424 // Prepare and cache statement...automatically finalized at DB close
425 sqlite3_stmt *stmt = Conn()->Prepare(DBConnection::GetSamples,
426 "SELECT samples FROM sampleblocks WHERE blockid = ?1;");
427
428 return GetBlob(dest,
429 destformat,
430 stmt,
432 sampleoffset * SAMPLE_SIZE(mSampleFormat),
434}
#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 576 of file SqliteSampleBlock.cpp.

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

399{
400 return mBlockID;
401}

References mBlockID.

◆ GetFloatSampleView()

BlockSampleView SqliteSampleBlock::GetFloatSampleView ( bool  mayThrow)
overridevirtual

Implements SampleBlock.

Definition at line 301 of file SqliteSampleBlock.cpp.

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

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 408 of file SqliteSampleBlock.cpp.

409{
410 return mSampleCount;
411}

References mSampleCount.

◆ GetSampleFormat()

sampleFormat SqliteSampleBlock::GetSampleFormat ( ) const

Definition at line 403 of file SqliteSampleBlock.cpp.

404{
405 return mSampleFormat;
406}

References mSampleFormat.

◆ GetSpaceUsage()

size_t SqliteSampleBlock::GetSpaceUsage ( ) const
overridevirtual

Implements SampleBlock.

Definition at line 568 of file SqliteSampleBlock.cpp.

569{
570 if (IsSilent())
571 return 0;
572 else
574}
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 465 of file SqliteSampleBlock.cpp.

470{
471 // Non-throwing, it returns true for success
472 bool silent = IsSilent();
473 if (!silent) {
474 // Not a silent block
475 try {
476 // Prepare and cache statement...automatically finalized at DB close
477 auto stmt = Conn()->Prepare(id, sql);
478 // Note GetBlob returns a size_t, not a bool
479 // REVIEW: An error in GetBlob() will throw an exception.
480 GetBlob(dest,
482 stmt,
484 frameoffset * fields * SAMPLE_SIZE(floatSample),
485 numframes * fields * SAMPLE_SIZE(floatSample));
486 return true;
487 }
488 catch ( const AudacityException & ) {
489 }
490 }
491 memset(dest, 0, 3 * numframes * sizeof( float ));
492 // Return true for success only if we didn't catch
493 return silent;
494}
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 449 of file SqliteSampleBlock.cpp.

452{
453 return GetSummary(dest, frameoffset, numframes, DBConnection::GetSummary256,
454 "SELECT summary256 FROM sampleblocks WHERE blockid = ?1;");
455}
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 457 of file SqliteSampleBlock.cpp.

460{
461 return GetSummary(dest, frameoffset, numframes, DBConnection::GetSummary64k,
462 "SELECT summary64k FROM sampleblocks WHERE blockid = ?1;");
463}

References GetSummary(), and DBConnection::GetSummary64k.

Here is the call graph for this function:

◆ GetSumMax()

double SqliteSampleBlock::GetSumMax ( ) const

Definition at line 501 of file SqliteSampleBlock.cpp.

502{
503 return mSumMax;
504}

References mSumMax.

◆ GetSumMin()

double SqliteSampleBlock::GetSumMin ( ) const

Definition at line 496 of file SqliteSampleBlock.cpp.

497{
498 return mSumMin;
499}

References mSumMin.

◆ GetSumRms()

double SqliteSampleBlock::GetSumRms ( ) const

Definition at line 506 of file SqliteSampleBlock.cpp.

507{
508 return mSumRms;
509}

References mSumRms.

◆ IsSilent()

bool SqliteSampleBlock::IsSilent ( ) const
inlineprivate

Definition at line 83 of file SqliteSampleBlock.cpp.

83{ 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 700 of file SqliteSampleBlock.cpp.

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

886{
887 xmlFile.WriteAttr(wxT("blockid"), mBlockID);
888}
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 436 of file SqliteSampleBlock.cpp.

439{
440 auto sizes = SetSizes(numsamples, srcformat);
442 memcpy(mSamples.get(), src, mSampleBytes);
443
444 CalcSummary( sizes );
445
446 Commit( sizes );
447}
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 890 of file SqliteSampleBlock.cpp.

892{
893 mSampleFormat = srcformat;
894 mSampleCount = numsamples;
896
897 int frames64k = (mSampleCount + 65535) / 65536;
898 int frames256 = frames64k * 256;
899 return { frames256 * bytesPerFrame, frames64k * bytesPerFrame };
900}

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 39 of file SqliteSampleBlock.cpp.

Referenced by Commit(), and GetFloatSampleView().

◆ mCacheMutex

std::mutex SqliteSampleBlock::mCacheMutex
private

Definition at line 40 of file SqliteSampleBlock.cpp.

Referenced by Commit(), and GetFloatSampleView().

◆ mLocked

bool SqliteSampleBlock::mLocked = false
private

Definition at line 117 of file SqliteSampleBlock.cpp.

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

◆ mpFactory

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

Definition at line 115 of file SqliteSampleBlock.cpp.

Referenced by Conn().

◆ mSampleBytes

size_t SqliteSampleBlock::mSampleBytes
private

Definition at line 122 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 121 of file SqliteSampleBlock.cpp.

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

◆ mSummary256

ArrayOf<char> SqliteSampleBlock::mSummary256
private

Definition at line 126 of file SqliteSampleBlock.cpp.

Referenced by CalcSummary(), and Commit().

◆ mSummary64k

ArrayOf<char> SqliteSampleBlock::mSummary64k
private

Definition at line 127 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 116 of file SqliteSampleBlock.cpp.

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

◆ SqliteSampleBlockFactory

friend SqliteSampleBlock::SqliteSampleBlockFactory
private

Definition at line 113 of file SqliteSampleBlock.cpp.


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