mirror of
https://github.com/cookiengineer/audacity
synced 2025-07-31 07:59:27 +02:00
Fix interaction of undo and record
This commit is contained in:
commit
517bdf1ba8
@ -2800,6 +2800,10 @@ void AudioIO::StopStream()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudacityProject *p = GetActiveProject();
|
||||||
|
ControlToolBar *bar = p->GetControlToolBar();
|
||||||
|
bar->CommitRecording();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -792,15 +792,6 @@ std::shared_ptr<TrackList> TrackList::Create()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackList& TrackList::operator= (const TrackList &that)
|
|
||||||
{
|
|
||||||
if (this != &that) {
|
|
||||||
this->Clear();
|
|
||||||
DoAssign(that);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
TrackList &TrackList::operator= (TrackList &&that)
|
TrackList &TrackList::operator= (TrackList &&that)
|
||||||
{
|
{
|
||||||
if (this != &that) {
|
if (this != &that) {
|
||||||
@ -810,23 +801,6 @@ TrackList &TrackList::operator= (TrackList &&that)
|
|||||||
return *this;
|
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->mPendingUpdates, mSelf, that.mPendingUpdates );
|
|
||||||
mUpdaters = that.mUpdaters;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrackList::Swap(TrackList &that)
|
void TrackList::Swap(TrackList &that)
|
||||||
{
|
{
|
||||||
auto SwapLOTs = [](
|
auto SwapLOTs = [](
|
||||||
|
15
src/Track.h
15
src/Track.h
@ -614,8 +614,13 @@ class TrackList final : public wxEvtHandler, public ListOfTracks
|
|||||||
// Create an empty TrackList
|
// Create an empty TrackList
|
||||||
TrackList();
|
TrackList();
|
||||||
|
|
||||||
|
// Disallow copy
|
||||||
TrackList(const TrackList &that) = delete;
|
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;
|
void clear() = delete;
|
||||||
|
|
||||||
@ -623,12 +628,6 @@ class TrackList final : public wxEvtHandler, public ListOfTracks
|
|||||||
// Create an empty TrackList
|
// Create an empty TrackList
|
||||||
static std::shared_ptr<TrackList> Create();
|
static std::shared_ptr<TrackList> 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
|
// Move is defined in terms of Swap
|
||||||
void Swap(TrackList &that);
|
void Swap(TrackList &that);
|
||||||
|
|
||||||
@ -776,8 +775,6 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoAssign(const TrackList &that);
|
|
||||||
|
|
||||||
void RecalcPositions(TrackNodePointer node);
|
void RecalcPositions(TrackNodePointer node);
|
||||||
void PermutationEvent();
|
void PermutationEvent();
|
||||||
void DeletionEvent();
|
void DeletionEvent();
|
||||||
|
@ -163,6 +163,33 @@ void WaveTrack::Init(const WaveTrack &orig)
|
|||||||
mDisplayLocationsCache.clear();
|
mDisplayLocationsCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WaveTrack::Reinit(const WaveTrack &orig)
|
||||||
|
{
|
||||||
|
Init(orig);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto &settings = orig.mpSpectrumSettings;
|
||||||
|
if (settings)
|
||||||
|
mpSpectrumSettings = std::make_unique<SpectrogramSettings>(*settings);
|
||||||
|
else
|
||||||
|
mpSpectrumSettings.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto &settings = orig.mpWaveformSettings;
|
||||||
|
if (settings)
|
||||||
|
mpWaveformSettings = std::make_unique<WaveformSettings>(*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)
|
void WaveTrack::Merge(const Track &orig)
|
||||||
{
|
{
|
||||||
if (orig.GetKind() == Wave)
|
if (orig.GetKind() == Wave)
|
||||||
|
@ -74,6 +74,12 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack {
|
|||||||
|
|
||||||
void Init(const WaveTrack &orig);
|
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;
|
Track::Holder Duplicate() const override;
|
||||||
|
|
||||||
friend class TrackFactory;
|
friend class TrackFactory;
|
||||||
|
@ -958,24 +958,11 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
|
|||||||
shifted = !shifted;
|
shifted = !shifted;
|
||||||
|
|
||||||
TrackList *trackList = p->GetTracks();
|
TrackList *trackList = p->GetTracks();
|
||||||
auto pTracksCopy = TrackList::Create();
|
|
||||||
auto &tracksCopy = *pTracksCopy;
|
|
||||||
bool tracksCopied = false;
|
|
||||||
|
|
||||||
WaveTrackArray recordingTracks;
|
WaveTrackArray recordingTracks;
|
||||||
|
|
||||||
auto cleanup = finally( [&] {
|
auto cleanup = finally( [&] {
|
||||||
if (!success) {
|
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);
|
SetPlay(false);
|
||||||
SetStop(false);
|
SetStop(false);
|
||||||
SetRecord(false);
|
SetRecord(false);
|
||||||
@ -1022,13 +1009,13 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
|
|||||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||||
midiTracks = trackList->GetNoteTrackArray(false);
|
midiTracks = trackList->GetNoteTrackArray(false);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
playbackTracks = WaveTrackConstArray();
|
playbackTracks = WaveTrackConstArray();
|
||||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||||
midiTracks = NoteTrackArray();
|
midiTracks = NoteTrackArray();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// If SHIFT key was down, the user wants append to tracks
|
// If SHIFT key was down, the user wants append to tracks
|
||||||
int recordingChannels = 0;
|
int recordingChannels = 0;
|
||||||
@ -1076,14 +1063,23 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
|
|||||||
t1 = wt->GetEndTime();
|
t1 = wt->GetEndTime();
|
||||||
// less than or equal, not just less than, to ensure a clip boundary.
|
// less than or equal, not just less than, to ensure a clip boundary.
|
||||||
// when append recording.
|
// 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<WaveTrack&>(d);
|
||||||
|
auto &src = static_cast<const WaveTrack&>(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<WaveTrack>(
|
||||||
|
p->GetTracks()->RegisterPendingChangedTrack(
|
||||||
|
updater, wt.get() ) );
|
||||||
|
|
||||||
if (t1 <= t0) {
|
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
|
// Pad the recording track with silence, up to the
|
||||||
// maximum time.
|
// maximum time.
|
||||||
@ -1091,10 +1087,10 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
|
|||||||
newTrack->SetWaveColorIndex( wt->GetWaveColorIndex() );
|
newTrack->SetWaveColorIndex( wt->GetWaveColorIndex() );
|
||||||
newTrack->InsertSilence(0.0, t0 - t1);
|
newTrack->InsertSilence(0.0, t0 - t1);
|
||||||
newTrack->Flush();
|
newTrack->Flush();
|
||||||
wt->Clear(t1, t0);
|
pending->Clear(t1, t0);
|
||||||
wt->Paste(t1, newTrack.get());
|
pending->Paste(t1, newTrack.get());
|
||||||
}
|
}
|
||||||
recordingTracks.push_back(wt);
|
recordingTracks.push_back(pending);
|
||||||
// Don't record more channels than configured recording pref.
|
// Don't record more channels than configured recording pref.
|
||||||
if( (int)recordingTracks.size() >= recordingChannels ){
|
if( (int)recordingTracks.size() >= recordingChannels ){
|
||||||
break;
|
break;
|
||||||
@ -1130,7 +1126,9 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
|
|||||||
wxString baseTrackName = recordingNameCustom? defaultRecordingTrackName : defaultTrackName;
|
wxString baseTrackName = recordingNameCustom? defaultRecordingTrackName : defaultTrackName;
|
||||||
|
|
||||||
for (int c = 0; c < recordingChannels; c++) {
|
for (int c = 0; c < recordingChannels; c++) {
|
||||||
auto newTrack = p->GetTrackFactory()->NewWaveTrack();
|
std::shared_ptr<WaveTrack> newTrack{
|
||||||
|
p->GetTrackFactory()->NewWaveTrack().release()
|
||||||
|
};
|
||||||
|
|
||||||
newTrack->SetOffset(t0);
|
newTrack->SetOffset(t0);
|
||||||
wxString nameSuffix = wxString(wxT(""));
|
wxString nameSuffix = wxString(wxT(""));
|
||||||
@ -1182,11 +1180,8 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
|
|||||||
newTrack->SetChannel( Track::MonoChannel );
|
newTrack->SetChannel( Track::MonoChannel );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let the list hold the track, and keep a pointer to it
|
p->GetTracks()->RegisterPendingNewTrack( newTrack );
|
||||||
recordingTracks.push_back(
|
recordingTracks.push_back( newTrack );
|
||||||
Track::Pointer<WaveTrack>(
|
|
||||||
trackList->Add(
|
|
||||||
std::move(newTrack))));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1212,6 +1207,8 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
|
|||||||
StartScrollingIfPreferred();
|
StartScrollingIfPreferred();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
CancelRecording();
|
||||||
|
|
||||||
// Show error message if stream could not be opened
|
// Show error message if stream could not be opened
|
||||||
ShowErrorDialog(this, _("Error"),
|
ShowErrorDialog(this, _("Error"),
|
||||||
_("Error opening sound device.\nTry changing the audio host, recording device and the project sample rate."),
|
_("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
|
project->GetPlaybackScroller().Activate
|
||||||
(AudacityProject::PlaybackScroller::Mode::Off);
|
(AudacityProject::PlaybackScroller::Mode::Off);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ControlToolBar::CommitRecording()
|
||||||
|
{
|
||||||
|
const auto project = GetActiveProject();
|
||||||
|
project->GetTracks()->ApplyPendingTracks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlToolBar::CancelRecording()
|
||||||
|
{
|
||||||
|
const auto project = GetActiveProject();
|
||||||
|
project->GetTracks()->ClearPendingTracks();
|
||||||
|
}
|
||||||
|
@ -112,6 +112,12 @@ class ControlToolBar final : public ToolBar {
|
|||||||
void StartScrolling();
|
void StartScrolling();
|
||||||
void StopScrolling();
|
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:
|
private:
|
||||||
|
|
||||||
AButton *MakeButton(teBmps eEnabledUp, teBmps eEnabledDown, teBmps eDisabled,
|
AButton *MakeButton(teBmps eEnabledUp, teBmps eEnabledDown, teBmps eDisabled,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user