mirror of
https://github.com/cookiengineer/audacity
synced 2025-07-02 17:23:18 +02:00
Document guarantees of now void-returning WaveTrack, WaveClip methods
This commit is contained in:
commit
e633dc0c8b
@ -2449,8 +2449,20 @@ void AudioIO::StopStream()
|
||||
// Stop those exceptions here, or else they propagate through too
|
||||
// many parts of Audacity that are not effects or editing
|
||||
// operations. GuardedCall ensures that the user sees a warning.
|
||||
|
||||
// Also be sure to Flush each track, at the top of the guarded call,
|
||||
// relying on the guarantee that the track will be left in a flushed
|
||||
// state, though the append buffer may be lost.
|
||||
|
||||
// If the other track operations fail their strong guarantees, then
|
||||
// the shift for latency correction may be skipped.
|
||||
GuardedCall<void>( [&] {
|
||||
WaveTrack* track = mCaptureTracks[i];
|
||||
|
||||
// use NOFAIL-GUARANTEE that track is flushed,
|
||||
// PARTIAL-GUARANTEE that some initial length of the recording
|
||||
// is saved.
|
||||
// See comments in FillBuffers().
|
||||
track->Flush();
|
||||
|
||||
if (mPlaybackTracks.size() > 0)
|
||||
@ -2475,12 +2487,15 @@ void AudioIO::StopStream()
|
||||
if( appendRecord )
|
||||
{ // append-recording
|
||||
if (recordingOffset < 0)
|
||||
// use STRONG-GUARANTEE
|
||||
track->Clear(mT0, mT0 - recordingOffset); // cut the latency out
|
||||
else
|
||||
// use STRONG-GUARANTEE
|
||||
track->InsertSilence(mT0, recordingOffset); // put silence in
|
||||
}
|
||||
else
|
||||
{ // recording into a NEW track
|
||||
// gives NOFAIL-GUARANTEE though we only need STRONG
|
||||
track->SetOffset(track->GetStartTime() + recordingOffset);
|
||||
if(track->GetEndTime() < 0.)
|
||||
{
|
||||
@ -2488,6 +2503,7 @@ void AudioIO::StopStream()
|
||||
"Latency Correction setting has caused the recorded audio to be hidden before zero.\nAudacity has brought it back to start at zero.\nYou may have to use the Time Shift Tool (<---> or F5) to drag the track to the right place."),
|
||||
_("Latency problem"), wxOK);
|
||||
m.ShowModal();
|
||||
// gives NOFAIL-GUARANTEE though we only need STRONG
|
||||
track->SetOffset(0.);
|
||||
}
|
||||
}
|
||||
|
@ -599,6 +599,7 @@ bool EnvelopeEditor::MouseEvent(const wxMouseEvent & event, wxRect & r,
|
||||
}
|
||||
|
||||
void Envelope::CollapseRegion(double t0, double t1)
|
||||
// NOFAIL-GUARANTEE
|
||||
{
|
||||
// This gets called when somebody clears samples. All of the
|
||||
// control points within the region disappear and the points
|
||||
@ -635,6 +636,7 @@ void Envelope::CollapseRegion(double t0, double t1)
|
||||
// envelope point applies one-past the last actual sample.
|
||||
// Rather than going to a .5-offset-index, we special case the framing.
|
||||
void Envelope::Paste(double t0, const Envelope *e)
|
||||
// NOFAIL-GUARANTEE
|
||||
{
|
||||
const bool wasEmpty = (this->mEnv.size() == 0);
|
||||
|
||||
@ -828,6 +830,7 @@ Old analysis of cases:
|
||||
// 'Unneeded' means that the envelope doesn't change by more than
|
||||
// 'tolerence' without the point being there.
|
||||
void Envelope::RemoveUnneededPoints(double time, double tolerence)
|
||||
// NOFAIL-GUARANTEE
|
||||
{
|
||||
unsigned int len = mEnv.size();
|
||||
unsigned int i;
|
||||
@ -864,6 +867,7 @@ void Envelope::RemoveUnneededPoints(double time, double tolerence)
|
||||
}
|
||||
|
||||
void Envelope::InsertSpace(double t0, double tlen)
|
||||
// NOFAIL-GUARANTEE
|
||||
{
|
||||
unsigned int len = mEnv.size();
|
||||
unsigned int i;
|
||||
@ -997,6 +1001,7 @@ int Envelope::Insert(double when, double value)
|
||||
// Control
|
||||
|
||||
void Envelope::SetOffset(double newOffset)
|
||||
// NOFAIL-GUARANTEE
|
||||
{
|
||||
mOffset = newOffset;
|
||||
}
|
||||
|
138
src/WaveClip.cpp
138
src/WaveClip.cpp
@ -345,6 +345,7 @@ WaveClip::WaveClip(const WaveClip& orig,
|
||||
mIsPlaceholder = orig.GetIsPlaceholder();
|
||||
}
|
||||
|
||||
// to do
|
||||
WaveClip::WaveClip(const WaveClip& orig,
|
||||
const std::shared_ptr<DirManager> &projDirManager,
|
||||
bool copyCutlines,
|
||||
@ -395,6 +396,7 @@ WaveClip::~WaveClip()
|
||||
}
|
||||
|
||||
void WaveClip::SetOffset(double offset)
|
||||
// NOFAIL-GUARANTEE
|
||||
{
|
||||
mOffset = offset;
|
||||
mEnvelope->SetOffset(mOffset);
|
||||
@ -406,12 +408,15 @@ bool WaveClip::GetSamples(samplePtr buffer, sampleFormat format,
|
||||
return mSequence->Get(buffer, format, start, len, mayThrow);
|
||||
}
|
||||
|
||||
bool WaveClip::SetSamples(samplePtr buffer, sampleFormat format,
|
||||
void WaveClip::SetSamples(samplePtr buffer, sampleFormat format,
|
||||
sampleCount start, size_t len)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
bool bResult = mSequence->Set(buffer, format, start, len);
|
||||
// use STRONG-GUARANTEE
|
||||
mSequence->Set(buffer, format, start, len);
|
||||
|
||||
// use NOFAIL-GUARANTEE
|
||||
MarkChanged();
|
||||
return bResult;
|
||||
}
|
||||
|
||||
BlockArray* WaveClip::GetSequenceBlockArray()
|
||||
@ -1345,6 +1350,7 @@ void WaveClip::ConvertToSampleFormat(sampleFormat format)
|
||||
}
|
||||
|
||||
void WaveClip::UpdateEnvelopeTrackLen()
|
||||
// NOFAIL-GUARANTEE
|
||||
{
|
||||
mEnvelope->SetTrackLen((mSequence->GetNumSamples().as_double()) / mRate);
|
||||
}
|
||||
@ -1375,9 +1381,12 @@ void WaveClip::GetDisplayRect(wxRect* r)
|
||||
*r = mDisplayRect;
|
||||
}
|
||||
|
||||
bool WaveClip::Append(samplePtr buffer, sampleFormat format,
|
||||
void WaveClip::Append(samplePtr buffer, sampleFormat format,
|
||||
size_t len, unsigned int stride /* = 1 */,
|
||||
XMLWriter* blockFileLog /*=NULL*/)
|
||||
// PARTIAL-GUARANTEE in case of exceptions:
|
||||
// Some prefix (maybe none) of the buffer is appended, and no content already
|
||||
// flushed to disk is lost.
|
||||
{
|
||||
//wxLogDebug(wxT("Append: len=%lli"), (long long) len);
|
||||
|
||||
@ -1388,13 +1397,23 @@ bool WaveClip::Append(samplePtr buffer, sampleFormat format,
|
||||
if (!mAppendBuffer.ptr())
|
||||
mAppendBuffer.Allocate(maxBlockSize, seqFormat);
|
||||
|
||||
auto cleanup = finally( [&] {
|
||||
// use NOFAIL-GUARANTEE
|
||||
UpdateEnvelopeTrackLen();
|
||||
MarkChanged();
|
||||
} );
|
||||
|
||||
for(;;) {
|
||||
if (mAppendBufferLen >= blockSize) {
|
||||
bool success =
|
||||
// flush some previously appended contents
|
||||
// use STRONG-GUARANTEE
|
||||
mSequence->Append(mAppendBuffer.ptr(), seqFormat, blockSize,
|
||||
blockFileLog);
|
||||
if (!success)
|
||||
return false;
|
||||
return;
|
||||
|
||||
// use NOFAIL-GUARANTEE for rest of this "if"
|
||||
memmove(mAppendBuffer.ptr(),
|
||||
mAppendBuffer.ptr() + blockSize * SAMPLE_SIZE(seqFormat),
|
||||
(mAppendBufferLen - blockSize) * SAMPLE_SIZE(seqFormat));
|
||||
@ -1405,6 +1424,7 @@ bool WaveClip::Append(samplePtr buffer, sampleFormat format,
|
||||
if (len == 0)
|
||||
break;
|
||||
|
||||
// use NOFAIL-GUARANTEE for rest of this "for"
|
||||
wxASSERT(mAppendBufferLen <= maxBlockSize);
|
||||
auto toCopy = std::min(len, maxBlockSize - mAppendBufferLen);
|
||||
|
||||
@ -1419,38 +1439,43 @@ bool WaveClip::Append(samplePtr buffer, sampleFormat format,
|
||||
buffer += toCopy * SAMPLE_SIZE(format) * stride;
|
||||
len -= toCopy;
|
||||
}
|
||||
|
||||
UpdateEnvelopeTrackLen();
|
||||
MarkChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WaveClip::AppendAlias(const wxString &fName, sampleCount start,
|
||||
void WaveClip::AppendAlias(const wxString &fName, sampleCount start,
|
||||
size_t len, int channel,bool useOD)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
// use STRONG-GUARANTEE
|
||||
bool result = mSequence->AppendAlias(fName, start, len, channel,useOD);
|
||||
|
||||
// use NOFAIL-GUARANTEE
|
||||
if (result)
|
||||
{
|
||||
UpdateEnvelopeTrackLen();
|
||||
MarkChanged();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WaveClip::AppendCoded(const wxString &fName, sampleCount start,
|
||||
void WaveClip::AppendCoded(const wxString &fName, sampleCount start,
|
||||
size_t len, int channel, int decodeType)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
// use STRONG-GUARANTEE
|
||||
bool result = mSequence->AppendCoded(fName, start, len, channel, decodeType);
|
||||
if (result)
|
||||
|
||||
// use NOFAIL-GUARANTEE
|
||||
if (result)
|
||||
{
|
||||
UpdateEnvelopeTrackLen();
|
||||
MarkChanged();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WaveClip::Flush()
|
||||
// NOFAIL-GUARANTEE that the clip will be in a flushed state.
|
||||
// PARTIAL-GUARANTEE in case of exceptions:
|
||||
// Some initial portion (maybe none) of the append buffer of the
|
||||
// clip gets appended; no previously flushed contents are lost.
|
||||
{
|
||||
//wxLogDebug(wxT("WaveClip::Flush"));
|
||||
//wxLogDebug(wxT(" mAppendBufferLen=%lli"), (long long) mAppendBufferLen);
|
||||
@ -1458,12 +1483,18 @@ bool WaveClip::Flush()
|
||||
|
||||
bool success = true;
|
||||
if (mAppendBufferLen > 0) {
|
||||
success = mSequence->Append(mAppendBuffer.ptr(), mSequence->GetSampleFormat(), mAppendBufferLen);
|
||||
if (success) {
|
||||
|
||||
auto cleanup = finally( [&] {
|
||||
// Blow away the append buffer even in case of failure. May lose some
|
||||
// data but don't leave the track in an un-flushed state.
|
||||
|
||||
// Use NOFAIL-GUARANTEE of these steps.
|
||||
mAppendBufferLen = 0;
|
||||
UpdateEnvelopeTrackLen();
|
||||
MarkChanged();
|
||||
}
|
||||
} );
|
||||
|
||||
success = mSequence->Append(mAppendBuffer.ptr(), mSequence->GetSampleFormat(), mAppendBufferLen);
|
||||
}
|
||||
|
||||
//wxLogDebug(wxT("now sample count %lli"), (long long) mSequence->GetNumSamples());
|
||||
@ -1538,7 +1569,7 @@ void WaveClip::WriteXML(XMLWriter &xmlFile) const
|
||||
xmlFile.EndTag(wxT("waveclip"));
|
||||
}
|
||||
|
||||
bool WaveClip::Paste(double t0, const WaveClip* other)
|
||||
void WaveClip::Paste(double t0, const WaveClip* other)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
const bool clipNeedsResampling = other->mRate != mRate;
|
||||
@ -1553,8 +1584,7 @@ bool WaveClip::Paste(double t0, const WaveClip* other)
|
||||
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))
|
||||
return false;
|
||||
newClip->Resample(mRate);
|
||||
if (clipNeedsNewFormat)
|
||||
// Force sample formats to match.
|
||||
newClip->ConvertToSampleFormat(mSequence->GetSampleFormat());
|
||||
@ -1582,8 +1612,6 @@ bool WaveClip::Paste(double t0, const WaveClip* other)
|
||||
sampleCount s0;
|
||||
TimeToSamplesClip(t0, &s0);
|
||||
|
||||
bool result = false;
|
||||
|
||||
// Assume STRONG-GUARANTEE from Sequence::Paste
|
||||
if (mSequence->Paste(s0, pastedClip->mSequence.get()))
|
||||
{
|
||||
@ -1596,38 +1624,40 @@ bool WaveClip::Paste(double t0, const WaveClip* other)
|
||||
for (auto &holder : newCutlines)
|
||||
mCutLines.push_back(std::move(holder));
|
||||
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WaveClip::InsertSilence(double t, double len)
|
||||
void WaveClip::InsertSilence(double t, double len)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
sampleCount s0;
|
||||
TimeToSamplesClip(t, &s0);
|
||||
auto slen = (sampleCount)floor(len * mRate + 0.5);
|
||||
|
||||
// use STRONG-GUARANTEE
|
||||
if (!GetSequence()->InsertSilence(s0, slen))
|
||||
{
|
||||
wxASSERT(false);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
// use NOFAIL-GUARANTEE
|
||||
OffsetCutLines(t, len);
|
||||
GetEnvelope()->InsertSpace(t, len);
|
||||
MarkChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WaveClip::Clear(double t0, double t1)
|
||||
void WaveClip::Clear(double t0, double t1)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
sampleCount s0, s1;
|
||||
|
||||
TimeToSamplesClip(t0, &s0);
|
||||
TimeToSamplesClip(t1, &s1);
|
||||
|
||||
// use STRONG-GUARANTEE
|
||||
if (GetSequence()->Delete(s0, s1-s0))
|
||||
// use NOFAIL-GUARANTEE in the remaining
|
||||
{
|
||||
// msmeyer
|
||||
//
|
||||
@ -1674,24 +1704,24 @@ bool WaveClip::Clear(double t0, double t1)
|
||||
Offset(-(GetStartTime() - t0));
|
||||
|
||||
MarkChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WaveClip::ClearAndAddCutLine(double t0, double t1)
|
||||
void WaveClip::ClearAndAddCutLine(double t0, double t1)
|
||||
// WEAK-GUARANTEE
|
||||
// this WaveClip remains destructible in case of AudacityException.
|
||||
// But some cutlines may be deleted
|
||||
{
|
||||
if (t0 > GetEndTime() || t1 < GetStartTime())
|
||||
return true; // time out of bounds
|
||||
return; // time out of bounds
|
||||
|
||||
const double clip_t0 = std::max( t0, GetStartTime() );
|
||||
const double clip_t1 = std::min( t1, GetEndTime() );
|
||||
|
||||
auto newClip = make_movable<WaveClip>
|
||||
auto newClip = make_movable< WaveClip >
|
||||
(*this, mSequence->GetDirManager(), true, clip_t0, clip_t1);
|
||||
|
||||
newClip->SetOffset(clip_t0-mOffset);
|
||||
newClip->SetOffset( clip_t0 - mOffset );
|
||||
|
||||
// Remove cutlines from this clip that were in the selection, shift
|
||||
// left those that were after the selection
|
||||
@ -1718,6 +1748,7 @@ bool WaveClip::ClearAndAddCutLine(double t0, double t1)
|
||||
TimeToSamplesClip(t0, &s0);
|
||||
TimeToSamplesClip(t1, &s1);
|
||||
|
||||
// use WEAK-GUARANTEE
|
||||
if (GetSequence()->Delete(s0, s1-s0))
|
||||
{
|
||||
// Collapse envelope
|
||||
@ -1728,10 +1759,7 @@ bool WaveClip::ClearAndAddCutLine(double t0, double t1)
|
||||
MarkChanged();
|
||||
|
||||
mCutLines.push_back(std::move(newClip));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WaveClip::FindCutLine(double cutLinePosition,
|
||||
@ -1753,7 +1781,7 @@ bool WaveClip::FindCutLine(double cutLinePosition,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WaveClip::ExpandCutLine(double cutLinePosition)
|
||||
void WaveClip::ExpandCutLine(double cutLinePosition)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
auto end = mCutLines.end();
|
||||
@ -1765,8 +1793,7 @@ bool WaveClip::ExpandCutLine(double cutLinePosition)
|
||||
if ( it != end ) {
|
||||
auto cutline = it->get();
|
||||
// assume STRONG-GUARANTEE from Paste
|
||||
if (!Paste(mOffset+cutline->GetOffset(), cutline))
|
||||
return false;
|
||||
Paste(mOffset+cutline->GetOffset(), cutline);
|
||||
// Now erase the cutline,
|
||||
// but be careful to find it again, because Paste above may
|
||||
// have modified the array of cutlines (if our cutline contained
|
||||
@ -1780,10 +1807,7 @@ bool WaveClip::ExpandCutLine(double cutLinePosition)
|
||||
// THROW_INCONSISTENCY_EXCEPTION;
|
||||
wxASSERT(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WaveClip::RemoveCutLine(double cutLinePosition)
|
||||
@ -1839,13 +1863,14 @@ void WaveClip::SetRate(int rate)
|
||||
MarkChanged();
|
||||
}
|
||||
|
||||
bool WaveClip::Resample(int rate, ProgressDialog *progress)
|
||||
void WaveClip::Resample(int rate, ProgressDialog *progress)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
// 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
|
||||
return; // Nothing to do
|
||||
|
||||
double factor = (double)rate / (double)mRate;
|
||||
::Resample resample(true, factor, factor); // constant rate resampling
|
||||
@ -1905,22 +1930,23 @@ bool WaveClip::Resample(int rate, ProgressDialog *progress)
|
||||
);
|
||||
error = (updateResult != ProgressResult::Success);
|
||||
if (error)
|
||||
{
|
||||
break;
|
||||
}
|
||||
//throw UserException{};
|
||||
}
|
||||
}
|
||||
|
||||
if (!error)
|
||||
if (error)
|
||||
;
|
||||
else
|
||||
{
|
||||
mSequence = std::move(newSequence);
|
||||
mRate = rate;
|
||||
// Use NOFAIL-GUARANTEE in these steps
|
||||
|
||||
// Invalidate wave display cache
|
||||
mWaveCache = std::make_unique<WaveCache>();
|
||||
// Invalidate the spectrum display cache
|
||||
mSpecCache = std::make_unique<SpecCache>();
|
||||
}
|
||||
|
||||
return !error;
|
||||
mSequence = std::move(newSequence);
|
||||
mRate = rate;
|
||||
}
|
||||
}
|
||||
|
@ -233,11 +233,12 @@ public:
|
||||
|
||||
// Resample clip. This also will set the rate, but without changing
|
||||
// the length of the clip
|
||||
bool Resample(int rate, ProgressDialog *progress = NULL);
|
||||
void Resample(int rate, ProgressDialog *progress = NULL);
|
||||
|
||||
void SetOffset(double offset);
|
||||
double GetOffset() const { return mOffset; }
|
||||
void Offset(double delta) { SetOffset(GetOffset() + delta); }
|
||||
void Offset(double delta) // NOFAIL-GUARANTEE
|
||||
{ SetOffset(GetOffset() + delta); }
|
||||
double GetStartTime() const;
|
||||
double GetEndTime() const;
|
||||
sampleCount GetStartSample() const;
|
||||
@ -253,7 +254,7 @@ public:
|
||||
|
||||
bool GetSamples(samplePtr buffer, sampleFormat format,
|
||||
sampleCount start, size_t len, bool mayThrow = true) const;
|
||||
bool SetSamples(samplePtr buffer, sampleFormat format,
|
||||
void SetSamples(samplePtr buffer, sampleFormat format,
|
||||
sampleCount start, size_t len);
|
||||
|
||||
Envelope* GetEnvelope() { return mEnvelope.get(); }
|
||||
@ -268,7 +269,8 @@ public:
|
||||
/** WaveTrack calls this whenever data in the wave clip changes. It is
|
||||
* called automatically when WaveClip has a chance to know that something
|
||||
* has changed, like when member functions SetSamples() etc. are called. */
|
||||
void MarkChanged() { mDirty++; }
|
||||
void MarkChanged() // NOFAIL-GUARANTEE
|
||||
{ mDirty++; }
|
||||
|
||||
/** Getting high-level data from the for screen display and clipping
|
||||
* calculations and Contrast */
|
||||
@ -295,31 +297,31 @@ public:
|
||||
void UpdateEnvelopeTrackLen();
|
||||
|
||||
/// You must call Flush after the last Append
|
||||
bool Append(samplePtr buffer, sampleFormat format,
|
||||
void Append(samplePtr buffer, sampleFormat format,
|
||||
size_t len, unsigned int stride=1,
|
||||
XMLWriter* blockFileLog = NULL);
|
||||
/// Flush must be called after last Append
|
||||
bool Flush();
|
||||
|
||||
bool AppendAlias(const wxString &fName, sampleCount start,
|
||||
void AppendAlias(const wxString &fName, sampleCount start,
|
||||
size_t len, int channel,bool useOD);
|
||||
|
||||
bool AppendCoded(const wxString &fName, sampleCount start,
|
||||
void AppendCoded(const wxString &fName, sampleCount start,
|
||||
size_t len, int channel, int decodeType);
|
||||
|
||||
/// This name is consistent with WaveTrack::Clear. It performs a "Cut"
|
||||
/// operation (but without putting the cutted audio to the clipboard)
|
||||
bool Clear(double t0, double t1);
|
||||
void Clear(double t0, double t1);
|
||||
|
||||
/// Clear, and add cut line that starts at t0 and contains everything until t1.
|
||||
bool ClearAndAddCutLine(double t0, double t1);
|
||||
void ClearAndAddCutLine(double t0, double t1);
|
||||
|
||||
/// Paste data from other clip, resampling it if not equal rate
|
||||
bool Paste(double t0, const WaveClip* other);
|
||||
void Paste(double t0, const WaveClip* other);
|
||||
|
||||
/** Insert silence - note that this is an efficient operation for large
|
||||
* amounts of silence */
|
||||
bool InsertSilence(double t, double len);
|
||||
void InsertSilence(double t, double len);
|
||||
|
||||
/// Get access to cut lines list
|
||||
WaveClipHolders &GetCutLines() { return mCutLines; }
|
||||
@ -337,7 +339,7 @@ public:
|
||||
/** Expand cut line (that is, re-insert audio, then DELETE audio saved in
|
||||
* cut line). Returns true if a cut line could be found and sucessfully
|
||||
* expanded, false otherwise */
|
||||
bool ExpandCutLine(double cutLinePosition);
|
||||
void ExpandCutLine(double cutLinePosition);
|
||||
|
||||
/// Remove cut line, without expanding the audio in it
|
||||
bool RemoveCutLine(double cutLinePosition);
|
||||
|
@ -188,10 +188,12 @@ double WaveTrack::GetOffset() const
|
||||
}
|
||||
|
||||
void WaveTrack::SetOffset(double o)
|
||||
// NOFAIL-GUARANTEE
|
||||
{
|
||||
double delta = o - GetOffset();
|
||||
|
||||
for (const auto &clip : mClips)
|
||||
// assume NOFAIL-GUARANTEE
|
||||
clip->SetOffset(clip->GetOffset() + delta);
|
||||
|
||||
mOffset = o;
|
||||
@ -543,6 +545,7 @@ Track::Holder WaveTrack::Cut(double t0, double t1)
|
||||
}
|
||||
|
||||
Track::Holder WaveTrack::SplitCut(double t0, double t1)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
if (t1 < t0)
|
||||
//THROW_INCONSISTENCY_EXCEPTION
|
||||
@ -579,6 +582,7 @@ Track::Holder WaveTrack::CutAndAddCutLine(double t0, double t1)
|
||||
//Trim trims within a clip, rather than trimming everything.
|
||||
//If a bound is outside a clip, it trims everything.
|
||||
void WaveTrack::Trim (double t0, double t1)
|
||||
// WEAK-GUARANTEE
|
||||
{
|
||||
bool inside0 = false;
|
||||
bool inside1 = false;
|
||||
@ -596,15 +600,13 @@ void WaveTrack::Trim (double t0, double t1)
|
||||
|
||||
if(t1 > clip->GetStartTime() && t1 < clip->GetEndTime())
|
||||
{
|
||||
if (!clip->Clear(t1,clip->GetEndTime()))
|
||||
return;
|
||||
clip->Clear(t1,clip->GetEndTime());
|
||||
inside1 = true;
|
||||
}
|
||||
|
||||
if(t0 > clip->GetStartTime() && t0 < clip->GetEndTime())
|
||||
{
|
||||
if (!clip->Clear(clip->GetStartTime(),t0))
|
||||
return;
|
||||
clip->Clear(clip->GetStartTime(),t0);
|
||||
clip->SetOffset(t0);
|
||||
inside0 = true;
|
||||
}
|
||||
@ -682,15 +684,9 @@ Track::Holder WaveTrack::Copy(double t0, double t1, bool forClipboard) const
|
||||
newTrack->GetSampleFormat(),
|
||||
static_cast<int>(newTrack->GetRate()));
|
||||
placeholder->SetIsPlaceholder(true);
|
||||
if ( ! placeholder->InsertSilence(
|
||||
0, (t1 - t0) - newTrack->GetEndTime()) )
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
placeholder->Offset(newTrack->GetEndTime());
|
||||
newTrack->mClips.push_back(std::move(placeholder)); // transfer ownership
|
||||
}
|
||||
placeholder->InsertSilence(0, (t1 - t0) - newTrack->GetEndTime());
|
||||
placeholder->Offset(newTrack->GetEndTime());
|
||||
newTrack->mClips.push_back(std::move(placeholder)); // transfer ownership
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -702,11 +698,13 @@ Track::Holder WaveTrack::CopyNonconst(double t0, double t1)
|
||||
}
|
||||
|
||||
void WaveTrack::Clear(double t0, double t1)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
HandleClear(t0, t1, false, false);
|
||||
}
|
||||
|
||||
void WaveTrack::ClearAndAddCutLine(double t0, double t1)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
HandleClear(t0, t1, true, false);
|
||||
}
|
||||
@ -793,17 +791,22 @@ void WaveTrack::ClearAndPaste(double t0, // Start of time to clear
|
||||
bool merge, // Whether to remove 'extra' splits
|
||||
const TimeWarper *effectWarper // How does time change
|
||||
)
|
||||
// WEAK-GUARANTEE
|
||||
// this WaveTrack remains destructible in case of AudacityException.
|
||||
// But some of its cutline clips may have been destroyed.
|
||||
{
|
||||
double dur = wxMin(t1 - t0, src->GetEndTime());
|
||||
wxArrayDouble splits;
|
||||
WaveClipHolders cuts;
|
||||
double dur = std::min(t1 - t0, src->GetEndTime());
|
||||
|
||||
// If duration is 0, then it's just a plain paste
|
||||
if (dur == 0.0) {
|
||||
// use WEAK-GUARANTEE
|
||||
Paste(t0, src);
|
||||
return;
|
||||
}
|
||||
|
||||
wxArrayDouble splits;
|
||||
WaveClipHolders cuts;
|
||||
|
||||
// If provided time warper was NULL, use a default one that does nothing
|
||||
IdentityTimeWarper localWarper;
|
||||
const TimeWarper *warper = (effectWarper ? effectWarper : &localWarper);
|
||||
@ -883,60 +886,63 @@ void WaveTrack::ClearAndPaste(double t0, // Start of time to clear
|
||||
prev = clip;
|
||||
}
|
||||
}
|
||||
|
||||
// Refill the array since clips have changed.
|
||||
clips = SortedClipArray();
|
||||
|
||||
{
|
||||
// Scan the sorted clips to look for the start of the pasted
|
||||
// region.
|
||||
WaveClip *prev = nullptr;
|
||||
for (const auto clip : clips) {
|
||||
if (prev) {
|
||||
MergeClips(GetClipIndex(prev), GetClipIndex(clip));
|
||||
break;
|
||||
}
|
||||
if (fabs(t0 - clip->GetEndTime()) < tolerance)
|
||||
// Merge this clip and the next clip if the start time
|
||||
// falls within it and this isn't the last clip in the track.
|
||||
prev = clip;
|
||||
else
|
||||
prev = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore cut/split lines
|
||||
if (preserve) {
|
||||
// Refill the array since clips have changed.
|
||||
auto clips = SortedClipArray();
|
||||
|
||||
// Restore the split lines, transforming the position appropriately
|
||||
for (const auto split: splits) {
|
||||
SplitAt(warper->Warp(split));
|
||||
}
|
||||
|
||||
// Restore the saved cut lines, also transforming if time altered
|
||||
for (const auto &clip : mClips) {
|
||||
double st;
|
||||
double et;
|
||||
|
||||
st = clip->GetStartTime();
|
||||
et = clip->GetEndTime();
|
||||
|
||||
// Scan the cuts for any that live within this clip
|
||||
for (auto it = cuts.begin(); it != cuts.end();) {
|
||||
WaveClip *cut = it->get();
|
||||
double cs = cut->GetOffset();
|
||||
|
||||
// Offset the cut from the start of the clip and add it to
|
||||
// this clips cutlines.
|
||||
if (cs >= st && cs <= et) {
|
||||
cut->SetOffset(warper->Warp(cs) - st);
|
||||
clip->GetCutLines().push_back( std::move(*it) ); // transfer ownership!
|
||||
it = cuts.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
{
|
||||
// Scan the sorted clips to look for the start of the pasted
|
||||
// region.
|
||||
WaveClip *prev = nullptr;
|
||||
for (const auto clip : clips) {
|
||||
if (prev) {
|
||||
// It must be that clip is what was pasted and it begins where
|
||||
// prev ends.
|
||||
// use WEAK-GUARANTEE
|
||||
MergeClips(GetClipIndex(prev), GetClipIndex(clip));
|
||||
break;
|
||||
}
|
||||
if (fabs(t0 - clip->GetEndTime()) < tolerance)
|
||||
// Merge this clip and the next clip if the start time
|
||||
// falls within it and this isn't the last clip in the track.
|
||||
prev = clip;
|
||||
else
|
||||
prev = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore cut/split lines
|
||||
if (preserve) {
|
||||
|
||||
// Restore the split lines, transforming the position appropriately
|
||||
for (const auto split: splits) {
|
||||
SplitAt(warper->Warp(split));
|
||||
}
|
||||
|
||||
// Restore the saved cut lines, also transforming if time altered
|
||||
for (const auto &clip : mClips) {
|
||||
double st;
|
||||
double et;
|
||||
|
||||
st = clip->GetStartTime();
|
||||
et = clip->GetEndTime();
|
||||
|
||||
// Scan the cuts for any that live within this clip
|
||||
for (auto it = cuts.begin(); it != cuts.end();) {
|
||||
WaveClip *cut = it->get();
|
||||
double cs = cut->GetOffset();
|
||||
|
||||
// Offset the cut from the start of the clip and add it to
|
||||
// this clips cutlines.
|
||||
if (cs >= st && cs <= et) {
|
||||
cut->SetOffset(warper->Warp(cs) - st);
|
||||
clip->GetCutLines().push_back( std::move(*it) ); // transfer ownership!
|
||||
it = cuts.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -944,6 +950,7 @@ void WaveTrack::ClearAndPaste(double t0, // Start of time to clear
|
||||
}
|
||||
|
||||
void WaveTrack::SplitDelete(double t0, double t1)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
bool addCutLines = false;
|
||||
bool split = true;
|
||||
@ -1007,6 +1014,7 @@ void WaveTrack::AddClip(movable_ptr<WaveClip> &&clip)
|
||||
|
||||
void WaveTrack::HandleClear(double t0, double t1,
|
||||
bool addCutLines, bool split)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
if (t1 < t0)
|
||||
// THROW_INCONSISTENCY_EXCEPTION; // ?
|
||||
@ -1045,7 +1053,12 @@ void WaveTrack::HandleClear(double t0, double t1,
|
||||
// Clip data is affected by command
|
||||
if (addCutLines)
|
||||
{
|
||||
clip->ClearAndAddCutLine(t0,t1);
|
||||
// Don't modify this clip in place, because we want a strong
|
||||
// guarantee, and might modify another clip
|
||||
clipsToDelete.push_back( clip.get() );
|
||||
auto newClip = make_movable<WaveClip>( *clip, mDirManager, true );
|
||||
newClip->ClearAndAddCutLine( t0, t1 );
|
||||
clipsToAdd.push_back( std::move( newClip ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1054,14 +1067,28 @@ void WaveTrack::HandleClear(double t0, double t1,
|
||||
|
||||
if (clip->BeforeClip(t0)) {
|
||||
// Delete from the left edge
|
||||
clip->Clear(clip->GetStartTime(), t1);
|
||||
clip->Offset(t1-clip->GetStartTime());
|
||||
} else
|
||||
if (clip->AfterClip(t1)) {
|
||||
|
||||
// Don't modify this clip in place, because we want a strong
|
||||
// guarantee, and might modify another clip
|
||||
clipsToDelete.push_back( clip.get() );
|
||||
auto newClip = make_movable<WaveClip>( *clip, mDirManager, true );
|
||||
newClip->Clear(clip->GetStartTime(), t1);
|
||||
newClip->Offset(t1-clip->GetStartTime());
|
||||
|
||||
clipsToAdd.push_back( std::move( newClip ) );
|
||||
}
|
||||
else if (clip->AfterClip(t1)) {
|
||||
// Delete to right edge
|
||||
clip->Clear(t0, clip->GetEndTime());
|
||||
} else
|
||||
{
|
||||
|
||||
// Don't modify this clip in place, because we want a strong
|
||||
// guarantee, and might modify another clip
|
||||
clipsToDelete.push_back( clip.get() );
|
||||
auto newClip = make_movable<WaveClip>( *clip, mDirManager, true );
|
||||
newClip->Clear(t0, clip->GetEndTime());
|
||||
|
||||
clipsToAdd.push_back( std::move( newClip ) );
|
||||
}
|
||||
else {
|
||||
// Delete in the middle of the clip...we actually create two
|
||||
// NEW clips out of the left and right halves...
|
||||
|
||||
@ -1080,7 +1107,14 @@ void WaveTrack::HandleClear(double t0, double t1,
|
||||
clipsToDelete.push_back(clip.get());
|
||||
}
|
||||
}
|
||||
else { // (We are not doing a split cut)
|
||||
else {
|
||||
// (We are not doing a split cut)
|
||||
|
||||
// Don't modify this clip in place, because we want a strong
|
||||
// guarantee, and might modify another clip
|
||||
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
|
||||
@ -1090,23 +1124,31 @@ void WaveTrack::HandleClear(double t0, double t1,
|
||||
// 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
|
||||
if (clip->WithinClip(t0)) {
|
||||
// start of region within clip
|
||||
val = clip->GetEnvelope()->GetValue(t0);
|
||||
clip->GetEnvelope()->Insert(t0 - clip->GetOffset() - 1.0/clip->GetRate(), val);
|
||||
}
|
||||
if (clip->WithinClip(t1))
|
||||
{ // end of region within clip
|
||||
newClip->GetEnvelope()->Insert(t0 - clip->GetOffset() - 1.0/clip->GetRate(), val);
|
||||
}
|
||||
if (clip->WithinClip(t1)) {
|
||||
// end of region within clip
|
||||
val = clip->GetEnvelope()->GetValue(t1);
|
||||
clip->GetEnvelope()->Insert(t1 - clip->GetOffset(), val);
|
||||
}
|
||||
newClip->GetEnvelope()->Insert(t1 - clip->GetOffset(), val);
|
||||
}
|
||||
}
|
||||
if (!clip->Clear(t0,t1))
|
||||
return;
|
||||
clip->GetEnvelope()->RemoveUnneededPoints(t0);
|
||||
newClip->Clear(t0,t1);
|
||||
newClip->GetEnvelope()->RemoveUnneededPoints(t0);
|
||||
|
||||
clipsToAdd.push_back( std::move( newClip ) );
|
||||
}
|
||||
}
|
||||
} else
|
||||
}
|
||||
}
|
||||
|
||||
// Only now, change the contents of this track
|
||||
// use NOFAIL-GUARANTEE for the rest
|
||||
|
||||
for (const auto &clip : mClips)
|
||||
{
|
||||
if (clip->BeforeClip(t1))
|
||||
{
|
||||
// Clip is "behind" the region -- offset it unless we're splitting
|
||||
@ -1359,17 +1401,14 @@ void WaveTrack::Silence(double t0, double t1)
|
||||
startDelta = 0;
|
||||
}
|
||||
|
||||
if (!clip->GetSequence()->SetSilence(inclipDelta, samplesToCopy))
|
||||
{
|
||||
wxASSERT(false); // should always work
|
||||
return;
|
||||
}
|
||||
clip->GetSequence()->SetSilence(inclipDelta, samplesToCopy);
|
||||
clip->MarkChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WaveTrack::InsertSilence(double t, double len)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
if (len <= 0)
|
||||
// THROW_INCONSISTENCY_EXCEPTION; // ?
|
||||
@ -1378,20 +1417,27 @@ void WaveTrack::InsertSilence(double t, double len)
|
||||
if (mClips.empty())
|
||||
{
|
||||
// Special case if there is no clip yet
|
||||
WaveClip* clip = CreateClip();
|
||||
auto clip = make_movable<WaveClip>(mDirManager, mFormat, mRate);
|
||||
clip->InsertSilence(0, len);
|
||||
// use NOFAIL-GUARANTEE
|
||||
mClips.push_back( std::move( clip ) );
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// Assume at most one clip contains t
|
||||
const auto end = mClips.end();
|
||||
const auto it = std::find_if( mClips.begin(), end,
|
||||
[&](const WaveClipHolder &clip) { return clip->WithinClip(t); } );
|
||||
|
||||
for (const auto &clip : mClips)
|
||||
{
|
||||
if (clip->BeforeClip(t))
|
||||
clip->Offset(len);
|
||||
else if (clip->WithinClip(t))
|
||||
// use STRONG-GUARANTEE
|
||||
if (it != end)
|
||||
it->get()->InsertSilence(t, len);
|
||||
|
||||
// use NOFAIL-GUARANTEE
|
||||
for (const auto &clip : mClips)
|
||||
{
|
||||
if (!clip->InsertSilence(t, len)) {
|
||||
return;
|
||||
}
|
||||
if (clip->BeforeClip(t))
|
||||
clip->Offset(len);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1399,6 +1445,7 @@ void WaveTrack::InsertSilence(double t, double len)
|
||||
//Performs the opposite of Join
|
||||
//Analyses selected region for possible Joined clips and disjoins them
|
||||
void WaveTrack::Disjoin(double t0, double t1)
|
||||
// WEAK-GUARANTEE
|
||||
{
|
||||
auto minSamples = TimeToLongSamples( WAVETRACK_MERGE_POINT_TOLERANCE );
|
||||
const size_t maxAtOnce = 1048576;
|
||||
@ -1476,6 +1523,7 @@ void WaveTrack::Disjoin(double t0, double t1)
|
||||
}
|
||||
|
||||
void WaveTrack::Join(double t0, double t1)
|
||||
// WEAK-GUARANTEE
|
||||
{
|
||||
// Merge all WaveClips overlapping selection into one
|
||||
|
||||
@ -1517,9 +1565,7 @@ void WaveTrack::Join(double t0, double t1)
|
||||
}
|
||||
|
||||
//printf("Pasting at %.6f\n", t);
|
||||
bool bResult = newClip->Paste(t, clip);
|
||||
wxASSERT(bResult); // TO DO: Actually handle this.
|
||||
wxUnusedVar(bResult);
|
||||
newClip->Paste(t, clip);
|
||||
t = newClip->GetEndTime();
|
||||
|
||||
auto it = FindClip(mClips, clip);
|
||||
@ -1530,6 +1576,9 @@ void WaveTrack::Join(double t0, double t1)
|
||||
void WaveTrack::Append(samplePtr buffer, sampleFormat format,
|
||||
size_t len, unsigned int stride /* = 1 */,
|
||||
XMLWriter *blockFileLog /* = NULL */)
|
||||
// PARTIAL-GUARANTEE in case of exceptions:
|
||||
// Some prefix (maybe none) of the buffer is appended, and no content already
|
||||
// flushed to disk is lost.
|
||||
{
|
||||
RightmostOrNewClip()->Append(buffer, format, len, stride,
|
||||
blockFileLog);
|
||||
@ -1537,12 +1586,14 @@ void WaveTrack::Append(samplePtr buffer, sampleFormat format,
|
||||
|
||||
void WaveTrack::AppendAlias(const wxString &fName, sampleCount start,
|
||||
size_t len, int channel,bool useOD)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
RightmostOrNewClip()->AppendAlias(fName, start, len, channel, useOD);
|
||||
}
|
||||
|
||||
void WaveTrack::AppendCoded(const wxString &fName, sampleCount start,
|
||||
size_t len, int channel, int decodeType)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
RightmostOrNewClip()->AppendCoded(fName, start, len, channel, decodeType);
|
||||
}
|
||||
@ -1616,6 +1667,10 @@ size_t WaveTrack::GetIdealBlockSize()
|
||||
}
|
||||
|
||||
void WaveTrack::Flush()
|
||||
// NOFAIL-GUARANTEE that the rightmost clip will be in a flushed state.
|
||||
// PARTIAL-GUARANTEE in case of exceptions:
|
||||
// Some initial portion (maybe none) of the append buffer of the rightmost
|
||||
// clip gets appended; no previously saved contents are lost.
|
||||
{
|
||||
// After appending, presumably. Do this to the clip that gets appended.
|
||||
RightmostOrNewClip()->Flush();
|
||||
@ -2020,6 +2075,7 @@ bool WaveTrack::Get(samplePtr buffer, sampleFormat format,
|
||||
|
||||
void WaveTrack::Set(samplePtr buffer, sampleFormat format,
|
||||
sampleCount start, size_t len)
|
||||
// WEAK-GUARANTEE
|
||||
{
|
||||
for (const auto &clip: mClips)
|
||||
{
|
||||
@ -2050,15 +2106,11 @@ void WaveTrack::Set(samplePtr buffer, sampleFormat format,
|
||||
// samplesToCopy is positive and not more than len
|
||||
}
|
||||
|
||||
if (!clip->SetSamples(
|
||||
clip->SetSamples(
|
||||
(samplePtr)(((char*)buffer) +
|
||||
startDelta.as_size_t() *
|
||||
SAMPLE_SIZE(format)),
|
||||
format, inclipDelta, samplesToCopy.as_size_t() ))
|
||||
{
|
||||
wxASSERT(false); // should always work
|
||||
return;
|
||||
}
|
||||
format, inclipDelta, samplesToCopy.as_size_t() );
|
||||
clip->MarkChanged();
|
||||
}
|
||||
}
|
||||
@ -2191,6 +2243,7 @@ WaveClip* WaveTrack::NewestOrNewClip()
|
||||
}
|
||||
|
||||
WaveClip* WaveTrack::RightmostOrNewClip()
|
||||
// NOFAIL-GUARANTEE
|
||||
{
|
||||
if (mClips.empty()) {
|
||||
WaveClip *clip = CreateClip();
|
||||
@ -2297,6 +2350,7 @@ bool WaveTrack::CanInsertClip(WaveClip* clip)
|
||||
}
|
||||
|
||||
void WaveTrack::Split( double t0, double t1 )
|
||||
// WEAK-GUARANTEE
|
||||
{
|
||||
SplitAt( t0 );
|
||||
if( t0 != t1 )
|
||||
@ -2304,6 +2358,7 @@ void WaveTrack::Split( double t0, double t1 )
|
||||
}
|
||||
|
||||
void WaveTrack::SplitAt(double t)
|
||||
// WEAK-GUARANTEE
|
||||
{
|
||||
for (const auto &c : mClips)
|
||||
{
|
||||
@ -2318,14 +2373,8 @@ void WaveTrack::SplitAt(double t)
|
||||
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, true );
|
||||
if (!c->Clear(t, c->GetEndTime()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!newClip->Clear(c->GetStartTime(), t))
|
||||
{
|
||||
return;
|
||||
}
|
||||
c->Clear(t, c->GetEndTime());
|
||||
newClip->Clear(c->GetStartTime(), t);
|
||||
|
||||
//offset the NEW clip by the splitpoint (noting that it is already offset to c->GetStartTime())
|
||||
sampleCount here = llrint(floor(((t - c->GetStartTime()) * mRate) + 0.5));
|
||||
@ -2333,6 +2382,7 @@ void WaveTrack::SplitAt(double t)
|
||||
// This could invalidate the iterators for the loop! But we return
|
||||
// at once so it's okay
|
||||
mClips.push_back(std::move(newClip)); // transfer ownership
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2435,8 +2485,7 @@ void WaveTrack::ExpandCutLine(double cutLinePosition, double* cutlineStart,
|
||||
}
|
||||
}
|
||||
|
||||
if (!clip->ExpandCutLine(cutLinePosition))
|
||||
return;
|
||||
clip->ExpandCutLine(cutLinePosition);
|
||||
|
||||
// STRONG-GUARANTEE provided that the following gives NOFAIL-GUARANTEE
|
||||
|
||||
@ -2467,6 +2516,7 @@ bool WaveTrack::RemoveCutLine(double cutLinePosition)
|
||||
}
|
||||
|
||||
void WaveTrack::MergeClips(int clipidx1, int clipidx2)
|
||||
// STRONG-GUARANTEE
|
||||
{
|
||||
WaveClip* clip1 = GetClipByIndex(clipidx1);
|
||||
WaveClip* clip2 = GetClipByIndex(clipidx2);
|
||||
@ -2475,9 +2525,10 @@ void WaveTrack::MergeClips(int clipidx1, int clipidx2)
|
||||
return; // Don't throw, just do nothing.
|
||||
|
||||
// Append data from second clip to first clip
|
||||
if (!clip1->Paste(clip1->GetEndTime(), clip2))
|
||||
return;
|
||||
|
||||
// use STRONG-GUARANTEE
|
||||
clip1->Paste(clip1->GetEndTime(), clip2);
|
||||
|
||||
// use NOFAIL-GUARANTEE for the rest
|
||||
// Delete second clip
|
||||
auto it = FindClip(mClips, clip2);
|
||||
mClips.erase(it);
|
||||
@ -2488,13 +2539,7 @@ void WaveTrack::Resample(int rate, ProgressDialog *progress)
|
||||
// Partial completion may leave clips at differing sample rates!
|
||||
{
|
||||
for (const auto &clip : mClips)
|
||||
if (!clip->Resample(rate, progress))
|
||||
{
|
||||
wxLogDebug( wxT("Resampling problem! We're partially resampled") );
|
||||
// FIXME: The track is now in an inconsistent state since some
|
||||
// clips are resampled and some are not
|
||||
return;
|
||||
}
|
||||
clip->Resample(rate, progress);
|
||||
|
||||
mRate = rate;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user