mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-16 16:10:06 +02:00
AUP3: Several fixes
These mainly address the bugs that Steve reported and a couple more I found along the way. Corrected ProjectFileIO::GetMinMaxRMS() - It was still using the original method of keep all block data in memory. I missed it when I redid everything. Fixes his Amplify crash. Temporary filenames should no longer be shown to the user. Resaves will no longer present a Save As dialog. Cleaned up duplicate pathname handling in ProjectFileIO. Returned proper errors when loading a project
This commit is contained in:
parent
299710f0a9
commit
8ea07572c1
@ -53,6 +53,7 @@ static const char *ProjectFileSchema =
|
|||||||
// One instance only.
|
// One instance only.
|
||||||
"CREATE TABLE IF NOT EXISTS project"
|
"CREATE TABLE IF NOT EXISTS project"
|
||||||
"("
|
"("
|
||||||
|
" id INTEGER PRIMARY KEY,"
|
||||||
" doc TEXT"
|
" doc TEXT"
|
||||||
");"
|
");"
|
||||||
""
|
""
|
||||||
@ -203,22 +204,25 @@ ProjectFileIO::~ProjectFileIO()
|
|||||||
{
|
{
|
||||||
if (mDB)
|
if (mDB)
|
||||||
{
|
{
|
||||||
|
// Save the filename since CloseDB() will clear it
|
||||||
|
wxString filename = mFileName;
|
||||||
|
|
||||||
// Not much we can do if this fails. The user will simply get
|
// Not much we can do if this fails. The user will simply get
|
||||||
// the recovery dialog upon next restart.
|
// the recovery dialog upon next restart.
|
||||||
if (CloseDB())
|
if (CloseDB())
|
||||||
{
|
{
|
||||||
// Always remove the journal now that the DB is closed
|
// Always remove the journal now that the DB is closed
|
||||||
wxRemoveFile(mDBPath + wxT("-journal"));
|
wxRemoveFile(filename + wxT("-journal"));
|
||||||
|
|
||||||
// At this point, we are shutting down cleanly and if the project file is
|
// At this point, we are shutting down cleanly and if the project file is
|
||||||
// still in the temp directory it means that the user has chosen not to
|
// still in the temp directory it means that the user has chosen not to
|
||||||
// save it. So, delete it.
|
// save it. So, delete it.
|
||||||
if (mTemporary && !mDBPath.empty())
|
if (mTemporary)
|
||||||
{
|
{
|
||||||
wxFileName temp(FileNames::TempDir());
|
wxFileName temp(FileNames::TempDir());
|
||||||
if (temp == wxPathOnly(mDBPath))
|
if (temp == wxPathOnly(filename))
|
||||||
{
|
{
|
||||||
wxRemoveFile(mDBPath);
|
wxRemoveFile(filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,6 +242,7 @@ sqlite3 *ProjectFileIO::DB()
|
|||||||
sqlite3 *ProjectFileIO::OpenDB(FilePath fileName)
|
sqlite3 *ProjectFileIO::OpenDB(FilePath fileName)
|
||||||
{
|
{
|
||||||
wxASSERT(mDB == nullptr);
|
wxASSERT(mDB == nullptr);
|
||||||
|
bool temp = false;
|
||||||
|
|
||||||
if (fileName.empty())
|
if (fileName.empty())
|
||||||
{
|
{
|
||||||
@ -245,33 +250,30 @@ sqlite3 *ProjectFileIO::OpenDB(FilePath fileName)
|
|||||||
if (fileName.empty())
|
if (fileName.empty())
|
||||||
{
|
{
|
||||||
fileName = FileNames::UnsavedProjectFileName();
|
fileName = FileNames::UnsavedProjectFileName();
|
||||||
mTemporary = true;
|
temp = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mTemporary = false;
|
temp = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc = sqlite3_open(fileName, &mDB);
|
int rc = sqlite3_open(fileName, &mDB);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
// AUD3 TODO COMPLAIN AND THROW - crash is inevitable otherwise
|
SetDBError(XO("Failed to open project file"));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AUD3 TODO get rid of the mDBPath?!?!?!?!
|
|
||||||
mDBPath = fileName;
|
|
||||||
mFileName = mDBPath;
|
|
||||||
|
|
||||||
if (!CheckVersion())
|
if (!CheckVersion())
|
||||||
{
|
{
|
||||||
CloseDB();
|
CloseDB();
|
||||||
|
|
||||||
// AUD3 TODO COMPLAIN AND THROW - crash is inevitable otherwise
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mTemporary = temp;
|
||||||
|
SetFileName(fileName);
|
||||||
|
|
||||||
return mDB;
|
return mDB;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,14 +286,15 @@ bool ProjectFileIO::CloseDB()
|
|||||||
rc = sqlite3_close(mDB);
|
rc = sqlite3_close(mDB);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mDB));
|
SetDBError(XO("Failed to close the project file"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
wxRemoveFile(mDBPath + wxT("-journal"));
|
wxRemoveFile(mFileName + wxT("-journal"));
|
||||||
}
|
}
|
||||||
|
|
||||||
mDB = nullptr;
|
mDB = nullptr;
|
||||||
|
SetFileName({});
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -299,17 +302,21 @@ bool ProjectFileIO::CloseDB()
|
|||||||
|
|
||||||
bool ProjectFileIO::DeleteDB()
|
bool ProjectFileIO::DeleteDB()
|
||||||
{
|
{
|
||||||
if (!mDBPath.empty() && IsTemporary())
|
wxASSERT(mDB == nullptr);
|
||||||
|
|
||||||
|
if (mTemporary && !mFileName.empty())
|
||||||
{
|
{
|
||||||
wxFileName temp(FileNames::TempDir());
|
wxFileName temp(FileNames::TempDir());
|
||||||
if (temp == wxPathOnly(mDBPath))
|
if (temp == wxPathOnly(mFileName))
|
||||||
{
|
{
|
||||||
if (!wxRemoveFile(mDBPath))
|
if (!wxRemoveFile(mFileName))
|
||||||
{
|
{
|
||||||
|
SetError(XO("Failed to close the project file"));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxRemoveFile(mDBPath + wxT("-journal"));
|
wxRemoveFile(mFileName + wxT("-journal"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,19 +330,19 @@ bool ProjectFileIO::CleanDB()
|
|||||||
|
|
||||||
AutoSave();
|
AutoSave();
|
||||||
|
|
||||||
wxString destpath = wxFileName::CreateTempFileName(mDBPath + ".xxxxx");
|
wxString destpath = wxFileName::CreateTempFileName(mFileName + ".xxxxx");
|
||||||
|
|
||||||
if (CopyTo(destpath))
|
if (CopyTo(destpath))
|
||||||
{
|
{
|
||||||
if (CloseDB())
|
if (CloseDB())
|
||||||
{
|
{
|
||||||
// This can be removed even if we fail below since the DB is closed
|
// This can be removed even if we fail below since the DB is closed
|
||||||
wxRemoveFile(mDBPath + wxT("-journal"));
|
wxRemoveFile(mFileName + wxT("-journal"));
|
||||||
|
|
||||||
wxString tmppath = wxFileName::CreateTempFileName(mDBPath + ".xxxxx");
|
wxString tmppath = wxFileName::CreateTempFileName(mFileName + ".xxxxx");
|
||||||
if (wxRename(mDBPath, tmppath) == 0)
|
if (wxRename(mFileName, tmppath) == 0)
|
||||||
{
|
{
|
||||||
if (wxRename(destpath, mDBPath) == 0)
|
if (wxRename(destpath, mFileName) == 0)
|
||||||
{
|
{
|
||||||
wxRemoveFile(tmppath);
|
wxRemoveFile(tmppath);
|
||||||
|
|
||||||
@ -343,10 +350,18 @@ bool ProjectFileIO::CleanDB()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wxRename(tmppath, mDBPath) == 0)
|
if (wxRename(tmppath, mFileName) == 0)
|
||||||
{
|
{
|
||||||
wxRemoveFile(destpath);
|
wxRemoveFile(destpath);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetError(XO("Could not rename %s back to %s during cleaning").Format(tmppath, mFileName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetError(XO("Could not rename %s during cleaning").Format(mFileName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -371,7 +386,10 @@ int ProjectFileIO::Exec(const char *query, ExecCB callback, wxString *result)
|
|||||||
|
|
||||||
if (errmsg)
|
if (errmsg)
|
||||||
{
|
{
|
||||||
mLastError.Format(XO("SQLite Error: %s"), wxString(errmsg));
|
SetDBError(
|
||||||
|
XO("Failed to execute a project file command:\n\n%s").Format(query)
|
||||||
|
);
|
||||||
|
mLibraryError = Verbatim(errmsg);
|
||||||
sqlite3_free(errmsg);
|
sqlite3_free(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,8 +414,7 @@ wxString ProjectFileIO::GetValue(const char *sql)
|
|||||||
int rc = Exec(sql, getresult, &value);
|
int rc = Exec(sql, getresult, &value);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("%s"), mLastError.Debug());
|
// Message already captured
|
||||||
// AUD TODO Handle error.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@ -420,15 +437,18 @@ bool ProjectFileIO::GetBlob(const char *sql, wxMemoryBuffer &buffer)
|
|||||||
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
|
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
SetDBError(
|
||||||
// AUD TODO handle error
|
XO("Unable to prepare project file command:\n\n%s").Format(sql)
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
if (rc != SQLITE_ROW)
|
if (rc != SQLITE_ROW)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
SetDBError(
|
||||||
|
XO("Failed to retrieve data from the project file.\nThe following command failed:\n\n%s").Format(sql)
|
||||||
|
);
|
||||||
// AUD TODO handle error
|
// AUD TODO handle error
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -449,30 +469,48 @@ bool ProjectFileIO::CheckVersion()
|
|||||||
// Install our schema if this is an empty DB
|
// Install our schema if this is an empty DB
|
||||||
long count = -1;
|
long count = -1;
|
||||||
GetValue("SELECT Count(*) FROM sqlite_master WHERE type='table';").ToLong(&count);
|
GetValue("SELECT Count(*) FROM sqlite_master WHERE type='table';").ToLong(&count);
|
||||||
|
if (count == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the return count is zero, then there are no tables defined, so this
|
||||||
|
// must be a new project file.
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
return InstallSchema();
|
return InstallSchema();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for our application ID
|
// Check for our application ID
|
||||||
long appid = 0;
|
long appid = -1;
|
||||||
GetValue("PRAGMA application_ID;").ToLong(&appid);
|
GetValue("PRAGMA application_ID;").ToLong(&appid);
|
||||||
|
if (appid == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's a database that SQLite recognizes, but it's not one of ours
|
||||||
if (appid != ProjectFileID)
|
if (appid != ProjectFileID)
|
||||||
{
|
{
|
||||||
mLastError = XO("This is not an Audacity AUP3 file");
|
SetError(XO("This is not an Audacity project file"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the project file version
|
// Get the project file version
|
||||||
long version;
|
long version = -1;
|
||||||
GetValue("PRAGMA user_version;").ToLong(&version);
|
GetValue("PRAGMA user_version;").ToLong(&version);
|
||||||
|
if (version == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Project file version is higher than ours. We will refuse
|
// Project file version is higher than ours. We will refuse to
|
||||||
// to process it since we can't trust anything about it.
|
// process it since we can't trust anything about it.
|
||||||
if (version > ProjectFileVersion)
|
if (version > ProjectFileVersion)
|
||||||
{
|
{
|
||||||
// AUD3 - complain about too new schema
|
SetError(
|
||||||
// can't handle it!
|
XO("This project was created with a newer version of Audacity:\n\nYou will need to upgrade to process it")
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,7 +540,9 @@ bool ProjectFileIO::InstallSchema()
|
|||||||
rc = sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
|
rc = sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
SetDBError(
|
||||||
|
XO("Unable to initialize the project file")
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,10 +578,12 @@ bool ProjectFileIO::CopyTo(const FilePath &destpath)
|
|||||||
{
|
{
|
||||||
int remaining = sqlite3_backup_remaining(backup);
|
int remaining = sqlite3_backup_remaining(backup);
|
||||||
int total = sqlite3_backup_pagecount(backup);
|
int total = sqlite3_backup_pagecount(backup);
|
||||||
wxLogDebug(wxT("remaining %d total %d"), remaining, total);
|
|
||||||
|
|
||||||
if (progress.Update(total - remaining, total) != ProgressResult::Success)
|
if (progress.Update(total - remaining, total) != ProgressResult::Success)
|
||||||
{
|
{
|
||||||
|
SetError(
|
||||||
|
XO("Copy processs cancelled.")
|
||||||
|
);
|
||||||
success = false;
|
success = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -553,14 +595,26 @@ bool ProjectFileIO::CopyTo(const FilePath &destpath)
|
|||||||
rc = sqlite3_backup_finish(backup);
|
rc = sqlite3_backup_finish(backup);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
|
SetDBError(
|
||||||
|
XO("The copy process failed for:\n\n%s").Format(destpath)
|
||||||
|
);
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetDBError(
|
||||||
|
XO("Unable to initiate the backup process.")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Close the DB
|
// Close the DB
|
||||||
rc = sqlite3_close(destdb);
|
rc = sqlite3_close(destdb);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
|
SetDBError(
|
||||||
|
XO("Failed to successfully close the destination project file:\n\n%s")
|
||||||
|
);
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,6 +628,9 @@ bool ProjectFileIO::CopyTo(const FilePath &destpath)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
SetDBError(
|
||||||
|
XO("Unable to open the destination project file:\n\n%s").Format(destpath)
|
||||||
|
);
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -630,14 +687,14 @@ void ProjectFileIO::SetProjectTitle(int number)
|
|||||||
|
|
||||||
const FilePath &ProjectFileIO::GetFileName() const
|
const FilePath &ProjectFileIO::GetFileName() const
|
||||||
{
|
{
|
||||||
wxASSERT(mFileName == mDBPath);
|
|
||||||
return mFileName;
|
return mFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectFileIO::SetFileName(const FilePath &fileName)
|
void ProjectFileIO::SetFileName(const FilePath &fileName)
|
||||||
{
|
{
|
||||||
mFileName = fileName;
|
mFileName = fileName;
|
||||||
if (mFileName.empty())
|
|
||||||
|
if (mTemporary)
|
||||||
{
|
{
|
||||||
mProject.SetProjectName({});
|
mProject.SetProjectName({});
|
||||||
}
|
}
|
||||||
@ -649,34 +706,6 @@ void ProjectFileIO::SetFileName(const FilePath &fileName)
|
|||||||
SetProjectTitle();
|
SetProjectTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Most of this string was duplicated 3 places. Made the warning consistent in this global.
|
|
||||||
// The %s is to be filled with the version string.
|
|
||||||
// PRL: Do not statically allocate a string in _() !
|
|
||||||
static TranslatableString gsLegacyFileWarning() { return
|
|
||||||
XO("This file was saved by Audacity version %s. The format has changed. \
|
|
||||||
\n\nAudacity can try to open and save this file, but saving it in this \
|
|
||||||
\nversion will then prevent any 1.2 or earlier version opening it. \
|
|
||||||
\n\nAudacity might corrupt the file in opening it, so you should \
|
|
||||||
back it up first. \
|
|
||||||
\n\nOpen this file now?");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProjectFileIO::WarnOfLegacyFile( )
|
|
||||||
{
|
|
||||||
auto &project = mProject;
|
|
||||||
auto &window = GetProjectFrame( project );
|
|
||||||
auto msg = gsLegacyFileWarning().Format( XO("1.0 or earlier") );
|
|
||||||
|
|
||||||
// Stop icon, and choose 'NO' by default.
|
|
||||||
int action =
|
|
||||||
AudacityMessageBox(
|
|
||||||
msg,
|
|
||||||
XO("Warning - Opening Old Project File"),
|
|
||||||
wxYES_NO | wxICON_STOP | wxNO_DEFAULT | wxCENTRE,
|
|
||||||
&window);
|
|
||||||
return (action != wxNO);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProjectFileIO::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
|
bool ProjectFileIO::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
|
||||||
{
|
{
|
||||||
auto &project = mProject;
|
auto &project = mProject;
|
||||||
@ -798,12 +827,8 @@ bool ProjectFileIO::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wxStrcmp(tag, wxT("audacityproject")) &&
|
if (wxStrcmp(tag, wxT("project")))
|
||||||
wxStrcmp(tag, wxT("project")))
|
|
||||||
{
|
{
|
||||||
// If the tag name is not one of these two (the NEW name is
|
|
||||||
// "project" with an Audacity namespace, but we don't detect
|
|
||||||
// the namespace yet), then we don't know what the error is
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -924,8 +949,9 @@ bool ProjectFileIO::AutoSave(const AutoSaveFile &autosave)
|
|||||||
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
|
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
SetDBError(
|
||||||
// handle error
|
XO("Unable to prepare project file command:\n\n%s").Format(sql)
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -939,8 +965,9 @@ bool ProjectFileIO::AutoSave(const AutoSaveFile &autosave)
|
|||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
if (rc != SQLITE_DONE)
|
if (rc != SQLITE_DONE)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
SetDBError(
|
||||||
// handle error
|
XO("Failed to update the project file.\nThe following command failed:\n\n%s").Format(sql)
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -955,8 +982,9 @@ bool ProjectFileIO::AutoSaveDelete()
|
|||||||
rc = sqlite3_exec(db, "DELETE FROM autosave;", nullptr, nullptr, nullptr);
|
rc = sqlite3_exec(db, "DELETE FROM autosave;", nullptr, nullptr, nullptr);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
SetDBError(
|
||||||
// handle error
|
XO("Failed to remove the autosave information from the project file.")
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -965,8 +993,26 @@ bool ProjectFileIO::AutoSaveDelete()
|
|||||||
|
|
||||||
bool ProjectFileIO::LoadProject(const FilePath &fileName)
|
bool ProjectFileIO::LoadProject(const FilePath &fileName)
|
||||||
{
|
{
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
// OpenDB() will change mFileName if the file opens/verifies successfully,
|
||||||
|
// so we must set it back to what it was if any errors are encountered here.
|
||||||
|
wxString oldFilename = mFileName;
|
||||||
|
|
||||||
|
auto cleanup = finally([&]
|
||||||
|
{
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
CloseDB();
|
||||||
|
SetFileName(oldFilename);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Open the project file
|
// Open the project file
|
||||||
OpenDB(fileName);
|
if (!OpenDB(fileName))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the XML document...either from the project or autosave
|
// Get the XML document...either from the project or autosave
|
||||||
wxString doc;
|
wxString doc;
|
||||||
@ -979,44 +1025,108 @@ bool ProjectFileIO::LoadProject(const FilePath &fileName)
|
|||||||
doc = AutoSaveFile::Decode(buffer);
|
doc = AutoSaveFile::Decode(buffer);
|
||||||
wasAutosave = true;
|
wasAutosave = true;
|
||||||
}
|
}
|
||||||
|
// Otherwise, get the project doc
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Get the project doc
|
|
||||||
doc = GetValue("SELECT doc FROM project;");
|
doc = GetValue("SELECT doc FROM project;");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doc.empty())
|
if (doc.empty())
|
||||||
{
|
{
|
||||||
// AUD3 fixme
|
|
||||||
wxLogDebug(wxT("%s"), mLastError.Translation());
|
|
||||||
// handle error
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLFileReader xmlFile;
|
XMLFileReader xmlFile;
|
||||||
|
|
||||||
bool success = xmlFile.ParseString(this, doc);
|
success = xmlFile.ParseString(this, doc);
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
mLastError = xmlFile.GetErrorStr();
|
SetError(
|
||||||
}
|
XO("Unable to parse project information.")
|
||||||
else
|
);
|
||||||
{
|
mLibraryError = xmlFile.GetErrorStr();
|
||||||
mRecovered = wasAutosave;
|
return false;
|
||||||
SetFileName(fileName);
|
|
||||||
SetProjectTitle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remember if it was recovered or not
|
||||||
|
mRecovered = wasAutosave;
|
||||||
if (mRecovered)
|
if (mRecovered)
|
||||||
{
|
{
|
||||||
mModified = true;
|
mModified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
// A previously saved project will have a document in the project table, so
|
||||||
|
// we use that knowledge to determine if this file is an unsaved/temporary
|
||||||
|
// file or not
|
||||||
|
long count = 0;
|
||||||
|
GetValue("SELECT Count(*) FROM project;").ToLong(&count);
|
||||||
|
mTemporary = (count != 1);
|
||||||
|
|
||||||
|
SetFileName(fileName);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProjectFileIO::SaveProject(const FilePath &fileName)
|
bool ProjectFileIO::SaveProject(const FilePath &fileName)
|
||||||
{
|
{
|
||||||
|
wxString origName;
|
||||||
|
bool wasTemp = false;
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
// Should probably simply all of the by using renames. But, one benefit
|
||||||
|
// of using CopyTo() for new file saves, is that it will be VACUUMED at
|
||||||
|
// the same time.
|
||||||
|
|
||||||
|
auto restore = finally([&]
|
||||||
|
{
|
||||||
|
if (!origName.empty())
|
||||||
|
{
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
// The Save was successful, so remove the original file if
|
||||||
|
// it was a temporary file
|
||||||
|
if (wasTemp)
|
||||||
|
{
|
||||||
|
wxRemoveFile(origName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Close the new database
|
||||||
|
CloseDB();
|
||||||
|
|
||||||
|
// Reopen the original database
|
||||||
|
if (OpenDB(origName))
|
||||||
|
{
|
||||||
|
// And delete the new database
|
||||||
|
wxRemoveFile(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// If we're saving to a different file than the current one, then copy the
|
||||||
|
// current to the new file and make it the active file.
|
||||||
|
if (mFileName != fileName)
|
||||||
|
{
|
||||||
|
if (!CopyTo(fileName))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember the original project filename and temporary status. Only do
|
||||||
|
// this after a successful copy so the "finally" block above doesn't monkey
|
||||||
|
// with the files.
|
||||||
|
origName = mFileName;
|
||||||
|
wasTemp = mTemporary;
|
||||||
|
|
||||||
|
// Close the original project file and open the new one
|
||||||
|
if (!CloseDB() || !OpenDB(fileName))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto db = DB();
|
auto db = DB();
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@ -1024,68 +1134,51 @@ bool ProjectFileIO::SaveProject(const FilePath &fileName)
|
|||||||
WriteXMLHeader(doc);
|
WriteXMLHeader(doc);
|
||||||
WriteXML(doc);
|
WriteXML(doc);
|
||||||
|
|
||||||
|
// Always use an ID of 1. This will replace any existing row.
|
||||||
char sql[256];
|
char sql[256];
|
||||||
sqlite3_snprintf(sizeof(sql),
|
sqlite3_snprintf(sizeof(sql),
|
||||||
sql,
|
sql,
|
||||||
"REPLACE INTO project (doc) VALUES(?);");
|
"INSERT INTO project(id, doc) VALUES(1, ?1)"
|
||||||
|
" ON CONFLICT(id) DO UPDATE SET doc = ?1;");
|
||||||
|
|
||||||
|
|
||||||
sqlite3_stmt *stmt = nullptr;
|
sqlite3_stmt *stmt = nullptr;
|
||||||
auto cleanup = finally([&]
|
|
||||||
{
|
|
||||||
if (stmt)
|
|
||||||
{
|
|
||||||
sqlite3_finalize(stmt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
|
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
SetDBError(
|
||||||
// handle error
|
XO("Unable to prepare project file command:\n\n%s").Format(sql)
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// BIND SQL project
|
// BIND SQL project
|
||||||
sqlite3_bind_text(stmt, 1, doc, -1, SQLITE_STATIC);
|
rc = sqlite3_bind_text(stmt, 1, doc, -1, SQLITE_STATIC);
|
||||||
|
if (rc != SQLITE_OK)
|
||||||
|
{
|
||||||
|
SetDBError(
|
||||||
|
XO("Unable to bind to project file document.")
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
|
|
||||||
|
// This will free the statement
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
|
||||||
if (rc != SQLITE_DONE)
|
if (rc != SQLITE_DONE)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
SetDBError(
|
||||||
// handle error
|
XO("Failed to save project file information.")
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_finalize(stmt);
|
// We need to remove the autosave info from the file since it is now
|
||||||
stmt = nullptr;
|
// clean and unmodified. Otherwise, it would be considered "recovered"
|
||||||
|
// when next opened.
|
||||||
if (mDBPath != fileName)
|
|
||||||
{
|
|
||||||
if (!CopyTo(fileName))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remember the original project filename
|
|
||||||
wxString origname = mDBPath;
|
|
||||||
|
|
||||||
// Close the original project file
|
|
||||||
CloseDB();
|
|
||||||
|
|
||||||
// Set the new filename
|
|
||||||
SetFileName(fileName);
|
|
||||||
|
|
||||||
// And open the new one
|
|
||||||
OpenDB(fileName);
|
|
||||||
|
|
||||||
// If the original project was temporary, then delete it now
|
|
||||||
if (mTemporary)
|
|
||||||
{
|
|
||||||
wxRemoveFile(origname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoSaveDelete();
|
AutoSaveDelete();
|
||||||
|
|
||||||
// No longer modified
|
// No longer modified
|
||||||
@ -1100,6 +1193,9 @@ bool ProjectFileIO::SaveProject(const FilePath &fileName)
|
|||||||
// Adjust the title
|
// Adjust the title
|
||||||
SetProjectTitle();
|
SetProjectTitle();
|
||||||
|
|
||||||
|
// Tell the finally block to behave
|
||||||
|
success = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1126,7 +1222,6 @@ void ProjectFileIO::Reset()
|
|||||||
mRecovered = false;
|
mRecovered = false;
|
||||||
|
|
||||||
SetFileName({});
|
SetFileName({});
|
||||||
SetProjectTitle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wxLongLong ProjectFileIO::GetFreeDiskSpace()
|
wxLongLong ProjectFileIO::GetFreeDiskSpace()
|
||||||
@ -1135,7 +1230,7 @@ wxLongLong ProjectFileIO::GetFreeDiskSpace()
|
|||||||
auto db = DB();
|
auto db = DB();
|
||||||
|
|
||||||
wxLongLong freeSpace;
|
wxLongLong freeSpace;
|
||||||
if (wxGetDiskSpace(wxPathOnly(mDBPath), NULL, &freeSpace))
|
if (wxGetDiskSpace(wxPathOnly(mFileName), NULL, &freeSpace))
|
||||||
{
|
{
|
||||||
return freeSpace;
|
return freeSpace;
|
||||||
}
|
}
|
||||||
@ -1148,3 +1243,22 @@ const TranslatableString & ProjectFileIO::GetLastError() const
|
|||||||
return mLastError;
|
return mLastError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TranslatableString & ProjectFileIO::GetLibraryError() const
|
||||||
|
{
|
||||||
|
return mLastError;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectFileIO::SetError(const TranslatableString & msg)
|
||||||
|
{
|
||||||
|
mLastError = msg;
|
||||||
|
mLibraryError = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectFileIO::SetDBError(const TranslatableString & msg)
|
||||||
|
{
|
||||||
|
mLastError = msg;
|
||||||
|
if (mDB)
|
||||||
|
{
|
||||||
|
mLibraryError = Verbatim(sqlite3_errmsg(mDB));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -71,6 +71,7 @@ public:
|
|||||||
wxLongLong GetFreeDiskSpace();
|
wxLongLong GetFreeDiskSpace();
|
||||||
|
|
||||||
const TranslatableString & GetLastError() const;
|
const TranslatableString & GetLastError() const;
|
||||||
|
const TranslatableString & GetLibraryError() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// XMLTagHandler callback methods
|
// XMLTagHandler callback methods
|
||||||
@ -103,6 +104,9 @@ private:
|
|||||||
|
|
||||||
bool CopyTo(const FilePath &destpath);
|
bool CopyTo(const FilePath &destpath);
|
||||||
|
|
||||||
|
void SetError(const TranslatableString & msg);
|
||||||
|
void SetDBError(const TranslatableString & msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// non-static data members
|
// non-static data members
|
||||||
AudacityProject &mProject;
|
AudacityProject &mProject;
|
||||||
@ -122,6 +126,7 @@ private:
|
|||||||
sqlite3 *mDB;
|
sqlite3 *mDB;
|
||||||
FilePath mDBPath;
|
FilePath mDBPath;
|
||||||
TranslatableString mLastError;
|
TranslatableString mLastError;
|
||||||
|
TranslatableString mLibraryError;
|
||||||
|
|
||||||
friend SampleBlock;
|
friend SampleBlock;
|
||||||
};
|
};
|
||||||
|
@ -144,6 +144,16 @@ auto ProjectFileManager::ReadProjectFile( const FilePath &fileName )
|
|||||||
|
|
||||||
if (bParseSuccess)
|
if (bParseSuccess)
|
||||||
{
|
{
|
||||||
|
if (projectFileIO.IsRecovered())
|
||||||
|
{
|
||||||
|
AudacityMessageBox(
|
||||||
|
XO("This project was not saved properly the last time Audacity ran.\n\n"
|
||||||
|
"It has been recovered to the last snapshot."),
|
||||||
|
XO("Project Recovered"),
|
||||||
|
wxICON_WARNING,
|
||||||
|
&window);
|
||||||
|
}
|
||||||
|
|
||||||
// By making a duplicate set of pointers to the existing blocks
|
// By making a duplicate set of pointers to the existing blocks
|
||||||
// on disk, we add one to their reference count, guaranteeing
|
// on disk, we add one to their reference count, guaranteeing
|
||||||
// that their reference counts will never reach zero and thus
|
// that their reference counts will never reach zero and thus
|
||||||
@ -168,10 +178,12 @@ auto ProjectFileManager::ReadProjectFile( const FilePath &fileName )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AUD3 - FIXME - error messages - needed?????
|
return
|
||||||
return {
|
{
|
||||||
false, bParseSuccess, err, projectFileIO.GetLastError(),
|
bParseSuccess,
|
||||||
FindHelpUrl( projectFileIO.GetLastError() )
|
err,
|
||||||
|
projectFileIO.GetLastError(),
|
||||||
|
FindHelpUrl(projectFileIO.GetLibraryError())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +192,7 @@ bool ProjectFileManager::Save()
|
|||||||
auto &projectFileIO = ProjectFileIO::Get(mProject);
|
auto &projectFileIO = ProjectFileIO::Get(mProject);
|
||||||
|
|
||||||
// Prompt for file name?
|
// Prompt for file name?
|
||||||
if (projectFileIO.IsModified())
|
if (projectFileIO.IsTemporary())
|
||||||
{
|
{
|
||||||
return SaveAs();
|
return SaveAs();
|
||||||
}
|
}
|
||||||
@ -229,8 +241,6 @@ bool ProjectFileManager::DoSave(const FilePath & fileName, const bool fromSaveAs
|
|||||||
auto &projectFileIO = ProjectFileIO::Get( proj );
|
auto &projectFileIO = ProjectFileIO::Get( proj );
|
||||||
const auto &settings = ProjectSettings::Get( proj );
|
const auto &settings = ProjectSettings::Get( proj );
|
||||||
|
|
||||||
wxASSERT_MSG(fromSaveAs, "Copy Project SHOULD only be available from SaveAs");
|
|
||||||
|
|
||||||
// Some confirmation dialogs
|
// Some confirmation dialogs
|
||||||
{
|
{
|
||||||
auto &tracks = TrackList::Get( proj );
|
auto &tracks = TrackList::Get( proj );
|
||||||
@ -363,11 +373,13 @@ bool ProjectFileManager::SaveAs()
|
|||||||
auto &window = GetProjectFrame( project );
|
auto &window = GetProjectFrame( project );
|
||||||
TitleRestorer Restorer( window, project ); // RAII
|
TitleRestorer Restorer( window, project ); // RAII
|
||||||
bool bHasPath = true;
|
bool bHasPath = true;
|
||||||
wxFileName filename{ projectFileIO.GetFileName() };
|
wxFileName filename;
|
||||||
|
|
||||||
wxString name = project.GetProjectName();
|
if (projectFileIO.IsTemporary()) {
|
||||||
if (!name.empty()) {
|
filename = FileNames::DefaultToDocumentsFolder(wxT("/SaveAs/Path"));
|
||||||
filename.SetName(name);
|
}
|
||||||
|
else {
|
||||||
|
filename = projectFileIO.GetFileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bug 1304: Set a default file path if none was given. For Save/SaveAs
|
// Bug 1304: Set a default file path if none was given. For Save/SaveAs
|
||||||
@ -790,9 +802,6 @@ void ProjectFileManager::OpenFile(const FilePath &fileNameArg, bool addtohistory
|
|||||||
|
|
||||||
auto results = ReadProjectFile( fileName );
|
auto results = ReadProjectFile( fileName );
|
||||||
|
|
||||||
if ( results.decodeError )
|
|
||||||
return;
|
|
||||||
|
|
||||||
const bool bParseSuccess = results.parseSuccess;
|
const bool bParseSuccess = results.parseSuccess;
|
||||||
const auto &errorStr = results.errorString;
|
const auto &errorStr = results.errorString;
|
||||||
const bool err = results.trackError;
|
const bool err = results.trackError;
|
||||||
|
@ -43,7 +43,6 @@ public:
|
|||||||
|
|
||||||
struct ReadProjectResults
|
struct ReadProjectResults
|
||||||
{
|
{
|
||||||
bool decodeError;
|
|
||||||
bool parseSuccess;
|
bool parseSuccess;
|
||||||
bool trackError;
|
bool trackError;
|
||||||
const TranslatableString errorString;
|
const TranslatableString errorString;
|
||||||
|
@ -295,18 +295,32 @@ double SampleBlock::GetSumRms() const
|
|||||||
///
|
///
|
||||||
/// @param start The offset in this block where the region should begin
|
/// @param start The offset in this block where the region should begin
|
||||||
/// @param len The number of samples to include in the region
|
/// @param len The number of samples to include in the region
|
||||||
MinMaxRMS SampleBlock::GetMinMaxRMS(size_t start, size_t len) const
|
MinMaxRMS SampleBlock::GetMinMaxRMS(size_t start, size_t len)
|
||||||
{
|
{
|
||||||
float min = FLT_MAX;
|
float min = FLT_MAX;
|
||||||
float max = -FLT_MAX;
|
float max = -FLT_MAX;
|
||||||
float sumsq = 0;
|
float sumsq = 0;
|
||||||
|
|
||||||
if (mValid && start < mSampleCount)
|
if (!mValid && mBlockID)
|
||||||
|
{
|
||||||
|
Load(mBlockID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start < mSampleCount)
|
||||||
{
|
{
|
||||||
float *samples = &((float *) mSamples.get())[start];
|
|
||||||
len = std::min(len, mSampleCount - start);
|
len = std::min(len, mSampleCount - start);
|
||||||
|
|
||||||
for (int i = 0; i < len; ++i, ++samples)
|
// TODO: actually use summaries
|
||||||
|
SampleBuffer blockData(len, floatSample);
|
||||||
|
float *samples = (float *) blockData.ptr();
|
||||||
|
|
||||||
|
size_t copied = GetBlob(samples,
|
||||||
|
floatSample,
|
||||||
|
"samples",
|
||||||
|
mSampleFormat,
|
||||||
|
start * SAMPLE_SIZE(mSampleFormat),
|
||||||
|
len * SAMPLE_SIZE(mSampleFormat)) / SAMPLE_SIZE(mSampleFormat);
|
||||||
|
for (size_t i = 0; i < copied; ++i, ++samples)
|
||||||
{
|
{
|
||||||
float sample = *samples;
|
float sample = *samples;
|
||||||
|
|
||||||
@ -347,6 +361,8 @@ size_t SampleBlock::GetBlob(void *dest,
|
|||||||
size_t srcoffset,
|
size_t srcoffset,
|
||||||
size_t srcbytes)
|
size_t srcbytes)
|
||||||
{
|
{
|
||||||
|
auto db = mIO.DB();
|
||||||
|
|
||||||
wxASSERT(mBlockID > 0);
|
wxASSERT(mBlockID > 0);
|
||||||
|
|
||||||
if (!mValid && mBlockID)
|
if (!mValid && mBlockID)
|
||||||
@ -373,17 +389,17 @@ size_t SampleBlock::GetBlob(void *dest,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
rc = sqlite3_prepare_v2(mIO.DB(), sql, -1, &stmt, 0);
|
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mIO.DB()));
|
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
if (rc != SQLITE_ROW)
|
if (rc != SQLITE_ROW)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mIO.DB()));
|
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -417,6 +433,8 @@ size_t SampleBlock::GetBlob(void *dest,
|
|||||||
|
|
||||||
bool SampleBlock::Load(SampleBlockID sbid)
|
bool SampleBlock::Load(SampleBlockID sbid)
|
||||||
{
|
{
|
||||||
|
auto db = mIO.DB();
|
||||||
|
|
||||||
wxASSERT(sbid > 0);
|
wxASSERT(sbid > 0);
|
||||||
|
|
||||||
int rc;
|
int rc;
|
||||||
@ -426,6 +444,9 @@ bool SampleBlock::Load(SampleBlockID sbid)
|
|||||||
mSummary64kBytes = 0;
|
mSummary64kBytes = 0;
|
||||||
mSampleCount = 0;
|
mSampleCount = 0;
|
||||||
mSampleBytes = 0;
|
mSampleBytes = 0;
|
||||||
|
mSumMin = FLT_MAX;
|
||||||
|
mSumMax = -FLT_MAX;
|
||||||
|
mSumMin = 0.0;
|
||||||
|
|
||||||
char sql[256];
|
char sql[256];
|
||||||
sqlite3_snprintf(sizeof(sql),
|
sqlite3_snprintf(sizeof(sql),
|
||||||
@ -444,10 +465,10 @@ bool SampleBlock::Load(SampleBlockID sbid)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
rc = sqlite3_prepare_v2(mIO.DB(), sql, -1, &stmt, 0);
|
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mIO.DB()));
|
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
||||||
// handle error
|
// handle error
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -455,7 +476,7 @@ bool SampleBlock::Load(SampleBlockID sbid)
|
|||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
if (rc != SQLITE_ROW)
|
if (rc != SQLITE_ROW)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mIO.DB()));
|
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
||||||
// handle error
|
// handle error
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -477,6 +498,7 @@ bool SampleBlock::Load(SampleBlockID sbid)
|
|||||||
|
|
||||||
bool SampleBlock::Commit()
|
bool SampleBlock::Commit()
|
||||||
{
|
{
|
||||||
|
auto db = mIO.DB();
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
char sql[256];
|
char sql[256];
|
||||||
@ -494,10 +516,10 @@ bool SampleBlock::Commit()
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
rc = sqlite3_prepare_v2(mIO.DB(), sql, -1, &stmt, 0);
|
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mIO.DB()));
|
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
||||||
// handle error
|
// handle error
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -514,12 +536,12 @@ bool SampleBlock::Commit()
|
|||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
if (rc != SQLITE_DONE)
|
if (rc != SQLITE_DONE)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mIO.DB()));
|
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
||||||
// handle error
|
// handle error
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mBlockID = sqlite3_last_insert_rowid(mIO.DB());
|
mBlockID = sqlite3_last_insert_rowid(db);
|
||||||
|
|
||||||
mSamples.reset();
|
mSamples.reset();
|
||||||
mSummary256.reset();
|
mSummary256.reset();
|
||||||
@ -532,6 +554,8 @@ bool SampleBlock::Commit()
|
|||||||
|
|
||||||
void SampleBlock::Delete()
|
void SampleBlock::Delete()
|
||||||
{
|
{
|
||||||
|
auto db = mIO.DB();
|
||||||
|
|
||||||
if (mBlockID)
|
if (mBlockID)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@ -542,10 +566,10 @@ void SampleBlock::Delete()
|
|||||||
"DELETE FROM sampleblocks WHERE blockid = %lld;",
|
"DELETE FROM sampleblocks WHERE blockid = %lld;",
|
||||||
mBlockID);
|
mBlockID);
|
||||||
|
|
||||||
rc = sqlite3_exec(mIO.DB(), sql, nullptr, nullptr, nullptr);
|
rc = sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(mIO.DB()));
|
wxLogDebug(wxT("SQLITE error %s"), sqlite3_errmsg(db));
|
||||||
// handle error
|
// handle error
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ public:
|
|||||||
double GetSumRms() const;
|
double GetSumRms() const;
|
||||||
|
|
||||||
/// Gets extreme values for the specified region
|
/// Gets extreme values for the specified region
|
||||||
MinMaxRMS GetMinMaxRMS(size_t start, size_t len) const;
|
MinMaxRMS GetMinMaxRMS(size_t start, size_t len);
|
||||||
|
|
||||||
/// Gets extreme values for the entire block
|
/// Gets extreme values for the entire block
|
||||||
MinMaxRMS GetMinMaxRMS() const;
|
MinMaxRMS GetMinMaxRMS() const;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user