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

 SqliteSampleBlock (const std::shared_ptr< SqliteSampleBlockFactory > &pFactory)
 
 ~SqliteSampleBlock () override
 
void CloseLock () 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 ()=0
 
virtual SampleBlockID GetBlockID () const =0
 
size_t GetSamples (samplePtr dest, sampleFormat destformat, size_t sampleoffset, size_t numsamples, bool mayThrow=true)
 
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

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

Member Enumeration Documentation

◆ anonymous enum

anonymous enum
private
Enumerator
fields 
bytesPerFrame 

Definition at line 88 of file SqliteSampleBlock.cpp.

88 {
89 fields = 3, /* min, max, rms */
90 bytesPerFrame = fields * sizeof(float),
91 };

Constructor & Destructor Documentation

◆ SqliteSampleBlock()

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

Definition at line 292 of file SqliteSampleBlock.cpp.

294: mpFactory(pFactory)
295{
297 mSampleBytes = 0;
298 mSampleCount = 0;
299
300 mSumMin = 0.0;
301 mSumMax = 0.0;
302 mSumRms = 0.0;
303}
sampleFormat mSampleFormat
const std::shared_ptr< SqliteSampleBlockFactory > mpFactory

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

◆ ~SqliteSampleBlock()

SqliteSampleBlock::~SqliteSampleBlock ( )
override

Definition at line 305 of file SqliteSampleBlock.cpp.

306{
308
309 if (IsSilent()) {
310 // The block object was constructed but failed to Load() or Commit().
311 // Or it's a silent block with no row in the database.
312 // Just let the stack unwind. Don't violate the assertion in
313 // Delete(), which may do odd recursive things in debug builds when it
314 // yields to the UI to put up a dialog, but then dispatches timer
315 // events that try again to finish recording.
316 return;
317 }
318
319 // See ProjectFileIO::Bypass() for a description of mIO.mBypass
320 GuardedCall( [this]{
321 if (!mLocked && !Conn()->ShouldBypass())
322 {
323 // In case Delete throws, don't let an exception escape a destructor,
324 // but we can still enqueue the delayed handler so that an error message
325 // is presented to the user.
326 // The failure in this case may be a less harmful waste of space in the
327 // database, which should not cause aborting of the attempted edit.
328 Delete();
329 }
330 } );
331}
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 861 of file SqliteSampleBlock.cpp.

