1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-11-08 14:13:57 +01:00

Bug1348, partial: Fix bad undo after cancelling Vamp or FindClipping analyzer

This commit is contained in:
Paul Licameli
2016-02-27 14:24:57 -05:00
parent 48a5f55179
commit 0094c4f465
5 changed files with 183 additions and 39 deletions

View File

@@ -40,6 +40,7 @@ greater use in future.
#include "audacity/ConfigInterface.h"
#include "../AudioIO.h"
#include "../LabelTrack.h"
#include "../Mix.h"
#include "../Prefs.h"
#include "../Project.h"
@@ -2131,6 +2132,88 @@ void Effect::AddToOutputTracks(Track *t)
mOMap.Add(t);
}
Effect::AddedAnalysisTrack::AddedAnalysisTrack(Effect *pEffect, const wxString &name)
: mpEffect(pEffect)
{
std::unique_ptr < LabelTrack > pTrack{ pEffect->mFactory->NewLabelTrack() };
mpTrack = pTrack.get();
if (!name.empty())
pTrack->SetName(name);
pEffect->mTracks->Add(pTrack.release());
}
Effect::AddedAnalysisTrack::AddedAnalysisTrack(AddedAnalysisTrack &&that)
{
mpEffect = that.mpEffect;
mpTrack = that.mpTrack;
that.Commit();
}
void Effect::AddedAnalysisTrack::Commit()
{
mpEffect = nullptr;
}
Effect::AddedAnalysisTrack::~AddedAnalysisTrack()
{
if (mpEffect) {
// not committed -- DELETE the label track
mpEffect->mTracks->Remove(mpTrack, true);
}
}
auto Effect::AddAnalysisTrack(const wxString &name) -> AddedAnalysisTrack
{
return {this, name};
}
Effect::ModifiedAnalysisTrack::ModifiedAnalysisTrack
(Effect *pEffect, const LabelTrack *pOrigTrack, const wxString &name)
: mpEffect(pEffect)
, mpOrigTrack(pOrigTrack)
{
Track *newTrack{};
// copy LabelTrack here, so it can be undone on cancel
pOrigTrack->Copy(pOrigTrack->GetStartTime(), pOrigTrack->GetEndTime(), &newTrack);
mpTrack = static_cast<LabelTrack*>(newTrack);
// Why doesn't LabelTrack::Copy complete the job? :
mpTrack->SetOffset(pOrigTrack->GetStartTime());
if (!name.empty())
mpTrack->SetName(name);
pEffect->mTracks->Replace(mpOrigTrack, mpTrack, false);
}
Effect::ModifiedAnalysisTrack::ModifiedAnalysisTrack(ModifiedAnalysisTrack &&that)
{
mpEffect = that.mpEffect;
mpTrack = that.mpTrack;
mpOrigTrack = that.mpOrigTrack;
that.Commit();
}
void Effect::ModifiedAnalysisTrack::Commit()
{
mpEffect = nullptr;
}
Effect::ModifiedAnalysisTrack::~ModifiedAnalysisTrack()
{
if (mpEffect) {
// not committed -- DELETE the label track
mpEffect->mTracks->Replace(mpTrack, mpOrigTrack, true);
}
}
auto Effect::ModifyAnalysisTrack
(const LabelTrack *pOrigTrack, const wxString &name) -> ModifiedAnalysisTrack
{
return{ this, pOrigTrack, name };
}
// If bGoodResult, replace mTracks tracks with successfully processed mOutputTracks copies.
// Else clear and DELETE mOutputTracks copies.
void Effect::ReplaceProcessedTracks(const bool bGoodResult)

View File

@@ -40,6 +40,7 @@ class ShuttleGui;
#define BUILTIN_EFFECT_PREFIX wxT("Built-in Effect: ")
class AudacityProject;
class LabelTrack;
class SelectedRegion;
class TimeWarper;
class EffectUIHost;
@@ -350,6 +351,69 @@ protected:
void CopyInputTracks(); // trackType = Track::Wave
void CopyInputTracks(int trackType);
// For the use of analyzers, which don't need to make output wave tracks,
// but may need to add label tracks.
class AddedAnalysisTrack {
friend Effect;
AddedAnalysisTrack(Effect *pEffect, const wxString &name);
AddedAnalysisTrack(const AddedAnalysisTrack&) PROHIBITED;
public:
AddedAnalysisTrack() {}
// So you can have a vector of them
AddedAnalysisTrack(AddedAnalysisTrack &&that);
LabelTrack *get() const { return mpTrack; }
// Call this to indicate successful completion of the analyzer.
void Commit();
// Destructor undoes the addition of the analysis track if not committed.
~AddedAnalysisTrack();
private:
Effect *mpEffect{};
LabelTrack *mpTrack{};
};
// Set name to given value if that is not empty, else use default name
AddedAnalysisTrack AddAnalysisTrack(const wxString &name = wxString());
// For the use of analyzers, which don't need to make output wave tracks,
// but may need to modify label tracks.
class ModifiedAnalysisTrack {
friend Effect;
ModifiedAnalysisTrack
(Effect *pEffect, const LabelTrack *pOrigTrack, const wxString &name);
ModifiedAnalysisTrack(const ModifiedAnalysisTrack&) PROHIBITED;
public:
ModifiedAnalysisTrack();
// So you can have a vector of them
ModifiedAnalysisTrack(ModifiedAnalysisTrack &&that);
LabelTrack *get() const { return mpTrack; }
// Call this to indicate successful completion of the analyzer.
void Commit();
// Destructor undoes the modification of the analysis track if not committed.
~ModifiedAnalysisTrack();
private:
Effect *mpEffect{};
LabelTrack *mpTrack{};
const LabelTrack *mpOrigTrack{};
};
// Set name to given value if that is not empty, else use default name
ModifiedAnalysisTrack ModifyAnalysisTrack
(const LabelTrack *pOrigTrack, const wxString &name = wxString());
// If bGoodResult, replace mWaveTracks tracks in mTracks with successfully processed
// mOutputTracks copies, get rid of old mWaveTracks, and set mWaveTracks to mOutputTracks.
// Else clear and DELETE mOutputTracks copies.

