From cea658d9eb2fef9601c87c83080b61701e06a34a Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 11 Jul 2020 01:49:37 -0400 Subject: [PATCH] Fix the reading of autosave files... (#610) * Fix the reading of autosave files... ... problem was in recreating strings from buffers, but copying too many because null terminators were lacking. * Autosave during recording backs up all tracks correctly... ... whether to new track, or appending; and it doesn't lose the other tracks besides the recording. It is also unnecessary when just starting to record, so remove one call. --- src/ProjectAudioManager.cpp | 8 +++----- src/ProjectFileIO.cpp | 35 ++++++++++++++++++++--------------- src/ProjectFileIO.h | 4 ++-- src/ProjectSerializer.cpp | 35 ++++++++++++++--------------------- 4 files changed, 39 insertions(+), 43 deletions(-) diff --git a/src/ProjectAudioManager.cpp b/src/ProjectAudioManager.cpp index e59530253..20d192877 100644 --- a/src/ProjectAudioManager.cpp +++ b/src/ProjectAudioManager.cpp @@ -854,10 +854,8 @@ void ProjectAudioManager::OnAudioIORate(int rate) void ProjectAudioManager::OnAudioIOStartRecording() { - auto &projectFileIO = ProjectFileIO::Get( mProject ); - // Before recording is started, auto-save the file. The file will have - // empty tracks at the bottom where the recording will be put into - projectFileIO.AutoSave(); + // Auto-save was done here before, but it is unnecessary, provided there + // are sufficient autosaves when pushing or modifying undo states. } // This is called after recording has stopped and all tracks have flushed. @@ -931,7 +929,7 @@ void ProjectAudioManager::OnAudioIONewBlockFiles(const WaveTrackArray *tracks) { auto &project = mProject; auto &projectFileIO = ProjectFileIO::Get( project ); - projectFileIO.AutoSave(tracks); + projectFileIO.AutoSave(true); } void ProjectAudioManager::OnCommitRecording() diff --git a/src/ProjectFileIO.cpp b/src/ProjectFileIO.cpp index 6aa03c578..bc25ebc04 100644 --- a/src/ProjectFileIO.cpp +++ b/src/ProjectFileIO.cpp @@ -1059,7 +1059,7 @@ void ProjectFileIO::WriteXMLHeader(XMLWriter &xmlFile) const xmlFile.Write(wxT(">\n")); } -void ProjectFileIO::WriteXML(XMLWriter &xmlFile, const WaveTrackArray *tracks) +void ProjectFileIO::WriteXML(XMLWriter &xmlFile, bool recording) // may throw { auto pProject = mpProject.lock(); @@ -1092,31 +1092,36 @@ void ProjectFileIO::WriteXML(XMLWriter &xmlFile, const WaveTrackArray *tracks) tags.WriteXML(xmlFile); unsigned int ndx = 0; - if (tracks) + tracklist.Any().Visit([&](Track *t) { - for (auto track : *tracks) - { - track->WriteXML(xmlFile); + auto useTrack = t; + if ( recording ) { + // When append-recording, there is a temporary "shadow" track accumulating + // changes and displayed on the screen but it is not yet part of the + // regular track list. That is the one that we want to back up. + // SubstitutePendingChangedTrack() fetches the shadow, if the track has + // one, else it gives the same track back. + useTrack = t->SubstitutePendingChangedTrack().get(); } - } - else - { - tracklist.Any().Visit([&](Track *t) - { - t->WriteXML(xmlFile); - }); - } + else if ( useTrack->GetId() == TrackId{} ) { + // This is a track added during a non-appending recording that is + // not yet in the undo history. The UndoManager skips backing it up + // when pushing. Don't auto-save it. + return; + } + useTrack->WriteXML(xmlFile); + }); xmlFile.EndTag(wxT("project")); //TIMER_STOP( xml_writer_timer ); } -bool ProjectFileIO::AutoSave(const WaveTrackArray *tracks) +bool ProjectFileIO::AutoSave(bool recording) { ProjectSerializer autosave; WriteXMLHeader(autosave); - WriteXML(autosave, tracks); + WriteXML(autosave, recording); if (WriteDoc("autosave", autosave)) { diff --git a/src/ProjectFileIO.h b/src/ProjectFileIO.h index 88cfc0507..223b90c00 100644 --- a/src/ProjectFileIO.h +++ b/src/ProjectFileIO.h @@ -72,7 +72,7 @@ public: void Reset(); - bool AutoSave(const WaveTrackArray *tracks = nullptr); + bool AutoSave(bool recording = false); bool AutoSaveDelete(sqlite3 *db = nullptr); bool LoadProject(const FilePath &fileName); @@ -81,7 +81,7 @@ public: XMLTagHandler *HandleXMLChild(const wxChar *tag) override; void WriteXMLHeader(XMLWriter &xmlFile) const; - void WriteXML(XMLWriter &xmlFile, const WaveTrackArray *tracks = nullptr) /* not override */; + void WriteXML(XMLWriter &xmlFile, bool recording = false) /* not override */; wxLongLong GetFreeDiskSpace(); diff --git a/src/ProjectSerializer.cpp b/src/ProjectSerializer.cpp index 10347f6d5..d2f96e876 100644 --- a/src/ProjectSerializer.cpp +++ b/src/ProjectSerializer.cpp @@ -291,22 +291,27 @@ wxString ProjectSerializer::Decode(const wxMemoryBuffer &buffer, BlockIDs &block return iter->second; }; - auto Convert = [&mCharSize](char *in, int len) -> wxString + auto ReadString = [&mCharSize, &in, &bytes](int len) -> wxString { + bytes.reserve( len + 4 ); + auto data = bytes.data(); + in.Read( data, len ); + // Make a null terminator of the widest type + memset( data + len, '\0', 4 ); wxUString str; - + switch (mCharSize) { case 1: - str.assignFromUTF8(in, len); + str.assignFromUTF8(data, len); break; case 2: - str.assignFromUTF16((wxChar16 *) in, len / 2); + str.assignFromUTF16((wxChar16 *) data, len / 2); break; case 4: - str = wxU32CharBuffer::CreateNonOwned((wxChar32 *) in, len / 4); + str = wxU32CharBuffer::CreateNonOwned((wxChar32 *) data, len / 4); break; default: @@ -345,10 +350,7 @@ wxString ProjectSerializer::Decode(const wxMemoryBuffer &buffer, BlockIDs &block in.Read(&id, sizeof(id)); in.Read(&len, sizeof(len)); - bytes.reserve(len); - in.Read(bytes.data(), len); - - mIds[id] = Convert(bytes.data(), len); + mIds[id] = ReadString(len); } break; @@ -374,10 +376,7 @@ wxString ProjectSerializer::Decode(const wxMemoryBuffer &buffer, BlockIDs &block in.Read(&id, sizeof(id)); in.Read(&len, sizeof(len)); - bytes.reserve(len); - in.Read(bytes.data(), len); - - out.WriteAttr(Lookup(id), Convert(bytes.data(), len)); + out.WriteAttr(Lookup(id), ReadString(len)); } break; @@ -476,10 +475,7 @@ wxString ProjectSerializer::Decode(const wxMemoryBuffer &buffer, BlockIDs &block int len; in.Read(&len, sizeof(len)); - bytes.reserve(len); - in.Read(bytes.data(), len); - - out.WriteData(Convert(bytes.data(), len)); + out.WriteData(ReadString(len)); } break; @@ -488,10 +484,7 @@ wxString ProjectSerializer::Decode(const wxMemoryBuffer &buffer, BlockIDs &block int len; in.Read(&len, sizeof(len)); - bytes.reserve(len); - in.Read(bytes.data(), len); - - out.Write(Convert(bytes.data(), len)); + out.Write(ReadString(len)); } break;