862{
863 const auto mSummary256Bytes = sizes.first;
864 const auto mSummary64kBytes = sizes.second;
865
866 Floats samplebuffer;
867 float *samples;
868
870 {
871 samples = (float *) mSamples.get();
872 }
873 else
874 {
875 samplebuffer.reinit((unsigned) mSampleCount);
877 samplebuffer.get(), mSampleCount);
878 samples = samplebuffer.get();
879 }
880
881 mSummary256.reinit(mSummary256Bytes);
882 mSummary64k.reinit(mSummary64kBytes);
883
884 float *summary256 = (float *) mSummary256.get();
885 float *summary64k = (float *) mSummary64k.get();
886
887 float min;
888 float max;
889 float sumsq;
890 double totalSquares = 0.0;
891 double fraction = 0.0;
892
893 // Recalc 256 summaries
894 int sumLen = (mSampleCount + 255) / 256;
895 int summaries = 256;
896
897 for (int i = 0; i < sumLen; ++i)
898 {
899 min = samples[i * 256];
900 max = samples[i * 256];
901 sumsq = min * min;
902
903 int jcount = 256;
904 if (jcount > mSampleCount - i * 256)
905 {
906 jcount = mSampleCount - i * 256;
907 fraction = 1.0 - (jcount / 256.0);
908 }
909
910 for (int j = 1; j < jcount; ++j)
911 {
912 float f1 = samples[i * 256 + j];
913 sumsq += f1 * f1;
914
915 if (f1 < min)
916 {
917 min = f1;
918 }
919 else if (f1 > max)
920 {
921 max = f1;
922 }
923 }
924
925 totalSquares += sumsq;
926
927 summary256[i * fields] = min;
928 summary256[i * fields + 1] = max;
929 // The rms is correct, but this may be for less than 256 samples in last loop.
930 summary256[i * fields + 2] = (float) sqrt(sumsq / jcount);
931 }
932
933 for (int i = sumLen, frames256 = mSummary256Bytes / bytesPerFrame;
934 i < frames256; ++i)
935 {
936 // filling in the remaining bits with non-harming/contributing values
937 // rms values are not "non-harming", so keep count of them:
938 summaries--;
939 summary256[i * fields] = FLT_MAX; // min
940 summary256[i * fields + 1] = -FLT_MAX; // max
941 summary256[i * fields + 2] = 0.0f; // rms
942 }
943
944 // Calculate now while we can do it accurately
945 mSumRms = sqrt(totalSquares / mSampleCount);
946
947 // Recalc 64K summaries
948 sumLen = (mSampleCount + 65535) / 65536;
949
950 for (int i = 0; i < sumLen; ++i)
951 {
952 min = summary256[3 * i * 256];
953 max = summary256[3 * i * 256 + 1];
954 sumsq = summary256[3 * i * 256 + 2];
955 sumsq *= sumsq;
956
957 for (int j = 1; j < 256; ++j)
958 {
959 // we can overflow the useful summary256 values here, but have put
960 // non-harmful values in them
961 if (summary256[3 * (i * 256 + j)] < min)
962 {
963 min = summary256[3 * (i * 256 + j)];
964 }
965
966 if (summary256[3 * (i * 256 + j) + 1] > max)
967 {
968 max = summary256[3 * (i * 256 + j) + 1];
969 }
970
971 float r1 = summary256[3 * (i * 256 + j) + 2];
972 sumsq += r1 * r1;
973 }
974
975 double denom = (i < sumLen - 1) ? 256.0 : summaries - fraction;
976 float rms = (float) sqrt(sumsq / denom);
977
978 summary64k[i * fields] = min;
979 summary64k[i * fields + 1] = max;
980 summary64k[i * fields + 2] = rms;
981 }
982
983 for (int i = sumLen, frames64k = mSummary64kBytes / bytesPerFrame;
984 i < frames64k; ++i)
985 {
986 wxASSERT_MSG(false, wxT("Out of data for mSummaryInfo")); // Do we ever get here?
987
988 summary64k[i * fields] = 0.0f; // probably should be FLT_MAX, need a test case
989 summary64k[i * fields + 1] = 0.0f; // probably should be -FLT_MAX, need a test case
990 summary64k[i * fields + 2] = 0.0f; // just padding
991 }
992
993 // Recalc block-level summary (mRMS already calculated)
994 min = summary64k[0];
995 max = summary64k[1];
996
997 for (int i = 1; i < sumLen; ++i)
998 {
999 if (summary64k[i * fields] < min)
1000 {
1001 min = summary64k[i * fields];
1002 }
1003
1004 if (summary64k[i * fields + 1] > max)
1005 {
1006 max = summary64k[i * fields + 1];
1007 }
1008 }
1009
1010 mSumMin = min;
1011 mSumMax = max;
1012}
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:57
ArrayOf< char > mSummary256
ArrayOf< char > mSummary64k
ArrayOf< char > mSamples

References bytesPerFrame, fields, floatSample, min(), mSampleCount, mSampleFormat, mSamples, mSummary256, mSummary64k, mSumMax, mSumMin, mSumRms, ArrayOf< X >::reinit(), SamplesToFloats(), 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 ( )
overridevirtual

Implements SampleBlock.

Definition at line 351 of file SqliteSampleBlock.cpp.

352{
353 mLocked = true;
354}

References mLocked.

◆ Commit()

void SqliteSampleBlock::Commit ( Sizes  sizes)

Definition at line 726 of file SqliteSampleBlock.cpp.

