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

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

396{
397 mLocked = true;
398}

References mLocked.

◆ Commit()

void SqliteSampleBlock::Commit ( Sizes  sizes)

Definition at line 770 of file SqliteSampleBlock.cpp.

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

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

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

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

566{
567 return { (float) mSumMin, (float) mSumMax, (float) mSumRms };
568}

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

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

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

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

401{
402 return mBlockID;
403}

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

411{
412 return mSampleCount;
413}

References mSampleCount.

◆ GetSampleFormat()

sampleFormat SqliteSampleBlock::GetSampleFormat ( ) const
overridevirtual

Implements SampleBlock.

Definition at line 405 of file SqliteSampleBlock.cpp.

406{
407 return mSampleFormat;
408}

References mSampleFormat.

◆ GetSpaceUsage()

size_t SqliteSampleBlock::GetSpaceUsage ( ) const
overridevirtual

Implements SampleBlock.

Definition at line 570 of file SqliteSampleBlock.cpp.

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

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

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

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

References GetSummary(), and DBConnection::GetSummary64k.

Here is the call graph for this function:

◆ GetSumMax()

double SqliteSampleBlock::GetSumMax ( ) const

Definition at line 503 of file SqliteSampleBlock.cpp.

504{
505 return mSumMax;
506}

References mSumMax.

◆ GetSumMin()

double SqliteSampleBlock::GetSumMin ( ) const

Definition at line 498 of file SqliteSampleBlock.cpp.

499{
500 return mSumMin;
501}

References mSumMin.

◆ GetSumRms()

double SqliteSampleBlock::GetSumRms ( ) const

Definition at line 508 of file SqliteSampleBlock.cpp.

509{
510 return mSumRms;
511}

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

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

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

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

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

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: