35 const std::shared_ptr<SqliteSampleBlockFactory> &pFactory);
44 using Sizes = std::pair< size_t, size_t >;
54 size_t numsamples)
override;
58 bool GetSummary256(
float *dest,
size_t frameoffset,
size_t numframes)
override;
59 bool GetSummary64k(
float *dest,
size_t frameoffset,
size_t numframes)
override;
106 const std::shared_ptr<SqliteSampleBlockFactory>
mpFactory;
123#if defined(WORDS_BIGENDIAN)
124#error All sample block data is little endian...big endian not yet supported
131static std::map< SampleBlockID, std::shared_ptr<SqliteSampleBlock> >
137 ,
public std::enable_shared_from_this<SqliteSampleBlockFactory>
166 std::optional<SampleBlock::DeletionCallback::Scope>
mScope;
174 std::map< SampleBlockID, std::weak_ptr< SqliteSampleBlock > >;
179 : mProject{ project }
184 switch (message.
type) {
185 case UndoRedoMessage::BeginPurge:
186 return OnBeginPurge(message.begin, message.end);
187 case UndoRedoMessage::EndPurge:
200 auto sb = std::make_shared<SqliteSampleBlock>(shared_from_this());
201 sb->SetSamples(src, numsamples, srcformat);
210 for (
auto end = mAllBlocks.end(), it = mAllBlocks.begin(); it !=
end;) {
211 if (it->second.expired())
213 it = mAllBlocks.erase(it);
215 result.insert( it->first );
228 result = std::make_shared<SqliteSampleBlock>(
nullptr);
229 result->mBlockID =
id;
233 result->mValid =
true;
243 std::shared_ptr<SampleBlock> sb;
248 for (
auto pair : attrs)
250 auto attr = pair.first;
251 auto value = pair.second;
255 if (attr ==
"blockid" && value.TryGet(nValue))
270 std::make_shared<SqliteSampleBlock>(shared_from_this());
273 ssb->mSampleFormat = srcformat;
293 const std::shared_ptr<SqliteSampleBlockFactory> &pFactory)
338 auto &pConnection =
mpFactory->mppConnection->mpConnection;
343 XO(
"Connection to project file is null"),
345 "Error:_Disk_full_or_not_writable"
348 return pConnection.get();
378 memset(dest, 0, numsamples *
size);
384 "SELECT samples FROM sampleblocks WHERE blockid = ?1;");
398 auto sizes =
SetSizes(numsamples, srcformat);
412 "SELECT summary256 FROM sampleblocks WHERE blockid = ?1;");
420 "SELECT summary64k FROM sampleblocks WHERE blockid = ?1;");
449 memset(dest, 0, 3 * numframes *
sizeof(
float ));
480 float max = -FLT_MAX;
494 float *samples = (
float *) blockData.
ptr();
497 for (
size_t i = 0; i < copied; ++i, ++samples)
499 float sample = *samples;
511 sumsq += (sample * sample);
515 return {
min, max, (float) sqrt(sumsq / len) };
556 if (sqlite3_bind_int64(stmt, 1,
mBlockID))
559 "sqlite3.rc", std::to_string(sqlite3_errcode(
Conn()->
DB())));
562 wxASSERT_MSG(
false,
wxT(
"Binding failed...bug!!!"));
566 rc = sqlite3_step(stmt);
567 if (rc != SQLITE_ROW)
572 wxLogDebug(
wxT(
"SqliteSampleBlock::GetBlob - SQLITE error %s"), sqlite3_errmsg(db));
575 sqlite3_clear_bindings(stmt);
592 size_t blobbytes = (size_t) sqlite3_column_bytes(stmt, 0);
594 srcoffset =
std::min(srcoffset, blobbytes);
595 minbytes =
std::min(srcbytes, blobbytes - srcoffset);
636 wxASSERT(destformat ==
floatSample || destformat == srcformat);
646 if (srcbytes - minbytes)
648 memset(dest, 0, srcbytes - minbytes);
652 sqlite3_clear_bindings(stmt);
674 "SELECT sampleformat, summin, summax, sumrms,"
676 " FROM sampleblocks WHERE blockid = ?1;");
681 if (sqlite3_bind_int64(stmt, 1, sbid))
687 wxASSERT_MSG(
false,
wxT(
"Binding failed...bug!!!"));
691 rc = sqlite3_step(stmt);
692 if (rc != SQLITE_ROW)
699 wxLogDebug(
wxT(
"SqliteSampleBlock::Load - SQLITE error %s"), sqlite3_errmsg(db));
702 sqlite3_clear_bindings(stmt);
713 mSumMin = sqlite3_column_double(stmt, 1);
714 mSumMax = sqlite3_column_double(stmt, 2);
715 mSumRms = sqlite3_column_double(stmt, 3);
720 sqlite3_clear_bindings(stmt);
728 const auto mSummary256Bytes = sizes.first;
729 const auto mSummary64kBytes = sizes.second;
736 "INSERT INTO sampleblocks (sampleformat, summin, summax, sumrms,"
737 " summary256, summary64k, samples)"
738 " VALUES(?1,?2,?3,?4,?5,?6,?7);");
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) ||
753 "sqlite3.rc", std::to_string(sqlite3_errcode(
Conn()->
DB())));
757 wxASSERT_MSG(
false,
wxT(
"Binding failed...bug!!!"));
761 rc = sqlite3_step(stmt);
762 if (rc != SQLITE_DONE)
767 wxLogDebug(
wxT(
"SqliteSampleBlock::Commit - SQLITE error %s"), sqlite3_errmsg(db));
770 sqlite3_clear_bindings(stmt);
779 mBlockID = sqlite3_last_insert_rowid(db);
787 sqlite3_clear_bindings(stmt);
802 "DELETE FROM sampleblocks WHERE blockid = ?1;");
807 if (sqlite3_bind_int64(stmt, 1,
mBlockID))
810 "sqlite3.rc", std::to_string(sqlite3_errcode(
Conn()->
DB())));
813 wxASSERT_MSG(
false,
wxT(
"Binding failed...bug!!!"));
817 rc = sqlite3_step(stmt);
818 if (rc != SQLITE_DONE)
823 wxLogDebug(
wxT(
"SqliteSampleBlock::Load - SQLITE error %s"), sqlite3_errmsg(db));
826 sqlite3_clear_bindings(stmt);
835 sqlite3_clear_bindings(stmt);
847 mSampleFormat = srcformat;
848 mSampleCount = numsamples;
849 mSampleBytes = mSampleCount *
SAMPLE_SIZE(mSampleFormat);
851 int frames64k = (mSampleCount + 65535) / 65536;
852 int frames256 = frames64k * 256;
853 return { frames256 * bytesPerFrame, frames64k * bytesPerFrame };
863 const auto mSummary256Bytes = sizes.first;
864 const auto mSummary64kBytes = sizes.second;
878 samples = samplebuffer.get();
890 double totalSquares = 0.0;
891 double fraction = 0.0;
897 for (
int i = 0; i < sumLen; ++i)
899 min = samples[i * 256];
900 max = samples[i * 256];
907 fraction = 1.0 - (jcount / 256.0);
910 for (
int j = 1; j < jcount; ++j)
912 float f1 = samples[i * 256 + j];
925 totalSquares += sumsq;
928 summary256[i *
fields + 1] = max;
930 summary256[i *
fields + 2] = (float) sqrt(sumsq / jcount);
933 for (
int i = sumLen, frames256 = mSummary256Bytes /
bytesPerFrame;
939 summary256[i *
fields] = FLT_MAX;
940 summary256[i *
fields + 1] = -FLT_MAX;
941 summary256[i *
fields + 2] = 0.0f;
950 for (
int i = 0; i < sumLen; ++i)
952 min = summary256[3 * i * 256];
953 max = summary256[3 * i * 256 + 1];
954 sumsq = summary256[3 * i * 256 + 2];
957 for (
int j = 1; j < 256; ++j)
961 if (summary256[3 * (i * 256 + j)] <
min)
963 min = summary256[3 * (i * 256 + j)];
966 if (summary256[3 * (i * 256 + j) + 1] > max)
968 max = summary256[3 * (i * 256 + j) + 1];
971 float r1 = summary256[3 * (i * 256 + j) + 2];
975 double denom = (i < sumLen - 1) ? 256.0 : summaries - fraction;
976 float rms = (float) sqrt(sumsq / denom);
979 summary64k[i *
fields + 1] = max;
980 summary64k[i *
fields + 2] = rms;
983 for (
int i = sumLen, frames64k = mSummary64kBytes /
bytesPerFrame;
986 wxASSERT_MSG(
false,
wxT(
"Out of data for mSummaryInfo"));
988 summary64k[i *
fields] = 0.0f;
989 summary64k[i *
fields + 1] = 0.0f;
990 summary64k[i *
fields + 2] = 0.0f;
997 for (
int i = 1; i < sumLen; ++i)
1004 if (summary64k[i *
fields + 1] > max)
1006 max = summary64k[i *
fields + 1];
1028 if (
const auto saved =
manager.GetSavedState(); saved >= 0)
1029 manager.VisitStates(f, saved, saved + 1);
1038 if (
id > 0 && !wontDelete.count(
id ) )
1039 mayDelete.insert(
id );
1043 return mayDelete.size();
1055 constexpr auto ProgressDialogShowDelay = std::chrono::milliseconds (200);
1059 auto purgeStartTime = std::chrono::system_clock::now();
1060 std::shared_ptr<ProgressDialog> progressDialog;
1061 mScope.emplace([=, nDeleted = 0](
auto&)
mutable {
1065 auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
1066 std::chrono::system_clock::now() - purgeStartTime);
1067 if(elapsed >= ProgressDialogShowDelay)
1068 progressDialog =
MakeProgress(
XO(
"Progress"),
XO(
"Discarding undo/redo history"));
1071 progressDialog->Poll(nDeleted, nToDelete);
1083 return std::make_shared<SqliteSampleBlockFactory>( project );
@ Internal
Indicates internal failure from Audacity.
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...
Toolkit-neutral facade for basic user interface services.
Declare DBConnection, which maintains database connection and associated status and background thread...
static const AttachedProjectObjects::RegisteredFactory manager
std::shared_ptr< SampleBlock > SampleBlockPtr
#define ADD_EXCEPTION_CONTEXT(name, value)
static size_t EstimateRemovedBlocks(AudacityProject &project, size_t begin, size_t end)
Just to find a denominator for a progress indicator.
static std::map< SampleBlockID, std::shared_ptr< SqliteSampleBlock > > sSilentBlocks
static SampleBlockFactory::Factory::Scope scope
void InspectBlocks(const TrackList &tracks, BlockInspector inspector, SampleBlockIDSet *pIDs)
std::unordered_set< SampleBlockID > SampleBlockIDSet
std::vector< Attribute > AttributesList
void reinit(Integral count, bool initialize=false)
Base class for exceptions specially processed by the application.
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
void ThrowException(bool write) const
throw and show appropriate message box
sqlite3_stmt * Prepare(enum StatementID id, const char *sql)
static result_type Call(Arguments &&...arguments)
Null check of the installed function is done for you.
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
A move-only handle representing a connection to a Publisher.
static int64_t GetDiskUsage(DBConnection &conn, SampleBlockID blockid)
abstract base class with methods to produce SampleBlock objects
std::unordered_set< SampleBlockID > SampleBlockIDs
Abstract class allows access to contents of a block of sound samples, serialization as XML,...
virtual SampleBlockID GetBlockID() const =0
A MessageBoxException that shows a given, unvarying string.
Implementation of SampleBlockFactory using Sqlite database.
SampleBlockIDs GetActiveBlockIDs() override
SampleBlockPtr DoCreateFromXML(sampleFormat srcformat, const AttributesList &attrs) override
std::optional< SampleBlock::DeletionCallback::Scope > mScope
std::map< SampleBlockID, std::weak_ptr< SqliteSampleBlock > > AllBlocksMap
SqliteSampleBlockFactory(AudacityProject &project)
AudacityProject & mProject
SampleBlockPtr DoCreate(constSamplePtr src, size_t numsamples, sampleFormat srcformat) override
void OnBeginPurge(size_t begin, size_t end)
const std::shared_ptr< ConnectionPtr > mppConnection
~SqliteSampleBlockFactory() override
SampleBlockPtr DoCreateSilent(size_t numsamples, sampleFormat srcformat) override
Observer::Subscription mUndoSubscription
Implementation of SampleBlock using Sqlite database.
size_t GetSpaceUsage() const override
size_t DoGetSamples(samplePtr dest, sampleFormat destformat, size_t sampleoffset, size_t numsamples) override
Sizes SetSizes(size_t numsamples, sampleFormat srcformat)
bool GetSummary(float *dest, size_t frameoffset, size_t numframes, DBConnection::StatementID id, const char *sql)
void Load(SampleBlockID sbid)
std::pair< size_t, size_t > Sizes
Numbers of bytes needed for 256 and for 64k summaries.
void CalcSummary(Sizes sizes)
bool GetSummary64k(float *dest, size_t frameoffset, size_t numframes) override
Non-throwing, should fill with zeroes on failure.
SqliteSampleBlock(const std::shared_ptr< SqliteSampleBlockFactory > &pFactory)
~SqliteSampleBlock() override
sampleFormat mSampleFormat
size_t GetBlob(void *dest, sampleFormat destformat, sqlite3_stmt *stmt, sampleFormat srcformat, size_t srcoffset, size_t srcbytes)
ArrayOf< char > mSummary256
ArrayOf< char > mSummary64k
const std::shared_ptr< SqliteSampleBlockFactory > mpFactory
MinMaxRMS DoGetMinMaxRMS() const override
Gets extreme values for the entire block.
friend SqliteSampleBlockFactory
void SetSamples(constSamplePtr src, size_t numsamples, sampleFormat srcformat)
DBConnection * Conn() const
This must never be called for silent blocks.
void CloseLock() override
SampleBlockID GetBlockID() const override
sampleFormat GetSampleFormat() const
bool GetSummary256(float *dest, size_t frameoffset, size_t numframes) override
Non-throwing, should fill with zeroes on failure.
size_t GetSampleCount() const override
void SaveXML(XMLWriter &xmlFile) override
static TrackList & Get(AudacityProject &project)
static UndoManager & Get(AudacityProject &project)
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
void WriteAttr(const wxString &name, const Identifier &value)
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
std::unique_ptr< ProgressDialog > MakeProgress(const TranslatableString &title, const TranslatableString &message, unsigned flags=(ProgressShowStop|ProgressShowCancel), const TranslatableString &remainingLabelText={})
Create and display a progress dialog.
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Type of message published by UndoManager.
enum UndoRedoMessage::Type type
Holds one item with description and time range for the UndoManager.
std::shared_ptr< TrackList > tracks