View File

@@ -93,26 +93,24 @@ bool EffectFindClipping::SetAutomationParameters(EffectAutomationParameters & pa
bool EffectFindClipping::Process()
{
LabelTrack *l = NULL;
Maybe<AddedAnalysisTrack> addedTrack;
Maybe<ModifiedAnalysisTrack> modifiedTrack;
Track *original = NULL;
const wxString name{ _("Clipping") };
LabelTrack *lt = NULL;
TrackListOfKindIterator iter(Track::Label, mTracks);
for (Track *t = iter.First(); t; t = iter.Next()) {
if (t->GetName() == wxT("Clipping")) {
l = (LabelTrack *) t;
// copy LabelTrack here, so it can be undone on cancel
l->Copy(l->GetStartTime(), l->GetEndTime(), &original);
original->SetOffset(l->GetStartTime());
original->SetName(wxT("Clipping"));
if (t->GetName() == name) {
lt = (LabelTrack *)t;
break;
}
}
if (!l) {
l = mFactory->NewLabelTrack();
l->SetName(_("Clipping"));
mTracks->Add((Track *) l);
}
if (!lt)
addedTrack.create(AddAnalysisTrack(name)), lt = addedTrack->get();
else
modifiedTrack.create(ModifyAnalysisTrack(lt, name)), lt = modifiedTrack->get();
int count = 0;
@@ -130,12 +128,7 @@ bool EffectFindClipping::Process()
sampleCount end = t->TimeToLongSamples(t1);
sampleCount len = (sampleCount)(end - start);
if (!ProcessOne(l, count, t, start, len)) {
//put it back how it was
mTracks->Remove((Track *) l);
if(original) {
mTracks->Add((Track *) original);
}
if (!ProcessOne(lt, count, t, start, len)) {
return false;
}
}
@@ -144,12 +137,17 @@ bool EffectFindClipping::Process()
t = (WaveTrack *) waves.Next();
}
// No cancellation, so commit the addition of the track.
if (addedTrack)
addedTrack->Commit();
if (modifiedTrack)
modifiedTrack->Commit();
return true;
}
bool EffectFindClipping::ProcessOne(LabelTrack * l,
bool EffectFindClipping::ProcessOne(LabelTrack * lt,
int count,
WaveTrack * t,
const WaveTrack * wt,
sampleCount start,
sampleCount len)
{
@@ -180,14 +178,14 @@ bool EffectFindClipping::ProcessOne(LabelTrack * l,
block = s + blockSize > len ? len - s : blockSize;
t->Get((samplePtr)buffer, floatSample, start + s, block);
wt->Get((samplePtr)buffer, floatSample, start + s, block);
ptr = buffer;
}
float v = fabs(*ptr++);
if (v >= MAX_AUDIO) {
if (startrun == 0) {
startTime = t->LongSamplesToTime(start + s);
startTime = wt->LongSamplesToTime(start + s);
samps = 0;
}
else {
@@ -202,8 +200,8 @@ bool EffectFindClipping::ProcessOne(LabelTrack * l,
samps++;
if (stoprun >= mStop) {
l->AddLabel(SelectedRegion(startTime,
t->LongSamplesToTime(start + s - mStop)),
lt->AddLabel(SelectedRegion(startTime,
wt->LongSamplesToTime(start + s - mStop)),
wxString::Format(wxT("%lld of %lld"), (long long) startrun, (long long) (samps - mStop)));
startrun = 0;
stoprun = 0;

View File

@@ -52,7 +52,7 @@ public:
private:
// EffectFindCliping implementation
bool ProcessOne(LabelTrack *l, int count, WaveTrack * t,
bool ProcessOne(LabelTrack *lt, int count, const WaveTrack * wt,
sampleCount start, sampleCount len);
private:

View File

@@ -419,6 +419,8 @@ bool VampEffect::Process()
multiple = true;
}
std::vector<Effect::AddedAnalysisTrack> addedTracks;
while (left)
{
sampleCount lstart, rstart = 0;
@@ -484,20 +486,13 @@ bool VampEffect::Process()
}
}
LabelTrack *ltrack = mFactory->NewLabelTrack();
if (!multiple)
{
ltrack->SetName(GetName());
}
else
{
ltrack->SetName(wxString::Format(wxT("%s: %s"),
left->GetName().c_str(),
GetName().c_str()));
}
mTracks->Add(ltrack);
addedTracks.push_back(AddAnalysisTrack(
multiple
? wxString::Format(wxT("%s: %s"),
left->GetName().c_str(), GetName().c_str())
: GetName()
));
LabelTrack *ltrack = addedTracks.back().get();
float **data = new float *[channels]; // ANSWER-ME: Vigilant Sentry marks this as memory leak, var "data" not deleted.
for (int c = 0; c < channels; ++c)
@@ -576,6 +571,10 @@ bool VampEffect::Process()
left = (WaveTrack *)iter.Next();
}
// All completed without cancellation, so commit the addition of tracks now
for (auto &addedTrack : addedTracks)
addedTrack.Commit();
return true;
}