727{
728 const auto mSummary256Bytes = sizes.first;
729 const auto mSummary64kBytes = sizes.second;
730
731 auto db = DB();
732 int rc;
733
734 // Prepare and cache statement...automatically finalized at DB close
735 sqlite3_stmt *stmt = Conn()->Prepare(DBConnection::InsertSampleBlock,
736 "INSERT INTO sampleblocks (sampleformat, summin, summax, sumrms,"
737 " summary256, summary64k, samples)"
738 " VALUES(?1,?2,?3,?4,?5,?6,?7);");
739
740 // Bind statement parameters
741 // Might return SQLITE_MISUSE which means it's our mistake that we violated
742 // preconditions; should return SQL_OK which is 0
743 if (sqlite3_bind_int(stmt, 1, static_cast<int>(mSampleFormat)) ||
744 sqlite3_bind_double(stmt, 2, mSumMin) ||
745 sqlite3_bind_double(stmt, 3, mSumMax) ||
746 sqlite3_bind_double(stmt, 4, mSumRms) ||
747 sqlite3_bind_blob(stmt, 5, mSummary256.get(), mSummary256Bytes, SQLITE_STATIC) ||
748 sqlite3_bind_blob(stmt, 6, mSummary64k.get(), mSummary64kBytes, SQLITE_STATIC) ||
749 sqlite3_bind_blob(stmt, 7, mSamples.get(), mSampleBytes, SQLITE_STATIC))
750 {
751
753 "sqlite3.rc", std::to_string(sqlite3_errcode(Conn()->DB())));
754 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Commit::bind");
755
756
757 wxASSERT_MSG(false, wxT("Binding failed...bug!!!"));
758 }
759
760 // Execute the statement
761 rc = sqlite3_step(stmt);
762 if (rc != SQLITE_DONE)
763 {
764 ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
765 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Commit::step");
766
767 wxLogDebug(wxT("SqliteSampleBlock::Commit - SQLITE error %s"), sqlite3_errmsg(db));
768
769 // Clear statement bindings and rewind statement
770 sqlite3_clear_bindings(stmt);
771 sqlite3_reset(stmt);
772
773 // Just showing the user a simple message, not the library error too
774 // which isn't internationalized
775 Conn()->ThrowException( true );
776 }
777
778 // Retrieve returned data
779 mBlockID = sqlite3_last_insert_rowid(db);
780
781 // Reset local arrays
782 mSamples.reset();
783 mSummary256.reset();
784 mSummary64k.reset();
785
786 // Clear statement bindings and rewind statement
787 sqlite3_clear_bindings(stmt);
788 sqlite3_reset(stmt);
789
790 mValid = true;
791}
#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)
sqlite3 * DB() const

References ADD_EXCEPTION_CONTEXT, Conn(), DB(), DBConnection::InsertSampleBlock, mBlockID, 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 333 of file SqliteSampleBlock.cpp.

334{
335 if (!mpFactory)
336 return nullptr;
337
338 auto &pConnection = mpFactory->mppConnection->mpConnection;
339 if (!pConnection) {
341 {
343 XO("Connection to project file is null"),
344 XO("Warning"),
345 "Error:_Disk_full_or_not_writable"
346 };
347 }
348 return pConnection.get();
349}
@ 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 99 of file SqliteSampleBlock.cpp.

100 {
101 return Conn()->DB();
102 }
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 793 of file SqliteSampleBlock.cpp.

794{
795 auto db = DB();
796 int rc;
797
798 wxASSERT(!IsSilent());
799
800 // Prepare and cache statement...automatically finalized at DB close
801 sqlite3_stmt *stmt = Conn()->Prepare(DBConnection::DeleteSampleBlock,
802 "DELETE FROM sampleblocks WHERE blockid = ?1;");
803
804 // Bind statement parameters
805 // Might return SQLITE_MISUSE which means it's our mistake that we violated
806 // preconditions; should return SQL_OK which is 0
807 if (sqlite3_bind_int64(stmt, 1, mBlockID))
808 {
810 "sqlite3.rc", std::to_string(sqlite3_errcode(Conn()->DB())));
811 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Delete::bind");
812
813 wxASSERT_MSG(false, wxT("Binding failed...bug!!!"));
814 }
815
816 // Execute the statement
817 rc = sqlite3_step(stmt);
818 if (rc != SQLITE_DONE)
819 {
820 ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
821 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Delete::step");
822
823 wxLogDebug(wxT("SqliteSampleBlock::Load - SQLITE error %s"), sqlite3_errmsg(db));
824
825 // Clear statement bindings and rewind statement
826 sqlite3_clear_bindings(stmt);
827 sqlite3_reset(stmt);
828
829 // Just showing the user a simple message, not the library error too
830 // which isn't internationalized
831 Conn()->ThrowException( true );
832 }
833
834 // Clear statement bindings and rewind statement
835 sqlite3_clear_bindings(stmt);
836 sqlite3_reset(stmt);
837}

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

522{
523 return { (float) mSumMin, (float) mSumMax, (float) mSumRms };
524}

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

