mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-26 17:18:41 +02:00
More exception handling; incidentally implement TimeTrack copy/paste
This commit is contained in:
commit
71dd75a596
@ -50,6 +50,21 @@ MessageBoxException::~MessageBoxException()
|
|||||||
wxAtomicDec( sOutstandingMessages );
|
wxAtomicDec( sOutstandingMessages );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SimpleMessageBoxException::~SimpleMessageBoxException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString SimpleMessageBoxException::ErrorMessage() const
|
||||||
|
{
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr< AudacityException > SimpleMessageBoxException::Move()
|
||||||
|
{
|
||||||
|
return std::unique_ptr< AudacityException >
|
||||||
|
{ safenew SimpleMessageBoxException{ std::move( *this ) } };
|
||||||
|
}
|
||||||
|
|
||||||
// This is meant to be invoked via wxEvtHandler::CallAfter
|
// This is meant to be invoked via wxEvtHandler::CallAfter
|
||||||
void MessageBoxException::DelayedHandlerAction()
|
void MessageBoxException::DelayedHandlerAction()
|
||||||
{
|
{
|
||||||
|
@ -69,6 +69,30 @@ private:
|
|||||||
mutable bool moved { false };
|
mutable bool moved { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// MessageBoxException that shows a given, unvarying string.
|
||||||
|
class SimpleMessageBoxException /* not final */ : public MessageBoxException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SimpleMessageBoxException( const wxString &message_,
|
||||||
|
const wxString &caption = wxString{} )
|
||||||
|
: MessageBoxException{ caption }
|
||||||
|
, message{ message_ }
|
||||||
|
{}
|
||||||
|
~SimpleMessageBoxException() override;
|
||||||
|
|
||||||
|
SimpleMessageBoxException( const SimpleMessageBoxException& ) = default;
|
||||||
|
SimpleMessageBoxException &operator = (
|
||||||
|
SimpleMessageBoxException && ) PROHIBITED;
|
||||||
|
|
||||||
|
std::unique_ptr< AudacityException > Move() override;
|
||||||
|
|
||||||
|
// Format a default, internationalized error message for this exception.
|
||||||
|
virtual wxString ErrorMessage() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxString message;
|
||||||
|
};
|
||||||
|
|
||||||
struct DefaultDelayedHandlerAction
|
struct DefaultDelayedHandlerAction
|
||||||
{
|
{
|
||||||
void operator () (AudacityException *pException) const
|
void operator () (AudacityException *pException) const
|
||||||
|
@ -337,11 +337,14 @@ void BenchmarkDialog::OnRun( wxCommandEvent & WXUNUSED(event))
|
|||||||
|
|
||||||
// Rememebr the old blocksize, so that we can restore it later.
|
// Rememebr the old blocksize, so that we can restore it later.
|
||||||
auto oldBlockSize = Sequence::GetMaxDiskBlockSize();
|
auto oldBlockSize = Sequence::GetMaxDiskBlockSize();
|
||||||
const auto cleanup = finally([=]
|
|
||||||
{ Sequence::SetMaxDiskBlockSize(oldBlockSize); }
|
|
||||||
);
|
|
||||||
Sequence::SetMaxDiskBlockSize(blockSize * 1024);
|
Sequence::SetMaxDiskBlockSize(blockSize * 1024);
|
||||||
|
|
||||||
|
const auto cleanup = finally( [&] {
|
||||||
|
Sequence::SetMaxDiskBlockSize(oldBlockSize);
|
||||||
|
gPrefs->Write(wxT("/GUI/EditClipCanMove"), editClipCanMove);
|
||||||
|
gPrefs->Flush();
|
||||||
|
} );
|
||||||
|
|
||||||
wxBusyCursor busy;
|
wxBusyCursor busy;
|
||||||
|
|
||||||
HoldPrint(true);
|
HoldPrint(true);
|
||||||
@ -426,8 +429,11 @@ void BenchmarkDialog::OnRun( wxCommandEvent & WXUNUSED(event))
|
|||||||
if (mEditDetail)
|
if (mEditDetail)
|
||||||
Printf(wxT("Cut: %d - %d \n"), x0 * chunkSize, (x0 + xlen) * chunkSize);
|
Printf(wxT("Cut: %d - %d \n"), x0 * chunkSize, (x0 + xlen) * chunkSize);
|
||||||
|
|
||||||
auto tmp = t->Cut(double (x0 * chunkSize), double ((x0 + xlen) * chunkSize));
|
Track::Holder tmp;
|
||||||
if (!tmp) {
|
try {
|
||||||
|
tmp = t->Cut(double (x0 * chunkSize), double ((x0 + xlen) * chunkSize));
|
||||||
|
}
|
||||||
|
catch (const AudacityException&) {
|
||||||
Printf(wxT("Trial %d\n"), z);
|
Printf(wxT("Trial %d\n"), z);
|
||||||
Printf(wxT("Cut (%d, %d) failed.\n"), (x0 * chunkSize),
|
Printf(wxT("Cut (%d, %d) failed.\n"), (x0 * chunkSize),
|
||||||
(x0 + xlen) * chunkSize);
|
(x0 + xlen) * chunkSize);
|
||||||
@ -540,7 +546,4 @@ void BenchmarkDialog::OnRun( wxCommandEvent & WXUNUSED(event))
|
|||||||
|
|
||||||
Printf(wxT("Benchmark completed successfully.\n"));
|
Printf(wxT("Benchmark completed successfully.\n"));
|
||||||
HoldPrint(false);
|
HoldPrint(false);
|
||||||
|
|
||||||
gPrefs->Write(wxT("/GUI/EditClipCanMove"), editClipCanMove);
|
|
||||||
gPrefs->Flush();
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ public:
|
|||||||
const wxString &caption = wxString{},
|
const wxString &caption = wxString{},
|
||||||
const wxFileName &renameTarget_ = {})
|
const wxFileName &renameTarget_ = {})
|
||||||
: MessageBoxException{ caption }
|
: MessageBoxException{ caption }
|
||||||
, fileName{ fileName_ }, cause{ cause_ }, renameTarget{ renameTarget_ }
|
, cause{ cause_ }, fileName{ fileName_ }, renameTarget{ renameTarget_ }
|
||||||
{}
|
{}
|
||||||
|
|
||||||
FileException(FileException&& that)
|
FileException(FileException&& that)
|
||||||
|
@ -2339,10 +2339,10 @@ bool LabelTrack::Save(wxTextFile * out, bool overwrite)
|
|||||||
Track::Holder LabelTrack::Cut(double t0, double t1)
|
Track::Holder LabelTrack::Cut(double t0, double t1)
|
||||||
{
|
{
|
||||||
auto tmp = Copy(t0, t1);
|
auto tmp = Copy(t0, t1);
|
||||||
if (!tmp)
|
|
||||||
return{};
|
|
||||||
if (!Clear(t0, t1))
|
if (!Clear(t0, t1))
|
||||||
return{};
|
//THROW_INCONSISTENCY_EXCEPTION
|
||||||
|
;
|
||||||
|
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
@ -2353,8 +2353,7 @@ Track::Holder LabelTrack::SplitCut(double t0, double t1)
|
|||||||
// SplitCut() == Copy() + SplitDelete()
|
// SplitCut() == Copy() + SplitDelete()
|
||||||
|
|
||||||
Track::Holder tmp = Copy(t0, t1);
|
Track::Holder tmp = Copy(t0, t1);
|
||||||
if (!tmp)
|
|
||||||
return {};
|
|
||||||
if (!SplitDelete(t0, t1))
|
if (!SplitDelete(t0, t1))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
136
src/Menus.cpp
136
src/Menus.cpp
@ -4177,8 +4177,7 @@ void AudacityProject::OnCut()
|
|||||||
dest = n->Copy(mViewInfo.selectedRegion.t0(),
|
dest = n->Copy(mViewInfo.selectedRegion.t0(),
|
||||||
mViewInfo.selectedRegion.t1());
|
mViewInfo.selectedRegion.t1());
|
||||||
|
|
||||||
if (dest)
|
FinishCopy(n, std::move(dest), newClipboard);
|
||||||
FinishCopy(n, std::move(dest), newClipboard);
|
|
||||||
}
|
}
|
||||||
n = iter.Next();
|
n = iter.Next();
|
||||||
}
|
}
|
||||||
@ -4309,8 +4308,7 @@ void AudacityProject::OnCopy()
|
|||||||
if (n->GetSelected()) {
|
if (n->GetSelected()) {
|
||||||
auto dest = n->Copy(mViewInfo.selectedRegion.t0(),
|
auto dest = n->Copy(mViewInfo.selectedRegion.t0(),
|
||||||
mViewInfo.selectedRegion.t1());
|
mViewInfo.selectedRegion.t1());
|
||||||
if (dest)
|
FinishCopy(n, std::move(dest), newClipboard);
|
||||||
FinishCopy(n, std::move(dest), newClipboard);
|
|
||||||
}
|
}
|
||||||
n = iter.Next();
|
n = iter.Next();
|
||||||
}
|
}
|
||||||
@ -4351,31 +4349,29 @@ void AudacityProject::OnPaste()
|
|||||||
if (c == NULL)
|
if (c == NULL)
|
||||||
return;
|
return;
|
||||||
Track *ff = NULL;
|
Track *ff = NULL;
|
||||||
const Track *tmpSrc = NULL;
|
const Track *lastClipBeforeMismatch = NULL;
|
||||||
const Track *tmpC = NULL;
|
const Track *mismatchedClip = NULL;
|
||||||
const Track *prev = NULL;
|
const Track *prevClip = NULL;
|
||||||
|
|
||||||
bool bAdvanceClipboard = true;
|
bool bAdvanceClipboard = true;
|
||||||
bool bPastedSomething = false;
|
bool bPastedSomething = false;
|
||||||
bool bTrackTypeMismatch = false;
|
|
||||||
|
|
||||||
while (n && c) {
|
while (n && c) {
|
||||||
if (n->GetSelected()) {
|
if (n->GetSelected()) {
|
||||||
bAdvanceClipboard = true;
|
bAdvanceClipboard = true;
|
||||||
if (tmpC)
|
if (mismatchedClip)
|
||||||
c = tmpC;
|
c = mismatchedClip;
|
||||||
if (c->GetKind() != n->GetKind()) {
|
if (c->GetKind() != n->GetKind()) {
|
||||||
if (!bTrackTypeMismatch) {
|
if (!mismatchedClip) {
|
||||||
tmpSrc = prev;
|
lastClipBeforeMismatch = prevClip;
|
||||||
tmpC = c;
|
mismatchedClip = c;
|
||||||
}
|
}
|
||||||
bTrackTypeMismatch = true;
|
|
||||||
bAdvanceClipboard = false;
|
bAdvanceClipboard = false;
|
||||||
c = tmpSrc;
|
c = lastClipBeforeMismatch;
|
||||||
|
|
||||||
// If the types still don't match...
|
// If the types still don't match...
|
||||||
while (c && c->GetKind() != n->GetKind()) {
|
while (c && c->GetKind() != n->GetKind()) {
|
||||||
prev = c;
|
prevClip = c;
|
||||||
c = clipIter.Next();
|
c = clipIter.Next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4383,7 +4379,7 @@ void AudacityProject::OnPaste()
|
|||||||
// Handle case where the first track in clipboard
|
// Handle case where the first track in clipboard
|
||||||
// is of different type than the first selected track
|
// is of different type than the first selected track
|
||||||
if (!c) {
|
if (!c) {
|
||||||
c = tmpC;
|
c = mismatchedClip;
|
||||||
while (n && (c->GetKind() != n->GetKind() || !n->GetSelected()))
|
while (n && (c->GetKind() != n->GetKind() || !n->GetSelected()))
|
||||||
{
|
{
|
||||||
// Must perform sync-lock adjustment before incrementing n
|
// Must perform sync-lock adjustment before incrementing n
|
||||||
@ -4399,39 +4395,40 @@ void AudacityProject::OnPaste()
|
|||||||
// The last possible case for cross-type pastes: triggered when we try to
|
// The last possible case for cross-type pastes: triggered when we try to
|
||||||
// paste 1+ tracks from one type into 1+ tracks of another type. If
|
// paste 1+ tracks from one type into 1+ tracks of another type. If
|
||||||
// there's a mix of types, this shouldn't run.
|
// there's a mix of types, this shouldn't run.
|
||||||
if (!c) {
|
if (!c)
|
||||||
wxMessageBox(
|
// Throw, so that any previous changes to the project in this loop
|
||||||
_("Pasting one type of track into another is not allowed."),
|
// are discarded.
|
||||||
_("Error"), wxICON_ERROR, this);
|
throw SimpleMessageBoxException{
|
||||||
c = n;//so we don't trigger any !c conditions on our way out
|
_("Pasting one type of track into another is not allowed.")
|
||||||
break;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
// When trying to copy from stereo to mono track, show error and exit
|
// When trying to copy from stereo to mono track, show error and exit
|
||||||
// TODO: Automatically offer user to mix down to mono (unfortunately
|
// TODO: Automatically offer user to mix down to mono (unfortunately
|
||||||
// this is not easy to implement
|
// this is not easy to implement
|
||||||
if (c->GetLinked() && !n->GetLinked())
|
if (c->GetLinked() && !n->GetLinked())
|
||||||
{
|
// Throw, so that any previous changes to the project in this loop
|
||||||
wxMessageBox(
|
// are discarded.
|
||||||
_("Copying stereo audio into a mono track is not allowed."),
|
throw SimpleMessageBoxException{
|
||||||
_("Error"), wxICON_ERROR, this);
|
_("Copying stereo audio into a mono track is not allowed.")
|
||||||
break;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
if (!ff)
|
if (!ff)
|
||||||
ff = n;
|
ff = n;
|
||||||
|
|
||||||
Maybe<WaveTrack::Locker> locker;
|
Maybe<WaveTrack::Locker> locker;
|
||||||
if (msClipProject != this && c->GetKind() == Track::Wave)
|
if (msClipProject != this && c->GetKind() == Track::Wave)
|
||||||
|
// Cause duplication of block files on disk, when copy is
|
||||||
|
// between projects
|
||||||
locker.create(static_cast<const WaveTrack*>(c));
|
locker.create(static_cast<const WaveTrack*>(c));
|
||||||
|
|
||||||
if (c->GetKind() == Track::Wave && n && n->GetKind() == Track::Wave)
|
wxASSERT( n && c );
|
||||||
|
if (c->GetKind() == Track::Wave && n->GetKind() == Track::Wave)
|
||||||
{
|
{
|
||||||
bPastedSomething |=
|
bPastedSomething |=
|
||||||
((WaveTrack*)n)->ClearAndPaste(t0, t1, (WaveTrack*)c, true, true);
|
((WaveTrack*)n)->ClearAndPaste(t0, t1, (WaveTrack*)c, true, true);
|
||||||
}
|
}
|
||||||
else if (c->GetKind() == Track::Label &&
|
else if (c->GetKind() == Track::Label &&
|
||||||
n && n->GetKind() == Track::Label)
|
n->GetKind() == Track::Label)
|
||||||
{
|
{
|
||||||
((LabelTrack *)n)->Clear(t0, t1);
|
((LabelTrack *)n)->Clear(t0, t1);
|
||||||
|
|
||||||
@ -4444,6 +4441,7 @@ void AudacityProject::OnPaste()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
n->Clear(t0, t1);
|
||||||
bPastedSomething |= n->Paste(t0, c);
|
bPastedSomething |= n->Paste(t0, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4464,7 +4462,7 @@ void AudacityProject::OnPaste()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bAdvanceClipboard){
|
if (bAdvanceClipboard){
|
||||||
prev = c;
|
prevClip = c;
|
||||||
c = clipIter.Next();
|
c = clipIter.Next();
|
||||||
}
|
}
|
||||||
} // if (n->GetSelected())
|
} // if (n->GetSelected())
|
||||||
@ -4487,7 +4485,8 @@ void AudacityProject::OnPaste()
|
|||||||
|
|
||||||
while (n) {
|
while (n) {
|
||||||
if (n->GetSelected() && n->GetKind()==Track::Wave) {
|
if (n->GetSelected() && n->GetKind()==Track::Wave) {
|
||||||
if (c && c->GetKind() == Track::Wave) {
|
if (c) {
|
||||||
|
wxASSERT(c->GetKind() == Track::Wave);
|
||||||
bPastedSomething |=
|
bPastedSomething |=
|
||||||
((WaveTrack *)n)->ClearAndPaste(t0, t1, (WaveTrack *)c, true, true);
|
((WaveTrack *)n)->ClearAndPaste(t0, t1, (WaveTrack *)c, true, true);
|
||||||
}
|
}
|
||||||
@ -4598,29 +4597,40 @@ bool AudacityProject::HandlePasteNothingSelected()
|
|||||||
while (pClip) {
|
while (pClip) {
|
||||||
Maybe<WaveTrack::Locker> locker;
|
Maybe<WaveTrack::Locker> locker;
|
||||||
if ((msClipProject != this) && (pClip->GetKind() == Track::Wave))
|
if ((msClipProject != this) && (pClip->GetKind() == Track::Wave))
|
||||||
|
// Cause duplication of block files on disk, when copy is
|
||||||
|
// between projects
|
||||||
locker.create(static_cast<const WaveTrack*>(pClip));
|
locker.create(static_cast<const WaveTrack*>(pClip));
|
||||||
|
|
||||||
Track::Holder pNewTrack;
|
Track::Holder uNewTrack;
|
||||||
|
Track *pNewTrack;
|
||||||
switch (pClip->GetKind()) {
|
switch (pClip->GetKind()) {
|
||||||
case Track::Wave:
|
case Track::Wave:
|
||||||
{
|
{
|
||||||
WaveTrack *w = (WaveTrack *)pClip;
|
WaveTrack *w = (WaveTrack *)pClip;
|
||||||
pNewTrack = mTrackFactory->NewWaveTrack(w->GetSampleFormat(), w->GetRate());
|
uNewTrack = mTrackFactory->NewWaveTrack(w->GetSampleFormat(), w->GetRate()),
|
||||||
|
pNewTrack = uNewTrack.get();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef USE_MIDI
|
#ifdef USE_MIDI
|
||||||
case Track::Note:
|
case Track::Note:
|
||||||
pNewTrack = mTrackFactory->NewNoteTrack();
|
uNewTrack = mTrackFactory->NewNoteTrack(),
|
||||||
|
pNewTrack = uNewTrack.get();
|
||||||
break;
|
break;
|
||||||
#endif // USE_MIDI
|
#endif // USE_MIDI
|
||||||
|
|
||||||
case Track::Label:
|
case Track::Label:
|
||||||
pNewTrack = mTrackFactory->NewLabelTrack();
|
uNewTrack = mTrackFactory->NewLabelTrack(),
|
||||||
|
pNewTrack = uNewTrack.get();
|
||||||
break;
|
break;
|
||||||
case Track::Time:
|
case Track::Time: {
|
||||||
pNewTrack = mTrackFactory->NewTimeTrack();
|
// Maintain uniqueness of the time track!
|
||||||
|
pNewTrack = GetTracks()->GetTimeTrack();
|
||||||
|
if (!pNewTrack)
|
||||||
|
uNewTrack = mTrackFactory->NewTimeTrack(),
|
||||||
|
pNewTrack = uNewTrack.get();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
pClip = iterClip.Next();
|
pClip = iterClip.Next();
|
||||||
continue;
|
continue;
|
||||||
@ -4632,10 +4642,13 @@ bool AudacityProject::HandlePasteNothingSelected()
|
|||||||
wxUnusedVar(bResult);
|
wxUnusedVar(bResult);
|
||||||
|
|
||||||
if (!pFirstNewTrack)
|
if (!pFirstNewTrack)
|
||||||
pFirstNewTrack = pNewTrack.get();
|
pFirstNewTrack = pNewTrack;
|
||||||
|
|
||||||
pNewTrack->SetSelected(true);
|
pNewTrack->SetSelected(true);
|
||||||
FinishCopy(pClip, std::move(pNewTrack), *mTracks);
|
if (uNewTrack)
|
||||||
|
FinishCopy(pClip, std::move(uNewTrack), *mTracks);
|
||||||
|
else
|
||||||
|
FinishCopy(pClip, pNewTrack);
|
||||||
|
|
||||||
pClip = iterClip.Next();
|
pClip = iterClip.Next();
|
||||||
}
|
}
|
||||||
@ -4899,11 +4912,9 @@ void AudacityProject::OnDuplicate()
|
|||||||
// Make copies not for clipboard but for direct addition to the project
|
// Make copies not for clipboard but for direct addition to the project
|
||||||
auto dest = n->Copy(mViewInfo.selectedRegion.t0(),
|
auto dest = n->Copy(mViewInfo.selectedRegion.t0(),
|
||||||
mViewInfo.selectedRegion.t1(), false);
|
mViewInfo.selectedRegion.t1(), false);
|
||||||
if (dest) {
|
dest->Init(*n);
|
||||||
dest->Init(*n);
|
dest->SetOffset(wxMax(mViewInfo.selectedRegion.t0(), n->GetOffset()));
|
||||||
dest->SetOffset(wxMax(mViewInfo.selectedRegion.t0(), n->GetOffset()));
|
mTracks->Add(std::move(dest));
|
||||||
mTracks->Add(std::move(dest));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n == l) {
|
if (n == l) {
|
||||||
@ -5114,22 +5125,19 @@ void AudacityProject::OnSplit()
|
|||||||
double sel0 = mViewInfo.selectedRegion.t0();
|
double sel0 = mViewInfo.selectedRegion.t0();
|
||||||
double sel1 = mViewInfo.selectedRegion.t1();
|
double sel1 = mViewInfo.selectedRegion.t1();
|
||||||
|
|
||||||
dest = NULL;
|
dest = n->Copy(sel0, sel1);
|
||||||
n->Copy(sel0, sel1, &dest);
|
dest->Init(*n);
|
||||||
if (dest) {
|
dest->SetOffset(wxMax(sel0, n->GetOffset()));
|
||||||
dest->Init(*n);
|
|
||||||
dest->SetOffset(wxMax(sel0, n->GetOffset()));
|
|
||||||
|
|
||||||
if (sel1 >= n->GetEndTime())
|
if (sel1 >= n->GetEndTime())
|
||||||
n->Clear(sel0, sel1);
|
n->Clear(sel0, sel1);
|
||||||
else if (sel0 <= n->GetOffset()) {
|
else if (sel0 <= n->GetOffset()) {
|
||||||
n->Clear(sel0, sel1);
|
n->Clear(sel0, sel1);
|
||||||
n->SetOffset(sel1);
|
n->SetOffset(sel1);
|
||||||
} else
|
} else
|
||||||
n->Silence(sel0, sel1);
|
n->Silence(sel0, sel1);
|
||||||
|
|
||||||
newTracks.Add(dest);
|
newTracks.Add(dest);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
n = iter.Next();
|
n = iter.Next();
|
||||||
}
|
}
|
||||||
@ -5175,10 +5183,8 @@ void AudacityProject::OnSplitNew()
|
|||||||
mViewInfo.selectedRegion.t1());
|
mViewInfo.selectedRegion.t1());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (dest) {
|
dest->SetOffset(wxMax(newt0, offset));
|
||||||
dest->SetOffset(wxMax(newt0, offset));
|
FinishCopy(n, std::move(dest), *mTracks);
|
||||||
FinishCopy(n, std::move(dest), *mTracks);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n == l) {
|
if (n == l) {
|
||||||
|
@ -435,7 +435,8 @@ int NoteTrack::GetVisibleChannels()
|
|||||||
Track::Holder NoteTrack::Cut(double t0, double t1)
|
Track::Holder NoteTrack::Cut(double t0, double t1)
|
||||||
{
|
{
|
||||||
if (t1 <= t0)
|
if (t1 <= t0)
|
||||||
return{};
|
//THROW_INCONSISTENCY_EXCEPTION
|
||||||
|
;
|
||||||
double len = t1-t0;
|
double len = t1-t0;
|
||||||
|
|
||||||
auto newTrack = std::make_unique<NoteTrack>(mDirManager);
|
auto newTrack = std::make_unique<NoteTrack>(mDirManager);
|
||||||
@ -457,7 +458,8 @@ Track::Holder NoteTrack::Cut(double t0, double t1)
|
|||||||
Track::Holder NoteTrack::Copy(double t0, double t1, bool) const
|
Track::Holder NoteTrack::Copy(double t0, double t1, bool) const
|
||||||
{
|
{
|
||||||
if (t1 <= t0)
|
if (t1 <= t0)
|
||||||
return{};
|
//THROW_INCONSISTENCY_EXCEPTION
|
||||||
|
;
|
||||||
double len = t1-t0;
|
double len = t1-t0;
|
||||||
|
|
||||||
auto newTrack = std::make_unique<NoteTrack>(mDirManager);
|
auto newTrack = std::make_unique<NoteTrack>(mDirManager);
|
||||||
@ -534,6 +536,18 @@ bool NoteTrack::Paste(double t, const Track *src)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NoteTrack::Silence(double, double)
|
||||||
|
{
|
||||||
|
// to do
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NoteTrack::InsertSilence(double, double)
|
||||||
|
{
|
||||||
|
// to do
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Call this function to manipulate the underlying sequence data. This is
|
// Call this function to manipulate the underlying sequence data. This is
|
||||||
// NOT the function that handles horizontal dragging.
|
// NOT the function that handles horizontal dragging.
|
||||||
bool NoteTrack::Shift(double t) // t is always seconds
|
bool NoteTrack::Shift(double t) // t is always seconds
|
||||||
|
@ -105,6 +105,8 @@ class AUDACITY_DLL_API NoteTrack final
|
|||||||
bool Trim (double t0, double t1) /* not override */;
|
bool Trim (double t0, double t1) /* not override */;
|
||||||
bool Clear(double t0, double t1) override;
|
bool Clear(double t0, double t1) override;
|
||||||
bool Paste(double t, const Track *src) override;
|
bool Paste(double t, const Track *src) override;
|
||||||
|
bool Silence(double t0, double t1) override;
|
||||||
|
bool InsertSilence(double t, double len) override;
|
||||||
bool Shift(double t) /* not override */;
|
bool Shift(double t) /* not override */;
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||||
|
@ -438,7 +438,8 @@ std::unique_ptr<Sequence> Sequence::Copy(sampleCount s0, sampleCount s1) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! ConsistencyCheck(wxT("Sequence::Copy()")))
|
if (! ConsistencyCheck(wxT("Sequence::Copy()")))
|
||||||
return {};
|
//THROW_INCONSISTENCY_EXCEPTION
|
||||||
|
;
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
@ -1114,6 +1115,7 @@ int Sequence::FindBlock(sampleCount pos) const
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//static
|
||||||
bool Sequence::Read(samplePtr buffer, sampleFormat format,
|
bool Sequence::Read(samplePtr buffer, sampleFormat format,
|
||||||
const SeqBlock &b, size_t blockRelativeStart, size_t len,
|
const SeqBlock &b, size_t blockRelativeStart, size_t len,
|
||||||
bool mayThrow)
|
bool mayThrow)
|
||||||
@ -1298,7 +1300,7 @@ struct MinMaxSumsq
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Sequence::GetWaveDisplay(float *min, float *max, float *rms, int* bl,
|
bool Sequence::GetWaveDisplay(float *min, float *max, float *rms, int* bl,
|
||||||
size_t len, const sampleCount *where)
|
size_t len, const sampleCount *where) const
|
||||||
{
|
{
|
||||||
wxASSERT(len > 0);
|
wxASSERT(len > 0);
|
||||||
const auto s0 = std::max(sampleCount(0), where[0]);
|
const auto s0 = std::max(sampleCount(0), where[0]);
|
||||||
@ -1333,7 +1335,7 @@ bool Sequence::GetWaveDisplay(float *min, float *max, float *rms, int* bl,
|
|||||||
|
|
||||||
// Find the range of sample values for this block that
|
// Find the range of sample values for this block that
|
||||||
// are in the display.
|
// are in the display.
|
||||||
SeqBlock &seqBlock = mBlock[b];
|
const SeqBlock &seqBlock = mBlock[b];
|
||||||
const auto start = seqBlock.start;
|
const auto start = seqBlock.start;
|
||||||
nextSrcX = std::min(s1, start + seqBlock.f->GetLength());
|
nextSrcX = std::min(s1, start + seqBlock.f->GetLength());
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{
|
|||||||
// bl is negative wherever data are not yet available.
|
// bl is negative wherever data are not yet available.
|
||||||
// Return true if successful.
|
// Return true if successful.
|
||||||
bool GetWaveDisplay(float *min, float *max, float *rms, int* bl,
|
bool GetWaveDisplay(float *min, float *max, float *rms, int* bl,
|
||||||
size_t len, const sampleCount *where);
|
size_t len, const sampleCount *where) const;
|
||||||
|
|
||||||
std::unique_ptr<Sequence> Copy(sampleCount s0, sampleCount s1) const;
|
std::unique_ptr<Sequence> Copy(sampleCount s0, sampleCount s1) const;
|
||||||
bool Paste(sampleCount s0, const Sequence *src);
|
bool Paste(sampleCount s0, const Sequence *src);
|
||||||
|
@ -63,20 +63,24 @@ TimeTrack::TimeTrack(const std::shared_ptr<DirManager> &projDirManager, const Zo
|
|||||||
blankPen.SetColour(214, 214, 214);
|
blankPen.SetColour(214, 214, 214);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeTrack::TimeTrack(const TimeTrack &orig):
|
TimeTrack::TimeTrack(const TimeTrack &orig, double *pT0, double *pT1)
|
||||||
Track(orig)
|
: Track(orig)
|
||||||
, mZoomInfo(orig.mZoomInfo)
|
, mZoomInfo(orig.mZoomInfo)
|
||||||
{
|
{
|
||||||
Init(orig); // this copies the TimeTrack metadata (name, range, etc)
|
Init(orig); // this copies the TimeTrack metadata (name, range, etc)
|
||||||
|
|
||||||
///@TODO: Give Envelope:: a copy-constructor instead of this?
|
///@TODO: Give Envelope:: a copy-constructor instead of this?
|
||||||
mEnvelope = std::make_unique<Envelope>();
|
mEnvelope = std::make_unique<Envelope>();
|
||||||
|
mEnvelope->Flatten(1.0);
|
||||||
mEnvelope->SetTrackLen(DBL_MAX);
|
mEnvelope->SetTrackLen(DBL_MAX);
|
||||||
SetInterpolateLog(orig.GetInterpolateLog()); // this calls Envelope::SetInterpolateDB
|
SetInterpolateLog(orig.GetInterpolateLog()); // this calls Envelope::SetInterpolateDB
|
||||||
mEnvelope->Flatten(1.0);
|
|
||||||
mEnvelope->SetOffset(0);
|
mEnvelope->SetOffset(0);
|
||||||
mEnvelope->SetRange(orig.mEnvelope->GetMinValue(), orig.mEnvelope->GetMaxValue());
|
mEnvelope->SetRange(orig.mEnvelope->GetMinValue(), orig.mEnvelope->GetMaxValue());
|
||||||
mEnvelope->Paste(0.0, orig.mEnvelope.get());
|
if ( pT0 && pT1 )
|
||||||
|
// restricted copy
|
||||||
|
mEnvelope->CopyFrom(orig.mEnvelope.get(), *pT0, *pT1);
|
||||||
|
else
|
||||||
|
mEnvelope->Paste(0.0, orig.mEnvelope.get());
|
||||||
|
|
||||||
///@TODO: Give Ruler:: a copy-constructor instead of this?
|
///@TODO: Give Ruler:: a copy-constructor instead of this?
|
||||||
mRuler = std::make_unique<Ruler>();
|
mRuler = std::make_unique<Ruler>();
|
||||||
@ -103,6 +107,45 @@ TimeTrack::~TimeTrack()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Track::Holder TimeTrack::Cut( double t0, double t1 )
|
||||||
|
{
|
||||||
|
auto result = Copy( t0, t1, false );
|
||||||
|
Clear( t0, t1 );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Track::Holder TimeTrack::Copy( double t0, double t1, bool ) const
|
||||||
|
{
|
||||||
|
auto result = std::make_unique<TimeTrack>( *this, &t0, &t1 );
|
||||||
|
return Track::Holder{ std::move( result ) };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimeTrack::Clear(double t0, double t1)
|
||||||
|
{
|
||||||
|
mEnvelope->CollapseRegion(t0, t1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimeTrack::Paste(double t, const Track * src)
|
||||||
|
{
|
||||||
|
if (src->GetKind() != Track::Time)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mEnvelope->Paste(t, static_cast<const TimeTrack*>(src)->mEnvelope.get());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimeTrack::Silence(double t0, double t1)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimeTrack::InsertSilence(double t, double len)
|
||||||
|
{
|
||||||
|
mEnvelope->InsertSpace(t, len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Track::Holder TimeTrack::Duplicate() const
|
Track::Holder TimeTrack::Duplicate() const
|
||||||
{
|
{
|
||||||
return std::make_unique<TimeTrack>(*this);
|
return std::make_unique<TimeTrack>(*this);
|
||||||
|
@ -34,11 +34,20 @@ class TimeTrack final : public Track {
|
|||||||
* Envelope:: and Ruler:: members in order to copy one to the other - unfortunately both lack a
|
* Envelope:: and Ruler:: members in order to copy one to the other - unfortunately both lack a
|
||||||
* copy-constructor to encapsulate this.
|
* copy-constructor to encapsulate this.
|
||||||
* @param orig The original track to copy from
|
* @param orig The original track to copy from
|
||||||
|
* @param pT0 if not null, then the start of the sub-range to copy
|
||||||
|
* @param pT1 if not null, then the end of the sub-range to copy
|
||||||
*/
|
*/
|
||||||
TimeTrack(const TimeTrack &orig);
|
TimeTrack(const TimeTrack &orig, double *pT0 = nullptr, double *pT1 = nullptr);
|
||||||
|
|
||||||
virtual ~TimeTrack();
|
virtual ~TimeTrack();
|
||||||
|
|
||||||
|
Holder Cut( double t0, double t1 ) override;
|
||||||
|
Holder Copy( double t0, double t1, bool forClipboard ) const override;
|
||||||
|
bool Clear(double t0, double t1) override;
|
||||||
|
bool Paste(double t, const Track * src) override;
|
||||||
|
bool Silence(double t0, double t1) override;
|
||||||
|
bool InsertSilence(double t, double len) override;
|
||||||
|
|
||||||
// Identifying the type of track
|
// Identifying the type of track
|
||||||
int GetKind() const override { return Time; }
|
int GetKind() const override { return Time; }
|
||||||
|
|
||||||
|
@ -309,7 +309,6 @@ bool Track::SyncLockAdjust(double oldT1, double newT1)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
auto tmp = Cut(oldT1, GetEndTime());
|
auto tmp = Cut(oldT1, GetEndTime());
|
||||||
if (!tmp) return false;
|
|
||||||
|
|
||||||
bool ret = Paste(newT1, tmp.get());
|
bool ret = Paste(newT1, tmp.get());
|
||||||
wxASSERT(ret); // TODO: handle this.
|
wxASSERT(ret); // TODO: handle this.
|
||||||
|
19
src/Track.h
19
src/Track.h
@ -206,28 +206,29 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler
|
|||||||
// separate from the Track.
|
// separate from the Track.
|
||||||
const std::shared_ptr<DirManager> &GetDirManager() const { return mDirManager; }
|
const std::shared_ptr<DirManager> &GetDirManager() const { return mDirManager; }
|
||||||
|
|
||||||
// Create a NEW track and modify this track (or return null for failure)
|
// Create a NEW track and modify this track
|
||||||
virtual Holder Cut(double WXUNUSED(t0), double WXUNUSED(t1)) { return{}; }
|
// Return non-NULL or else throw
|
||||||
|
virtual Holder Cut(double WXUNUSED(t0), double WXUNUSED(t1)) = 0;
|
||||||
|
|
||||||
// Create a NEW track and don't modify this track (or return null for failure)
|
// Create a NEW track and don't modify this track
|
||||||
|
// Return non-NULL or else throw
|
||||||
// Note that subclasses may want to distinguish tracks stored in a clipboard
|
// Note that subclasses may want to distinguish tracks stored in a clipboard
|
||||||
// from those stored in a project
|
// from those stored in a project
|
||||||
virtual Holder Copy
|
virtual Holder Copy
|
||||||
(double WXUNUSED(t0), double WXUNUSED(t1), bool forClipboard = true) const
|
(double WXUNUSED(t0), double WXUNUSED(t1), bool forClipboard = true) const = 0;
|
||||||
{ return{}; }
|
|
||||||
|
|
||||||
// Return true for success
|
// Return true for success
|
||||||
virtual bool Clear(double WXUNUSED(t0), double WXUNUSED(t1)) {return false;}
|
virtual bool Clear(double WXUNUSED(t0), double WXUNUSED(t1)) = 0;
|
||||||
|
|
||||||
// Return true for success
|
// Return true for success
|
||||||
virtual bool Paste(double WXUNUSED(t), const Track * WXUNUSED(src)) {return false;}
|
virtual bool Paste(double WXUNUSED(t), const Track * WXUNUSED(src)) = 0;
|
||||||
|
|
||||||
// This can be used to adjust a sync-lock selected track when the selection
|
// This can be used to adjust a sync-lock selected track when the selection
|
||||||
// is replaced by one of a different length.
|
// is replaced by one of a different length.
|
||||||
virtual bool SyncLockAdjust(double oldT1, double newT1);
|
virtual bool SyncLockAdjust(double oldT1, double newT1);
|
||||||
|
|
||||||
virtual bool Silence(double WXUNUSED(t0), double WXUNUSED(t1)) {return false;}
|
virtual bool Silence(double WXUNUSED(t0), double WXUNUSED(t1)) = 0;
|
||||||
virtual bool InsertSilence(double WXUNUSED(t), double WXUNUSED(len)) {return false;}
|
virtual bool InsertSilence(double WXUNUSED(t), double WXUNUSED(len)) = 0;
|
||||||
|
|
||||||
virtual int GetKind() const { return None; }
|
virtual int GetKind() const { return None; }
|
||||||
|
|
||||||
|
@ -1539,6 +1539,7 @@ void WaveClip::WriteXML(XMLWriter &xmlFile) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WaveClip::Paste(double t0, const WaveClip* other)
|
bool WaveClip::Paste(double t0, const WaveClip* other)
|
||||||
|
// STRONG-GUARANTEE
|
||||||
{
|
{
|
||||||
const bool clipNeedsResampling = other->mRate != mRate;
|
const bool clipNeedsResampling = other->mRate != mRate;
|
||||||
const bool clipNeedsNewFormat =
|
const bool clipNeedsNewFormat =
|
||||||
@ -1558,34 +1559,42 @@ bool WaveClip::Paste(double t0, const WaveClip* other)
|
|||||||
// Force sample formats to match.
|
// Force sample formats to match.
|
||||||
newClip->ConvertToSampleFormat(mSequence->GetSampleFormat());
|
newClip->ConvertToSampleFormat(mSequence->GetSampleFormat());
|
||||||
pastedClip = newClip.get();
|
pastedClip = newClip.get();
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// No resampling or format change needed, just use original clip without making a copy
|
// No resampling or format change needed, just use original clip without making a copy
|
||||||
pastedClip = other;
|
pastedClip = other;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Paste cut lines contained in pasted clip
|
||||||
|
WaveClipHolders newCutlines;
|
||||||
|
for (const auto &cutline: pastedClip->mCutLines)
|
||||||
|
{
|
||||||
|
newCutlines.push_back(
|
||||||
|
make_movable<WaveClip>
|
||||||
|
( *cutline, mSequence->GetDirManager(),
|
||||||
|
// Recursively copy cutlines of cutlines. They don't need
|
||||||
|
// their offsets adjusted.
|
||||||
|
true));
|
||||||
|
newCutlines.back()->Offset(t0 - mOffset);
|
||||||
|
}
|
||||||
|
|
||||||
sampleCount s0;
|
sampleCount s0;
|
||||||
TimeToSamplesClip(t0, &s0);
|
TimeToSamplesClip(t0, &s0);
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
|
// Assume STRONG-GUARANTEE from Sequence::Paste
|
||||||
if (mSequence->Paste(s0, pastedClip->mSequence.get()))
|
if (mSequence->Paste(s0, pastedClip->mSequence.get()))
|
||||||
{
|
{
|
||||||
|
// Assume NOFAIL-GUARANTEE in the remaining
|
||||||
MarkChanged();
|
MarkChanged();
|
||||||
mEnvelope->Paste(s0.as_double()/mRate + mOffset, pastedClip->mEnvelope.get());
|
mEnvelope->Paste(s0.as_double()/mRate + mOffset, pastedClip->mEnvelope.get());
|
||||||
mEnvelope->RemoveUnneededPoints();
|
mEnvelope->RemoveUnneededPoints();
|
||||||
OffsetCutLines(t0, pastedClip->GetEndTime() - pastedClip->GetStartTime());
|
OffsetCutLines(t0, pastedClip->GetEndTime() - pastedClip->GetStartTime());
|
||||||
|
|
||||||
// Paste cut lines contained in pasted clip
|
for (auto &holder : newCutlines)
|
||||||
for (const auto &cutline: pastedClip->mCutLines)
|
mCutLines.push_back(std::move(holder));
|
||||||
{
|
|
||||||
mCutLines.push_back(
|
|
||||||
make_movable<WaveClip>
|
|
||||||
( *cutline, mSequence->GetDirManager(),
|
|
||||||
// Recursively copy cutlines of cutlines. They don't need
|
|
||||||
// their offsets adjusted.
|
|
||||||
true));
|
|
||||||
mCutLines.back()->Offset(t0 - mOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
@ -1727,7 +1736,7 @@ bool WaveClip::ClearAndAddCutLine(double t0, double t1)
|
|||||||
|
|
||||||
bool WaveClip::FindCutLine(double cutLinePosition,
|
bool WaveClip::FindCutLine(double cutLinePosition,
|
||||||
double* cutlineStart /* = NULL */,
|
double* cutlineStart /* = NULL */,
|
||||||
double* cutlineEnd /* = NULL */)
|
double* cutlineEnd /* = NULL */) const
|
||||||
{
|
{
|
||||||
for (const auto &cutline: mCutLines)
|
for (const auto &cutline: mCutLines)
|
||||||
{
|
{
|
||||||
@ -1745,28 +1754,33 @@ bool WaveClip::FindCutLine(double cutLinePosition,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WaveClip::ExpandCutLine(double cutLinePosition)
|
bool WaveClip::ExpandCutLine(double cutLinePosition)
|
||||||
|
// STRONG-GUARANTEE
|
||||||
{
|
{
|
||||||
for (auto it = mCutLines.begin(); it != mCutLines.end(); ++it)
|
auto end = mCutLines.end();
|
||||||
{
|
auto it = std::find_if( mCutLines.begin(), end,
|
||||||
WaveClip *const cutline = it->get();
|
[&](const WaveClipHolder &cutline) {
|
||||||
if (fabs(mOffset + cutline->GetOffset() - cutLinePosition) < 0.0001)
|
return fabs(mOffset + cutline->GetOffset() - cutLinePosition) < 0.0001;
|
||||||
{
|
} );
|
||||||
if (!Paste(mOffset+cutline->GetOffset(), cutline))
|
|
||||||
return false;
|
if ( it != end ) {
|
||||||
// Now erase the cutline,
|
auto cutline = it->get();
|
||||||
// but be careful to find it again, because Paste above may
|
// assume STRONG-GUARANTEE from Paste
|
||||||
// have modified the array of cutlines (if our cutline contained
|
if (!Paste(mOffset+cutline->GetOffset(), cutline))
|
||||||
// another cutline!), invalidating the iterator we had.
|
return false;
|
||||||
auto begin = mCutLines.begin(), end = mCutLines.end();
|
// Now erase the cutline,
|
||||||
it = std::find_if(begin, end,
|
// but be careful to find it again, because Paste above may
|
||||||
[=](decltype(*begin) &p){ return p.get() == cutline; });
|
// have modified the array of cutlines (if our cutline contained
|
||||||
if (it != end)
|
// another cutline!), invalidating the iterator we had.
|
||||||
mCutLines.erase(it); // deletes cutline!
|
end = mCutLines.end();
|
||||||
else {
|
it = std::find_if(mCutLines.begin(), end,
|
||||||
wxASSERT(false);
|
[=](const WaveClipHolder &p) { return p.get() == cutline; });
|
||||||
}
|
if (it != end)
|
||||||
return true;
|
mCutLines.erase(it); // deletes cutline!
|
||||||
|
else {
|
||||||
|
// THROW_INCONSISTENCY_EXCEPTION;
|
||||||
|
wxASSERT(false);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -1788,6 +1802,7 @@ bool WaveClip::RemoveCutLine(double cutLinePosition)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WaveClip::OffsetCutLines(double t0, double len)
|
void WaveClip::OffsetCutLines(double t0, double len)
|
||||||
|
// NOFAIL-GUARANTEE
|
||||||
{
|
{
|
||||||
for (const auto &cutLine : mCutLines)
|
for (const auto &cutLine : mCutLines)
|
||||||
{
|
{
|
||||||
|
@ -141,7 +141,8 @@ public:
|
|||||||
class WaveClip;
|
class WaveClip;
|
||||||
|
|
||||||
// Array of pointers that assume ownership
|
// Array of pointers that assume ownership
|
||||||
using WaveClipHolders = std::vector < movable_ptr< WaveClip > >;
|
using WaveClipHolder = movable_ptr< WaveClip >;
|
||||||
|
using WaveClipHolders = std::vector < WaveClipHolder >;
|
||||||
using WaveClipConstHolders = std::vector < movable_ptr< const WaveClip > >;
|
using WaveClipConstHolders = std::vector < movable_ptr< const WaveClip > >;
|
||||||
|
|
||||||
// Temporary arrays of mere pointers
|
// Temporary arrays of mere pointers
|
||||||
@ -331,7 +332,7 @@ public:
|
|||||||
* position could be found. Return false otherwise. */
|
* position could be found. Return false otherwise. */
|
||||||
bool FindCutLine(double cutLinePosition,
|
bool FindCutLine(double cutLinePosition,
|
||||||
double* cutLineStart = NULL,
|
double* cutLineStart = NULL,
|
||||||
double *cutLineEnd = NULL);
|
double *cutLineEnd = NULL) const;
|
||||||
|
|
||||||
/** Expand cut line (that is, re-insert audio, then DELETE audio saved in
|
/** 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
|
* cut line). Returns true if a cut line could be found and sucessfully
|
||||||
|
@ -532,15 +532,14 @@ bool WaveTrack::IsEmpty(double t0, double t1) const
|
|||||||
Track::Holder WaveTrack::Cut(double t0, double t1)
|
Track::Holder WaveTrack::Cut(double t0, double t1)
|
||||||
{
|
{
|
||||||
if (t1 < t0)
|
if (t1 < t0)
|
||||||
return{};
|
// THROW_INCONSISTENCY_EXCEPTION
|
||||||
|
;
|
||||||
|
|
||||||
auto tmp = Copy(t0, t1);
|
auto tmp = Copy(t0, t1);
|
||||||
|
|
||||||
if (!tmp)
|
|
||||||
return{};
|
|
||||||
|
|
||||||
if (!Clear(t0, t1))
|
if (!Clear(t0, t1))
|
||||||
return{};
|
// THROW_INCONSISTENCY_EXCEPTION
|
||||||
|
;
|
||||||
|
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
@ -548,14 +547,15 @@ Track::Holder WaveTrack::Cut(double t0, double t1)
|
|||||||
Track::Holder WaveTrack::SplitCut(double t0, double t1)
|
Track::Holder WaveTrack::SplitCut(double t0, double t1)
|
||||||
{
|
{
|
||||||
if (t1 < t0)
|
if (t1 < t0)
|
||||||
return{};
|
//THROW_INCONSISTENCY_EXCEPTION
|
||||||
|
;
|
||||||
|
|
||||||
// SplitCut is the same as 'Copy', then 'SplitDelete'
|
// SplitCut is the same as 'Copy', then 'SplitDelete'
|
||||||
auto tmp = Copy(t0, t1);
|
auto tmp = Copy(t0, t1);
|
||||||
if (!tmp)
|
|
||||||
return{};
|
|
||||||
if (!SplitDelete(t0, t1))
|
if (!SplitDelete(t0, t1))
|
||||||
return{};
|
//THROW_INCONSISTENCY_EXCEPTION
|
||||||
|
;
|
||||||
|
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
@ -564,14 +564,15 @@ Track::Holder WaveTrack::SplitCut(double t0, double t1)
|
|||||||
Track::Holder WaveTrack::CutAndAddCutLine(double t0, double t1)
|
Track::Holder WaveTrack::CutAndAddCutLine(double t0, double t1)
|
||||||
{
|
{
|
||||||
if (t1 < t0)
|
if (t1 < t0)
|
||||||
return {};
|
//THROW_INCONSISTENCY_EXCEPTION
|
||||||
|
;
|
||||||
|
|
||||||
// Cut is the same as 'Copy', then 'Delete'
|
// Cut is the same as 'Copy', then 'Delete'
|
||||||
auto tmp = Copy(t0, t1);
|
auto tmp = Copy(t0, t1);
|
||||||
if (!tmp)
|
|
||||||
return {};
|
|
||||||
if (!ClearAndAddCutLine(t0, t1))
|
if (!ClearAndAddCutLine(t0, t1))
|
||||||
return {};
|
//THROW_INCONSISTENCY_EXCEPTION
|
||||||
|
;
|
||||||
|
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
@ -636,7 +637,8 @@ bool WaveTrack::Trim (double t0, double t1)
|
|||||||
Track::Holder WaveTrack::Copy(double t0, double t1, bool forClipboard) const
|
Track::Holder WaveTrack::Copy(double t0, double t1, bool forClipboard) const
|
||||||
{
|
{
|
||||||
if (t1 <= t0)
|
if (t1 <= t0)
|
||||||
return{};
|
//THROW_INCONSISTENCY_EXCEPTION
|
||||||
|
;
|
||||||
|
|
||||||
WaveTrack *newTrack;
|
WaveTrack *newTrack;
|
||||||
Track::Holder result
|
Track::Holder result
|
||||||
@ -1166,8 +1168,6 @@ bool WaveTrack::SyncLockAdjust(double oldT1, double newT1)
|
|||||||
gPrefs->Read(wxT("/GUI/EditClipCanMove"), &clipsCanMove);
|
gPrefs->Read(wxT("/GUI/EditClipCanMove"), &clipsCanMove);
|
||||||
if (clipsCanMove) {
|
if (clipsCanMove) {
|
||||||
auto tmp = Cut (oldT1, GetEndTime() + 1.0/GetRate());
|
auto tmp = Cut (oldT1, GetEndTime() + 1.0/GetRate());
|
||||||
if (!tmp)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ret = Paste(newT1, tmp.get());
|
ret = Paste(newT1, tmp.get());
|
||||||
wxASSERT(ret);
|
wxASSERT(ret);
|
||||||
@ -1202,6 +1202,7 @@ bool WaveTrack::SyncLockAdjust(double oldT1, double newT1)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WaveTrack::Paste(double t0, const Track *src)
|
bool WaveTrack::Paste(double t0, const Track *src)
|
||||||
|
// WEAK-GUARANTEE
|
||||||
{
|
{
|
||||||
bool editClipCanMove = true;
|
bool editClipCanMove = true;
|
||||||
gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove);
|
gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove);
|
||||||
@ -1287,7 +1288,8 @@ bool WaveTrack::Paste(double t0, const Track *src)
|
|||||||
insideClip = clip.get();
|
insideClip = clip.get();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// If clips are immovable we also allow prepending to clips
|
// If clips are immovable we also allow prepending to clips
|
||||||
if (clip->WithinClip(t0) ||
|
if (clip->WithinClip(t0) ||
|
||||||
@ -1312,12 +1314,11 @@ bool WaveTrack::Paste(double t0, const Track *src)
|
|||||||
if (clip->GetStartTime() > insideClip->GetStartTime() &&
|
if (clip->GetStartTime() > insideClip->GetStartTime() &&
|
||||||
insideClip->GetEndTime() + insertDuration >
|
insideClip->GetEndTime() + insertDuration >
|
||||||
clip->GetStartTime())
|
clip->GetStartTime())
|
||||||
{
|
// STRONG-GUARANTEE in case of this path
|
||||||
wxMessageBox(
|
// not that it matters.
|
||||||
_("There is not enough room available to paste the selection"),
|
throw SimpleMessageBoxException{
|
||||||
_("Error"), wxICON_STOP);
|
_("There is not enough room available to paste the selection")
|
||||||
return false;
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1331,12 +1332,11 @@ bool WaveTrack::Paste(double t0, const Track *src)
|
|||||||
//printf("paste: multi clip mode!\n");
|
//printf("paste: multi clip mode!\n");
|
||||||
|
|
||||||
if (!editClipCanMove && !IsEmpty(t0, t0+insertDuration-1.0/mRate))
|
if (!editClipCanMove && !IsEmpty(t0, t0+insertDuration-1.0/mRate))
|
||||||
{
|
// STRONG-GUARANTEE in case of this path
|
||||||
wxMessageBox(
|
// not that it matters.
|
||||||
_("There is not enough room available to paste the selection"),
|
throw SimpleMessageBoxException{
|
||||||
_("Error"), wxICON_STOP);
|
_("There is not enough room available to paste the selection")
|
||||||
return false;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &clip : other->mClips)
|
for (const auto &clip : other->mClips)
|
||||||
{
|
{
|
||||||
@ -2447,50 +2447,52 @@ void WaveTrack::UpdateLocationsCache() const
|
|||||||
// Expand cut line (that is, re-insert audio, then DELETE audio saved in cut line)
|
// Expand cut line (that is, re-insert audio, then DELETE audio saved in cut line)
|
||||||
bool WaveTrack::ExpandCutLine(double cutLinePosition, double* cutlineStart,
|
bool WaveTrack::ExpandCutLine(double cutLinePosition, double* cutlineStart,
|
||||||
double* cutlineEnd)
|
double* cutlineEnd)
|
||||||
|
// STRONG-GUARANTEE
|
||||||
{
|
{
|
||||||
bool editClipCanMove = true;
|
bool editClipCanMove = true;
|
||||||
gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove);
|
gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove);
|
||||||
|
|
||||||
// Find clip which contains this cut line
|
// Find clip which contains this cut line
|
||||||
for (const auto &clip : mClips)
|
double start = 0, end = 0;
|
||||||
|
auto pEnd = mClips.end();
|
||||||
|
auto pClip = std::find_if( mClips.begin(), pEnd,
|
||||||
|
[&](const WaveClipHolder &clip) {
|
||||||
|
return clip->FindCutLine(cutLinePosition, &start, &end); } );
|
||||||
|
if (pClip != pEnd)
|
||||||
{
|
{
|
||||||
double start = 0, end = 0;
|
auto &clip = *pClip;
|
||||||
|
if (!editClipCanMove)
|
||||||
if (clip->FindCutLine(cutLinePosition, &start, &end))
|
|
||||||
{
|
{
|
||||||
if (!editClipCanMove)
|
// We are not allowed to move the other clips, so see if there
|
||||||
|
// is enough room to expand the cut line
|
||||||
|
for (const auto &clip2: mClips)
|
||||||
{
|
{
|
||||||
// We are not allowed to move the other clips, so see if there
|
if (clip2->GetStartTime() > clip->GetStartTime() &&
|
||||||
// is enough room to expand the cut line
|
clip->GetEndTime() + end - start > clip2->GetStartTime())
|
||||||
for (const auto &clip2: mClips)
|
// STRONG-GUARANTEE in case of this path
|
||||||
{
|
throw SimpleMessageBoxException{
|
||||||
if (clip2->GetStartTime() > clip->GetStartTime() &&
|
_("There is not enough room available to expand the cut line")
|
||||||
clip->GetEndTime() + end - start > clip2->GetStartTime())
|
};
|
||||||
{
|
}
|
||||||
wxMessageBox(
|
}
|
||||||
_("There is not enough room available to expand the cut line"),
|
|
||||||
_("Error"), wxICON_STOP);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!clip->ExpandCutLine(cutLinePosition))
|
if (!clip->ExpandCutLine(cutLinePosition))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (cutlineStart)
|
// STRONG-GUARANTEE provided that the following gives NOFAIL-GUARANTEE
|
||||||
*cutlineStart = start;
|
|
||||||
if (cutlineEnd)
|
|
||||||
*cutlineEnd = end;
|
|
||||||
|
|
||||||
// Move clips which are to the right of the cut line
|
if (cutlineStart)
|
||||||
if (editClipCanMove)
|
*cutlineStart = start;
|
||||||
|
if (cutlineEnd)
|
||||||
|
*cutlineEnd = end;
|
||||||
|
|
||||||
|
// Move clips which are to the right of the cut line
|
||||||
|
if (editClipCanMove)
|
||||||
|
{
|
||||||
|
for (const auto &clip2 : mClips)
|
||||||
{
|
{
|
||||||
for (const auto &clip2 : mClips)
|
if (clip2->GetStartTime() > clip->GetStartTime())
|
||||||
{
|
clip2->Offset(end - start);
|
||||||
if (clip2->GetStartTime() > clip->GetStartTime())
|
|
||||||
clip2->Offset(end - start);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1278,8 +1278,6 @@ bool Effect::ProcessPass()
|
|||||||
{
|
{
|
||||||
bool bGoodResult = true;
|
bool bGoodResult = true;
|
||||||
bool isGenerator = GetType() == EffectTypeGenerate;
|
bool isGenerator = GetType() == EffectTypeGenerate;
|
||||||
bool editClipCanMove;
|
|
||||||
gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove, true);
|
|
||||||
|
|
||||||
FloatBuffers inBuffer, outBuffer;
|
FloatBuffers inBuffer, outBuffer;
|
||||||
ArrayOf<float *> inBufPos, outBufPos;
|
ArrayOf<float *> inBufPos, outBufPos;
|
||||||
|
@ -1173,20 +1173,17 @@ bool EffectEqualization::ProcessOne(int count, WaveTrack * t,
|
|||||||
//remove the old audio and get the NEW
|
//remove the old audio and get the NEW
|
||||||
t->Clear(clipStartEndTimes[i].first,clipStartEndTimes[i].second);
|
t->Clear(clipStartEndTimes[i].first,clipStartEndTimes[i].second);
|
||||||
auto toClipOutput = output->Copy(clipStartEndTimes[i].first-startT+offsetT0,clipStartEndTimes[i].second-startT+offsetT0);
|
auto toClipOutput = output->Copy(clipStartEndTimes[i].first-startT+offsetT0,clipStartEndTimes[i].second-startT+offsetT0);
|
||||||
if(toClipOutput)
|
//put the processed audio in
|
||||||
{
|
bool bResult = t->Paste(clipStartEndTimes[i].first, toClipOutput.get());
|
||||||
//put the processed audio in
|
wxASSERT(bResult); // TO DO: Actually handle this.
|
||||||
bool bResult = t->Paste(clipStartEndTimes[i].first, toClipOutput.get());
|
wxUnusedVar(bResult);
|
||||||
wxASSERT(bResult); // TO DO: Actually handle this.
|
//if the clip was only partially selected, the Paste will have created a split line. Join is needed to take care of this
|
||||||
wxUnusedVar(bResult);
|
//This is not true when the selection is fully contained within one clip (second half of conditional)
|
||||||
//if the clip was only partially selected, the Paste will have created a split line. Join is needed to take care of this
|
if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first ||
|
||||||
//This is not true when the selection is fully contained within one clip (second half of conditional)
|
clipRealStartEndTimes[i].second != clipStartEndTimes[i].second) &&
|
||||||
if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first ||
|
!(clipRealStartEndTimes[i].first <= startT &&
|
||||||
clipRealStartEndTimes[i].second != clipStartEndTimes[i].second) &&
|
clipRealStartEndTimes[i].second >= startT+lenT) )
|
||||||
!(clipRealStartEndTimes[i].first <= startT &&
|
t->Join(clipRealStartEndTimes[i].first,clipRealStartEndTimes[i].second);
|
||||||
clipRealStartEndTimes[i].second >= startT+lenT) )
|
|
||||||
t->Join(clipRealStartEndTimes[i].first,clipRealStartEndTimes[i].second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,19 +558,16 @@ bool EffectEqualization48x::ProcessTail(WaveTrack * t, WaveTrack * output, sampl
|
|||||||
t->Clear(clipStartEndTimes[i].first,clipStartEndTimes[i].second);
|
t->Clear(clipStartEndTimes[i].first,clipStartEndTimes[i].second);
|
||||||
// output->Copy(clipStartEndTimes[i].first-startT+offsetT0,clipStartEndTimes[i].second-startT+offsetT0, &toClipOutput);
|
// output->Copy(clipStartEndTimes[i].first-startT+offsetT0,clipStartEndTimes[i].second-startT+offsetT0, &toClipOutput);
|
||||||
auto toClipOutput = output->Copy(clipStartEndTimes[i].first-startT, clipStartEndTimes[i].second-startT);
|
auto toClipOutput = output->Copy(clipStartEndTimes[i].first-startT, clipStartEndTimes[i].second-startT);
|
||||||
if(toClipOutput)
|
//put the processed audio in
|
||||||
{
|
bool bResult = t->Paste(clipStartEndTimes[i].first, toClipOutput.get());
|
||||||
//put the processed audio in
|
wxASSERT(bResult); // TO DO: Actually handle this.
|
||||||
bool bResult = t->Paste(clipStartEndTimes[i].first, toClipOutput.get());
|
//if the clip was only partially selected, the Paste will have created a split line. Join is needed to take care of this
|
||||||
wxASSERT(bResult); // TO DO: Actually handle this.
|
//This is not true when the selection is fully contained within one clip (second half of conditional)
|
||||||
//if the clip was only partially selected, the Paste will have created a split line. Join is needed to take care of this
|
if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first ||
|
||||||
//This is not true when the selection is fully contained within one clip (second half of conditional)
|
clipRealStartEndTimes[i].second != clipStartEndTimes[i].second) &&
|
||||||
if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first ||
|
!(clipRealStartEndTimes[i].first <= startT &&
|
||||||
clipRealStartEndTimes[i].second != clipStartEndTimes[i].second) &&
|
clipRealStartEndTimes[i].second >= startT+lenT) )
|
||||||
!(clipRealStartEndTimes[i].first <= startT &&
|
t->Join(clipRealStartEndTimes[i].first,clipRealStartEndTimes[i].second);
|
||||||
clipRealStartEndTimes[i].second >= startT+lenT) )
|
|
||||||
t->Join(clipRealStartEndTimes[i].first,clipRealStartEndTimes[i].second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user