mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-10 17:11:17 +02:00
Wave track duplication: don't append empty clips, do copy cutlines
This commit is contained in:
commit
9119d703ce
@ -2361,7 +2361,7 @@ Track::Holder LabelTrack::SplitCut(double t0, double t1)
|
||||
}
|
||||
#endif
|
||||
|
||||
Track::Holder LabelTrack::Copy(double t0, double t1) const
|
||||
Track::Holder LabelTrack::Copy(double t0, double t1, bool) const
|
||||
{
|
||||
auto tmp = std::make_unique<LabelTrack>(GetDirManager());
|
||||
const auto lt = static_cast<LabelTrack*>(tmp.get());
|
||||
|
@ -155,11 +155,7 @@ class AUDACITY_DLL_API LabelTrack final : public Track
|
||||
#endif
|
||||
|
||||
Track::Holder Cut (double t0, double t1) override;
|
||||
// JKC Do not add the const modifier to Copy(), Clear()
|
||||
// or Paste() because then it
|
||||
// is no longer recognised as a virtual function matching the
|
||||
// one in Track.
|
||||
Track::Holder Copy (double t0, double t1) const override;
|
||||
Track::Holder Copy (double t0, double t1, bool forClipboard = true) const override;
|
||||
bool Clear(double t0, double t1) override;
|
||||
bool Paste(double t, const Track * src) override;
|
||||
bool Repeat(double t0, double t1, int n);
|
||||
|
@ -4789,8 +4789,9 @@ void AudacityProject::OnDuplicate()
|
||||
|
||||
while (n) {
|
||||
if (n->GetSelected()) {
|
||||
// Make copies not for clipboard but for direct addition to the project
|
||||
auto dest = n->Copy(mViewInfo.selectedRegion.t0(),
|
||||
mViewInfo.selectedRegion.t1());
|
||||
mViewInfo.selectedRegion.t1(), false);
|
||||
if (dest) {
|
||||
dest->Init(*n);
|
||||
dest->SetOffset(wxMax(mViewInfo.selectedRegion.t0(), n->GetOffset()));
|
||||
|
@ -454,7 +454,7 @@ Track::Holder NoteTrack::Cut(double t0, double t1)
|
||||
return std::move(newTrack);
|
||||
}
|
||||
|
||||
Track::Holder NoteTrack::Copy(double t0, double t1) const
|
||||
Track::Holder NoteTrack::Copy(double t0, double t1, bool) const
|
||||
{
|
||||
if (t1 <= t0)
|
||||
return{};
|
||||
|
@ -91,7 +91,7 @@ class AUDACITY_DLL_API NoteTrack final : public Track {
|
||||
|
||||
// High-level editing
|
||||
Track::Holder Cut (double t0, double t1) override;
|
||||
Track::Holder Copy (double t0, double t1) const override;
|
||||
Track::Holder Copy (double t0, double t1, bool forClipboard = true) const override;
|
||||
bool Trim (double t0, double t1) /* not override */;
|
||||
bool Clear(double t0, double t1) override;
|
||||
bool Paste(double t, const Track *src) override;
|
||||
|
@ -4905,6 +4905,7 @@ void AudacityProject::EditClipboardByLabel( EditDestFunction action )
|
||||
if( n->GetKind() == Track::Wave && ( allTracks || n->GetSelected() ) )
|
||||
{
|
||||
WaveTrack *wt = ( WaveTrack* )n;
|
||||
// This track accumulates the needed clips, right to left:
|
||||
Track::Holder merged;
|
||||
for( int i = (int)regions.size() - 1; i >= 0; i-- )
|
||||
{
|
||||
@ -4923,6 +4924,11 @@ void AudacityProject::EditClipboardByLabel( EditDestFunction action )
|
||||
merged->Offset(
|
||||
regions.at(i + 1).start - region.end);
|
||||
|
||||
// dest may have a placeholder clip at the end that is
|
||||
// removed when pasting, which is okay because we proceed
|
||||
// right to left. Any placeholder already in merged is kept.
|
||||
// Only the rightmost placeholder is important in the final
|
||||
// result.
|
||||
bool bResult = merged->Paste( 0.0 , dest.get() );
|
||||
wxASSERT(bResult); // TO DO: Actually handle this.
|
||||
wxUnusedVar(bResult);
|
||||
|
@ -385,12 +385,10 @@ bool Sequence::GetRMS(sampleCount start, sampleCount len,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sequence::Copy(sampleCount s0, sampleCount s1, std::unique_ptr<Sequence> &dest) const
|
||||
std::unique_ptr<Sequence> Sequence::Copy(sampleCount s0, sampleCount s1) const
|
||||
{
|
||||
dest.reset();
|
||||
|
||||
if (s0 >= s1 || s0 >= mNumSamples || s1 < 0)
|
||||
return false;
|
||||
return {};
|
||||
|
||||
int numBlocks = mBlock.size();
|
||||
|
||||
@ -402,7 +400,7 @@ bool Sequence::Copy(sampleCount s0, sampleCount s1, std::unique_ptr<Sequence> &d
|
||||
wxUnusedVar(numBlocks);
|
||||
wxASSERT(b0 <= b1);
|
||||
|
||||
dest = std::make_unique<Sequence>(mDirManager, mSampleFormat);
|
||||
auto dest = std::make_unique<Sequence>(mDirManager, mSampleFormat);
|
||||
dest->mBlock.reserve(b1 - b0 + 1);
|
||||
|
||||
SampleBuffer buffer(mMaxSamples, mSampleFormat);
|
||||
@ -445,7 +443,10 @@ bool Sequence::Copy(sampleCount s0, sampleCount s1, std::unique_ptr<Sequence> &d
|
||||
dest->AppendBlock(block); // Increase ref count or duplicate file
|
||||
}
|
||||
|
||||
return ConsistencyCheck(wxT("Sequence::Copy()"));
|
||||
if (! ConsistencyCheck(wxT("Sequence::Copy()")))
|
||||
return {};
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -103,7 +103,7 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{
|
||||
bool GetWaveDisplay(float *min, float *max, float *rms, int* bl,
|
||||
size_t len, const sampleCount *where);
|
||||
|
||||
bool Copy(sampleCount s0, sampleCount s1, std::unique_ptr<Sequence> &dest) const;
|
||||
std::unique_ptr<Sequence> Copy(sampleCount s0, sampleCount s1) const;
|
||||
bool Paste(sampleCount s0, const Sequence *src);
|
||||
|
||||
size_t GetIdealAppendLen() const;
|
||||
|
@ -216,7 +216,11 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler
|
||||
virtual Holder Cut(double WXUNUSED(t0), double WXUNUSED(t1)) { return{}; }
|
||||
|
||||
// Create a NEW track and don't modify this track (or return null for failure)
|
||||
virtual Holder Copy(double WXUNUSED(t0), double WXUNUSED(t1)) const { return{}; }
|
||||
// Note that subclasses may want to distinguish tracks stored in a clipboard
|
||||
// from those stored in a project
|
||||
virtual Holder Copy
|
||||
(double WXUNUSED(t0), double WXUNUSED(t1), bool forClipboard = true) const
|
||||
{ return{}; }
|
||||
|
||||
// Return true for success
|
||||
virtual bool Clear(double WXUNUSED(t0), double WXUNUSED(t1)) {return false;}
|
||||
|
132
src/WaveClip.cpp
132
src/WaveClip.cpp
@ -300,21 +300,22 @@ static void ComputeSpectrumUsingRealFFTf
|
||||
}
|
||||
}
|
||||
|
||||
WaveClip::WaveClip(const std::shared_ptr<DirManager> &projDirManager, sampleFormat format, int rate)
|
||||
WaveClip::WaveClip(const std::shared_ptr<DirManager> &projDirManager,
|
||||
sampleFormat format, int rate)
|
||||
{
|
||||
mOffset = 0;
|
||||
mRate = rate;
|
||||
mSequence = std::make_unique<Sequence>(projDirManager, format);
|
||||
|
||||
mEnvelope = std::make_unique<Envelope>();
|
||||
|
||||
mWaveCache = std::make_unique<WaveCache>();
|
||||
mSpecCache = std::make_unique<SpecCache>();
|
||||
mSpecPxCache = std::make_unique<SpecPxCache>(1);
|
||||
mAppendBufferLen = 0;
|
||||
mDirty = 0;
|
||||
mIsPlaceholder = false;
|
||||
}
|
||||
|
||||
WaveClip::WaveClip(const WaveClip& orig, const std::shared_ptr<DirManager> &projDirManager)
|
||||
WaveClip::WaveClip(const WaveClip& orig,
|
||||
const std::shared_ptr<DirManager> &projDirManager,
|
||||
bool copyCutlines)
|
||||
{
|
||||
// essentially a copy constructor - but you must pass in the
|
||||
// current project's DirManager, because we might be copying
|
||||
@ -323,22 +324,69 @@ WaveClip::WaveClip(const WaveClip& orig, const std::shared_ptr<DirManager> &proj
|
||||
mOffset = orig.mOffset;
|
||||
mRate = orig.mRate;
|
||||
mSequence = std::make_unique<Sequence>(*orig.mSequence, projDirManager);
|
||||
|
||||
mEnvelope = std::make_unique<Envelope>();
|
||||
mEnvelope->Paste(0.0, orig.mEnvelope.get());
|
||||
mEnvelope->SetOffset(orig.GetOffset());
|
||||
mEnvelope->SetTrackLen((orig.mSequence->GetNumSamples().as_double()) / orig.mRate);
|
||||
|
||||
mWaveCache = std::make_unique<WaveCache>();
|
||||
mSpecCache = std::make_unique<SpecCache>();
|
||||
mSpecPxCache = std::make_unique<SpecPxCache>(1);
|
||||
|
||||
if ( copyCutlines )
|
||||
for (const auto &clip: orig.mCutLines)
|
||||
mCutLines.push_back(make_movable<WaveClip>(*clip, projDirManager));
|
||||
mCutLines.push_back
|
||||
( make_movable<WaveClip>( *clip, projDirManager, true ) );
|
||||
|
||||
mAppendBufferLen = 0;
|
||||
mDirty = 0;
|
||||
mIsPlaceholder = orig.GetIsPlaceholder();
|
||||
}
|
||||
|
||||
WaveClip::WaveClip(const WaveClip& orig,
|
||||
const std::shared_ptr<DirManager> &projDirManager,
|
||||
bool copyCutlines,
|
||||
double t0, double t1)
|
||||
{
|
||||
// Copy only a range of the other WaveClip
|
||||
|
||||
mOffset = orig.mOffset;
|
||||
mRate = orig.mRate;
|
||||
|
||||
mWaveCache = std::make_unique<WaveCache>();
|
||||
mSpecCache = std::make_unique<SpecCache>();
|
||||
mSpecPxCache = std::make_unique<SpecPxCache>(1);
|
||||
|
||||
mIsPlaceholder = orig.GetIsPlaceholder();
|
||||
|
||||
sampleCount s0, s1;
|
||||
|
||||
orig.TimeToSamplesClip(t0, &s0);
|
||||
orig.TimeToSamplesClip(t1, &s1);
|
||||
|
||||
mSequence = orig.mSequence->Copy(s0, s1);
|
||||
|
||||
mEnvelope = std::make_unique<Envelope>();
|
||||
mEnvelope->CopyFrom(orig.mEnvelope.get(),
|
||||
mOffset + s0.as_double()/mRate,
|
||||
mOffset + s1.as_double()/mRate);
|
||||
|
||||
if ( copyCutlines )
|
||||
// Copy cutline clips that fall in the range
|
||||
for (const auto &ppClip : orig.mCutLines)
|
||||
{
|
||||
const WaveClip* clip = ppClip.get();
|
||||
double cutlinePosition = orig.mOffset + clip->GetOffset();
|
||||
if (cutlinePosition >= t0 && cutlinePosition <= t1)
|
||||
{
|
||||
auto newCutLine =
|
||||
make_movable< WaveClip >( *clip, projDirManager, true );
|
||||
newCutLine->SetOffset( cutlinePosition - t0 );
|
||||
mCutLines.push_back(std::move(newCutLine));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WaveClip::~WaveClip()
|
||||
{
|
||||
}
|
||||
@ -1277,6 +1325,9 @@ bool WaveClip::GetRMS(float *rms, double t0,
|
||||
|
||||
void WaveClip::ConvertToSampleFormat(sampleFormat format)
|
||||
{
|
||||
// Note: it is not necessary to do this recursively to cutlines.
|
||||
// They get converted as needed when they are expanded.
|
||||
|
||||
bool bChanged;
|
||||
bool bResult = mSequence->ConvertToSampleFormat(format, &bChanged);
|
||||
if (bResult && bChanged)
|
||||
@ -1477,30 +1528,6 @@ void WaveClip::WriteXML(XMLWriter &xmlFile) const
|
||||
xmlFile.EndTag(wxT("waveclip"));
|
||||
}
|
||||
|
||||
bool WaveClip::CreateFromCopy(double t0, double t1, const WaveClip* other)
|
||||
{
|
||||
sampleCount s0, s1;
|
||||
|
||||
other->TimeToSamplesClip(t0, &s0);
|
||||
other->TimeToSamplesClip(t1, &s1);
|
||||
|
||||
std::unique_ptr<Sequence> oldSequence = std::move(mSequence);
|
||||
if (!other->mSequence->Copy(s0, s1, mSequence))
|
||||
{
|
||||
mSequence = std::move(oldSequence);
|
||||
return false;
|
||||
}
|
||||
|
||||
mEnvelope = std::make_unique<Envelope>();
|
||||
mEnvelope->CopyFrom(other->mEnvelope.get(),
|
||||
mOffset + s0.as_double()/mRate,
|
||||
mOffset + s1.as_double()/mRate);
|
||||
|
||||
MarkChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WaveClip::Paste(double t0, const WaveClip* other)
|
||||
{
|
||||
const bool clipNeedsResampling = other->mRate != mRate;
|
||||
@ -1512,7 +1539,7 @@ bool WaveClip::Paste(double t0, const WaveClip* other)
|
||||
if (clipNeedsResampling || clipNeedsNewFormat)
|
||||
{
|
||||
newClip =
|
||||
std::make_unique<WaveClip>(*other, mSequence->GetDirManager());
|
||||
std::make_unique<WaveClip>(*other, mSequence->GetDirManager(), true);
|
||||
if (clipNeedsResampling)
|
||||
// The other clip's rate is different from ours, so resample
|
||||
if (!newClip->Resample(mRate))
|
||||
@ -1542,7 +1569,11 @@ bool WaveClip::Paste(double t0, const WaveClip* other)
|
||||
for (const auto &cutline: pastedClip->mCutLines)
|
||||
{
|
||||
mCutLines.push_back(
|
||||
make_movable<WaveClip>(*cutline, mSequence->GetDirManager()));
|
||||
make_movable<WaveClip>
|
||||
( *cutline, mSequence->GetDirManager(),
|
||||
// Recursively copy cutlines of cutlines. They don't need
|
||||
// their offsets adjusted.
|
||||
true));
|
||||
mCutLines.back()->Offset(t0 - mOffset);
|
||||
}
|
||||
|
||||
@ -1635,32 +1666,23 @@ bool WaveClip::ClearAndAddCutLine(double t0, double t1)
|
||||
if (t0 > GetEndTime() || t1 < GetStartTime())
|
||||
return true; // time out of bounds
|
||||
|
||||
auto newClip = make_movable<WaveClip>
|
||||
(mSequence->GetDirManager(), mSequence->GetSampleFormat(), mRate);
|
||||
double clip_t0 = t0;
|
||||
double clip_t1 = t1;
|
||||
if (clip_t0 < GetStartTime())
|
||||
clip_t0 = GetStartTime();
|
||||
if (clip_t1 > GetEndTime())
|
||||
clip_t1 = GetEndTime();
|
||||
const double clip_t0 = std::max( t0, GetStartTime() );
|
||||
const double clip_t1 = std::min( t1, GetEndTime() );
|
||||
|
||||
auto newClip = make_movable<WaveClip>
|
||||
(*this, mSequence->GetDirManager(), true, clip_t0, clip_t1);
|
||||
|
||||
newClip->SetOffset(this->mOffset);
|
||||
if (!newClip->CreateFromCopy(clip_t0, clip_t1, this))
|
||||
return false;
|
||||
newClip->SetOffset(clip_t0-mOffset);
|
||||
|
||||
// Sort out cutlines that belong to the NEW cutline
|
||||
// Remove cutlines from this clip that were in the selection, shift
|
||||
// left those that were after the selection
|
||||
// May DELETE as we iterate, so don't use range-for
|
||||
for (auto it = mCutLines.begin(); it != mCutLines.end();)
|
||||
{
|
||||
WaveClip* clip = it->get();
|
||||
double cutlinePosition = mOffset + clip->GetOffset();
|
||||
if (cutlinePosition >= t0 && cutlinePosition <= t1)
|
||||
{
|
||||
clip->SetOffset(cutlinePosition - newClip->GetOffset() - mOffset);
|
||||
newClip->mCutLines.push_back(std::move(*it)); // transfer ownership!!
|
||||
it = mCutLines.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cutlinePosition >= t1)
|
||||
@ -1755,11 +1777,6 @@ bool WaveClip::RemoveCutLine(double cutLinePosition)
|
||||
return false;
|
||||
}
|
||||
|
||||
void WaveClip::RemoveAllCutLines()
|
||||
{
|
||||
mCutLines.clear();
|
||||
}
|
||||
|
||||
void WaveClip::OffsetCutLines(double t0, double len)
|
||||
{
|
||||
for (const auto &cutLine : mCutLines)
|
||||
@ -1799,6 +1816,9 @@ void WaveClip::SetRate(int rate)
|
||||
|
||||
bool WaveClip::Resample(int rate, ProgressDialog *progress)
|
||||
{
|
||||
// Note: it is not necessary to do this recursively to cutlines.
|
||||
// They get resampled as needed when they are expanded.
|
||||
|
||||
if (rate == mRate)
|
||||
return true; // Nothing to do
|
||||
|
||||
|
@ -215,7 +215,15 @@ public:
|
||||
// essentially a copy constructor - but you must pass in the
|
||||
// current project's DirManager, because we might be copying
|
||||
// from one project to another
|
||||
WaveClip(const WaveClip& orig, const std::shared_ptr<DirManager> &projDirManager);
|
||||
WaveClip(const WaveClip& orig,
|
||||
const std::shared_ptr<DirManager> &projDirManager,
|
||||
bool copyCutlines);
|
||||
|
||||
// Copy only a range from the given WaveClip
|
||||
WaveClip(const WaveClip& orig,
|
||||
const std::shared_ptr<DirManager> &projDirManager,
|
||||
bool copyCutlines,
|
||||
double t0, double t1);
|
||||
|
||||
virtual ~WaveClip();
|
||||
|
||||
@ -266,9 +274,6 @@ public:
|
||||
* has changed, like when member functions SetSamples() etc. are called. */
|
||||
void MarkChanged() { mDirty++; }
|
||||
|
||||
/// Create clip from copy, discarding previous information in the clip
|
||||
bool CreateFromCopy(double t0, double t1, const WaveClip* other);
|
||||
|
||||
/** Getting high-level data from the for screen display and clipping
|
||||
* calculations and Contrast */
|
||||
bool GetWaveDisplay(WaveDisplay &display,
|
||||
@ -339,7 +344,6 @@ public:
|
||||
|
||||
/// Remove cut line, without expanding the audio in it
|
||||
bool RemoveCutLine(double cutLinePosition);
|
||||
void RemoveAllCutLines();
|
||||
|
||||
/// Offset cutlines right to time 't0' by time amount 'len'
|
||||
void OffsetCutLines(double t0, double len);
|
||||
@ -367,35 +371,35 @@ public:
|
||||
XMLTagHandler *HandleXMLChild(const wxChar *tag) override;
|
||||
void WriteXML(XMLWriter &xmlFile) const /* not override */;
|
||||
|
||||
// Cache of values to colour pixels of Spectrogram - used by TrackArtist
|
||||
mutable std::unique_ptr<SpecPxCache> mSpecPxCache;
|
||||
|
||||
// AWD, Oct 2009: for pasting whitespace at the end of selection
|
||||
bool GetIsPlaceholder() const { return mIsPlaceholder; }
|
||||
void SetIsPlaceholder(bool val) { mIsPlaceholder = val; }
|
||||
|
||||
protected:
|
||||
mutable wxRect mDisplayRect;
|
||||
public:
|
||||
// Cache of values to colour pixels of Spectrogram - used by TrackArtist
|
||||
mutable std::unique_ptr<SpecPxCache> mSpecPxCache;
|
||||
|
||||
double mOffset;
|
||||
protected:
|
||||
mutable wxRect mDisplayRect {};
|
||||
|
||||
double mOffset { 0 };
|
||||
int mRate;
|
||||
int mDirty;
|
||||
bool mIsCutLine;
|
||||
int mDirty { 0 };
|
||||
std::unique_ptr<Sequence> mSequence;
|
||||
std::unique_ptr<Envelope> mEnvelope;
|
||||
|
||||
mutable std::unique_ptr<WaveCache> mWaveCache;
|
||||
mutable ODLock mWaveCacheMutex;
|
||||
mutable ODLock mWaveCacheMutex {};
|
||||
mutable std::unique_ptr<SpecCache> mSpecCache;
|
||||
SampleBuffer mAppendBuffer;
|
||||
size_t mAppendBufferLen;
|
||||
SampleBuffer mAppendBuffer {};
|
||||
size_t mAppendBufferLen { 0 };
|
||||
|
||||
// Cut Lines are nothing more than ordinary wave clips, with the
|
||||
// offset relative to the start of the clip.
|
||||
WaveClipHolders mCutLines;
|
||||
WaveClipHolders mCutLines {};
|
||||
|
||||
// AWD, Oct. 2009: for whitespace-at-end-of-selection pasting
|
||||
bool mIsPlaceholder;
|
||||
bool mIsPlaceholder { false };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -132,7 +132,8 @@ WaveTrack::WaveTrack(const WaveTrack &orig):
|
||||
Init(orig);
|
||||
|
||||
for (const auto &clip : orig.mClips)
|
||||
mClips.push_back(make_movable<WaveClip>(*clip, mDirManager));
|
||||
mClips.push_back
|
||||
( make_movable<WaveClip>( *clip, mDirManager, true ) );
|
||||
}
|
||||
|
||||
// Copy the track metadata but not the contents.
|
||||
@ -630,7 +631,7 @@ bool WaveTrack::Trim (double t0, double t1)
|
||||
|
||||
|
||||
|
||||
Track::Holder WaveTrack::Copy(double t0, double t1) const
|
||||
Track::Holder WaveTrack::Copy(double t0, double t1, bool forClipboard) const
|
||||
{
|
||||
if (t1 <= t0)
|
||||
return{};
|
||||
@ -641,6 +642,10 @@ Track::Holder WaveTrack::Copy(double t0, double t1) const
|
||||
|
||||
newTrack->Init(*this);
|
||||
|
||||
// PRL: Why shouldn't cutlines be copied and pasted too? I don't know, but
|
||||
// that was the old behavior. But this function is also used by the
|
||||
// Duplicate command and I changed its behavior in that case.
|
||||
|
||||
for (const auto &clip : mClips)
|
||||
{
|
||||
if (t0 <= clip->GetStartTime() && t1 >= clip->GetEndTime())
|
||||
@ -649,25 +654,20 @@ Track::Holder WaveTrack::Copy(double t0, double t1) const
|
||||
//printf("copy: clip %i is in copy region\n", (int)clip);
|
||||
|
||||
newTrack->mClips.push_back
|
||||
(make_movable<WaveClip>(*clip, mDirManager));
|
||||
(make_movable<WaveClip>(*clip, mDirManager, ! forClipboard));
|
||||
WaveClip *const newClip = newTrack->mClips.back().get();
|
||||
newClip->RemoveAllCutLines();
|
||||
newClip->Offset(-t0);
|
||||
}
|
||||
else
|
||||
if (t1 > clip->GetStartTime() && t0 < clip->GetEndTime())
|
||||
else if (t1 > clip->GetStartTime() && t0 < clip->GetEndTime())
|
||||
{
|
||||
// Clip is affected by command
|
||||
//printf("copy: clip %i is affected by command\n", (int)clip);
|
||||
|
||||
auto newClip = make_movable<WaveClip>(*clip, mDirManager);
|
||||
newClip->RemoveAllCutLines();
|
||||
double clip_t0 = t0;
|
||||
double clip_t1 = t1;
|
||||
if (clip_t0 < clip->GetStartTime())
|
||||
clip_t0 = clip->GetStartTime();
|
||||
if (clip_t1 > clip->GetEndTime())
|
||||
clip_t1 = clip->GetEndTime();
|
||||
const double clip_t0 = std::max(t0, clip->GetStartTime());
|
||||
const double clip_t1 = std::min(t1, clip->GetEndTime());
|
||||
|
||||
auto newClip = make_movable<WaveClip>
|
||||
(*clip, mDirManager, ! forClipboard, clip_t0, clip_t1);
|
||||
|
||||
//printf("copy: clip_t0=%f, clip_t1=%f\n", clip_t0, clip_t1);
|
||||
|
||||
@ -675,27 +675,16 @@ Track::Holder WaveTrack::Copy(double t0, double t1) const
|
||||
if (newClip->GetOffset() < 0)
|
||||
newClip->SetOffset(0);
|
||||
|
||||
//printf("copy: clip offset is now %f\n", newClip->GetOffset());
|
||||
|
||||
if (!newClip->CreateFromCopy(clip_t0, clip_t1, clip.get()))
|
||||
{
|
||||
//printf("paste: CreateFromCopy(%f, %f, %i) returns false, quitting\n",
|
||||
// clip_t0, clip_t1, (int)clip);
|
||||
// JKC: July 2007, previously we did 'return false' here which
|
||||
// could leave *dest undefined.
|
||||
// I think this is dealing with clips that don't have any sequence content
|
||||
// i.e. we don't copy cut lines and such - anyone like to explain more?
|
||||
}
|
||||
else
|
||||
{
|
||||
newTrack->mClips.push_back(std::move(newClip)); // transfer ownership
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AWD, Oct 2009: If the selection ends in whitespace, create a placeholder
|
||||
// clip representing that whitespace
|
||||
if (newTrack->GetEndTime() + 1.0 / newTrack->GetRate() < t1 - t0)
|
||||
// PRL: Only if we want the track for pasting into other tracks. Not if it
|
||||
// goes directly into a project as in the Duplicate command.
|
||||
if (forClipboard &&
|
||||
newTrack->GetEndTime() + 1.0 / newTrack->GetRate() < t1 - t0)
|
||||
{
|
||||
auto placeholder = make_movable<WaveClip>(mDirManager,
|
||||
newTrack->GetSampleFormat(),
|
||||
@ -1069,7 +1058,8 @@ bool WaveTrack::HandleClear(double t0, double t1,
|
||||
{
|
||||
if (!clip->ClearAndAddCutLine(t0,t1))
|
||||
return false;
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
if (split) {
|
||||
// Three cases:
|
||||
@ -1088,11 +1078,13 @@ bool WaveTrack::HandleClear(double t0, double t1,
|
||||
// NEW clips out of the left and right halves...
|
||||
|
||||
// left
|
||||
clipsToAdd.push_back(make_movable<WaveClip>(*clip, mDirManager));
|
||||
clipsToAdd.push_back
|
||||
( make_movable<WaveClip>( *clip, mDirManager, true ) );
|
||||
clipsToAdd.back()->Clear(t0, clip->GetEndTime());
|
||||
|
||||
// right
|
||||
clipsToAdd.push_back(make_movable<WaveClip>(*clip, mDirManager));
|
||||
clipsToAdd.push_back
|
||||
( make_movable<WaveClip>( *clip, mDirManager, true ) );
|
||||
WaveClip *const right = clipsToAdd.back().get();
|
||||
right->Clear(clip->GetStartTime(), t1);
|
||||
right->Offset(t1 - clip->GetStartTime());
|
||||
@ -1349,7 +1341,8 @@ bool WaveTrack::Paste(double t0, const Track *src)
|
||||
// AWD Oct. 2009: Don't actually paste in placeholder clips
|
||||
if (!clip->GetIsPlaceholder())
|
||||
{
|
||||
auto newClip = make_movable<WaveClip>(*clip, mDirManager);
|
||||
auto newClip =
|
||||
make_movable<WaveClip>( *clip, mDirManager, true );
|
||||
newClip->Resample(mRate);
|
||||
newClip->Offset(t0);
|
||||
newClip->MarkChanged();
|
||||
@ -2377,7 +2370,7 @@ bool WaveTrack::SplitAt(double t)
|
||||
if(t - 1.0/c->GetRate() >= c->GetOffset())
|
||||
c->GetEnvelope()->Insert(t - c->GetOffset() - 1.0/c->GetRate(), val); // frame end points
|
||||
c->GetEnvelope()->Insert(t - c->GetOffset(), val);
|
||||
auto newClip = make_movable<WaveClip>(*c, mDirManager);
|
||||
auto newClip = make_movable<WaveClip>( *c, mDirManager, true );
|
||||
if (!c->Clear(t, c->GetEndTime()))
|
||||
{
|
||||
return false;
|
||||
|
@ -167,8 +167,14 @@ class AUDACITY_DLL_API WaveTrack final : public Track {
|
||||
//
|
||||
|
||||
Track::Holder Cut(double t0, double t1) override;
|
||||
Track::Holder Copy(double t0, double t1) const override;
|
||||
|
||||
// If forClipboard is true,
|
||||
// and there is no clip at the end time of the selection, then the result
|
||||
// will contain a "placeholder" clip whose only purpose is to make
|
||||
// GetEndTime() correct. This clip is not re-copied when pasting.
|
||||
Track::Holder Copy(double t0, double t1, bool forClipboard = true) const override;
|
||||
Track::Holder CopyNonconst(double t0, double t1) /* not override */;
|
||||
|
||||
bool Clear(double t0, double t1) override;
|
||||
bool Paste(double t0, const Track *src) override;
|
||||
bool ClearAndPaste(double t0, double t1,
|
||||
|
Loading…
x
Reference in New Issue
Block a user