475{
476 if (IsSilent())
477 return {};
478
479 float min = FLT_MAX;
480 float max = -FLT_MAX;
481 float sumsq = 0;
482
483 if (!mValid)
484 {
485 Load(mBlockID);
486 }
487
488 if (start < mSampleCount)
489 {
490 len = std::min(len, mSampleCount - start);
491
492 // TODO: actually use summaries
493 SampleBuffer blockData(len, floatSample);
494 float *samples = (float *) blockData.ptr();
495
496 size_t copied = DoGetSamples((samplePtr) samples, floatSample, start, len);
497 for (size_t i = 0; i < copied; ++i, ++samples)
498 {
499 float sample = *samples;
500
501 if (sample > max)
502 {
503 max = sample;
504 }
505
506 if (sample < min)
507 {
508 min = sample;
509 }
510
511 sumsq += (sample * sample);
512 }
513 }
514
515 return { min, max, (float) sqrt(sumsq / len) };
516}
char * samplePtr
Definition: SampleFormat.h:55
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, and SampleBuffer::ptr().

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

375{
376 if (IsSilent()) {
377 auto size = SAMPLE_SIZE(destformat);
378 memset(dest, 0, numsamples * size);
379 return numsamples;
380 }
381
382 // Prepare and cache statement...automatically finalized at DB close
383 sqlite3_stmt *stmt = Conn()->Prepare(DBConnection::GetSamples,
384 "SELECT samples FROM sampleblocks WHERE blockid = ?1;");
385
386 return GetBlob(dest,
387 destformat,
388 stmt,
390 sampleoffset * SAMPLE_SIZE(mSampleFormat),
392}
#define SAMPLE_SIZE(SampleFormat)
Definition: SampleFormat.h:50
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().

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

540{
541 auto db = DB();
542
543 wxASSERT(!IsSilent());
544
545 if (!mValid)
546 {
547 Load(mBlockID);
548 }
549
550 int rc;
551 size_t minbytes = 0;
552
553 // Bind statement parameters
554 // Might return SQLITE_MISUSE which means it's our mistake that we violated
555 // preconditions; should return SQL_OK which is 0
556 if (sqlite3_bind_int64(stmt, 1, mBlockID))
557 {
559 "sqlite3.rc", std::to_string(sqlite3_errcode(Conn()->DB())));
560 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::GetBlob::bind");
561
562 wxASSERT_MSG(false, wxT("Binding failed...bug!!!"));
563 }
564
565 // Execute the statement
566 rc = sqlite3_step(stmt);
567 if (rc != SQLITE_ROW)
568 {
569 ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
570 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::GetBlob::step");
571
572 wxLogDebug(wxT("SqliteSampleBlock::GetBlob - SQLITE error %s"), sqlite3_errmsg(db));
573
574 // Clear statement bindings and rewind statement
575 sqlite3_clear_bindings(stmt);
576 sqlite3_reset(stmt);
577
578 // Just showing the user a simple message, not the library error too
579 // which isn't internationalized
580 // Actually this can lead to 'Could not read from file' error message
581 // but it can also lead to no error message at all and a flat line,
582 // depending on where GetBlob is called from.
583 // The latter can happen when repainting the screen.
584 // That possibly happens on a very slow machine. Possibly that's the
585 // right trade off when a machine can't keep up?
586 // ANSWER-ME: Do we always report an error when we should here?
587 Conn()->ThrowException( false );
588 }
589
590 // Retrieve returned data
591 samplePtr src = (samplePtr) sqlite3_column_blob(stmt, 0);
592 size_t blobbytes = (size_t) sqlite3_column_bytes(stmt, 0);
593
594 srcoffset = std::min(srcoffset, blobbytes);
595 minbytes = std::min(srcbytes, blobbytes - srcoffset);
596
597 if (srcoffset != 0)
598 {
599 srcoffset += 0;
600 }
601
602 /*
603 Will dithering happen in CopySamples? Answering this as of 3.0.3 by
604 examining all uses.
605
606 As this function is called from GetSummary, no, because destination format
607 is float.
608
609 There is only one other call to this function, in DoGetSamples. At one
610 call to that function, in DoGetMinMaxRMS, again format is float always.
611
612 There is only one other call to DoGetSamples, in SampleBlock::GetSamples().
613 In one call to that function, in WaveformView.cpp, again format is float.
614
615 That leaves two calls in Sequence.cpp. One of those can be proved to be
616 used only in copy and paste operations, always supplying the same sample
617 format as the samples were stored in, therefore no dither.
618
619 That leaves uses of Sequence::Read(). There are uses of Read() in internal
620 operations also easily shown to use only the saved format, and
621 GetWaveDisplay() always reads as float.
622
623 The remaining use of Sequence::Read() is in Sequence::Get(). That is used
624 by WaveClip::Resample(), always fetching float. It is also used in
625 WaveClip::GetSamples().
626
627 There is only one use of that function not always fetching float, in
628 WaveTrack::Get().
629
630 It can be shown that the only paths to WaveTrack::Get() not specifying
631 floatSample are in Benchmark, which is only a diagnostic test, and there
632 the sample format is the same as what the track was constructed with.
633
634 Therefore, no dithering even there!
635 */
636 wxASSERT(destformat == floatSample || destformat == srcformat);
637
638 CopySamples(src + srcoffset,
639 srcformat,
640 (samplePtr) dest,
641 destformat,
642 minbytes / SAMPLE_SIZE(srcformat));
643
644 dest = ((samplePtr) dest) + minbytes;
645
646 if (srcbytes - minbytes)
647 {
648 memset(dest, 0, srcbytes - minbytes);
649 }
650
651 // Clear statement bindings and rewind statement
652 sqlite3_clear_bindings(stmt);
653 sqlite3_reset(stmt);
654
655 return srcbytes;
656}
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 356 of file SqliteSampleBlock.cpp.

