From 89d8fe18b1ef774d59238ac660bb7b472b18aff9 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 10 Jan 2018 13:20:31 -0500 Subject: [PATCH 1/3] Define WaveTrack::Reinit() --- src/WaveTrack.cpp | 27 +++++++++++++++++++++++++++ src/WaveTrack.h | 6 ++++++ 2 files changed, 33 insertions(+) diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 5eb7c9e80..bb581b6d8 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -163,6 +163,33 @@ void WaveTrack::Init(const WaveTrack &orig) mDisplayLocationsCache.clear(); } +void WaveTrack::Reinit(const WaveTrack &orig) +{ + Init(orig); + + { + auto &settings = orig.mpSpectrumSettings; + if (settings) + mpSpectrumSettings = std::make_unique(*settings); + else + mpSpectrumSettings.reset(); + } + + { + auto &settings = orig.mpWaveformSettings; + if (settings) + mpWaveformSettings = std::make_unique(*settings); + else + mpWaveformSettings.reset(); + } + + this->SetOffset(orig.GetOffset()); + +#ifdef EXPERIMENTAL_OUTPUT_DISPLAY + // To do: mYv, mHeightV, mPerY, mVirtualStereo +#endif +} + void WaveTrack::Merge(const Track &orig) { if (orig.GetKind() == Wave) diff --git a/src/WaveTrack.h b/src/WaveTrack.h index 17fb1e3f9..d461f4b53 100644 --- a/src/WaveTrack.h +++ b/src/WaveTrack.h @@ -74,6 +74,12 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { void Init(const WaveTrack &orig); +public: + // overwrite data excluding the sample sequence but including display + // settings + void Reinit(const WaveTrack &orig); + +private: Track::Holder Duplicate() const override; friend class TrackFactory; From 91f5446eb134bbefbd9df637d5d53c4bd2ce6f77 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 10 Jan 2018 13:23:01 -0500 Subject: [PATCH 2/3] Fix interaction of recording and undo... ... in case you also do things, concurrent with the recording, that affect the undo stack, either by pushing it (such as by changing the gain on one of the playing tracks, or making a label) or by "Modifying state" without a new undo item (such as when you change its size or mute or solo). --- src/AudioIO.cpp | 4 ++ src/toolbars/ControlToolBar.cpp | 71 +++++++++++++++++++-------------- src/toolbars/ControlToolBar.h | 6 +++ 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index 5a65e84c6..a35f3ccc7 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -2782,6 +2782,10 @@ void AudioIO::StopStream() } } ); } + + AudacityProject *p = GetActiveProject(); + ControlToolBar *bar = p->GetControlToolBar(); + bar->CommitRecording(); } } diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index 49d35269d..2a4a45f79 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -958,24 +958,11 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) shifted = !shifted; TrackList *trackList = p->GetTracks(); - auto pTracksCopy = TrackList::Create(); - auto &tracksCopy = *pTracksCopy; - bool tracksCopied = false; WaveTrackArray recordingTracks; auto cleanup = finally( [&] { if (!success) { - if (tracksCopied) - // Restore the tracks to remove any inserted silence - *trackList = std::move(tracksCopy); - - if ( ! shifted ) { - // msmeyer: Delete recently added tracks if opening stream fails - for ( auto track : recordingTracks ) - trackList->Remove(track.get()); - } - SetPlay(false); SetStop(false); SetRecord(false); @@ -1022,13 +1009,13 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) #ifdef EXPERIMENTAL_MIDI_OUT midiTracks = trackList->GetNoteTrackArray(false); #endif - } + } else { playbackTracks = WaveTrackConstArray(); #ifdef EXPERIMENTAL_MIDI_OUT midiTracks = NoteTrackArray(); #endif - } + } // If SHIFT key was down, the user wants append to tracks int recordingChannels = 0; @@ -1076,14 +1063,23 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) t1 = wt->GetEndTime(); // less than or equal, not just less than, to ensure a clip boundary. // when append recording. + + // A function that copies all the non-sample data between + // wave tracks; in case the track recorded to changes scale + // type (for instance), during the recording. + auto updater = [](Track &d, const Track &s){ + auto &dst = static_cast(d); + auto &src = static_cast(s); + dst.Reinit(src); + }; + + // Get a copy of the track to be appended, to be pushed into + // undo history only later. + auto pending = std::static_pointer_cast( + p->GetTracks()->RegisterPendingChangedTrack( + updater, wt.get() ) ); + if (t1 <= t0) { - if (!tracksCopied) { - // Duplicate all tracks before modifying any of them. - // The duplicates are used to restore state in case - // of failure. - tracksCopied = true; - tracksCopy = *trackList; - } // Pad the recording track with silence, up to the // maximum time. @@ -1091,10 +1087,10 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) newTrack->SetWaveColorIndex( wt->GetWaveColorIndex() ); newTrack->InsertSilence(0.0, t0 - t1); newTrack->Flush(); - wt->Clear(t1, t0); - wt->Paste(t1, newTrack.get()); + pending->Clear(t1, t0); + pending->Paste(t1, newTrack.get()); } - recordingTracks.push_back(wt); + recordingTracks.push_back(pending); // Don't record more channels than configured recording pref. if( (int)recordingTracks.size() >= recordingChannels ){ break; @@ -1130,7 +1126,9 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) wxString baseTrackName = recordingNameCustom? defaultRecordingTrackName : defaultTrackName; for (int c = 0; c < recordingChannels; c++) { - auto newTrack = p->GetTrackFactory()->NewWaveTrack(); + std::shared_ptr newTrack{ + p->GetTrackFactory()->NewWaveTrack().release() + }; newTrack->SetOffset(t0); wxString nameSuffix = wxString(wxT("")); @@ -1182,11 +1180,8 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) newTrack->SetChannel( Track::MonoChannel ); } - // Let the list hold the track, and keep a pointer to it - recordingTracks.push_back( - Track::Pointer( - trackList->Add( - std::move(newTrack)))); + p->GetTracks()->RegisterPendingNewTrack( newTrack ); + recordingTracks.push_back( newTrack ); } } @@ -1212,6 +1207,8 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) StartScrollingIfPreferred(); } else { + CancelRecording(); + // Show error message if stream could not be opened ShowErrorDialog(this, _("Error"), _("Error opening sound device.\nTry changing the audio host, recording device and the project sample rate."), @@ -1453,3 +1450,15 @@ void ControlToolBar::StopScrolling() project->GetPlaybackScroller().Activate (AudacityProject::PlaybackScroller::Mode::Off); } + +void ControlToolBar::CommitRecording() +{ + const auto project = GetActiveProject(); + project->GetTracks()->ApplyPendingTracks(); +} + +void ControlToolBar::CancelRecording() +{ + const auto project = GetActiveProject(); + project->GetTracks()->ClearPendingTracks(); +} diff --git a/src/toolbars/ControlToolBar.h b/src/toolbars/ControlToolBar.h index 4182e5c35..0ab7088b4 100644 --- a/src/toolbars/ControlToolBar.h +++ b/src/toolbars/ControlToolBar.h @@ -112,6 +112,12 @@ class ControlToolBar final : public ToolBar { void StartScrolling(); void StopScrolling(); + // Commit the addition of temporary recording tracks into the project + void CommitRecording(); + + // Cancel the addition of temporary recording tracks into the project + void CancelRecording(); + private: AButton *MakeButton(teBmps eEnabledUp, teBmps eEnabledDown, teBmps eDisabled, From 2409d46d4c165a9bac7cb69547a88c3a546994c5 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 10 Jan 2018 23:58:36 -0500 Subject: [PATCH 3/3] Prohibit copy of TrackList, no longer needed; allow swap and move --- src/Track.cpp | 27 --------------------------- src/Track.h | 15 ++++++--------- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/src/Track.cpp b/src/Track.cpp index 8e387d011..a65da94b8 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -792,15 +792,6 @@ std::shared_ptr TrackList::Create() return result; } -TrackList& TrackList::operator= (const TrackList &that) -{ - if (this != &that) { - this->Clear(); - DoAssign(that); - } - return *this; -} - TrackList &TrackList::operator= (TrackList &&that) { if (this != &that) { @@ -810,24 +801,6 @@ TrackList &TrackList::operator= (TrackList &&that) return *this; } -void TrackList::DoAssign(const TrackList &that) -{ - auto copyLOT = []( - ListOfTracks &dst, const std::weak_ptr< TrackList > &self, - const ListOfTracks &src ) - { - for (const auto &ptr : src) - dst.push_back( - ListOfTracks::value_type{ ptr->Duplicate().release() } ); - for (auto it = dst.begin(), last = dst.end(); it != last; ++it) - (*it)->SetOwner(self, it); - }; - copyLOT( *this, mSelf, that ); - copyLOT( this->mPendingAdditions, mSelf, that.mPendingAdditions ); - copyLOT( this->mPendingUpdates, mSelf, that.mPendingUpdates ); - mUpdaters = that.mUpdaters; -} - void TrackList::Swap(TrackList &that) { auto SwapLOTs = []( diff --git a/src/Track.h b/src/Track.h index 89842228e..0c5d5c7d1 100644 --- a/src/Track.h +++ b/src/Track.h @@ -659,8 +659,13 @@ class TrackList final : public wxEvtHandler, public ListOfTracks // Create an empty TrackList TrackList(); + // Disallow copy TrackList(const TrackList &that) = delete; - TrackList(TrackList &&that) = delete; + TrackList &operator= (const TrackList&) = delete; + + // Allow move + TrackList(TrackList &&that) : TrackList() { Swap(that); } + TrackList& operator= (TrackList&&); void clear() = delete; @@ -668,12 +673,6 @@ class TrackList final : public wxEvtHandler, public ListOfTracks // Create an empty TrackList static std::shared_ptr Create(); - // Allow copy -- a deep copy that duplicates all tracks - TrackList &operator= (const TrackList &that); - - // Allow move - TrackList& operator= (TrackList&&); - // Move is defined in terms of Swap void Swap(TrackList &that); @@ -831,8 +830,6 @@ private: } } - void DoAssign(const TrackList &that); - void RecalcPositions(TrackNodePointer node); void PermutationEvent(); void DeletionEvent();