diff --git a/.gitignore b/.gitignore index 7f7e325bb..3a26b4edc 100644 --- a/.gitignore +++ b/.gitignore @@ -177,6 +177,7 @@ win/Debug win/Release win/Projects/*/Debug win/Projects/*/Release +win/.vs/ # All those help files help/manual* diff --git a/include/audacity/Types.h b/include/audacity/Types.h index 1614cc7dd..63f028964 100644 --- a/include/audacity/Types.h +++ b/include/audacity/Types.h @@ -70,7 +70,9 @@ public: sampleCount ( int v ) : value { v } {} sampleCount ( unsigned v ) : value { v } {} sampleCount ( long v ) : value { v } {} - sampleCount ( unsigned long v ) : value { v } {} + + // unsigned long is 64 bit on some platforms. Let it narrow. + sampleCount ( unsigned long v ) : value ( v ) {} // Beware implicit conversions from floating point values! // Otherwise the meaning of binary operators with sampleCount change diff --git a/locale/es.po b/locale/es.po index e52c72d91..aef54c70c 100644 --- a/locale/es.po +++ b/locale/es.po @@ -3,10 +3,10 @@ # Antonio Paniagua Navarro , 2011, 2012, 2013, 2014, 2015, 2016. msgid "" msgstr "" -"Project-Id-Version: Audacity 2.0.x\n" +"Project-Id-Version: Audacity 2.2.x\n" "Report-Msgid-Bugs-To: audacity-translation@lists.sourceforge.net\n" "POT-Creation-Date: 2017-03-18 18:41+0000\n" -"PO-Revision-Date: 2016-11-22 17:44+0100\n" +"PO-Revision-Date: 2017-03-30 02:21-0000\n" "Last-Translator: Antonio Paniagua Navarro \n" "Language-Team: Spanish \n" "Language: es\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Lokalize 1.5\n" +"X-Generator: Poedit 1.6.9\n" #: lib-src/FileDialog/gtk/FileDialogPrivate.cpp:75 #, c-format @@ -3812,7 +3812,7 @@ msgstr "Pistas seleccionadas silenciadas durante %.2f segundos en %.2f" #: src/Menus.cpp:4772 src/effects/Silence.h:22 msgid "Silence" -msgstr "Silenciar" +msgstr "Silencio" #: src/Menus.cpp:4803 msgid "Duplicated" diff --git a/plug-ins/clipfix.ny b/plug-ins/clipfix.ny index 637f4d8d3..2f1ec93a2 100644 --- a/plug-ins/clipfix.ny +++ b/plug-ins/clipfix.ny @@ -1,141 +1,100 @@ ;nyquist plug-in -;version 1 +;version 4 ;type process ;preview enabled -;categories "http://audacityteam.org/namespace#NoiseRemoval" ;name "Clip Fix..." ;action "Reconstructing clips..." -;author "Benjamin Schwartz" +;author "Benjamin Schwartz and Steve Daulton" ;copyright "Licensing confirmed under terms of the GNU General Public License version 2" -;; clipfix.ny by Benjamin Schwartz. -;; Licensing confirmed under terms of the GNU General Public License version 2: -;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html -;; with kind agreement of Benjamin Schwartz, December 2011. -;; GUI updated by Steve Daulton July 2012 -;; -;; For information about writing and modifying Nyquist plug-ins: -;; http://wiki.audacityteam.org/wiki/Nyquist_Plug-ins_Reference +;; Algorithm by Benjamin Schwartz +;; Clip Fix is a simple, stupid (but not blind) digital-clipping-corrector +;; The algorithm is fairly simple: +;; 1. Find all clipped regions +;; 2. Get the slope immediately on either side of the region +;; 3. Do a cubic spline interpolation. +;; 4. Go to next region -;control thresh "Threshold of Clipping (%)" real "" 95 0 100 +;control threshold "Threshold of Clipping (%)" float "" 95 0 100 +;control gain "Reduce amplitude to allow for restored peaks (dB)" float "" -9 -30 0 -(setf largenumber 100000000) ;;Largest number of samples that can be imported -(setf blocksize 100000) - -;;Clip Fix is a simple, stupid (but not blind) digital-clipping-corrector -;;The algorithm is fairly simple: -;;1. Find all clipped regions -;;2. Get the slope immediately on either side of the region -;;3. Do a cubic spline interpolation. -;;4. Go to next region - -;;Coded from start (didn't know lisp (well, scheme, but not not lisp and certainly not -;;some XLISP 2.0 derivative)) to finish -;;(fully working, more or less) in one afternoon (and some evening). -;;Written by Benjamin Schwartz, MIT class of 2006, on May 25, 2004. -;;Explanatory text added by Gale Andrews, May 2008. - -(defun declip (sin) ;;Central function -(let* ((threshold (* (peak sin largenumber) thresh 0.01)) -(s2 (snd-copy sin)) -(samplerate (snd-srate s2)) -(s2length (snd-length s2 largenumber))) - -(seqrep (i (1+ (/ s2length blocksize))) - (let ((l (min blocksize (- s2length (* i blocksize))))) - ;;(print (list i t0 l samplerate)) - (snd-from-array 0 samplerate - (workhorse - ;;(let () (print (list s2 (type-of s2) l (type-of l))) - (snd-fetch-array s2 l l) - ;;) - threshold)))) - -;;(setf r (snd-fetch-array (snd-copy s) (snd-length s largenumber) 1)) ;;Create a sound array -;;(snd-from-array (snd-t0 s) (snd-srate s) (workhorse r threshold)) -)) - -(defun workhorse (r threshold) - -(setf n (length r)) ;; Record its length - -(setf exithigh ()) ;;Times when the wavefrom left the allowed region -(setf returnhigh ()) ;;Times when it returned to the allowed region - -(setf drange 4) - -(let ((i drange) (max (- n drange))) ;;Leave room at ends for derivative processing - (while (< i max) - (if (>= (aref r i) threshold) - (if (< (aref r (- i 1)) threshold) - (setq exithigh (cons (- i 1) exithigh))) ;;We just crossed the threshold up - (if (>= (aref r (- i 1)) threshold) - (setq returnhigh (cons i returnhigh)))) ;;We just crossed the threshold down - (setq i (1+ i)))) - -(setq exithigh (reverse exithigh)) ;;List comes out backwards -(setq returnhigh (reverse returnhigh)) - -(if (>= (aref r (1- drange)) threshold) ;;If the audio begins in a clipped region, ignore - (setq returnhigh (cdr returnhigh))) ;the extra return from threshold - -(setf exitlow ()) ;; Same as above, but for the bottom threshold -(setf returnlow ()) - -(setf threshlow (* -1 threshold)) ;;Assumes your digital range is zero-centered +(setf threshold (/ threshold 100)) +(setf gain (db-to-linear gain)) +(setf buffersize 100000) +(setf slopelength 4) ; number of samples used to calculate the exit / re-entry slope -(let ((i drange) (max (- n drange))) - (while (< i max) - (if (<= (aref r i) threshlow) - (if (> (aref r (- i 1)) threshlow) - (setq exitlow (cons (- i 1) exitlow))) - (if (<= (aref r (- i 1)) threshlow) - (setq returnlow (cons i returnlow)))) - (setq i (1+ i)))) +(defun declip (sig thresh peak) + (let* ((threshold (* thresh peak)) + (ln (truncate len)) + (finalbufsize (rem ln buffersize))) + ;; Calculate the number of buffers we can process. + ;; if final buffer is not large enough for de-clipping we + ;; will just add it on the end as is. + (if (>= finalbufsize slopelength) + (setf buffercount (1+ (/ ln buffersize))) + (setf buffercount (/ ln buffersize))) + ;;; Make output sequence from processed buffers + (setf out + (seqrep (i buffercount) + (let* ((step (min buffersize (- ln (* i buffersize)))) + (buffer (snd-fetch-array sig step step)) + (processed (process buffer threshold step))) + (cue (mult gain + (snd-from-array 0 *sound-srate* processed)))))) + ;;; If there's unprocessed audio remaining, add it to the end + (if (and (> finalbufsize 0)(< finalbufsize slopelength)) + (seq out (cue (getfinalblock sig finalbufsize gain))) + out))) -(setq exitlow (reverse exitlow)) -(setq returnlow (reverse returnlow)) -(if (<= (aref r (1- drange)) threshlow) - (setq returnlow (cdr returnlow))) +(defun getfinalblock (sig step gain) + (let ((block (snd-fetch-array sig step step))) + (mult gain (snd-from-array 0 *sound-srate* block)))) -(while (and exithigh returnhigh) ;;If there are more clipped regions - (let* ((t1 (car exithigh)) ;;exit time - (t2 (car returnhigh)) ;;return time - (d1 (max 0 (/ (- (aref r t1) (aref r (- t1 (1- drange)))) (1- drange)))) ;;slope at exit - (d2 (min 0 (/ (- (aref r (+ t2 (1- drange))) (aref r t2)) (1- drange)))) ;;slope at return - (m (/ (+ d2 d1) (* (- t2 t1) (- t2 t1)))) ;;interpolation is by (t-t1)(t-t2)(mx+b) - (b (- (/ d2 (- t2 t1)) (* m t2))) ;;These values of m and b make the cubic seamless - (j (1+ t1))) ;; j is the index - (while (< j t2) - (setf (aref r j) (+ (aref r t1) (* (- j t1) (- j t2) (+ (* m j) b)))) - (setf (aref r j) (+ (* (- t2 j) (/ (aref r t1) (- t2 t1))) (* (- j t1) (/ (aref r t2) (- t2 t1))) (* (- j t1) (- j t2) (+ (* m j) b)))) - (setq j (1+ j)))) - (setq exithigh (cdr exithigh)) - (setq returnhigh (cdr returnhigh))) +(defun process (buffer threshold bufferlength) + ;;; Find threshold crossings + (setf exit-list ()) ; list of times when waveform exceeds threshold + (setf return-list ()) ; list of times when waveform returns below threshold + ;; Limitation of algorithm: the first and last 'slopelength' at ends of buffer are ignored + ;; so that we have enough samples beyond the threshold crossing to calculate the slope. + (let ((last-sample (- bufferlength slopelength))) + (do ((i slopelength (1+ i))) + ((>= i last-sample)) + (if (>= (abs (aref buffer i)) threshold) + (when (< (abs (aref buffer (- i 1))) threshold) ; we just crossed threshold + (push (- i 1) exit-list)) + (when (>= (abs (aref buffer (- i 1))) threshold) ; we just got back in range + (push i return-list))))) + ;; Reverse lists back into chronological order. + ;; This is faster than appending values in chronological order. + (setf exit-list (reverse exit-list)) + (setf return-list (reverse return-list)) + ;; If the audio begins in a clipped region, discard the first return + (when (>= (abs (aref buffer (1- slopelength))) threshold) + (setq return-list (cdr return-list))) + ;; Interpolate between each pair of exit / entry points + (let ((slopelen (1- slopelength))) + (mapc (lambda (t0 t1) + (interpolate buffer t0 t1 slopelen)) + exit-list return-list)) + buffer) -(while (and exitlow returnlow) ;;Same for bottom - (let* ((t1 (car exitlow)) - (t2 (car returnlow)) - (d1 (min 0 (/ (- (aref r t1) (aref r (- t1 (1- drange)))) (1- drange)))) ;;slope at exit - (d2 (max 0 (/ (- (aref r (+ t2 (1- drange))) (aref r t2)) (1- drange)))) ;;slope at return - (m (/ (+ d2 d1) (* (- t2 t1) (- t2 t1)))) - (b (- (/ d2 (- t2 t1)) (* m t2))) - (a (/ (+ (aref r t1) (aref r t2)) 2)) - (j (1+ t1))) - (while (< j t2) - (setf (aref r j) (+ (* (- t2 j) (/ (aref r t1) (- t2 t1))) (* (- j t1) (/ (aref r t2) (- t2 t1))) (* (- j t1) (- j t2) (+ (* m j) b)))) - (setq j (1+ j)))) - (setq exitlow (cdr exitlow)) - (setq returnlow (cdr returnlow))) -r) +(defun interpolate (buffer t0 t1 dur) + "Cubic spline interpolation" + (let* ((d0 (/ (- (aref buffer t0) (aref buffer (- t0 dur))) dur)) ; slope at start + (d1 (/ (- (aref buffer (+ t1 dur)) (aref buffer t1)) dur)) ; slope at end + (m (/ (+ d1 d0) (* (- t1 t0) (- t1 t0)))) + (b (- (/ d1 (- t1 t0)) (* m t1)))) + (do ((j (1+ t0) (1+ j))) + ((= j t1)) + (setf (aref buffer j) + (+ (* (- t1 j) (/ (aref buffer t0) (- t1 t0))) + (* (- j t0) (/ (aref buffer t1) (- t1 t0))) + (* (- j t0) (- j t1) (+ (* m j) b))))))) -(if (arrayp s) - (dotimes (j (length s)) - (setf (aref s j) (declip (aref s j)))) - (setq s (declip s))) -s +;; (get '*selection* 'peak) introduced in Audacity 2.1.3 +(multichan-expand #'declip *track* threshold (get '*selection* 'peak)) diff --git a/src/AudacityException.cpp b/src/AudacityException.cpp index 46504d4cc..e37edf175 100644 --- a/src/AudacityException.cpp +++ b/src/AudacityException.cpp @@ -50,6 +50,21 @@ MessageBoxException::~MessageBoxException() 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 void MessageBoxException::DelayedHandlerAction() { diff --git a/src/AudacityException.h b/src/AudacityException.h index a0960fbdc..31e2e3382 100644 --- a/src/AudacityException.h +++ b/src/AudacityException.h @@ -69,6 +69,30 @@ private: 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 { void operator () (AudacityException *pException) const diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index a740523cc..8a4852f01 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -2474,13 +2474,10 @@ void AudioIO::StopStream() } if( appendRecord ) { // append-recording - bool bResult; if (recordingOffset < 0) - bResult = track->Clear(mT0, mT0 - recordingOffset); // cut the latency out + track->Clear(mT0, mT0 - recordingOffset); // cut the latency out else - bResult = track->InsertSilence(mT0, recordingOffset); // put silence in - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + track->InsertSilence(mT0, recordingOffset); // put silence in } else { // recording into a NEW track diff --git a/src/Benchmark.cpp b/src/Benchmark.cpp index 22f78fa2f..e83fe3d64 100644 --- a/src/Benchmark.cpp +++ b/src/Benchmark.cpp @@ -337,11 +337,14 @@ void BenchmarkDialog::OnRun( wxCommandEvent & WXUNUSED(event)) // Rememebr the old blocksize, so that we can restore it later. auto oldBlockSize = Sequence::GetMaxDiskBlockSize(); - const auto cleanup = finally([=] - { Sequence::SetMaxDiskBlockSize(oldBlockSize); } - ); Sequence::SetMaxDiskBlockSize(blockSize * 1024); + const auto cleanup = finally( [&] { + Sequence::SetMaxDiskBlockSize(oldBlockSize); + gPrefs->Write(wxT("/GUI/EditClipCanMove"), editClipCanMove); + gPrefs->Flush(); + } ); + wxBusyCursor busy; HoldPrint(true); @@ -426,8 +429,11 @@ void BenchmarkDialog::OnRun( wxCommandEvent & WXUNUSED(event)) if (mEditDetail) Printf(wxT("Cut: %d - %d \n"), x0 * chunkSize, (x0 + xlen) * chunkSize); - auto tmp = t->Cut(double (x0 * chunkSize), double ((x0 + xlen) * chunkSize)); - if (!tmp) { + Track::Holder tmp; + try { + tmp = t->Cut(double (x0 * chunkSize), double ((x0 + xlen) * chunkSize)); + } + catch (const AudacityException&) { Printf(wxT("Trial %d\n"), z); Printf(wxT("Cut (%d, %d) failed.\n"), (x0 * chunkSize), (x0 + xlen) * chunkSize); @@ -443,8 +449,10 @@ void BenchmarkDialog::OnRun( wxCommandEvent & WXUNUSED(event)) if (mEditDetail) Printf(wxT("Paste: %d\n"), y0 * chunkSize); - if (!t->Paste((double)(y0 * chunkSize), tmp.get())) - { + try { + t->Paste((double)(y0 * chunkSize), tmp.get()); + } + catch (const AudacityException&) { Printf(wxT("Trial %d\nFailed on Paste.\n"), z); goto fail; } @@ -540,7 +548,4 @@ void BenchmarkDialog::OnRun( wxCommandEvent & WXUNUSED(event)) Printf(wxT("Benchmark completed successfully.\n")); HoldPrint(false); - - gPrefs->Write(wxT("/GUI/EditClipCanMove"), editClipCanMove); - gPrefs->Flush(); } diff --git a/src/Envelope.cpp b/src/Envelope.cpp index 1fb1b7da2..e483bb2b4 100644 --- a/src/Envelope.cpp +++ b/src/Envelope.cpp @@ -198,7 +198,7 @@ EnvPoint *Envelope::AddPointAtEnd( double t, double val ) void Envelope::CopyFrom(const Envelope *e, double t0, double t1) { - wxASSERT( t0 < t1 ); + wxASSERT( t0 <= t1 ); mOffset = wxMax(t0, e->mOffset); mTrackLen = wxMin(t1, e->mOffset + e->mTrackLen) - mOffset; diff --git a/src/FileException.h b/src/FileException.h index ef8f5e506..0d0225fc0 100644 --- a/src/FileException.h +++ b/src/FileException.h @@ -22,7 +22,7 @@ public: const wxString &caption = wxString{}, const wxFileName &renameTarget_ = {}) : MessageBoxException{ caption } - , fileName{ fileName_ }, cause{ cause_ }, renameTarget{ renameTarget_ } + , cause{ cause_ }, fileName{ fileName_ }, renameTarget{ renameTarget_ } {} FileException(FileException&& that) diff --git a/src/LabelTrack.cpp b/src/LabelTrack.cpp index e3cfd720f..53922ac64 100644 --- a/src/LabelTrack.cpp +++ b/src/LabelTrack.cpp @@ -153,7 +153,7 @@ void LabelTrack::SetOffset(double dOffset) labelStruct.selectedRegion.move(dOffset); } -bool LabelTrack::Clear(double b, double e) +void LabelTrack::Clear(double b, double e) { // May DELETE labels, so use subscripts to iterate for (size_t i = 0; i < mLabels.size(); ++i) { @@ -175,8 +175,6 @@ bool LabelTrack::Clear(double b, double e) else if (relation == LabelStruct::WITHIN_LABEL) labelStruct.selectedRegion.moveT1( - (e-b)); } - - return true; } #if 0 @@ -2339,10 +2337,8 @@ bool LabelTrack::Save(wxTextFile * out, bool overwrite) Track::Holder LabelTrack::Cut(double t0, double t1) { auto tmp = Copy(t0, t1); - if (!tmp) - return{}; - if (!Clear(t0, t1)) - return{}; + + Clear(t0, t1); return tmp; } @@ -2353,8 +2349,7 @@ Track::Holder LabelTrack::SplitCut(double t0, double t1) // SplitCut() == Copy() + SplitDelete() Track::Holder tmp = Copy(t0, t1); - if (!tmp) - return {}; + if (!SplitDelete(t0, t1)) return {}; @@ -2417,6 +2412,7 @@ Track::Holder LabelTrack::Copy(double t0, double t1, bool) const bool LabelTrack::PasteOver(double t, const Track * src) { if (src->GetKind() != Track::Label) + // THROW_INCONSISTENCY_EXCEPTION; // ? return false; int len = mLabels.size(); @@ -2440,17 +2436,18 @@ bool LabelTrack::PasteOver(double t, const Track * src) return true; } -bool LabelTrack::Paste(double t, const Track *src) +void LabelTrack::Paste(double t, const Track *src) { if (src->GetKind() != Track::Label) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; LabelTrack *lt = (LabelTrack *)src; double shiftAmt = lt->mClipLen > 0.0 ? lt->mClipLen : lt->GetEndTime(); ShiftLabelsOnInsert(shiftAmt, t); - return PasteOver(t, src); + PasteOver(t, src); } // This repeats the labels in a time interval a specified number of times. @@ -2506,7 +2503,7 @@ bool LabelTrack::Repeat(double t0, double t1, int n) return true; } -bool LabelTrack::Silence(double t0, double t1) +void LabelTrack::Silence(double t0, double t1) { int len = mLabels.size(); @@ -2550,11 +2547,9 @@ bool LabelTrack::Silence(double t0, double t1) } SortLabels(); - - return true; } -bool LabelTrack::InsertSilence(double t, double len) +void LabelTrack::InsertSilence(double t, double len) { for (auto &labelStruct: mLabels) { double t0 = labelStruct.getT0(); @@ -2566,8 +2561,6 @@ bool LabelTrack::InsertSilence(double t, double len) t1 += len; labelStruct.selectedRegion.setTimes(t0, t1); } - - return true; } int LabelTrack::GetNumLabels() const diff --git a/src/LabelTrack.h b/src/LabelTrack.h index 1f9b1fd9c..720b659e3 100644 --- a/src/LabelTrack.h +++ b/src/LabelTrack.h @@ -156,12 +156,12 @@ class AUDACITY_DLL_API LabelTrack final : public Track Track::Holder Cut (double t0, double t1) override; Track::Holder Copy (double t0, double t1, bool forClipboard = true) const override; - bool Clear(double t0, double t1) override; - bool Paste(double t, const Track * src) override; + void Clear(double t0, double t1) override; + void Paste(double t, const Track * src) override; bool Repeat(double t0, double t1, int n); - bool Silence(double t0, double t1) override; - bool InsertSilence(double t, double len) override; + void Silence(double t0, double t1) override; + void InsertSilence(double t, double len) override; int OverGlyph(int x, int y); static wxBitmap & GetGlyph( int i); diff --git a/src/Menus.cpp b/src/Menus.cpp index 970602c62..18c4bf000 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -4177,8 +4177,7 @@ void AudacityProject::OnCut() dest = n->Copy(mViewInfo.selectedRegion.t0(), mViewInfo.selectedRegion.t1()); - if (dest) - FinishCopy(n, std::move(dest), newClipboard); + FinishCopy(n, std::move(dest), newClipboard); } n = iter.Next(); } @@ -4309,8 +4308,7 @@ void AudacityProject::OnCopy() if (n->GetSelected()) { auto dest = n->Copy(mViewInfo.selectedRegion.t0(), mViewInfo.selectedRegion.t1()); - if (dest) - FinishCopy(n, std::move(dest), newClipboard); + FinishCopy(n, std::move(dest), newClipboard); } n = iter.Next(); } @@ -4351,31 +4349,29 @@ void AudacityProject::OnPaste() if (c == NULL) return; Track *ff = NULL; - const Track *tmpSrc = NULL; - const Track *tmpC = NULL; - const Track *prev = NULL; + const Track *lastClipBeforeMismatch = NULL; + const Track *mismatchedClip = NULL; + const Track *prevClip = NULL; bool bAdvanceClipboard = true; bool bPastedSomething = false; - bool bTrackTypeMismatch = false; while (n && c) { if (n->GetSelected()) { bAdvanceClipboard = true; - if (tmpC) - c = tmpC; + if (mismatchedClip) + c = mismatchedClip; if (c->GetKind() != n->GetKind()) { - if (!bTrackTypeMismatch) { - tmpSrc = prev; - tmpC = c; + if (!mismatchedClip) { + lastClipBeforeMismatch = prevClip; + mismatchedClip = c; } - bTrackTypeMismatch = true; bAdvanceClipboard = false; - c = tmpSrc; + c = lastClipBeforeMismatch; // If the types still don't match... while (c && c->GetKind() != n->GetKind()) { - prev = c; + prevClip = c; c = clipIter.Next(); } } @@ -4383,12 +4379,16 @@ void AudacityProject::OnPaste() // Handle case where the first track in clipboard // is of different type than the first selected track if (!c) { - c = tmpC; + c = mismatchedClip; while (n && (c->GetKind() != n->GetKind() || !n->GetSelected())) { // Must perform sync-lock adjustment before incrementing n if (n->IsSyncLockSelected()) { - bPastedSomething |= n->SyncLockAdjust(t1, t0+(msClipT1 - msClipT0)); + auto newT1 = t0 + (msClipT1 - msClipT0); + if (t1 != newT1 && t1 <= n->GetEndTime()) { + n->SyncLockAdjust(t1, newT1); + bPastedSomething = true; + } } n = iter.Next(); } @@ -4399,39 +4399,40 @@ void AudacityProject::OnPaste() // 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 // there's a mix of types, this shouldn't run. - if (!c) { - wxMessageBox( - _("Pasting one type of track into another is not allowed."), - _("Error"), wxICON_ERROR, this); - c = n;//so we don't trigger any !c conditions on our way out - break; - } + if (!c) + // Throw, so that any previous changes to the project in this loop + // are discarded. + throw SimpleMessageBoxException{ + _("Pasting one type of track into another is not allowed.") + }; // When trying to copy from stereo to mono track, show error and exit // TODO: Automatically offer user to mix down to mono (unfortunately // this is not easy to implement if (c->GetLinked() && !n->GetLinked()) - { - wxMessageBox( - _("Copying stereo audio into a mono track is not allowed."), - _("Error"), wxICON_ERROR, this); - break; - } + // Throw, so that any previous changes to the project in this loop + // are discarded. + throw SimpleMessageBoxException{ + _("Copying stereo audio into a mono track is not allowed.") + }; if (!ff) ff = n; Maybe locker; if (msClipProject != this && c->GetKind() == Track::Wave) + // Cause duplication of block files on disk, when copy is + // between projects locker.create(static_cast(c)); - if (c->GetKind() == Track::Wave && n && n->GetKind() == Track::Wave) + wxASSERT( n && c ); + if (c->GetKind() == Track::Wave && n->GetKind() == Track::Wave) { - bPastedSomething |= - ((WaveTrack*)n)->ClearAndPaste(t0, t1, (WaveTrack*)c, true, true); + bPastedSomething = true; + ((WaveTrack*)n)->ClearAndPaste(t0, t1, (WaveTrack*)c, true, true); } else if (c->GetKind() == Track::Label && - n && n->GetKind() == Track::Label) + n->GetKind() == Track::Label) { ((LabelTrack *)n)->Clear(t0, t1); @@ -4444,7 +4445,9 @@ void AudacityProject::OnPaste() } else { - bPastedSomething |= n->Paste(t0, c); + bPastedSomething = true; + n->Clear(t0, t1); + n->Paste(t0, c); } // When copying from mono to stereo track, paste the wave form @@ -4454,23 +4457,29 @@ void AudacityProject::OnPaste() n = iter.Next(); if (n->GetKind() == Track::Wave) { - bPastedSomething |= ((WaveTrack *)n)->ClearAndPaste(t0, t1, c, true, true); + bPastedSomething = true; + ((WaveTrack *)n)->ClearAndPaste(t0, t1, c, true, true); } else { n->Clear(t0, t1); - bPastedSomething |= n->Paste(t0, c); + bPastedSomething = true; + n->Paste(t0, c); } } if (bAdvanceClipboard){ - prev = c; + prevClip = c; c = clipIter.Next(); } } // if (n->GetSelected()) else if (n->IsSyncLockSelected()) { - bPastedSomething |= n->SyncLockAdjust(t1, t0 + msClipT1 - msClipT0); + auto newT1 = t0 + (msClipT1 - msClipT0); + if (t1 != newT1 && t1 <= n->GetEndTime()) { + n->SyncLockAdjust(t1, newT1); + bPastedSomething = true; + } } n = iter.Next(); @@ -4487,19 +4496,18 @@ void AudacityProject::OnPaste() while (n) { if (n->GetSelected() && n->GetKind()==Track::Wave) { - if (c && c->GetKind() == Track::Wave) { - bPastedSomething |= - ((WaveTrack *)n)->ClearAndPaste(t0, t1, (WaveTrack *)c, true, true); + if (c) { + wxASSERT(c->GetKind() == Track::Wave); + bPastedSomething = true; + ((WaveTrack *)n)->ClearAndPaste(t0, t1, (WaveTrack *)c, true, true); } else { auto tmp = mTrackFactory->NewWaveTrack( ((WaveTrack*)n)->GetSampleFormat(), ((WaveTrack*)n)->GetRate()); - bool bResult = tmp->InsertSilence(0.0, msClipT1 - msClipT0); // MJS: Is this correct? - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + tmp->InsertSilence(0.0, msClipT1 - msClipT0); // MJS: Is this correct? tmp->Flush(); - bPastedSomething |= - ((WaveTrack *)n)->ClearAndPaste(t0, t1, tmp.get(), true, true); + bPastedSomething = true; + ((WaveTrack *)n)->ClearAndPaste(t0, t1, tmp.get(), true, true); } } else if (n->GetKind() == Track::Label && n->GetSelected()) @@ -4598,44 +4606,56 @@ bool AudacityProject::HandlePasteNothingSelected() while (pClip) { Maybe locker; if ((msClipProject != this) && (pClip->GetKind() == Track::Wave)) + // Cause duplication of block files on disk, when copy is + // between projects locker.create(static_cast(pClip)); - Track::Holder pNewTrack; + Track::Holder uNewTrack; + Track *pNewTrack; switch (pClip->GetKind()) { case Track::Wave: { WaveTrack *w = (WaveTrack *)pClip; - pNewTrack = mTrackFactory->NewWaveTrack(w->GetSampleFormat(), w->GetRate()); + uNewTrack = mTrackFactory->NewWaveTrack(w->GetSampleFormat(), w->GetRate()), + pNewTrack = uNewTrack.get(); } break; #ifdef USE_MIDI case Track::Note: - pNewTrack = mTrackFactory->NewNoteTrack(); + uNewTrack = mTrackFactory->NewNoteTrack(), + pNewTrack = uNewTrack.get(); break; #endif // USE_MIDI case Track::Label: - pNewTrack = mTrackFactory->NewLabelTrack(); + uNewTrack = mTrackFactory->NewLabelTrack(), + pNewTrack = uNewTrack.get(); break; - case Track::Time: - pNewTrack = mTrackFactory->NewTimeTrack(); + case Track::Time: { + // Maintain uniqueness of the time track! + pNewTrack = GetTracks()->GetTimeTrack(); + if (!pNewTrack) + uNewTrack = mTrackFactory->NewTimeTrack(), + pNewTrack = uNewTrack.get(); break; + } default: pClip = iterClip.Next(); continue; } wxASSERT(pClip); - bool bResult = pNewTrack->Paste(0.0, pClip); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + pNewTrack->Paste(0.0, pClip); if (!pFirstNewTrack) - pFirstNewTrack = pNewTrack.get(); + pFirstNewTrack = pNewTrack; pNewTrack->SetSelected(true); - FinishCopy(pClip, std::move(pNewTrack), *mTracks); + if (uNewTrack) + FinishCopy(pClip, std::move(uNewTrack), *mTracks); + else + FinishCopy(pClip, pNewTrack); pClip = iterClip.Next(); } @@ -4899,11 +4919,9 @@ void AudacityProject::OnDuplicate() // Make copies not for clipboard but for direct addition to the project auto dest = n->Copy(mViewInfo.selectedRegion.t0(), mViewInfo.selectedRegion.t1(), false); - if (dest) { - dest->Init(*n); - dest->SetOffset(wxMax(mViewInfo.selectedRegion.t0(), n->GetOffset())); - mTracks->Add(std::move(dest)); - } + dest->Init(*n); + dest->SetOffset(wxMax(mViewInfo.selectedRegion.t0(), n->GetOffset())); + mTracks->Add(std::move(dest)); } if (n == l) { @@ -5114,22 +5132,19 @@ void AudacityProject::OnSplit() double sel0 = mViewInfo.selectedRegion.t0(); double sel1 = mViewInfo.selectedRegion.t1(); - dest = NULL; - n->Copy(sel0, sel1, &dest); - if (dest) { - dest->Init(*n); - dest->SetOffset(wxMax(sel0, n->GetOffset())); + dest = n->Copy(sel0, sel1); + dest->Init(*n); + dest->SetOffset(wxMax(sel0, n->GetOffset())); - if (sel1 >= n->GetEndTime()) - n->Clear(sel0, sel1); - else if (sel0 <= n->GetOffset()) { - n->Clear(sel0, sel1); - n->SetOffset(sel1); - } else - n->Silence(sel0, sel1); + if (sel1 >= n->GetEndTime()) + n->Clear(sel0, sel1); + else if (sel0 <= n->GetOffset()) { + n->Clear(sel0, sel1); + n->SetOffset(sel1); + } else + n->Silence(sel0, sel1); - newTracks.Add(dest); - } + newTracks.Add(dest); } n = iter.Next(); } @@ -5175,10 +5190,8 @@ void AudacityProject::OnSplitNew() mViewInfo.selectedRegion.t1()); } #endif - if (dest) { - dest->SetOffset(wxMax(newt0, offset)); - FinishCopy(n, std::move(dest), *mTracks); - } + dest->SetOffset(wxMax(newt0, offset)); + FinishCopy(n, std::move(dest), *mTracks); } if (n == l) { @@ -7225,8 +7238,7 @@ void AudacityProject::OnResample() // But the thrown exception will cause rollback in the application // level handler. - if (!((WaveTrack*)t)->Resample(newRate, &progress)) - break; + ((WaveTrack*)t)->Resample(newRate, &progress); // Each time a track is successfully, completely resampled, // commit that to the undo stack. The second and later times, diff --git a/src/Mix.cpp b/src/Mix.cpp index a16ca05e2..27993a8dd 100644 --- a/src/Mix.cpp +++ b/src/Mix.cpp @@ -255,7 +255,7 @@ Mixer::Mixer(const WaveTrackConstArray &inputTracks, , mQueueMaxLen{ 65536 } , mSampleQueue{ mNumInputTracks, mQueueMaxLen } - , mNumChannels{ static_cast(numOutChannels) } + , mNumChannels{ numOutChannels } , mGains{ mNumChannels } , mMayThrow{ mayThrow } diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 2b3ffef51..2538e85fe 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -191,6 +191,7 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent, size.GetHeight() - ctrlPos.y - kQuadrupleInset; ctrlSize.Set(kLeftSideStackWidth - kQuadrupleInset, nGainSliderHeight); +#ifdef USE_MIDI if (GetNote()) { mSlider_Gain = safenew MixerTrackSlider( @@ -201,6 +202,7 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent, true, 0.0, wxVERTICAL); } else +#endif mSlider_Gain = safenew MixerTrackSlider( this, ID_SLIDER_GAIN, @@ -322,15 +324,17 @@ WaveTrack *MixerTrackCluster::GetRight() const { auto left = GetWave(); if (left) - return static_cast(left); + return static_cast(left->GetLink()); else return nullptr; } +#ifdef USE_MIDI NoteTrack *MixerTrackCluster::GetNote() const { return dynamic_cast< NoteTrack * >( mTrack ); } +#endif void MixerTrackCluster::UpdatePrefs() { diff --git a/src/NoteTrack.cpp b/src/NoteTrack.cpp index 234975a24..746765cd9 100644 --- a/src/NoteTrack.cpp +++ b/src/NoteTrack.cpp @@ -435,7 +435,8 @@ int NoteTrack::GetVisibleChannels() Track::Holder NoteTrack::Cut(double t0, double t1) { if (t1 <= t0) - return{}; + //THROW_INCONSISTENCY_EXCEPTION + ; double len = t1-t0; auto newTrack = std::make_unique(mDirManager); @@ -457,7 +458,8 @@ Track::Holder NoteTrack::Cut(double t0, double t1) Track::Holder NoteTrack::Copy(double t0, double t1, bool) const { if (t1 <= t0) - return{}; + //THROW_INCONSISTENCY_EXCEPTION + ; double len = t1-t0; auto newTrack = std::make_unique(mDirManager); @@ -490,20 +492,19 @@ bool NoteTrack::Trim(double t0, double t1) return true; } -bool NoteTrack::Clear(double t0, double t1) +void NoteTrack::Clear(double t0, double t1) { // If t1 = t0, should Clear return true? if (t1 <= t0) - return false; + // THROW_INCONSISTENCY_EXCEPTION; ? + return; double len = t1-t0; if (mSeq) mSeq->clear(t0 - GetOffset(), len, false); - - return true; } -bool NoteTrack::Paste(double t, const Track *src) +void NoteTrack::Paste(double t, const Track *src) { // Paste inserts src at time t. If src has a positive offset, // the offset is treated as silence which is also inserted. If @@ -515,11 +516,13 @@ bool NoteTrack::Paste(double t, const Track *src) //Check that src is a non-NULL NoteTrack if (src == NULL || src->GetKind() != Track::Note) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; NoteTrack* other = (NoteTrack*)src; if (other->mSeq == NULL) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; if(!mSeq) mSeq = std::make_unique(); @@ -530,8 +533,16 @@ bool NoteTrack::Paste(double t, const Track *src) t += other->GetOffset(); } mSeq->paste(t - GetOffset(), other->mSeq.get()); +} - return true; +void NoteTrack::Silence(double, double) +{ + // to do +} + +void NoteTrack::InsertSilence(double, double) +{ + // to do } // Call this function to manipulate the underlying sequence data. This is @@ -758,6 +769,8 @@ bool NoteTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs) double dblValue; if (!wxStrcmp(attr, wxT("name")) && XMLValueChecker::IsGoodString(strValue)) mName = strValue; + else if (this->NoteTrackBase::HandleXMLAttribute(attr, value)) + {} else if (!wxStrcmp(attr, wxT("offset")) && XMLValueChecker::IsGoodString(strValue) && Internat::CompatibleToDouble(strValue, &dblValue)) @@ -831,10 +844,7 @@ void NoteTrack::WriteXML(XMLWriter &xmlFile) const saveme->mSeq->write(data, true); xmlFile.StartTag(wxT("notetrack")); xmlFile.WriteAttr(wxT("name"), saveme->mName); -#ifdef EXPERIMENTAL_MIDI_OUT - xmlFile.WriteAttr(wxT("mute"), mMute); - xmlFile.WriteAttr(wxT("solo"), mSolo); -#endif + this->NoteTrackBase::WriteXMLAttributes(xmlFile); xmlFile.WriteAttr(wxT("offset"), saveme->GetOffset()); xmlFile.WriteAttr(wxT("visiblechannels"), saveme->mVisibleChannels); xmlFile.WriteAttr(wxT("height"), saveme->GetActualHeight()); diff --git a/src/NoteTrack.h b/src/NoteTrack.h index a314db574..b6d1e5a2a 100644 --- a/src/NoteTrack.h +++ b/src/NoteTrack.h @@ -103,8 +103,10 @@ class AUDACITY_DLL_API NoteTrack final Track::Holder Cut (double t0, double t1) override; Track::Holder Copy (double t0, double t1, bool forClipboard = true) const override; bool Trim (double t0, double t1) /* not override */; - bool Clear(double t0, double t1) override; - bool Paste(double t, const Track *src) override; + void Clear(double t0, double t1) override; + void Paste(double t, const Track *src) override; + void Silence(double t0, double t1) override; + void InsertSilence(double t, double len) override; bool Shift(double t) /* not override */; #ifdef EXPERIMENTAL_MIDI_OUT diff --git a/src/Project.cpp b/src/Project.cpp index 0683c5f3c..1290455bb 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -4993,9 +4993,7 @@ void AudacityProject::EditClipboardByLabel( EditDestFunction action ) // right to left. Any placeholder already in merged is kept. // Only the rightmost placeholder is important in the final // result. - bool bResult = merged->Paste( 0.0 , dest.get() ); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + merged->Paste( 0.0 , dest.get() ); } } else // nothing copied but there is a 'region', so the 'region' must be a 'point label' so offset diff --git a/src/Project.h b/src/Project.h index 971c92006..0c6c88b44 100644 --- a/src/Project.h +++ b/src/Project.h @@ -382,7 +382,7 @@ public: void SkipEnd(bool shift); - typedef bool (WaveTrack::* EditFunction)(double, double); + typedef void (WaveTrack::* EditFunction)(double, double); typedef std::unique_ptr (WaveTrack::* EditDestFunction)(double, double); void EditByLabel(EditFunction action, bool bSyncLockedTracks); diff --git a/src/Sequence.cpp b/src/Sequence.cpp index 955672150..5058573ed 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -378,8 +378,10 @@ float Sequence::GetRMS(sampleCount start, sampleCount len, bool mayThrow) const std::unique_ptr Sequence::Copy(sampleCount s0, sampleCount s1) const { - if (s0 >= s1 || s0 >= mNumSamples || s1 < 0) - return {}; + auto dest = std::make_unique(mDirManager, mSampleFormat); + if (s0 >= s1 || s0 >= mNumSamples || s1 < 0) { + return dest; + } int numBlocks = mBlock.size(); @@ -391,7 +393,6 @@ std::unique_ptr Sequence::Copy(sampleCount s0, sampleCount s1) const wxUnusedVar(numBlocks); wxASSERT(b0 <= b1); - auto dest = std::make_unique(mDirManager, mSampleFormat); dest->mBlock.reserve(b1 - b0 + 1); SampleBuffer buffer(mMaxSamples, mSampleFormat); @@ -437,7 +438,8 @@ std::unique_ptr Sequence::Copy(sampleCount s0, sampleCount s1) const } if (! ConsistencyCheck(wxT("Sequence::Copy()"))) - return {}; + //THROW_INCONSISTENCY_EXCEPTION + ; return dest; } @@ -1113,6 +1115,7 @@ int Sequence::FindBlock(sampleCount pos) const return rval; } +//static bool Sequence::Read(samplePtr buffer, sampleFormat format, const SeqBlock &b, size_t blockRelativeStart, size_t len, bool mayThrow) @@ -1297,7 +1300,7 @@ struct MinMaxSumsq } 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); const auto s0 = std::max(sampleCount(0), where[0]); @@ -1332,7 +1335,7 @@ bool Sequence::GetWaveDisplay(float *min, float *max, float *rms, int* bl, // Find the range of sample values for this block that // are in the display. - SeqBlock &seqBlock = mBlock[b]; + const SeqBlock &seqBlock = mBlock[b]; const auto start = seqBlock.start; nextSrcX = std::min(s1, start + seqBlock.f->GetLength()); diff --git a/src/Sequence.h b/src/Sequence.h index c458c6119..ede815556 100644 --- a/src/Sequence.h +++ b/src/Sequence.h @@ -101,7 +101,7 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{ // bl is negative wherever data are not yet available. // Return true if successful. 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 Copy(sampleCount s0, sampleCount s1) const; bool Paste(sampleCount s0, const Sequence *src); diff --git a/src/TimeTrack.cpp b/src/TimeTrack.cpp index 6f47af6f3..b48aea123 100644 --- a/src/TimeTrack.cpp +++ b/src/TimeTrack.cpp @@ -63,20 +63,24 @@ TimeTrack::TimeTrack(const std::shared_ptr &projDirManager, const Zo blankPen.SetColour(214, 214, 214); } -TimeTrack::TimeTrack(const TimeTrack &orig): - Track(orig) +TimeTrack::TimeTrack(const TimeTrack &orig, double *pT0, double *pT1) + : Track(orig) , mZoomInfo(orig.mZoomInfo) { Init(orig); // this copies the TimeTrack metadata (name, range, etc) ///@TODO: Give Envelope:: a copy-constructor instead of this? mEnvelope = std::make_unique(); + mEnvelope->Flatten(1.0); mEnvelope->SetTrackLen(DBL_MAX); SetInterpolateLog(orig.GetInterpolateLog()); // this calls Envelope::SetInterpolateDB - mEnvelope->Flatten(1.0); mEnvelope->SetOffset(0); 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? mRuler = std::make_unique(); @@ -103,6 +107,42 @@ 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( *this, &t0, &t1 ); + return Track::Holder{ std::move( result ) }; +} + +void TimeTrack::Clear(double t0, double t1) +{ + mEnvelope->CollapseRegion(t0, t1); +} + +void TimeTrack::Paste(double t, const Track * src) +{ + if (src->GetKind() != Track::Time) + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; + + mEnvelope->Paste(t, static_cast(src)->mEnvelope.get()); +} + +void TimeTrack::Silence(double t0, double t1) +{ +} + +void TimeTrack::InsertSilence(double t, double len) +{ + mEnvelope->InsertSpace(t, len); +} + Track::Holder TimeTrack::Duplicate() const { return std::make_unique(*this); diff --git a/src/TimeTrack.h b/src/TimeTrack.h index 03aa29860..9a6214070 100644 --- a/src/TimeTrack.h +++ b/src/TimeTrack.h @@ -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 * copy-constructor to encapsulate this. * @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(); + Holder Cut( double t0, double t1 ) override; + Holder Copy( double t0, double t1, bool forClipboard ) const override; + void Clear(double t0, double t1) override; + void Paste(double t, const Track * src) override; + void Silence(double t0, double t1) override; + void InsertSilence(double t, double len) override; + // Identifying the type of track int GetKind() const override { return Time; } diff --git a/src/Track.cpp b/src/Track.cpp index 166b2393b..0f6a50f11 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -300,29 +300,22 @@ bool Track::IsSyncLockSelected() const return false; } -bool Track::SyncLockAdjust(double oldT1, double newT1) +void Track::SyncLockAdjust(double oldT1, double newT1) { if (newT1 > oldT1) { // Insert space within the track if (oldT1 > GetEndTime()) - return true; + return; auto tmp = Cut(oldT1, GetEndTime()); - if (!tmp) return false; - bool ret = Paste(newT1, tmp.get()); - wxASSERT(ret); // TODO: handle this. - - return ret; + Paste(newT1, tmp.get()); } else if (newT1 < oldT1) { // Remove from the track - return Clear(newT1, oldT1); + Clear(newT1, oldT1); } - - // fall-through: no change - return true; } void PlayableTrack::Init( const PlayableTrack &orig ) @@ -341,6 +334,33 @@ void PlayableTrack::Merge( const Track &orig ) AudioTrack::Merge( *pOrig ); } +// Serialize, not with tags of its own, but as attributes within a tag. +void PlayableTrack::WriteXMLAttributes(XMLWriter &xmlFile) const +{ + xmlFile.WriteAttr(wxT("mute"), mMute); + xmlFile.WriteAttr(wxT("solo"), mSolo); + AudioTrack::WriteXMLAttributes(xmlFile); +} + +// Return true iff the attribute is recognized. +bool PlayableTrack::HandleXMLAttribute(const wxChar *attr, const wxChar *value) +{ + const wxString strValue{ value }; + long nValue; + if (!wxStrcmp(attr, wxT("mute")) && + XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) { + mMute = (nValue != 0); + return true; + } + else if (!wxStrcmp(attr, wxT("solo")) && + XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) { + mSolo = (nValue != 0); + return true; + } + + return AudioTrack::HandleXMLAttribute(attr, value); +} + // TrackListIterator TrackListIterator::TrackListIterator(TrackList * val) : l(val) @@ -589,16 +609,9 @@ SyncLockedTracksIterator::SyncLockedTracksIterator(TrackList * val) } namespace { - bool IsSyncLockableNonLabelTrack( const Track *pTrack ) + inline bool IsSyncLockableNonLabelTrack( const Track *pTrack ) { - if ( pTrack->GetKind() == Track::Wave ) - return true; -#ifdef USE_MIDI - else if ( pTrack->GetKind() == Track::Note ) - return true; -#endif - else - return false; + return nullptr != dynamic_cast< const AudioTrack * >( pTrack ); } } diff --git a/src/Track.h b/src/Track.h index 39a994168..77df12fa5 100644 --- a/src/Track.h +++ b/src/Track.h @@ -206,28 +206,27 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler // separate from the Track. const std::shared_ptr &GetDirManager() const { return mDirManager; } - // Create a NEW track and modify this track (or return null for failure) - virtual Holder Cut(double WXUNUSED(t0), double WXUNUSED(t1)) { return{}; } + // Create a NEW track and modify this track + // 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 // from those stored in a project virtual Holder Copy - (double WXUNUSED(t0), double WXUNUSED(t1), bool forClipboard = true) const - { return{}; } + (double WXUNUSED(t0), double WXUNUSED(t1), bool forClipboard = true) const = 0; - // Return true for success - virtual bool Clear(double WXUNUSED(t0), double WXUNUSED(t1)) {return false;} + virtual void Clear(double WXUNUSED(t0), double WXUNUSED(t1)) = 0; - // Return true for success - virtual bool Paste(double WXUNUSED(t), const Track * WXUNUSED(src)) {return false;} + virtual void Paste(double WXUNUSED(t), const Track * WXUNUSED(src)) = 0; // This can be used to adjust a sync-lock selected track when the selection // is replaced by one of a different length. - virtual bool SyncLockAdjust(double oldT1, double newT1); + virtual void SyncLockAdjust(double oldT1, double newT1); - virtual bool Silence(double WXUNUSED(t0), double WXUNUSED(t1)) {return false;} - virtual bool InsertSilence(double WXUNUSED(t), double WXUNUSED(len)) {return false;} + virtual void Silence(double WXUNUSED(t0), double WXUNUSED(t1)) = 0; + virtual void InsertSilence(double WXUNUSED(t), double WXUNUSED(len)) = 0; virtual int GetKind() const { return None; } @@ -251,6 +250,13 @@ public: AudioTrack(const std::shared_ptr &projDirManager) : Track{ projDirManager } {} AudioTrack(const Track &orig) : Track{ orig } {} + + // Serialize, not with tags of its own, but as attributes within a tag. + void WriteXMLAttributes(XMLWriter &xmlFile) const {} + + // Return true iff the attribute is recognized. + bool HandleXMLAttribute(const wxChar * /*attr*/, const wxChar * /*value*/) + { return false; } }; class PlayableTrack /* not final */ : public AudioTrack @@ -268,6 +274,12 @@ public: void Init( const PlayableTrack &init ); void Merge( const Track &init ) override; + // Serialize, not with tags of its own, but as attributes within a tag. + void WriteXMLAttributes(XMLWriter &xmlFile) const; + + // Return true iff the attribute is recognized. + bool HandleXMLAttribute(const wxChar *attr, const wxChar *value); + protected: bool mMute { false }; bool mSolo { false }; diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 14a71406e..8ccc83a28 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -6283,25 +6283,14 @@ bool TrackPanel::HandleTrackLocationMouseEvent(WaveTrack * track, const wxRect & // When user presses left button on cut line, expand the line again double cutlineStart = 0, cutlineEnd = 0; - if (track->ExpandCutLine(mCapturedTrackLocation.pos, &cutlineStart, &cutlineEnd)) + track->ExpandCutLine(mCapturedTrackLocation.pos, &cutlineStart, &cutlineEnd); { // Assume linked track is wave or null const auto linked = static_cast(track->GetLink()); - if (linked) { + if (linked) // Expand the cutline in the opposite channel if it is present. - - // PRL: Do NOT report that the event is not handled if the other - // channel doesn't also have a cutline to expand at the same time. - // Just ignore the return. Bug1310. - - /* bool success = */ - linked->ExpandCutLine(mCapturedTrackLocation.pos); - /* - if (!success) - return false; - */ - } + linked->ExpandCutLine(mCapturedTrackLocation.pos); mViewInfo->selectedRegion.setTimes(cutlineStart, cutlineEnd); DisplaySelection(); @@ -6311,8 +6300,7 @@ bool TrackPanel::HandleTrackLocationMouseEvent(WaveTrack * track, const wxRect & } else if (mCapturedTrackLocation.typ == WaveTrackLocation::locationMergePoint) { const double pos = mCapturedTrackLocation.pos; - if (!track->MergeClips(mCapturedTrackLocation.clipidx1, mCapturedTrackLocation.clipidx2)) - return false; + track->MergeClips(mCapturedTrackLocation.clipidx1, mCapturedTrackLocation.clipidx2); // Assume linked track is wave or null const auto linked = @@ -6322,8 +6310,7 @@ bool TrackPanel::HandleTrackLocationMouseEvent(WaveTrack * track, const wxRect & int idx = FindMergeLine(linked, pos); if (idx >= 0) { WaveTrack::Location location = linked->GetCachedLocations()[idx]; - if (!linked->MergeClips(location.clipidx1, location.clipidx2)) - return false; + linked->MergeClips(location.clipidx1, location.clipidx2); } } @@ -8338,16 +8325,12 @@ void TrackPanel::OnFormatChange(wxCommandEvent & event) if (newFormat == ((WaveTrack*)mPopupMenuTarget)->GetSampleFormat()) return; // Nothing to do. - bool bResult = ((WaveTrack*)mPopupMenuTarget)->ConvertToSampleFormat(newFormat); - wxASSERT(bResult); // TO DO: Actually handle this. + ((WaveTrack*)mPopupMenuTarget)->ConvertToSampleFormat(newFormat); // Assume linked track is wave or null const auto partner = static_cast(mPopupMenuTarget->GetLink()); if (partner) - { - bResult = partner->ConvertToSampleFormat(newFormat); - wxASSERT(bResult); // TO DO: Actually handle this. - } + partner->ConvertToSampleFormat(newFormat); MakeParentPushState(wxString::Format(_("Changed '%s' to %s"), mPopupMenuTarget->GetName(). diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp index cfc527576..9d85cc16a 100644 --- a/src/WaveClip.cpp +++ b/src/WaveClip.cpp @@ -1539,6 +1539,7 @@ void WaveClip::WriteXML(XMLWriter &xmlFile) const } bool WaveClip::Paste(double t0, const WaveClip* other) +// STRONG-GUARANTEE { const bool clipNeedsResampling = other->mRate != mRate; const bool clipNeedsNewFormat = @@ -1558,34 +1559,42 @@ bool WaveClip::Paste(double t0, const WaveClip* other) // Force sample formats to match. newClip->ConvertToSampleFormat(mSequence->GetSampleFormat()); pastedClip = newClip.get(); - } else + } + else { // No resampling or format change needed, just use original clip without making a copy pastedClip = other; } + // Paste cut lines contained in pasted clip + WaveClipHolders newCutlines; + for (const auto &cutline: pastedClip->mCutLines) + { + newCutlines.push_back( + make_movable + ( *cutline, mSequence->GetDirManager(), + // Recursively copy cutlines of cutlines. They don't need + // their offsets adjusted. + true)); + newCutlines.back()->Offset(t0 - mOffset); + } + sampleCount s0; TimeToSamplesClip(t0, &s0); bool result = false; + + // Assume STRONG-GUARANTEE from Sequence::Paste if (mSequence->Paste(s0, pastedClip->mSequence.get())) { + // Assume NOFAIL-GUARANTEE in the remaining MarkChanged(); mEnvelope->Paste(s0.as_double()/mRate + mOffset, pastedClip->mEnvelope.get()); mEnvelope->RemoveUnneededPoints(); OffsetCutLines(t0, pastedClip->GetEndTime() - pastedClip->GetStartTime()); - // Paste cut lines contained in pasted clip - for (const auto &cutline: pastedClip->mCutLines) - { - mCutLines.push_back( - make_movable - ( *cutline, mSequence->GetDirManager(), - // Recursively copy cutlines of cutlines. They don't need - // their offsets adjusted. - true)); - mCutLines.back()->Offset(t0 - mOffset); - } + for (auto &holder : newCutlines) + mCutLines.push_back(std::move(holder)); result = true; } @@ -1727,7 +1736,7 @@ bool WaveClip::ClearAndAddCutLine(double t0, double t1) bool WaveClip::FindCutLine(double cutLinePosition, double* cutlineStart /* = NULL */, - double* cutlineEnd /* = NULL */) + double* cutlineEnd /* = NULL */) const { for (const auto &cutline: mCutLines) { @@ -1745,28 +1754,33 @@ bool WaveClip::FindCutLine(double cutLinePosition, } bool WaveClip::ExpandCutLine(double cutLinePosition) +// STRONG-GUARANTEE { - for (auto it = mCutLines.begin(); it != mCutLines.end(); ++it) - { - WaveClip *const cutline = it->get(); - if (fabs(mOffset + cutline->GetOffset() - cutLinePosition) < 0.0001) - { - if (!Paste(mOffset+cutline->GetOffset(), cutline)) - return false; - // 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 - // another cutline!), invalidating the iterator we had. - auto begin = mCutLines.begin(), end = mCutLines.end(); - it = std::find_if(begin, end, - [=](decltype(*begin) &p){ return p.get() == cutline; }); - if (it != end) - mCutLines.erase(it); // deletes cutline! - else { - wxASSERT(false); - } - return true; + auto end = mCutLines.end(); + auto it = std::find_if( mCutLines.begin(), end, + [&](const WaveClipHolder &cutline) { + return fabs(mOffset + cutline->GetOffset() - cutLinePosition) < 0.0001; + } ); + + if ( it != end ) { + auto cutline = it->get(); + // assume STRONG-GUARANTEE from Paste + if (!Paste(mOffset+cutline->GetOffset(), cutline)) + return false; + // 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 + // another cutline!), invalidating the iterator we had. + end = mCutLines.end(); + it = std::find_if(mCutLines.begin(), end, + [=](const WaveClipHolder &p) { return p.get() == cutline; }); + if (it != end) + mCutLines.erase(it); // deletes cutline! + else { + // THROW_INCONSISTENCY_EXCEPTION; + wxASSERT(false); } + return true; } return false; @@ -1788,6 +1802,7 @@ bool WaveClip::RemoveCutLine(double cutLinePosition) } void WaveClip::OffsetCutLines(double t0, double len) +// NOFAIL-GUARANTEE { for (const auto &cutLine : mCutLines) { diff --git a/src/WaveClip.h b/src/WaveClip.h index 95fa6103e..44ee6a65f 100644 --- a/src/WaveClip.h +++ b/src/WaveClip.h @@ -141,7 +141,8 @@ public: class WaveClip; // 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 > >; // Temporary arrays of mere pointers @@ -331,7 +332,7 @@ public: * position could be found. Return false otherwise. */ bool FindCutLine(double cutLinePosition, double* cutLineStart = NULL, - double *cutLineEnd = NULL); + double *cutLineEnd = NULL) const; /** 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 diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 6c2fed45f..18be5d7a9 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -501,13 +501,13 @@ float WaveTrack::GetChannelGain(int channel) const return right*mGain; } -bool WaveTrack::ConvertToSampleFormat(sampleFormat format) +void WaveTrack::ConvertToSampleFormat(sampleFormat format) +// WEAK-GUARANTEE +// might complete on only some tracks { for (const auto &clip : mClips) clip->ConvertToSampleFormat(format); mFormat = format; - - return true; } bool WaveTrack::IsEmpty(double t0, double t1) const @@ -532,15 +532,12 @@ bool WaveTrack::IsEmpty(double t0, double t1) const Track::Holder WaveTrack::Cut(double t0, double t1) { if (t1 < t0) - return{}; + // THROW_INCONSISTENCY_EXCEPTION + ; auto tmp = Copy(t0, t1); - if (!tmp) - return{}; - - if (!Clear(t0, t1)) - return{}; + Clear(t0, t1); return tmp; } @@ -548,14 +545,13 @@ Track::Holder WaveTrack::Cut(double t0, double t1) Track::Holder WaveTrack::SplitCut(double t0, double t1) { if (t1 < t0) - return{}; + //THROW_INCONSISTENCY_EXCEPTION + ; // SplitCut is the same as 'Copy', then 'SplitDelete' auto tmp = Copy(t0, t1); - if (!tmp) - return{}; - if (!SplitDelete(t0, t1)) - return{}; + + SplitDelete(t0, t1); return tmp; } @@ -564,14 +560,15 @@ Track::Holder WaveTrack::SplitCut(double t0, double t1) Track::Holder WaveTrack::CutAndAddCutLine(double t0, double t1) { if (t1 < t0) - return {}; + //THROW_INCONSISTENCY_EXCEPTION + ; // Cut is the same as 'Copy', then 'Delete' auto tmp = Copy(t0, t1); - if (!tmp) - return {}; + if (!ClearAndAddCutLine(t0, t1)) - return {}; + //THROW_INCONSISTENCY_EXCEPTION + ; return tmp; } @@ -581,7 +578,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. -bool WaveTrack::Trim (double t0, double t1) +void WaveTrack::Trim (double t0, double t1) { bool inside0 = false; bool inside1 = false; @@ -600,14 +597,14 @@ bool WaveTrack::Trim (double t0, double t1) if(t1 > clip->GetStartTime() && t1 < clip->GetEndTime()) { if (!clip->Clear(t1,clip->GetEndTime())) - return false; + return; inside1 = true; } if(t0 > clip->GetStartTime() && t0 < clip->GetEndTime()) { if (!clip->Clear(clip->GetStartTime(),t0)) - return false; + return; clip->SetOffset(t0); inside0 = true; } @@ -616,18 +613,10 @@ bool WaveTrack::Trim (double t0, double t1) //if inside0 is false, then the left selector was between //clips, so DELETE everything to its left. if(false == inside1) - { - if (!Clear(t1,GetEndTime())) - return false; - } + Clear(t1,GetEndTime()); if(false == inside0) - { - if (!SplitDelete(0,t0)) - return false; - } - - return true; + SplitDelete(0,t0); } @@ -636,7 +625,8 @@ bool WaveTrack::Trim (double t0, double t1) Track::Holder WaveTrack::Copy(double t0, double t1, bool forClipboard) const { if (t1 <= t0) - return{}; + //THROW_INCONSISTENCY_EXCEPTION + ; WaveTrack *newTrack; Track::Holder result @@ -711,14 +701,14 @@ Track::Holder WaveTrack::CopyNonconst(double t0, double t1) return Copy(t0, t1); } -bool WaveTrack::Clear(double t0, double t1) +void WaveTrack::Clear(double t0, double t1) { - return HandleClear(t0, t1, false, false); + HandleClear(t0, t1, false, false); } -bool WaveTrack::ClearAndAddCutLine(double t0, double t1) +void WaveTrack::ClearAndAddCutLine(double t0, double t1) { - return HandleClear(t0, t1, true, false); + HandleClear(t0, t1, true, false); } const SpectrogramSettings &WaveTrack::GetSpectrogramSettings() const @@ -796,7 +786,7 @@ void WaveTrack::SetWaveformSettings(std::unique_ptr &&pSetting // be pasted with visible split lines. Normally, effects do not // want these extra lines, so they may be merged out. // -bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear +void WaveTrack::ClearAndPaste(double t0, // Start of time to clear double t1, // End of time to clear const Track *src, // What to paste bool preserve, // Whether to reinsert splits/cuts @@ -810,7 +800,8 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear // If duration is 0, then it's just a plain paste if (dur == 0.0) { - return Paste(t0, src); + Paste(t0, src); + return; } // If provided time warper was NULL, use a default one that does nothing @@ -862,10 +853,12 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear const auto tolerance = 2.0 / GetRate(); // Now, clear the selection - if (HandleClear(t0, t1, false, false)) { + HandleClear(t0, t1, false, false); + { // And paste in the NEW data - if (Paste(t0, src)) { + Paste(t0, src); + { // First, merge the NEW clip(s) in with the existing clips if (merge && splits.GetCount() > 0) { @@ -883,11 +876,8 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear // Merge this clip and the previous clip if the end time // falls within it and this isn't the first clip in the track. if (fabs(t1 - clip->GetStartTime()) < tolerance) { - if (prev) { - bool bResult = MergeClips(GetClipIndex(prev), GetClipIndex(clip)); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); - } + if (prev) + MergeClips(GetClipIndex(prev), GetClipIndex(clip)); break; } prev = clip; @@ -903,9 +893,7 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear WaveClip *prev = nullptr; for (const auto clip : clips) { if (prev) { - bool bResult = MergeClips(GetClipIndex(prev), GetClipIndex(clip)); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + MergeClips(GetClipIndex(prev), GetClipIndex(clip)); break; } if (fabs(t0 - clip->GetEndTime()) < tolerance) @@ -953,15 +941,13 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear } } } - - return true; } -bool WaveTrack::SplitDelete(double t0, double t1) +void WaveTrack::SplitDelete(double t0, double t1) { bool addCutLines = false; bool split = true; - return HandleClear(t0, t1, addCutLines, split); + HandleClear(t0, t1, addCutLines, split); } namespace @@ -1019,11 +1005,12 @@ void WaveTrack::AddClip(movable_ptr &&clip) mClips.push_back(std::move(clip)); // transfer ownership } -bool WaveTrack::HandleClear(double t0, double t1, +void WaveTrack::HandleClear(double t0, double t1, bool addCutLines, bool split) { if (t1 < t0) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; bool editClipCanMove = true; gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove); @@ -1058,8 +1045,7 @@ bool WaveTrack::HandleClear(double t0, double t1, // Clip data is affected by command if (addCutLines) { - if (!clip->ClearAndAddCutLine(t0,t1)) - return false; + clip->ClearAndAddCutLine(t0,t1); } else { @@ -1116,7 +1102,7 @@ bool WaveTrack::HandleClear(double t0, double t1, } } if (!clip->Clear(t0,t1)) - return false; + return; clip->GetEnvelope()->RemoveUnneededPoints(t0); } } @@ -1141,11 +1127,9 @@ bool WaveTrack::HandleClear(double t0, double t1, for (auto &clip: clipsToAdd) mClips.push_back(std::move(clip)); // transfer ownership - - return true; } -bool WaveTrack::SyncLockAdjust(double oldT1, double newT1) +void WaveTrack::SyncLockAdjust(double oldT1, double newT1) { if (newT1 > oldT1) { // Insert space within the track @@ -1154,63 +1138,57 @@ bool WaveTrack::SyncLockAdjust(double oldT1, double newT1) // GetEndTime() looks through the clips and may give us EXACTLY the same // value as T1, when T1 was set to be at the end of one of those clips. if (oldT1 >= GetEndTime()) - return true; + return; // If track is empty at oldT1 insert whitespace; otherwise, silence if (IsEmpty(oldT1, oldT1)) { - bool ret = true; - // Check if clips can move bool clipsCanMove = true; gPrefs->Read(wxT("/GUI/EditClipCanMove"), &clipsCanMove); if (clipsCanMove) { auto tmp = Cut (oldT1, GetEndTime() + 1.0/GetRate()); - if (!tmp) - return false; - ret = Paste(newT1, tmp.get()); - wxASSERT(ret); + Paste(newT1, tmp.get()); } - - return ret; + return; } else { // AWD: Could just use InsertSilence() on its own here, but it doesn't // follow EditClipCanMove rules (Paste() does it right) AudacityProject *p = GetActiveProject(); - if (!p) return false; + if (!p) + // THROW_INCONSISTENCY_EXCEPTION + ; TrackFactory *f = p->GetTrackFactory(); - if (!f) return false; + if (!f) + // THROW_INCONSISTENCY_EXCEPTION + ; auto tmp = f->NewWaveTrack(GetSampleFormat(), GetRate()); - bool bResult = tmp->InsertSilence(0.0, newT1 - oldT1); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + tmp->InsertSilence(0.0, newT1 - oldT1); tmp->Flush(); - bResult = Paste(oldT1, tmp.get()); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + Paste(oldT1, tmp.get()); } } else if (newT1 < oldT1) { - return Clear(newT1, oldT1); + Clear(newT1, oldT1); } - - // fall-through: no change - return true; } -bool WaveTrack::Paste(double t0, const Track *src) +void WaveTrack::Paste(double t0, const Track *src) +// WEAK-GUARANTEE { bool editClipCanMove = true; gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove); if( src == NULL ) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; if (src->GetKind() != Track::Wave) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; const WaveTrack* other = static_cast(src); @@ -1236,7 +1214,7 @@ bool WaveTrack::Paste(double t0, const Track *src) // if (other->GetNumClips() == 0) - return false; + return; //printf("paste: we have at least one clip\n"); @@ -1253,9 +1231,7 @@ bool WaveTrack::Paste(double t0, const Track *src) // move everything to the right, then try to paste again if (!IsEmpty(t0, GetEndTime())) { auto tmp = Cut(t0, GetEndTime()+1.0/mRate); - bool bResult = Paste(t0 + insertDuration, tmp.get()); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + Paste(t0 + insertDuration, tmp.get()); } } else { @@ -1287,7 +1263,8 @@ bool WaveTrack::Paste(double t0, const Track *src) insideClip = clip.get(); break; } - } else + } + else { // If clips are immovable we also allow prepending to clips if (clip->WithinClip(t0) || @@ -1312,16 +1289,16 @@ bool WaveTrack::Paste(double t0, const Track *src) if (clip->GetStartTime() > insideClip->GetStartTime() && insideClip->GetEndTime() + insertDuration > clip->GetStartTime()) - { - wxMessageBox( - _("There is not enough room available to paste the selection"), - _("Error"), wxICON_STOP); - return false; - } + // STRONG-GUARANTEE in case of this path + // not that it matters. + throw SimpleMessageBoxException{ + _("There is not enough room available to paste the selection") + }; } } - return insideClip->Paste(t0, other->GetClipByIndex(0)); + insideClip->Paste(t0, other->GetClipByIndex(0)); + return; } // Just fall through and exhibit NEW behaviour @@ -1331,12 +1308,11 @@ bool WaveTrack::Paste(double t0, const Track *src) //printf("paste: multi clip mode!\n"); if (!editClipCanMove && !IsEmpty(t0, t0+insertDuration-1.0/mRate)) - { - wxMessageBox( - _("There is not enough room available to paste the selection"), - _("Error"), wxICON_STOP); - return false; - } + // STRONG-GUARANTEE in case of this path + // not that it matters. + throw SimpleMessageBoxException{ + _("There is not enough room available to paste the selection") + }; for (const auto &clip : other->mClips) { @@ -1351,13 +1327,13 @@ bool WaveTrack::Paste(double t0, const Track *src) mClips.push_back(std::move(newClip)); // transfer ownership } } - return true; } -bool WaveTrack::Silence(double t0, double t1) +void WaveTrack::Silence(double t0, double t1) { if (t1 < t0) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; auto start = (sampleCount)floor(t0 * mRate + 0.5); auto len = (sampleCount)floor(t1 * mRate + 0.5) - start; @@ -1386,25 +1362,25 @@ bool WaveTrack::Silence(double t0, double t1) if (!clip->GetSequence()->SetSilence(inclipDelta, samplesToCopy)) { wxASSERT(false); // should always work - return false; + return; } clip->MarkChanged(); } } - - return result; } -bool WaveTrack::InsertSilence(double t, double len) +void WaveTrack::InsertSilence(double t, double len) { if (len <= 0) - return false; + // THROW_INCONSISTENCY_EXCEPTION; // ? + return; if (mClips.empty()) { // Special case if there is no clip yet WaveClip* clip = CreateClip(); - return clip->InsertSilence(0, len); + clip->InsertSilence(0, len); + return; } for (const auto &clip : mClips) @@ -1414,17 +1390,15 @@ bool WaveTrack::InsertSilence(double t, double len) else if (clip->WithinClip(t)) { if (!clip->InsertSilence(t, len)) { - return false; + return; } } } - - return true; } //Performs the opposite of Join //Analyses selected region for possible Joined clips and disjoins them -bool WaveTrack::Disjoin(double t0, double t1) +void WaveTrack::Disjoin(double t0, double t1) { auto minSamples = TimeToLongSamples( WAVETRACK_MERGE_POINT_TOLERANCE ); const size_t maxAtOnce = 1048576; @@ -1499,11 +1473,9 @@ bool WaveTrack::Disjoin(double t0, double t1) const Region ®ion = regions.at(i); SplitDelete(region.start, region.end ); } - - return true; } -bool WaveTrack::Join(double t0, double t1) +void WaveTrack::Join(double t0, double t1) { // Merge all WaveClips overlapping selection into one @@ -1527,7 +1499,7 @@ bool WaveTrack::Join(double t0, double t1) //if there are no clips to DELETE, nothing to do if( clipsToDelete.size() == 0 ) - return true; + return; newClip = CreateClip(); double t = clipsToDelete[0]->GetOffset(); @@ -1540,9 +1512,7 @@ bool WaveTrack::Join(double t0, double t1) if (clip->GetOffset() - t > (1.0 / mRate)) { double addedSilence = (clip->GetOffset() - t); //printf("Adding %.6f seconds of silence\n"); - bool bResult = newClip->InsertSilence(t, addedSilence); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + newClip->InsertSilence(t, addedSilence); t += addedSilence; } @@ -1555,29 +1525,26 @@ bool WaveTrack::Join(double t0, double t1) auto it = FindClip(mClips, clip); mClips.erase(it); // deletes the clip } - - return true; } -bool WaveTrack::Append(samplePtr buffer, sampleFormat format, +void WaveTrack::Append(samplePtr buffer, sampleFormat format, size_t len, unsigned int stride /* = 1 */, XMLWriter *blockFileLog /* = NULL */) { - return RightmostOrNewClip()->Append(buffer, format, len, stride, + RightmostOrNewClip()->Append(buffer, format, len, stride, blockFileLog); } -bool WaveTrack::AppendAlias(const wxString &fName, sampleCount start, +void WaveTrack::AppendAlias(const wxString &fName, sampleCount start, size_t len, int channel,bool useOD) { - return RightmostOrNewClip()->AppendAlias(fName, start, len, channel, useOD); + RightmostOrNewClip()->AppendAlias(fName, start, len, channel, useOD); } - -bool WaveTrack::AppendCoded(const wxString &fName, sampleCount start, +void WaveTrack::AppendCoded(const wxString &fName, sampleCount start, size_t len, int channel, int decodeType) { - return RightmostOrNewClip()->AppendCoded(fName, start, len, channel, decodeType); + RightmostOrNewClip()->AppendCoded(fName, start, len, channel, decodeType); } ///gets an int with OD flags so that we can determine which ODTasks should be run on this track after save/open, etc. @@ -1648,10 +1615,10 @@ size_t WaveTrack::GetIdealBlockSize() return NewestOrNewClip()->GetSequence()->GetIdealBlockSize(); } -bool WaveTrack::Flush() +void WaveTrack::Flush() { // After appending, presumably. Do this to the clip that gets appended. - return RightmostOrNewClip()->Flush(); + RightmostOrNewClip()->Flush(); } bool WaveTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs) @@ -1685,12 +1652,8 @@ bool WaveTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs) // track is created. mLegacyProjectFileOffset = dblValue; } - else if (!wxStrcmp(attr, wxT("mute")) && - XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) - mMute = (nValue != 0); - else if (!wxStrcmp(attr, wxT("solo")) && - XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) - mSolo = (nValue != 0); + else if (this->PlayableTrack::HandleXMLAttribute(attr, value)) + {} else if (!wxStrcmp(attr, wxT("height")) && XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) mHeight = nValue; @@ -1789,8 +1752,7 @@ void WaveTrack::WriteXML(XMLWriter &xmlFile) const xmlFile.WriteAttr(wxT("name"), mName); xmlFile.WriteAttr(wxT("channel"), mChannel); xmlFile.WriteAttr(wxT("linked"), mLinked); - xmlFile.WriteAttr(wxT("mute"), mMute); - xmlFile.WriteAttr(wxT("solo"), mSolo); + this->PlayableTrack::WriteXMLAttributes(xmlFile); #ifdef EXPERIMENTAL_OUTPUT_DISPLAY int height; if(MONO_PAN) @@ -2056,11 +2018,9 @@ bool WaveTrack::Get(samplePtr buffer, sampleFormat format, return result; } -bool WaveTrack::Set(samplePtr buffer, sampleFormat format, +void WaveTrack::Set(samplePtr buffer, sampleFormat format, sampleCount start, size_t len) { - bool result = true; - for (const auto &clip: mClips) { auto clipStart = clip->GetStartSample(); @@ -2097,13 +2057,11 @@ bool WaveTrack::Set(samplePtr buffer, sampleFormat format, format, inclipDelta, samplesToCopy.as_size_t() )) { wxASSERT(false); // should always work - return false; + return; } clip->MarkChanged(); } } - - return result; } void WaveTrack::GetEnvelopeValues(double *buffer, size_t bufferLen, @@ -2338,15 +2296,14 @@ bool WaveTrack::CanInsertClip(WaveClip* clip) return true; } -bool WaveTrack::Split( double t0, double t1 ) +void WaveTrack::Split( double t0, double t1 ) { - bool ret = SplitAt( t0 ); - if( ret && t0 != t1 ) - ret = SplitAt( t1 ); - return ret; + SplitAt( t0 ); + if( t0 != t1 ) + SplitAt( t1 ); } -bool WaveTrack::SplitAt(double t) +void WaveTrack::SplitAt(double t) { for (const auto &c : mClips) { @@ -2363,11 +2320,11 @@ bool WaveTrack::SplitAt(double t) auto newClip = make_movable( *c, mDirManager, true ); if (!c->Clear(t, c->GetEndTime())) { - return false; + return; } if (!newClip->Clear(c->GetStartTime(), t)) { - return false; + return; } //offset the NEW clip by the splitpoint (noting that it is already offset to c->GetStartTime()) @@ -2376,11 +2333,8 @@ bool 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 true; } } - - return true; } void WaveTrack::UpdateLocationsCache() const @@ -2450,59 +2404,57 @@ void WaveTrack::UpdateLocationsCache() const } // Expand cut line (that is, re-insert audio, then DELETE audio saved in cut line) -bool WaveTrack::ExpandCutLine(double cutLinePosition, double* cutlineStart, +void WaveTrack::ExpandCutLine(double cutLinePosition, double* cutlineStart, double* cutlineEnd) +// STRONG-GUARANTEE { bool editClipCanMove = true; gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove); // 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; - - if (clip->FindCutLine(cutLinePosition, &start, &end)) + auto &clip = *pClip; + if (!editClipCanMove) { - 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 - // is enough room to expand the cut line - for (const auto &clip2: mClips) - { - if (clip2->GetStartTime() > clip->GetStartTime() && - clip->GetEndTime() + end - start > clip2->GetStartTime()) - { - wxMessageBox( - _("There is not enough room available to expand the cut line"), - _("Error"), wxICON_STOP); - return false; - } - } - } + if (clip2->GetStartTime() > clip->GetStartTime() && + clip->GetEndTime() + end - start > clip2->GetStartTime()) + // STRONG-GUARANTEE in case of this path + throw SimpleMessageBoxException{ + _("There is not enough room available to expand the cut line") + }; + } + } - if (!clip->ExpandCutLine(cutLinePosition)) - return false; + if (!clip->ExpandCutLine(cutLinePosition)) + return; - if (cutlineStart) - *cutlineStart = start; - if (cutlineEnd) - *cutlineEnd = end; + // STRONG-GUARANTEE provided that the following gives NOFAIL-GUARANTEE - // Move clips which are to the right of the cut line - if (editClipCanMove) + if (cutlineStart) + *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 false; } bool WaveTrack::RemoveCutLine(double cutLinePosition) @@ -2514,26 +2466,26 @@ bool WaveTrack::RemoveCutLine(double cutLinePosition) return false; } -bool WaveTrack::MergeClips(int clipidx1, int clipidx2) +void WaveTrack::MergeClips(int clipidx1, int clipidx2) { WaveClip* clip1 = GetClipByIndex(clipidx1); WaveClip* clip2 = GetClipByIndex(clipidx2); if (!clip1 || !clip2) // Could happen if one track of a linked pair had a split and the other didn't. - return false; + return; // Don't throw, just do nothing. // Append data from second clip to first clip if (!clip1->Paste(clip1->GetEndTime(), clip2)) - return false; + return; // Delete second clip auto it = FindClip(mClips, clip2); mClips.erase(it); - - return true; } -bool WaveTrack::Resample(int rate, ProgressDialog *progress) +void WaveTrack::Resample(int rate, ProgressDialog *progress) +// WEAK-GUARANTEE +// Partial completion may leave clips at differing sample rates! { for (const auto &clip : mClips) if (!clip->Resample(rate, progress)) @@ -2541,12 +2493,10 @@ bool WaveTrack::Resample(int rate, ProgressDialog *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 false; + return; } mRate = rate; - - return true; } namespace { diff --git a/src/WaveTrack.h b/src/WaveTrack.h index 50e922b2d..5aa22d967 100644 --- a/src/WaveTrack.h +++ b/src/WaveTrack.h @@ -150,7 +150,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { void SetVirtualState(bool state, bool half=false); #endif sampleFormat GetSampleFormat() const { return mFormat; } - bool ConvertToSampleFormat(sampleFormat format); + void ConvertToSampleFormat(sampleFormat format); const SpectrogramSettings &GetSpectrogramSettings() const; SpectrogramSettings &GetSpectrogramSettings(); @@ -175,32 +175,32 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { Track::Holder Copy(double t0, double t1, bool forClipboard = true) const override; Track::Holder CopyNonconst(double t0, double t1) /* not override */; - bool Clear(double t0, double t1) override; - bool Paste(double t0, const Track *src) override; - bool ClearAndPaste(double t0, double t1, + void Clear(double t0, double t1) override; + void Paste(double t0, const Track *src) override; + void ClearAndPaste(double t0, double t1, const Track *src, bool preserve = true, bool merge = true, const TimeWarper *effectWarper = NULL) /* not override */; - bool Silence(double t0, double t1) override; - bool InsertSilence(double t, double len) override; + void Silence(double t0, double t1) override; + void InsertSilence(double t, double len) override; - bool SplitAt(double t) /* not override */; - bool Split(double t0, double t1) /* not override */; + void SplitAt(double t) /* not override */; + void Split(double t0, double t1) /* not override */; // Track::Holder CutAndAddCutLine(double t0, double t1) /* not override */; - bool ClearAndAddCutLine(double t0, double t1) /* not override */; + void ClearAndAddCutLine(double t0, double t1) /* not override */; Track::Holder SplitCut(double t0, double t1) /* not override */; - bool SplitDelete(double t0, double t1) /* not override */; - bool Join(double t0, double t1) /* not override */; - bool Disjoin(double t0, double t1) /* not override */; + void SplitDelete(double t0, double t1) /* not override */; + void Join(double t0, double t1) /* not override */; + void Disjoin(double t0, double t1) /* not override */; - bool Trim(double t0, double t1) /* not override */; + void Trim(double t0, double t1) /* not override */; - bool HandleClear(double t0, double t1, bool addCutLines, bool split); + void HandleClear(double t0, double t1, bool addCutLines, bool split); - bool SyncLockAdjust(double oldT1, double newT1) override; + void SyncLockAdjust(double oldT1, double newT1) override; /** @brief Returns true if there are no WaveClips in the specified region * @@ -216,20 +216,20 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { * appended to that clip. If there are no WaveClips in the track, then a NEW * one is created. */ - 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(); + void Flush(); - bool AppendAlias(const wxString &fName, sampleCount start, + void AppendAlias(const wxString &fName, sampleCount start, size_t len, int channel,bool useOD); ///for use with On-Demand decoding of compressed files. ///decodeType should be an enum from ODDecodeTask that specifies what ///Type of encoded file this is, such as eODFLAC //vvv Why not use the ODTypeEnum typedef to enforce that for the parameter? - bool AppendCoded(const wxString &fName, sampleCount start, + void AppendCoded(const wxString &fName, sampleCount start, size_t len, int channel, int decodeType); ///gets an int with OD flags so that we can determine which ODTasks should be run on this track after save/open, etc. @@ -254,7 +254,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { bool Get(samplePtr buffer, sampleFormat format, sampleCount start, size_t len, fillFormat fill = fillZero, bool mayThrow = true) const; - bool Set(samplePtr buffer, sampleFormat format, + void Set(samplePtr buffer, sampleFormat format, sampleCount start, size_t len); void GetEnvelopeValues(double *buffer, size_t bufferLen, double t0) const; @@ -486,7 +486,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { // Merge two clips, that is append data from clip2 to clip1, // then remove clip2 from track. // clipidx1 and clipidx2 are indices into the clip list. - bool MergeClips(int clipidx1, int clipidx2); + void MergeClips(int clipidx1, int clipidx2); // Cache special locations (e.g. cut lines) for later speedy access void UpdateLocationsCache() const; @@ -495,7 +495,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { const std::vector &GetCachedLocations() const { return mDisplayLocationsCache; } // Expand cut line (that is, re-insert audio, then DELETE audio saved in cut line) - bool ExpandCutLine(double cutLinePosition, double* cutlineStart = NULL, double* cutlineEnd = NULL); + void ExpandCutLine(double cutLinePosition, double* cutlineStart = NULL, double* cutlineEnd = NULL); // Remove cut line, without expanding the audio in it bool RemoveCutLine(double cutLinePosition); @@ -505,7 +505,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { void Merge(const Track &orig) override; // Resample track (i.e. all clips in the track) - bool Resample(int rate, ProgressDialog *progress = NULL); + void Resample(int rate, ProgressDialog *progress = NULL); // // AutoSave related diff --git a/src/effects/ChangeSpeed.cpp b/src/effects/ChangeSpeed.cpp index 17fb84cfe..d764bbce4 100644 --- a/src/effects/ChangeSpeed.cpp +++ b/src/effects/ChangeSpeed.cpp @@ -539,7 +539,7 @@ bool EffectChangeSpeed::ProcessOne(WaveTrack * track, if (bResult) { LinearTimeWarper warper { mCurT0, mCurT0, mCurT1, mCurT0 + newLength }; - bResult = track->ClearAndPaste( + track->ClearAndPaste( mCurT0, mCurT1, outputTrack.get(), true, false, &warper); } diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index e0e36d7ed..7257a99e7 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -1278,8 +1278,6 @@ bool Effect::ProcessPass() { bool bGoodResult = true; bool isGenerator = GetType() == EffectTypeGenerate; - bool editClipCanMove; - gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove, true); FloatBuffers inBuffer, outBuffer; ArrayOf inBufPos, outBufPos; @@ -1970,8 +1968,7 @@ void Effect::GetSamples( t1 = t0 + mDuration; if (mT0 == mT1) { // Not really part of the calculation, but convenient to put here - bool bResult = track->InsertSilence(t0, t1); - wxASSERT(bResult); // TO DO: Actually handle this. + track->InsertSilence(t0, t1); } } #endif diff --git a/src/effects/Equalization.cpp b/src/effects/Equalization.cpp index 954f733fb..97d4fb631 100644 --- a/src/effects/Equalization.cpp +++ b/src/effects/Equalization.cpp @@ -1173,20 +1173,15 @@ bool EffectEqualization::ProcessOne(int count, WaveTrack * t, //remove the old audio and get the NEW t->Clear(clipStartEndTimes[i].first,clipStartEndTimes[i].second); 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()); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); - //if the clip was only partially selected, the Paste will have created a split line. Join is needed to take care of this - //This is not true when the selection is fully contained within one clip (second half of conditional) - if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first || - clipRealStartEndTimes[i].second != clipStartEndTimes[i].second) && - !(clipRealStartEndTimes[i].first <= startT && - clipRealStartEndTimes[i].second >= startT+lenT) ) - t->Join(clipRealStartEndTimes[i].first,clipRealStartEndTimes[i].second); - } + //put the processed audio in + 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 + //This is not true when the selection is fully contained within one clip (second half of conditional) + if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first || + clipRealStartEndTimes[i].second != clipStartEndTimes[i].second) && + !(clipRealStartEndTimes[i].first <= startT && + clipRealStartEndTimes[i].second >= startT+lenT) ) + t->Join(clipRealStartEndTimes[i].first,clipRealStartEndTimes[i].second); } } diff --git a/src/effects/Equalization48x.cpp b/src/effects/Equalization48x.cpp index 0a6c2170c..028d188da 100644 --- a/src/effects/Equalization48x.cpp +++ b/src/effects/Equalization48x.cpp @@ -558,19 +558,15 @@ bool EffectEqualization48x::ProcessTail(WaveTrack * t, WaveTrack * output, sampl t->Clear(clipStartEndTimes[i].first,clipStartEndTimes[i].second); // 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); - if(toClipOutput) - { - //put the processed audio in - bool bResult = t->Paste(clipStartEndTimes[i].first, toClipOutput.get()); - 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 - //This is not true when the selection is fully contained within one clip (second half of conditional) - if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first || - clipRealStartEndTimes[i].second != clipStartEndTimes[i].second) && - !(clipRealStartEndTimes[i].first <= startT && - clipRealStartEndTimes[i].second >= startT+lenT) ) - t->Join(clipRealStartEndTimes[i].first,clipRealStartEndTimes[i].second); - } + //put the processed audio in + 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 + //This is not true when the selection is fully contained within one clip (second half of conditional) + if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first || + clipRealStartEndTimes[i].second != clipStartEndTimes[i].second) && + !(clipRealStartEndTimes[i].first <= startT && + clipRealStartEndTimes[i].second >= startT+lenT) ) + t->Join(clipRealStartEndTimes[i].first,clipRealStartEndTimes[i].second); } return true; } diff --git a/src/effects/Generator.cpp b/src/effects/Generator.cpp index c366aed1e..48c025a2a 100644 --- a/src/effects/Generator.cpp +++ b/src/effects/Generator.cpp @@ -80,7 +80,7 @@ bool Generator::Process() tmp->Flush(); StepTimeWarper warper{ mT0+GetDuration(), GetDuration()-(mT1-mT0) }; - bGoodResult = track->ClearAndPaste( + track->ClearAndPaste( p->GetSel0(), p->GetSel1(), &*tmp, true, false, &warper); } diff --git a/src/effects/NoiseReduction.cpp b/src/effects/NoiseReduction.cpp index 647879780..01192b3be 100644 --- a/src/effects/NoiseReduction.cpp +++ b/src/effects/NoiseReduction.cpp @@ -1333,9 +1333,7 @@ bool EffectNoiseReduction::Worker::ProcessOne double tLen = outputTrack->LongSamplesToTime(len); // Filtering effects always end up with more data than they started with. Delete this 'tail'. outputTrack->HandleClear(tLen, outputTrack->GetEndTime(), false, false); - bool bResult = track->ClearAndPaste(t0, t0 + tLen, &*outputTrack, true, false); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + track->ClearAndPaste(t0, t0 + tLen, &*outputTrack, true, false); } return bLoopSuccess; diff --git a/src/effects/NoiseRemoval.cpp b/src/effects/NoiseRemoval.cpp index 761bf6098..5a12c0693 100644 --- a/src/effects/NoiseRemoval.cpp +++ b/src/effects/NoiseRemoval.cpp @@ -575,8 +575,7 @@ bool EffectNoiseRemoval::ProcessOne(int count, WaveTrack * track, double tLen = mOutputTrack->LongSamplesToTime(len); // Filtering effects always end up with more data than they started with. Delete this 'tail'. mOutputTrack->HandleClear(tLen, mOutputTrack->GetEndTime(), false, false); - bool bResult = track->ClearAndPaste(t0, t0 + tLen, mOutputTrack.get(), true, false); - wxASSERT(bResult); // TO DO: Actually handle this. + track->ClearAndPaste(t0, t0 + tLen, mOutputTrack.get(), true, false); } } diff --git a/src/effects/Paulstretch.cpp b/src/effects/Paulstretch.cpp index fda0397b4..72b4f66b8 100644 --- a/src/effects/Paulstretch.cpp +++ b/src/effects/Paulstretch.cpp @@ -378,11 +378,11 @@ bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int coun } } - outputTrack->Flush(); + if (!cancelled){ + outputTrack->Flush(); - track->Clear(t0,t1); - bool success = track->Paste(t0, outputTrack.get()); - if (!cancelled && success){ + track->Clear(t0,t1); + track->Paste(t0, outputTrack.get()); m_t1 = mT0 + outputTrack->GetEndTime(); } diff --git a/src/effects/Repeat.cpp b/src/effects/Repeat.cpp index cbeeddbd5..e436cc5e3 100644 --- a/src/effects/Repeat.cpp +++ b/src/effects/Repeat.cpp @@ -139,12 +139,12 @@ bool EffectRepeat::Process() auto dest = track->Copy(mT0, mT1); for(int j=0; jPaste(tc, dest.get()) || - TrackProgress(nTrack, j / repeatCount)) // TrackProgress returns true on Cancel. + if (TrackProgress(nTrack, j / repeatCount)) // TrackProgress returns true on Cancel. { bGoodResult = false; break; } + track->Paste(tc, dest.get()); tc += tLen; } if (tc > maxDestLen) diff --git a/src/effects/SBSMSEffect.cpp b/src/effects/SBSMSEffect.cpp index 8278cd7ac..eb7336d49 100644 --- a/src/effects/SBSMSEffect.cpp +++ b/src/effects/SBSMSEffect.cpp @@ -440,19 +440,12 @@ bool EffectSBSMS::Process() if(rightTrack) rb.outputRightTrack->Flush(); - bool bResult = leftTrack->ClearAndPaste(mCurT0, mCurT1, rb.outputLeftTrack.get(), true, false, warper.get()); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); if(rightTrack) - { - bResult = rightTrack->ClearAndPaste(mCurT0, mCurT1, rb.outputRightTrack.get(), true, false, warper.get()); - wxASSERT(bResult); // TO DO: Actually handle this. - } } } mCurTrackNum++; diff --git a/src/effects/Silence.cpp b/src/effects/Silence.cpp index 1085db9d2..16ca05507 100644 --- a/src/effects/Silence.cpp +++ b/src/effects/Silence.cpp @@ -97,7 +97,6 @@ bool EffectSilence::GenerateTrack(WaveTrack *tmp, const WaveTrack & WXUNUSED(track), int WXUNUSED(ntrack)) { - bool bResult = tmp->InsertSilence(0.0, GetDuration()); - wxASSERT(bResult); - return bResult; + tmp->InsertSilence(0.0, GetDuration()); + return true; } diff --git a/src/effects/StereoToMono.cpp b/src/effects/StereoToMono.cpp index f4721f067..6599f38f4 100644 --- a/src/effects/StereoToMono.cpp +++ b/src/effects/StereoToMono.cpp @@ -157,15 +157,15 @@ bool EffectStereoToMono::ProcessOne(int count) curMonoFrame = (curLeftFrame + curRightFrame) / 2.0; leftBuffer[i] = curMonoFrame; } - bResult &= mOutTrack->Append((samplePtr)leftBuffer.get(), floatSample, limit); + mOutTrack->Append((samplePtr)leftBuffer.get(), floatSample, limit); if (TrackProgress(count, 2.*(index.as_double() / (mEnd - mStart).as_double()))) return false; } double minStart = wxMin(mLeftTrack->GetStartTime(), mRightTrack->GetStartTime()); - bResult &= mLeftTrack->Clear(mLeftTrack->GetStartTime(), mLeftTrack->GetEndTime()); - bResult &= mOutTrack->Flush(); - bResult &= mLeftTrack->Paste(minStart, mOutTrack.get()); + mLeftTrack->Clear(mLeftTrack->GetStartTime(), mLeftTrack->GetEndTime()); + mOutTrack->Flush(); + mLeftTrack->Paste(minStart, mOutTrack.get()); mLeftTrack->SetLinked(false); mRightTrack->SetLinked(false); mLeftTrack->SetChannel(Track::MonoChannel); diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp index b78157608..9b4b2b275 100644 --- a/src/effects/nyquist/Nyquist.cpp +++ b/src/effects/nyquist/Nyquist.cpp @@ -998,7 +998,6 @@ bool NyquistEffect::ProcessOne() cmd += wxString::Format(wxT("(putprop '*SELECTION* (vector %s) 'PEAK)\n"), peakString) : cmd += wxString::Format(wxT("(putprop '*SELECTION* %s 'PEAK)\n"), peakString); - // TODO: Documen, PEAK-LEVEL is deprecated as of 2.1.3. // TODO: Document, PEAK-LEVEL is nil if NaN or INF. if (!std::isinf(maxPeakLevel) && !std::isnan(maxPeakLevel) && (maxPeakLevel < FLT_MAX)) { cmd += wxString::Format(wxT("(putprop '*SELECTION* (float %s) 'PEAK-LEVEL)\n"), @@ -1881,11 +1880,9 @@ int NyquistEffect::PutCallback(float *buffer, int channel, } } - if (mOutputTrack[channel]->Append((samplePtr)buffer, floatSample, len)) { - return 0; // success - } + mOutputTrack[channel]->Append((samplePtr)buffer, floatSample, len); - return -1; // failure + return 0; // success }, MakeSimpleGuard( -1 ) ); // translate all exceptions into failure } diff --git a/src/prefs/MidiIOPrefs.cpp b/src/prefs/MidiIOPrefs.cpp index 926775602..5d3b3d63f 100644 --- a/src/prefs/MidiIOPrefs.cpp +++ b/src/prefs/MidiIOPrefs.cpp @@ -175,8 +175,10 @@ void MidiIOPrefs::PopulateOrExchange( ShuttleGui & S ) { void MidiIOPrefs::OnHost(wxCommandEvent & e) { + wxString itemAtIndex; int index = mHost->GetCurrentSelection(); - wxString itemAtIndex = mHostNames.Item(index); + if (index >= 0 && index < mHostNames.Count()) + itemAtIndex = mHostNames.Item(index); int nDevices = Pm_CountDevices(); if (nDevices == 0) { diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index 6fc4b24c6..5e3442241 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -1003,9 +1003,7 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt) newTrack->InsertSilence(0.0, t0 - t1); newTrack->Flush(); wt->Clear(t1, t0); - bool bResult = wt->Paste(t1, newTrack.get()); - wxASSERT(bResult); // TO DO: Actually handle this. - wxUnusedVar(bResult); + wt->Paste(t1, newTrack.get()); } recordingTracks.push_back(wt); // Don't record more channels than configured recording pref. diff --git a/win/compile.txt b/win/compile.txt index 4352a7ce0..b4cac5c2f 100644 --- a/win/compile.txt +++ b/win/compile.txt @@ -14,7 +14,8 @@ Authors: Martyn Shaw ======================================================================== -This document is for Audacity version 2.1.2. +This document is for Audacity version 2.1.3 and is currently also valid +for building 2.2.0-alpha. If the advice here is inaccurate or incomplete, email audacity-devel@lists.sourceforge.net. @@ -41,7 +42,7 @@ To simplify the implementation of a near-identical user interface across platforms, Audacity uses wxWidgets, a GUI framework. -Audacity 2.1.2 requires wxWidgets 3.0.2. +Audacity 2.1.3 requires wxWidgets 3.0.2. To be able to build Audacity for Windows, download and install wxWidgets from http://www.wxwidgets.org/.