357{
358 return mBlockID;
359}

References mBlockID.

◆ GetSampleCount()

size_t SqliteSampleBlock::GetSampleCount ( ) const
overridevirtual

Implements SampleBlock.

Definition at line 366 of file SqliteSampleBlock.cpp.

367{
368 return mSampleCount;
369}

References mSampleCount.

◆ GetSampleFormat()

sampleFormat SqliteSampleBlock::GetSampleFormat ( ) const

Definition at line 361 of file SqliteSampleBlock.cpp.

362{
363 return mSampleFormat;
364}

References mSampleFormat.

◆ GetSpaceUsage()

size_t SqliteSampleBlock::GetSpaceUsage ( ) const
overridevirtual

Implements SampleBlock.

Definition at line 526 of file SqliteSampleBlock.cpp.

527{
528 if (IsSilent())
529 return 0;
530 else
532}
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 423 of file SqliteSampleBlock.cpp.

428{
429 // Non-throwing, it returns true for success
430 bool silent = IsSilent();
431 if (!silent) {
432 // Not a silent block
433 try {
434 // Prepare and cache statement...automatically finalized at DB close
435 auto stmt = Conn()->Prepare(id, sql);
436 // Note GetBlob returns a size_t, not a bool
437 // REVIEW: An error in GetBlob() will throw an exception.
438 GetBlob(dest,
440 stmt,
442 frameoffset * fields * SAMPLE_SIZE(floatSample),
443 numframes * fields * SAMPLE_SIZE(floatSample));
444 return true;
445 }
446 catch ( const AudacityException & ) {
447 }
448 }
449 memset(dest, 0, 3 * numframes * sizeof( float ));
450 // Return true for success only if we didn't catch
451 return silent;
452}
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 407 of file SqliteSampleBlock.cpp.

410{
411 return GetSummary(dest, frameoffset, numframes, DBConnection::GetSummary256,
412 "SELECT summary256 FROM sampleblocks WHERE blockid = ?1;");
413}
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 415 of file SqliteSampleBlock.cpp.

418{
419 return GetSummary(dest, frameoffset, numframes, DBConnection::GetSummary64k,
420 "SELECT summary64k FROM sampleblocks WHERE blockid = ?1;");
421}

References GetSummary(), and DBConnection::GetSummary64k.

Here is the call graph for this function:

◆ GetSumMax()

double SqliteSampleBlock::GetSumMax ( ) const

Definition at line 459 of file SqliteSampleBlock.cpp.

460{
461 return mSumMax;
462}

References mSumMax.

◆ GetSumMin()

double SqliteSampleBlock::GetSumMin ( ) const

Definition at line 454 of file SqliteSampleBlock.cpp.

455{
456 return mSumMin;
457}

References mSumMin.

◆ GetSumRms()

double SqliteSampleBlock::GetSumRms ( ) const

Definition at line 464 of file SqliteSampleBlock.cpp.

465{
466 return mSumRms;
467}

References mSumRms.

