mirror of
https://github.com/cookiengineer/audacity
synced 2025-09-23 07:29:46 +02:00
Merge branch 'master' into HEAD
This commit is contained in:
commit
1f0e01b8ca
1
.gitignore
vendored
1
.gitignore
vendored
@ -177,6 +177,7 @@ win/Debug
|
||||
win/Release
|
||||
win/Projects/*/Debug
|
||||
win/Projects/*/Release
|
||||
win/.vs/
|
||||
|
||||
# All those help files
|
||||
help/manual*
|
||||
|
@ -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
|
||||
|
@ -3,10 +3,10 @@
|
||||
# Antonio Paniagua Navarro <aplist@gmail.com>, 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 <aplist@gmail.com>\n"
|
||||
"Language-Team: Spanish <audacity-translation@lists.sourceforge.net>\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"
|
||||
|
@ -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))
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
180
src/Menus.cpp
180
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<WaveTrack::Locker> locker;
|
||||
if (msClipProject != this && c->GetKind() == Track::Wave)
|
||||
// Cause duplication of block files on disk, when copy is
|
||||
// between projects
|
||||
locker.create(static_cast<const WaveTrack*>(c));
|
||||
|
||||
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<WaveTrack::Locker> locker;
|
||||
if ((msClipProject != this) && (pClip->GetKind() == Track::Wave))
|
||||
// Cause duplication of block files on disk, when copy is
|
||||
// between projects
|
||||
locker.create(static_cast<const WaveTrack*>(pClip));
|
||||
|
||||
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,
|
||||
|
@ -255,7 +255,7 @@ Mixer::Mixer(const WaveTrackConstArray &inputTracks,
|
||||
, mQueueMaxLen{ 65536 }
|
||||
, mSampleQueue{ mNumInputTracks, mQueueMaxLen }
|
||||
|
||||
, mNumChannels{ static_cast<size_t>(numOutChannels) }
|
||||
, mNumChannels{ numOutChannels }
|
||||
, mGains{ mNumChannels }
|
||||
|
||||
, mMayThrow{ mayThrow }
|
||||
|
@ -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<WaveTrack*>(left);
|
||||
return static_cast<WaveTrack*>(left->GetLink());
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef USE_MIDI
|
||||
NoteTrack *MixerTrackCluster::GetNote() const
|
||||
{
|
||||
return dynamic_cast< NoteTrack * >( mTrack );
|
||||
}
|
||||
#endif
|
||||
|
||||
void MixerTrackCluster::UpdatePrefs()
|
||||
{
|
||||
|
@ -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<NoteTrack>(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<NoteTrack>(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<Alg_seq>();
|
||||
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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<Track> (WaveTrack::* EditDestFunction)(double, double);
|
||||
|
||||
void EditByLabel(EditFunction action, bool bSyncLockedTracks);
|
||||
|
@ -378,8 +378,10 @@ float Sequence::GetRMS(sampleCount start, sampleCount len, bool mayThrow) const
|
||||
|
||||
std::unique_ptr<Sequence> Sequence::Copy(sampleCount s0, sampleCount s1) const
|
||||
{
|
||||
if (s0 >= s1 || s0 >= mNumSamples || s1 < 0)
|
||||
return {};
|
||||
auto dest = std::make_unique<Sequence>(mDirManager, mSampleFormat);
|
||||
if (s0 >= s1 || s0 >= mNumSamples || s1 < 0) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
int numBlocks = mBlock.size();
|
||||
|
||||
@ -391,7 +393,6 @@ std::unique_ptr<Sequence> Sequence::Copy(sampleCount s0, sampleCount s1) const
|
||||
wxUnusedVar(numBlocks);
|
||||
wxASSERT(b0 <= b1);
|
||||
|
||||
auto dest = std::make_unique<Sequence>(mDirManager, mSampleFormat);
|
||||
dest->mBlock.reserve(b1 - b0 + 1);
|
||||
|
||||
SampleBuffer buffer(mMaxSamples, mSampleFormat);
|
||||
@ -437,7 +438,8 @@ std::unique_ptr<Sequence> 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());
|
||||
|
||||
|
@ -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<Sequence> Copy(sampleCount s0, sampleCount s1) const;
|
||||
bool Paste(sampleCount s0, const Sequence *src);
|
||||
|
@ -63,20 +63,24 @@ TimeTrack::TimeTrack(const std::shared_ptr<DirManager> &projDirManager, const Zo
|
||||
blankPen.SetColour(214, 214, 214);
|
||||
}
|
||||
|
||||
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<Envelope>();
|
||||
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<Ruler>();
|
||||
@ -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<TimeTrack>( *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<const TimeTrack*>(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<TimeTrack>(*this);
|
||||
|
@ -34,11 +34,20 @@ class TimeTrack final : public Track {
|
||||
* Envelope:: and Ruler:: members in order to copy one to the other - unfortunately both lack a
|
||||
* 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; }
|
||||
|
||||
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
36
src/Track.h
36
src/Track.h
@ -206,28 +206,27 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler
|
||||
// separate from the Track.
|
||||
const std::shared_ptr<DirManager> &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<DirManager> &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 };
|
||||
|
@ -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<WaveTrack*>(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<WaveTrack*>(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().
|
||||
|
@ -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<WaveClip>
|
||||
( *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<WaveClip>
|
||||
( *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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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<WaveformSettings> &&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<WaveClip> &&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<const WaveTrack*>(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<WaveClip>( *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 {
|
||||
|
@ -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<Location> &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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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<float *> 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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -139,12 +139,12 @@ bool EffectRepeat::Process()
|
||||
auto dest = track->Copy(mT0, mT1);
|
||||
for(int j=0; j<repeatCount; j++)
|
||||
{
|
||||
if (!track->Paste(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)
|
||||
|
@ -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++;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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/.
|
||||
|
Loading…
x
Reference in New Issue
Block a user