1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-05 14:18:53 +02:00

Update envelope properly for TimeTrack and WaveTrack editing...

... Formerly this was done correctly only for cut and delete from WaveTrack,
paste into WaveTrack, and sync-lock adjustment of WaveTrack (either lengthening
or shortening).

Now also properly done for TimeTrack cut and paste, and also for:

Split cut
Split delete
Trim
This commit is contained in:
Paul Licameli 2017-05-03 08:48:24 -04:00
parent 2d84c65c94
commit aba52bc79e
5 changed files with 58 additions and 44 deletions

View File

@ -606,36 +606,62 @@ bool EnvelopeEditor::MouseEvent(const wxMouseEvent & event, wxRect & r,
return false;
}
void Envelope::CollapseRegion(double t0, double t1)
void Envelope::CollapseRegion( double t0, double t1, double sampleTime )
// NOFAIL-GUARANTEE
{
// This gets called when somebody clears samples. All of the
// control points within the region disappear and the points
// to the right get shifted over.
// This gets called when somebody clears samples.
t0 -= mOffset;
t1 -= mOffset;
// Snip points in the interval (t0, t1), shift values left at times after t1.
// For the boundaries of the interval, preserve the left-side limit at the
// start and right-side limit at the end.
t0 = std::max(0.0, std::min(mTrackLen, t0));
t1 = std::max(0.0, std::min(mTrackLen, t1));
const auto epsilon = sampleTime / 2;
t0 = std::max( 0.0, std::min( mTrackLen, t0 - mOffset ) );
t1 = std::max( 0.0, std::min( mTrackLen, t1 - mOffset ) );
int len = mEnv.size();
int i;
// Remove points in deleted region.
for (i = 0; i < len - 0; i++)
if (mEnv[i].GetT() >= t0 && mEnv[i].GetT() < t1) {
Delete(i);
len--;
i--;
// Determine the start of the range of points to remove from the array.
auto range0 = EqualRange( t0, 0 );
auto begin = range0.first;
if ( begin == range0.second ) {
if ( t0 > epsilon ) {
// There was no point exactly at t0;
// insert a point to preserve the value.
auto val = GetValueRelative( t0 );
InsertOrReplaceRelative( t0, val );
++begin;
}
}
else
// We will keep the first (or only) point that was at t0.
++begin;
// We want end to be the index one past the range of points to remove from
// the array.
// At first, find index of the first point after t1:
auto range1 = EqualRange( t1, 0 );
auto end = range1.second;
if ( range1.first == end ) {
if ( mTrackLen - t1 > epsilon ) {
// There was no point exactly at t1; insert a point to preserve the value.
auto val = GetValueRelative( t1 );
InsertOrReplaceRelative( t1, val );
// end is now the index of this NEW point and that is correct.
}
}
else
// We will keep the last (or only) point that was at t1.
--end;
mEnv.erase( mEnv.begin() + begin, mEnv.begin() + end );
// Shift points left after deleted region.
for (i = 0; i < len; i++)
if (mEnv[i].GetT() >= t1)
mEnv[i].SetT(mEnv[i].GetT() - (t1 - t0));
auto len = mEnv.size();
for ( size_t i = begin; i < len; ++i ) {
auto &point = mEnv[i];
point.SetT( point.GetT() - (t1 - t0) );
}
mTrackLen -= (t1-t0);
mTrackLen -= ( t1 - t0 );
}
// This operation is trickier than it looks; the basic rub is that

View File

@ -118,8 +118,11 @@ public:
float zoomMin, float zoomMax, bool mirrored) const;
// Handling Cut/Copy/Paste events
void CollapseRegion(double t0, double t1);
// sampleTime determines when the endpoint of the collapse is near enough
// to an endpoint of the domain, that an extra control point is not needed.
void CollapseRegion(double t0, double t1, double sampleTime);
void Paste(double t0, const Envelope *e);
void InsertSpace(double t0, double tlen);
void RemoveUnneededPoints(double time = -1, double tolerence = 0.001);

View File

@ -22,6 +22,7 @@
#include "widgets/Ruler.h"
#include "Envelope.h"
#include "Prefs.h"
#include "Project.h"
#include "Internat.h"
#include "ViewInfo.h"
#include "AllThemeResources.h"
@ -108,7 +109,8 @@ Track::Holder TimeTrack::Copy( double t0, double t1, bool ) const
void TimeTrack::Clear(double t0, double t1)
{
mEnvelope->CollapseRegion(t0, t1);
auto sampleTime = 1.0 / GetActiveProject()->GetRate();
mEnvelope->CollapseRegion( t0, t1, sampleTime );
}
void TimeTrack::Paste(double t, const Track * src)

View File

@ -1676,7 +1676,8 @@ void WaveClip::Clear(double t0, double t1)
}
// Collapse envelope
GetEnvelope()->CollapseRegion(t0, t1);
auto sampleTime = 1.0 / GetRate();
GetEnvelope()->CollapseRegion( t0, t1, sampleTime );
if (t0 < GetStartTime())
Offset(-(GetStartTime() - t0));
@ -1728,7 +1729,8 @@ void WaveClip::ClearAndAddCutLine(double t0, double t1)
GetSequence()->Delete(s0, s1-s0);
// Collapse envelope
GetEnvelope()->CollapseRegion(t0, t1);
auto sampleTime = 1.0 / GetRate();
GetEnvelope()->CollapseRegion( t0, t1, sampleTime );
if (t0 < GetStartTime())
Offset(-(GetStartTime() - t0));

View File

@ -1138,26 +1138,7 @@ void WaveTrack::HandleClear(double t0, double t1,
clipsToDelete.push_back( clip.get() );
auto newClip = make_movable<WaveClip>( *clip, mDirManager, true );
/* We are going to DELETE part of the clip here. The clip may
* have envelope points, and we need to ensure that the envelope
* outside of the cleared region is not affected. This means
* putting in "glue" points where the clip enters and leaves the
* region being cleared. If one of the ends of the clip is inside
* the region, then one of the glue points will be redundant. */
// clip->Clear keeps points < t0 and >= t1 via Envelope::CollapseRegion
if (clip->GetEnvelope()->GetNumberOfPoints() > 0) { // don't insert env pts if none exist
double val;
if (clip->WithinClip(t0)) {
// start of region within clip
val = clip->GetEnvelope()->GetValue(t0);
newClip->GetEnvelope()->InsertOrReplace(t0 - 1.0 / clip->GetRate(), val);
}
if (clip->WithinClip(t1))
{ // end of region within clip
val = clip->GetEnvelope()->GetValue(t1);
newClip->GetEnvelope()->InsertOrReplace(t1 , val);
}
}
newClip->Clear(t0,t1);
newClip->GetEnvelope()->RemoveUnneededPoints(t0);