◆ IsSilent()

bool SqliteSampleBlock::IsSilent ( ) const
inlineprivate

Definition at line 74 of file SqliteSampleBlock.cpp.

74{ 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 658 of file SqliteSampleBlock.cpp.

659{
660 auto db = DB();
661 int rc;
662
663 wxASSERT(sbid > 0);
664
665 mValid = false;
666 mSampleCount = 0;
667 mSampleBytes = 0;
668 mSumMin = FLT_MAX;
669 mSumMax = -FLT_MAX;
670 mSumMin = 0.0;
671
672 // Prepare and cache statement...automatically finalized at DB close
673 sqlite3_stmt *stmt = Conn()->Prepare(DBConnection::LoadSampleBlock,
674 "SELECT sampleformat, summin, summax, sumrms,"
675 " length(samples)"
676 " FROM sampleblocks WHERE blockid = ?1;");
677
678 // Bind statement parameters
679 // Might return SQLITE_MISUSE which means it's our mistake that we violated
680 // preconditions; should return SQL_OK which is 0
681 if (sqlite3_bind_int64(stmt, 1, sbid))
682 {
683
684 ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(sqlite3_errcode(Conn()->DB())));
685 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Load::bind");
686
687 wxASSERT_MSG(false, wxT("Binding failed...bug!!!"));
688 }
689
690 // Execute the statement
691 rc = sqlite3_step(stmt);
692 if (rc != SQLITE_ROW)
693 {
694
695 ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
696 ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Load::step");
697
698
699 wxLogDebug(wxT("SqliteSampleBlock::Load - SQLITE error %s"), sqlite3_errmsg(db));
700
701 // Clear statement bindings and rewind statement
702 sqlite3_clear_bindings(stmt);
703 sqlite3_reset(stmt);
704
705 // Just showing the user a simple message, not the library error too
706 // which isn't internationalized
707 Conn()->ThrowException( false );
708 }
709
710 // Retrieve returned data
711 mBlockID = sbid;
712 mSampleFormat = (sampleFormat) sqlite3_column_int(stmt, 0);
713 mSumMin = sqlite3_column_double(stmt, 1);
714 mSumMax = sqlite3_column_double(stmt, 2);
715 mSumRms = sqlite3_column_double(stmt, 3);
716 mSampleBytes = sqlite3_column_int(stmt, 4);
718
719 // Clear statement bindings and rewind statement
720 sqlite3_clear_bindings(stmt);
721 sqlite3_reset(stmt);
722
723 mValid = true;
724}
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 839 of file SqliteSampleBlock.cpp.

840{
841 xmlFile.WriteAttr(wxT("blockid"), mBlockID);
842}
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 394 of file SqliteSampleBlock.cpp.

397{
398 auto sizes = SetSizes(numsamples, srcformat);
400 memcpy(mSamples.get(), src, mSampleBytes);
401
402 CalcSummary( sizes );
403
404 Commit( sizes );
405}
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 844 of file SqliteSampleBlock.cpp.

846{
847 mSampleFormat = srcformat;
848 mSampleCount = numsamples;
850
851 int frames64k = (mSampleCount + 65535) / 65536;
852 int frames256 = frames64k * 256;
853 return { frames256 * bytesPerFrame, frames64k * bytesPerFrame };
854}

References SAMPLE_SIZE.

Referenced by SetSamples().

Here is the caller graph for this function:

Member Data Documentation

◆ mBlockID

SampleBlockID SqliteSampleBlock::mBlockID { 0 }
private

◆ mLocked

bool SqliteSampleBlock::mLocked = false
private

Definition at line 108 of file SqliteSampleBlock.cpp.

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

◆ mpFactory

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

Definition at line 106 of file SqliteSampleBlock.cpp.

Referenced by Conn().

◆ mSampleBytes

size_t SqliteSampleBlock::mSampleBytes
private

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

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

◆ mSummary256

ArrayOf<char> SqliteSampleBlock::mSummary256
private

Definition at line 117 of file SqliteSampleBlock.cpp.

Referenced by CalcSummary(), and Commit().

◆ mSummary64k

ArrayOf<char> SqliteSampleBlock::mSummary64k
private

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

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

◆ SqliteSampleBlockFactory

friend SqliteSampleBlock::SqliteSampleBlockFactory
private

Definition at line 104 of file SqliteSampleBlock.cpp.


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