Audacity  3.0.3
WaveTrack.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  WaveTrack.cpp
6 
7  Dominic Mazzoni
8 
9 *******************************************************************//****************************************************************//****************************************************************/
21 
29 #include "WaveTrack.h"
30 
31 
32 
33 #include "WaveClip.h"
34 
35 #include <wx/defs.h>
36 #include <wx/intl.h>
37 #include <wx/debug.h>
38 #include <wx/log.h>
39 
40 #include <float.h>
41 #include <math.h>
42 #include <algorithm>
43 
44 #include "float_cast.h"
45 
46 #include "Envelope.h"
47 #include "Sequence.h"
48 
49 #include "Project.h"
50 #include "ProjectRate.h"
51 
52 #include "Prefs.h"
53 
54 #include "effects/TimeWarper.h"
55 #include "QualitySettings.h"
57 #include "prefs/TracksPrefs.h"
59 #include "prefs/WaveformSettings.h"
60 
61 #include "InconsistencyException.h"
62 
63 #include "tracks/ui/TrackView.h"
65 
66 using std::max;
67 
68 namespace {
69 
71 {
72  if (a.size() != b.size())
73  return false;
74 
75  const auto compare = [](const WaveClip* a, const WaveClip* b) {
76  // clips are aligned if both sequence start/end
77  // points and play start/end points of the first clip match
78  // the corresponding points of the other clip
79  return a->GetPlayStartTime() == b->GetPlayStartTime() &&
80  a->GetSequenceStartTime() == b->GetSequenceStartTime() &&
81  a->GetPlayEndTime() == b->GetPlayEndTime() &&
82  a->GetSequenceEndTime() == b->GetSequenceEndTime();
83  };
84 
85  return std::mismatch(a.begin(), a.end(), b.begin(), compare).first == a.end();
86 }
87 
88 //Handles possible future file values
90 {
91  if (value < 0)
92  return Track::LinkType::None;
93  else if (value > 3)
95  return static_cast<Track::LinkType>(value);
96 }
97 
98 }
99 
101  wxT( "wavetrack" ),
102  []( AudacityProject &project ){
103  auto &trackFactory = WaveTrackFactory::Get( project );
104  auto &tracks = TrackList::Get( project );
105  auto result = tracks.Add(trackFactory.NewWaveTrack());
106  TrackView::Get( *result );
107  TrackControls::Get( *result );
108  return result;
109  }
110 };
111 
113 {
114  return std::static_pointer_cast<WaveTrack>( orig.Duplicate() );
115 }
116 
117 
119 {
120  if (format == (sampleFormat)0)
122  if (rate == 0)
123  rate = mRate.GetRate();
124  return std::make_shared<WaveTrack> ( mpFactory, format, rate );
125 }
126 
128  sampleFormat format, double rate )
129  : PlayableTrack()
130  , mpFactory(pFactory)
131 {
133 
134  mFormat = format;
135  mRate = (int) rate;
136  mGain = 1.0;
137  mPan = 0.0;
138  mOldGain[0] = 0.0;
139  mOldGain[1] = 0.0;
140  mWaveColorIndex = 0;
143  mDisplayMin = -1.0;
144  mDisplayMax = 1.0;
145  mSpectrumMin = mSpectrumMax = -1; // so values will default to settings
146  mLastScaleType = -1;
147  mLastdBRange = -1;
148 }
149 
151  PlayableTrack(orig)
152  , mpFactory( orig.mpFactory )
153  , mpSpectrumSettings(orig.mpSpectrumSettings
154  ? std::make_unique<SpectrogramSettings>(*orig.mpSpectrumSettings)
155  : nullptr
156  )
157  , mpWaveformSettings(orig.mpWaveformSettings
158  ? std::make_unique<WaveformSettings>(*orig.mpWaveformSettings)
159  : nullptr
160  )
161 {
162  mLastScaleType = -1;
163  mLastdBRange = -1;
164 
166 
167  Init(orig);
168 
169  for (const auto &clip : orig.mClips)
170  mClips.push_back
171  ( std::make_unique<WaveClip>( *clip, mpFactory, true ) );
172 }
173 
174 // Copy the track metadata but not the contents.
175 void WaveTrack::Init(const WaveTrack &orig)
176 {
177  PlayableTrack::Init(orig);
178  mpFactory = orig.mpFactory;
179 
180  mFormat = orig.mFormat;
182  mRate = orig.mRate;
183  mGain = orig.mGain;
184  mPan = orig.mPan;
185  mOldGain[0] = 0.0;
186  mOldGain[1] = 0.0;
188  SetName(orig.GetName());
189  mDisplayMin = orig.mDisplayMin;
190  mDisplayMax = orig.mDisplayMax;
191  mSpectrumMin = orig.mSpectrumMin;
192  mSpectrumMax = orig.mSpectrumMax;
193  mDisplayLocationsCache.clear();
194 }
195 
196 void WaveTrack::Reinit(const WaveTrack &orig)
197 {
198  Init(orig);
199 
200  {
201  auto &settings = orig.mpSpectrumSettings;
202  if (settings)
203  mpSpectrumSettings = std::make_unique<SpectrogramSettings>(*settings);
204  else
205  mpSpectrumSettings.reset();
206  }
207 
208  {
209  auto &settings = orig.mpWaveformSettings;
210  if (settings)
211  mpWaveformSettings = std::make_unique<WaveformSettings>(*settings);
212  else
213  mpWaveformSettings.reset();
214  }
215 }
216 
217 void WaveTrack::Merge(const Track &orig)
218 {
219  orig.TypeSwitch( [&](const WaveTrack *pwt) {
220  const WaveTrack &wt = *pwt;
221  mGain = wt.mGain;
222  mPan = wt.mPan;
226  ? std::make_unique<SpectrogramSettings>(*wt.mpSpectrumSettings) : nullptr);
228  (wt.mpWaveformSettings ? std::make_unique<WaveformSettings>(*wt.mpWaveformSettings) : nullptr);
229  });
230  PlayableTrack::Merge(orig);
231 }
232 
234 {
235 }
236 
237 double WaveTrack::GetOffset() const
238 {
239  return GetStartTime();
240 }
241 
243 void WaveTrack::SetOffset(double o)
244 {
245  double delta = o - GetOffset();
246 
247  for (const auto &clip : mClips)
248  // assume No-fail-guarantee
249  clip->Offset(delta);
250 
251  mOffset = o;
252 }
253 
255  return mChannel;
256 }
257 
259 {
261  return mChannel;
262  auto pan = GetPan();
263  if( pan < -0.99 )
264  return Track::LeftChannel;
265  if( pan > 0.99 )
266  return Track::RightChannel;
267  return mChannel;
268 }
269 
271 {
273  SetPan( -1.0f );
274  else if( mChannel == Track::RightChannel )
275  SetPan( 1.0f );
276 }
277 
279 {
281 
282  auto linkType = GetLinkType();
283  if (static_cast<int>(linkType) == 1 || //Comes from old audacity version
284  linkType == LinkType::Aligned)
285  {
286  auto next = dynamic_cast<WaveTrack*>(*std::next(GetOwner()->Find(this)));
287  if (next == nullptr)
288  {
289  //next track is not a wave track, fix and report error
290  wxLogWarning(
291  wxT("Right track %s is expected to be a WaveTrack.\n Removing link from left wave track %s."),
292  next->GetName(), GetName());
295  err = true;
296  }
297  else
298  {
299  auto newLinkType = AreAligned(SortedClipArray(), next->SortedClipArray())
301  //not an error
302  if (newLinkType != linkType)
303  SetLinkType(newLinkType);
304  }
305  }
306  return !err;
307 }
308 
309 
311 {
313 }
314 
316 {
318 }
319 
320 void WaveTrack::GetDisplayBounds(float *min, float *max) const
321 {
322  *min = mDisplayMin;
323  *max = mDisplayMax;
324 }
325 
326 void WaveTrack::SetDisplayBounds(float min, float max) const
327 {
328  mDisplayMin = min;
329  mDisplayMax = max;
330 }
331 
332 void WaveTrack::GetSpectrumBounds(float *min, float *max) const
333 {
334  const double rate = GetRate();
335 
337  const SpectrogramSettings::ScaleType type = settings.scaleType;
338 
339  const float top = (rate / 2.);
340 
341  float bottom;
342  if (type == SpectrogramSettings::stLinear)
343  bottom = 0.0f;
344  else if (type == SpectrogramSettings::stPeriod) {
345  // special case
346  const auto half = settings.GetFFTLength() / 2;
347  // EAC returns no data for below this frequency:
348  const float bin2 = rate / half;
349  bottom = bin2;
350  }
351  else
352  // logarithmic, etc.
353  bottom = 1.0f;
354 
355  {
356  float spectrumMax = mSpectrumMax;
357  if (spectrumMax < 0)
358  spectrumMax = settings.maxFreq;
359  if (spectrumMax < 0)
360  *max = top;
361  else
362  *max = std::max(bottom, std::min(top, spectrumMax));
363  }
364 
365  {
366  float spectrumMin = mSpectrumMin;
367  if (spectrumMin < 0)
368  spectrumMin = settings.minFreq;
369  if (spectrumMin < 0)
370  *min = std::max(bottom, top / 1000.0f);
371  else
372  *min = std::max(bottom, std::min(top, spectrumMin));
373  }
374 }
375 
376 void WaveTrack::SetSpectrumBounds(float min, float max) const
377 {
378  mSpectrumMin = min;
379  mSpectrumMax = max;
380 }
381 
382 int WaveTrack::ZeroLevelYCoordinate(wxRect rect) const
383 {
384  return rect.GetTop() +
385  (int)((mDisplayMax / (mDisplayMax - mDisplayMin)) * rect.height);
386 }
387 
388 template< typename Container >
389 static Container MakeIntervals(const std::vector<WaveClipHolder> &clips)
390 {
391  Container result;
392  for (const auto &clip: clips) {
393  result.emplace_back( clip->GetPlayStartTime(), clip->GetPlayEndTime(),
394  std::make_unique<WaveTrack::IntervalData>( clip ) );
395  }
396  return result;
397 }
398 
400 {
401  auto &trackFactory = WaveTrackFactory::Get( project );
402  auto &pSampleBlockFactory = trackFactory.GetSampleBlockFactory();
403  auto pNewTrack = EmptyCopy( pSampleBlockFactory );
404  pNewTrack->Paste(0.0, this);
405  return pNewTrack;
406 }
407 
409 {
410  return MakeIntervals<ConstIntervals>( mClips );
411 }
412 
414 {
415  return MakeIntervals<Intervals>( mClips );
416 }
417 
418 const WaveClip* WaveTrack::FindClipByName(const wxString& name) const
419 {
420  for (const auto& clip : mClips)
421  {
422  if (clip->GetName() == name)
423  return clip.get();
424  }
425  return nullptr;
426 }
427 
429 {
430  return std::make_shared<WaveTrack>( *this );
431 }
432 
433 wxString WaveTrack::MakeClipCopyName(const wxString& originalName) const
434 {
435  auto name = originalName;
436  for (auto i = 1;; ++i)
437  {
438  if (FindClipByName(name) == nullptr)
439  return name;
440  //i18n-hint Template for clip name generation on copy-paste
441  name = XC("%s.%i", "clip name template").Format(originalName, i).Translation();
442  }
443 }
444 
446 {
447  auto name = GetName();
448  for (auto i = 1;; ++i)
449  {
450  if (FindClipByName(name) == nullptr)
451  return name;
452  //i18n-hint Template for clip name generation on inserting new empty clip
453  name = XC("%s %i", "clip name template").Format(GetName(), i).Translation();
454  }
455 }
456 
457 double WaveTrack::GetRate() const
458 {
459  return mRate;
460 }
461 
462 void WaveTrack::SetRate(double newRate)
463 {
464  wxASSERT( newRate > 0 );
465  newRate = std::max( 1.0, newRate );
466  auto ratio = mRate / newRate;
467  mRate = (int) newRate;
468  for (const auto &clip : mClips) {
469  clip->SetRate((int)newRate);
470  clip->SetSequenceStartTime( clip->GetSequenceStartTime() * ratio );
471  }
472 }
473 
474 float WaveTrack::GetGain() const
475 {
476  return mGain;
477 }
478 
479 void WaveTrack::SetGain(float newGain)
480 {
481  if (mGain != newGain) {
482  mGain = newGain;
483  Notify();
484  }
485 }
486 
487 float WaveTrack::GetPan() const
488 {
489  return mPan;
490 }
491 
492 void WaveTrack::SetPan(float newPan)
493 {
494  if (newPan > 1.0)
495  newPan = 1.0;
496  else if (newPan < -1.0)
497  newPan = -1.0;
498 
499  if ( mPan != newPan ) {
500  mPan = newPan;
501  Notify();
502  }
503 }
504 
505 float WaveTrack::GetChannelGain(int channel) const
506 {
507  float left = 1.0;
508  float right = 1.0;
509 
510  if (mPan < 0)
511  right = (mPan + 1.0);
512  else if (mPan > 0)
513  left = 1.0 - mPan;
514 
515  if ((channel%2) == 0)
516  return left*mGain;
517  else
518  return right*mGain;
519 }
520 
521 float WaveTrack::GetOldChannelGain(int channel) const
522 {
523  return mOldGain[channel%2];
524 }
525 
526 void WaveTrack::SetOldChannelGain(int channel, float gain)
527 {
528  mOldGain[channel % 2] = gain;
529 }
530 
531 
532 
534 void WaveTrack::SetWaveColorIndex(int colorIndex)
535 {
536  for (const auto &clip : mClips)
537  clip->SetColourIndex( colorIndex );
538  mWaveColorIndex = colorIndex;
539 }
540 
542 {
543  sampleCount result{ 0 };
544 
545  for (const auto& clip : mClips)
546  result += clip->GetPlaySamplesCount();
547 
548  return result;
549 }
550 
552 {
553  sampleCount result{ 0 };
554 
555  for (const auto& clip : mClips)
556  result += clip->GetSequenceSamplesCount();
557 
558  return result;
559 }
560 
563  const std::function<void(size_t)> & progressReport)
564 {
565  for (const auto& clip : mClips)
566  clip->ConvertToSampleFormat(format, progressReport);
567  mFormat = format;
568 }
569 
570 
571 bool WaveTrack::IsEmpty(double t0, double t1) const
572 {
573  if (t0 > t1)
574  return true;
575 
576  //wxPrintf("Searching for overlap in %.6f...%.6f\n", t0, t1);
577  for (const auto &clip : mClips)
578  {
579  if (!clip->BeforePlayStartTime(t1) && !clip->AfterPlayEndTime(t0)) {
580  //wxPrintf("Overlapping clip: %.6f...%.6f\n",
581  // clip->GetStartTime(),
582  // clip->GetEndTime());
583  // We found a clip that overlaps this region
584  return false;
585  }
586  }
587  //wxPrintf("No overlap found\n");
588 
589  // Otherwise, no clips overlap this region
590  return true;
591 }
592 
593 Track::Holder WaveTrack::Cut(double t0, double t1)
594 {
595  if (t1 < t0)
597 
598  auto tmp = Copy(t0, t1);
599 
600  Clear(t0, t1);
601 
602  return tmp;
603 }
604 
606 Track::Holder WaveTrack::SplitCut(double t0, double t1)
607 {
608  if (t1 < t0)
610 
611  // SplitCut is the same as 'Copy', then 'SplitDelete'
612  auto tmp = Copy(t0, t1);
613 
614  SplitDelete(t0, t1);
615 
616  return tmp;
617 }
618 
619 #if 0
620 Track::Holder WaveTrack::CutAndAddCutLine(double t0, double t1)
621 {
622  if (t1 < t0)
624 
625  // Cut is the same as 'Copy', then 'Delete'
626  auto tmp = Copy(t0, t1);
627 
628  ClearAndAddCutLine(t0, t1);
629 
630  return tmp;
631 }
632 #endif
633 
634 
635 
636 //Trim trims within a clip, rather than trimming everything.
637 //If a bound is outside a clip, it trims everything.
639 void WaveTrack::Trim (double t0, double t1)
640 {
641  bool inside0 = false;
642  bool inside1 = false;
643 
644  for (const auto &clip : mClips)
645  {
646  if(t1 > clip->GetPlayStartTime() && t1 < clip->GetPlayEndTime())
647  {
648  clip->SetTrimRight(clip->GetTrimRight() + clip->GetPlayEndTime() - t1);
649  inside1 = true;
650  }
651 
652  if(t0 > clip->GetPlayStartTime() && t0 < clip->GetPlayEndTime())
653  {
654  clip->SetTrimLeft(clip->GetTrimLeft() + t0 - clip->GetPlayStartTime());
655  inside0 = true;
656  }
657  }
658 
659  //if inside0 is false, then the left selector was between
660  //clips, so DELETE everything to its left.
661  if(!inside1 && t1 < GetEndTime())
662  Clear(t1,GetEndTime());
663 
664  if(!inside0 && t0 > GetStartTime())
665  SplitDelete(GetStartTime(), t0);
666 }
667 
668 
669 
670 
672  const SampleBlockFactoryPtr &pFactory ) const
673 {
674  auto result = std::make_shared<WaveTrack>( pFactory, mFormat, mRate );
675  result->Init(*this);
676  result->mpFactory = pFactory ? pFactory : mpFactory;
677  return result;
678 }
679 
680 Track::Holder WaveTrack::Copy(double t0, double t1, bool forClipboard) const
681 {
682  if (t1 < t0)
684 
685  auto result = EmptyCopy();
686  WaveTrack *newTrack = result.get();
687 
688  // PRL: Why shouldn't cutlines be copied and pasted too? I don't know, but
689  // that was the old behavior. But this function is also used by the
690  // Duplicate command and I changed its behavior in that case.
691 
692  for (const auto &clip : mClips)
693  {
694  if (t0 <= clip->GetPlayStartTime() && t1 >= clip->GetPlayEndTime())
695  {
696  // Whole clip is in copy region
697  //wxPrintf("copy: clip %i is in copy region\n", (int)clip);
698 
699  newTrack->mClips.push_back
700  (std::make_unique<WaveClip>(*clip, mpFactory, ! forClipboard));
701  WaveClip *const newClip = newTrack->mClips.back().get();
702  newClip->Offset(-t0);
703  }
704  else if (t1 > clip->GetPlayStartTime() && t0 < clip->GetPlayEndTime())
705  {
706  // Clip is affected by command
707  //wxPrintf("copy: clip %i is affected by command\n", (int)clip);
708 
709  const double clip_t0 = std::max(t0, clip->GetPlayStartTime());
710  const double clip_t1 = std::min(t1, clip->GetPlayEndTime());
711 
712  auto newClip = std::make_unique<WaveClip>
713  (*clip, mpFactory, ! forClipboard, clip_t0, clip_t1);
714  newClip->SetName(clip->GetName());
715 
716  //wxPrintf("copy: clip_t0=%f, clip_t1=%f\n", clip_t0, clip_t1);
717 
718  newClip->Offset(-t0);
719  if (newClip->GetPlayStartTime() < 0)
720  newClip->SetPlayStartTime(0);
721 
722  newTrack->mClips.push_back(std::move(newClip)); // transfer ownership
723  }
724  }
725 
726  // AWD, Oct 2009: If the selection ends in whitespace, create a placeholder
727  // clip representing that whitespace
728  // PRL: Only if we want the track for pasting into other tracks. Not if it
729  // goes directly into a project as in the Duplicate command.
730  if (forClipboard &&
731  newTrack->GetEndTime() + 1.0 / newTrack->GetRate() < t1 - t0)
732  {
733  auto placeholder = std::make_unique<WaveClip>(mpFactory,
734  newTrack->GetSampleFormat(),
735  static_cast<int>(newTrack->GetRate()),
736  0 /*colourindex*/);
737  placeholder->SetIsPlaceholder(true);
738  placeholder->InsertSilence(0, (t1 - t0) - newTrack->GetEndTime());
739  placeholder->Offset(newTrack->GetEndTime());
740  newTrack->mClips.push_back(std::move(placeholder)); // transfer ownership
741  }
742 
743  return result;
744 }
745 
747 {
748  return Copy(t0, t1);
749 }
750 
752 void WaveTrack::Clear(double t0, double t1)
753 {
754  HandleClear(t0, t1, false, false);
755 }
756 
758 void WaveTrack::ClearAndAddCutLine(double t0, double t1)
759 {
760  HandleClear(t0, t1, true, false);
761 }
762 
764 {
765  if (mpSpectrumSettings)
766  return *mpSpectrumSettings;
767  else
769 }
770 
772 {
773  if (mpSpectrumSettings)
774  return *mpSpectrumSettings;
775  else
777 }
778 
780 {
781  if (!mpSpectrumSettings)
783  std::make_unique<SpectrogramSettings>(SpectrogramSettings::defaults());
784  return *mpSpectrumSettings;
785 }
786 
787 void WaveTrack::SetSpectrogramSettings(std::unique_ptr<SpectrogramSettings> &&pSettings)
788 {
789  if (mpSpectrumSettings != pSettings) {
790  mpSpectrumSettings = std::move(pSettings);
791  }
792 }
793 
795 {
796  if( bUse ){
797  if( !mpSpectrumSettings )
798  return;
799  // reset it, and next we will be getting the defaults.
800  mpSpectrumSettings.reset();
801  }
802  else {
803  if( mpSpectrumSettings )
804  return;
806  }
807 }
808 
809 
810 
812 {
813  // Create on demand
814  return const_cast<WaveTrack*>(this)->GetWaveformSettings();
815 }
816 
818 {
819  // Create on demand
820  if (!mpWaveformSettings)
821  mpWaveformSettings = std::make_unique<WaveformSettings>(WaveformSettings::defaults());
822  return *mpWaveformSettings;
823 }
824 
825 void WaveTrack::SetWaveformSettings(std::unique_ptr<WaveformSettings> &&pSettings)
826 {
827  if (mpWaveformSettings != pSettings) {
828  mpWaveformSettings = std::move(pSettings);
829  }
830 }
831 
832 //
833 // ClearAndPaste() is a specialized version of HandleClear()
834 // followed by Paste() and is used mostly by effects that
835 // can't replace track data directly using Get()/Set().
836 //
837 // HandleClear() removes any cut/split lines with the
838 // cleared range, but, in most cases, effects want to preserve
839 // the existing cut/split lines, so they are saved before the
840 // HandleClear()/Paste() and restored after.
841 //
842 // If the pasted track overlaps two or more clips, then it will
843 // be pasted with visible split lines. Normally, effects do not
844 // want these extra lines, so they may be merged out.
845 //
848 void WaveTrack::ClearAndPaste(double t0, // Start of time to clear
849  double t1, // End of time to clear
850  const Track *src, // What to paste
851  bool preserve, // Whether to reinsert splits/cuts
852  bool merge, // Whether to remove 'extra' splits
853  const TimeWarper *effectWarper // How does time change
854  )
855 {
856  double dur = std::min(t1 - t0, src->GetEndTime());
857 
858  // If duration is 0, then it's just a plain paste
859  if (dur == 0.0) {
860  // use Weak-guarantee
861  Paste(t0, src);
862  return;
863  }
864 
865  std::vector<double> splits;
866  WaveClipHolders cuts;
867 
868  // If provided time warper was NULL, use a default one that does nothing
869  IdentityTimeWarper localWarper;
870  const TimeWarper *warper = (effectWarper ? effectWarper : &localWarper);
871 
872  // Align to a sample
875 
876  // Save the cut/split lines whether preserving or not since merging
877  // needs to know if a clip boundary is being crossed since Paste()
878  // will add split lines around the pasted clip if so.
879  for (const auto &clip : mClips) {
880  double st;
881 
882  // Remember clip boundaries as locations to split
883  st = LongSamplesToTime(TimeToLongSamples(clip->GetPlayStartTime()));
884  if (st >= t0 && st <= t1 && !make_iterator_range(splits).contains(st)) {
885  splits.push_back(st);
886  }
887 
888  st = LongSamplesToTime(TimeToLongSamples(clip->GetPlayEndTime()));
889  if (st >= t0 && st <= t1 && !make_iterator_range(splits).contains(st)) {
890  splits.push_back(st);
891  }
892 
893  // Search for cut lines
894  auto &cutlines = clip->GetCutLines();
895  // May erase from cutlines, so don't use range-for
896  for (auto it = cutlines.begin(); it != cutlines.end(); ) {
897  WaveClip *cut = it->get();
898  double cs = LongSamplesToTime(TimeToLongSamples(clip->GetSequenceStartTime() +
899  cut->GetSequenceStartTime()));
900 
901  // Remember cut point
902  if (cs >= t0 && cs <= t1) {
903 
904  // Remember the absolute offset and add to our cuts array.
905  cut->SetSequenceStartTime(cs);
906  cuts.push_back(std::move(*it)); // transfer ownership!
907  it = cutlines.erase(it);
908  }
909  else
910  ++it;
911  }
912  }
913 
914  const auto tolerance = 2.0 / GetRate();
915 
916  // Now, clear the selection
917  HandleClear(t0, t1, false, false);
918  {
919 
920  // And paste in the NEW data
921  Paste(t0, src);
922  {
923  // First, merge the NEW clip(s) in with the existing clips
924  if (merge && splits.size() > 0)
925  {
926  // Now t1 represents the absolute end of the pasted data.
927  t1 = t0 + src->GetEndTime();
928 
929  // Get a sorted array of the clips
930  auto clips = SortedClipArray();
931 
932  // Scan the sorted clips for the first clip whose start time
933  // exceeds the pasted regions end time.
934  {
935  WaveClip *prev = nullptr;
936  for (const auto clip : clips) {
937  // Merge this clip and the previous clip if the end time
938  // falls within it and this isn't the first clip in the track.
939  if (fabs(t1 - clip->GetPlayStartTime()) < tolerance) {
940  if (prev)
941  MergeClips(GetClipIndex(prev), GetClipIndex(clip));
942  break;
943  }
944  prev = clip;
945  }
946  }
947  }
948 
949  // Refill the array since clips have changed.
950  auto clips = SortedClipArray();
951 
952  {
953  // Scan the sorted clips to look for the start of the pasted
954  // region.
955  WaveClip *prev = nullptr;
956  for (const auto clip : clips) {
957  if (prev) {
958  // It must be that clip is what was pasted and it begins where
959  // prev ends.
960  // use Weak-guarantee
961  MergeClips(GetClipIndex(prev), GetClipIndex(clip));
962  break;
963  }
964  if (fabs(t0 - clip->GetPlayEndTime()) < tolerance)
965  // Merge this clip and the next clip if the start time
966  // falls within it and this isn't the last clip in the track.
967  prev = clip;
968  else
969  prev = nullptr;
970  }
971  }
972  }
973 
974  // Restore cut/split lines
975  if (preserve) {
976 
977  // Restore the split lines, transforming the position appropriately
978  for (const auto split: splits) {
979  SplitAt(warper->Warp(split));
980  }
981 
982  // Restore the saved cut lines, also transforming if time altered
983  for (const auto &clip : mClips) {
984  double st;
985  double et;
986 
987  st = clip->GetPlayStartTime();
988  et = clip->GetPlayEndTime();
989 
990  // Scan the cuts for any that live within this clip
991  for (auto it = cuts.begin(); it != cuts.end();) {
992  WaveClip *cut = it->get();
993  //cutlines in this array were orphaned previously
994  double cs = cut->GetSequenceStartTime();
995 
996  // Offset the cut from the start of the clip and add it to
997  // this clips cutlines.
998  if (cs >= st && cs <= et) {
999  cut->SetSequenceStartTime(warper->Warp(cs) - st);
1000  clip->GetCutLines().push_back( std::move(*it) ); // transfer ownership!
1001  it = cuts.erase(it);
1002  }
1003  else
1004  ++it;
1005  }
1006  }
1007  }
1008  }
1009 }
1010 
1012 void WaveTrack::SplitDelete(double t0, double t1)
1013 {
1014  bool addCutLines = false;
1015  bool split = true;
1016  HandleClear(t0, t1, addCutLines, split);
1017 }
1018 
1019 namespace
1020 {
1021  WaveClipHolders::const_iterator
1022  FindClip(const WaveClipHolders &list, const WaveClip *clip, int *distance = nullptr)
1023  {
1024  if (distance)
1025  *distance = 0;
1026  auto it = list.begin();
1027  for (const auto end = list.end(); it != end; ++it)
1028  {
1029  if (it->get() == clip)
1030  break;
1031  if (distance)
1032  ++*distance;
1033  }
1034  return it;
1035  }
1036 
1037  WaveClipHolders::iterator
1038  FindClip(WaveClipHolders &list, const WaveClip *clip, int *distance = nullptr)
1039  {
1040  if (distance)
1041  *distance = 0;
1042  auto it = list.begin();
1043  for (const auto end = list.end(); it != end; ++it)
1044  {
1045  if (it->get() == clip)
1046  break;
1047  if (distance)
1048  ++*distance;
1049  }
1050  return it;
1051  }
1052 }
1053 
1054 std::shared_ptr<WaveClip> WaveTrack::RemoveAndReturnClip(WaveClip* clip)
1055 {
1056  // Be clear about who owns the clip!!
1057  auto it = FindClip(mClips, clip);
1058  if (it != mClips.end()) {
1059  auto result = std::move(*it); // Array stops owning the clip, before we shrink it
1060  mClips.erase(it);
1061  return result;
1062  }
1063  else
1064  return {};
1065 }
1066 
1067 bool WaveTrack::AddClip(const std::shared_ptr<WaveClip> &clip)
1068 {
1069  if (clip->GetSequence()->GetFactory() != this->mpFactory)
1070  return false;
1071 
1072  // Uncomment the following line after we correct the problem of zero-length clips
1073  //if (CanInsertClip(clip))
1074  mClips.push_back(clip); // transfer ownership
1075 
1076  return true;
1077 }
1078 
1080 void WaveTrack::HandleClear(double t0, double t1,
1081  bool addCutLines, bool split)
1082 {
1083  // For debugging, use an ASSERT so that we stop
1084  // closer to the problem.
1085  wxASSERT( t1 >= t0 );
1086  if (t1 < t0)
1088 
1089  bool editClipCanMove = GetEditClipsCanMove();
1090 
1091  WaveClipPointers clipsToDelete;
1092  WaveClipHolders clipsToAdd;
1093 
1094  // We only add cut lines when deleting in the middle of a single clip
1095  // The cut line code is not really prepared to handle other situations
1096  if (addCutLines)
1097  {
1098  for (const auto &clip : mClips)
1099  {
1100  if (!clip->BeforePlayStartTime(t1) && !clip->AfterPlayEndTime(t0) &&
1101  (clip->BeforePlayStartTime(t0) || clip->AfterPlayEndTime(t1)))
1102  {
1103  addCutLines = false;
1104  break;
1105  }
1106  }
1107  }
1108 
1109  for (const auto &clip : mClips)
1110  {
1111  if (clip->BeforePlayStartTime(t0) && clip->AfterPlayEndTime(t1))
1112  {
1113  // Whole clip must be deleted - remember this
1114  clipsToDelete.push_back(clip.get());
1115  }
1116  else if (!clip->BeforePlayStartTime(t1) && !clip->AfterPlayEndTime(t0))
1117  {
1118  // Clip data is affected by command
1119  if (addCutLines)
1120  {
1121  // Don't modify this clip in place, because we want a strong
1122  // guarantee, and might modify another clip
1123  clipsToDelete.push_back( clip.get() );
1124  auto newClip = std::make_unique<WaveClip>( *clip, mpFactory, true );
1125  newClip->ClearAndAddCutLine( t0, t1 );
1126  clipsToAdd.push_back( std::move( newClip ) );
1127  }
1128  else
1129  {
1130  if (split) {
1131  // Three cases:
1132 
1133  if (clip->BeforePlayStartTime(t0)) {
1134  // Delete from the left edge
1135 
1136  // Don't modify this clip in place, because we want a strong
1137  // guarantee, and might modify another clip
1138  clipsToDelete.push_back( clip.get() );
1139  auto newClip = std::make_unique<WaveClip>( *clip, mpFactory, true );
1140  newClip->TrimLeft(t1 - clip->GetPlayStartTime());
1141  clipsToAdd.push_back( std::move( newClip ) );
1142  }
1143  else if (clip->AfterPlayEndTime(t1)) {
1144  // Delete to right edge
1145 
1146  // Don't modify this clip in place, because we want a strong
1147  // guarantee, and might modify another clip
1148  clipsToDelete.push_back( clip.get() );
1149  auto newClip = std::make_unique<WaveClip>( *clip, mpFactory, true );
1150  newClip->TrimRight(clip->GetPlayEndTime() - t0);
1151 
1152  clipsToAdd.push_back( std::move( newClip ) );
1153  }
1154  else {
1155  // Delete in the middle of the clip...we actually create two
1156  // NEW clips out of the left and right halves...
1157 
1158  auto leftClip = std::make_unique<WaveClip>(*clip, mpFactory, true);
1159  leftClip->TrimRight(clip->GetPlayEndTime() - t0);
1160  clipsToAdd.push_back(std::move(leftClip));
1161 
1162  auto rightClip = std::make_unique<WaveClip>(*clip, mpFactory, true);
1163  rightClip->TrimLeft(t1 - rightClip->GetPlayStartTime());
1164  clipsToAdd.push_back(std::move(rightClip));
1165 
1166  clipsToDelete.push_back(clip.get());
1167  }
1168  }
1169  else {
1170  // (We are not doing a split cut)
1171 
1172  // Don't modify this clip in place, because we want a strong
1173  // guarantee, and might modify another clip
1174  clipsToDelete.push_back( clip.get() );
1175  auto newClip = std::make_unique<WaveClip>( *clip, mpFactory, true );
1176 
1177  // clip->Clear keeps points < t0 and >= t1 via Envelope::CollapseRegion
1178  newClip->Clear(t0,t1);
1179 
1180  clipsToAdd.push_back( std::move( newClip ) );
1181  }
1182  }
1183  }
1184  }
1185 
1186  // Only now, change the contents of this track
1187  // use No-fail-guarantee for the rest
1188 
1189  if (!split && editClipCanMove)
1190  {
1191  // Clip is "behind" the region -- offset it unless we're splitting
1192  // or we're using the "don't move other clips" mode
1193  for (const auto& clip : mClips)
1194  {
1195  if (clip->BeforePlayStartTime(t1))
1196  clip->Offset(-(t1 - t0));
1197  }
1198  }
1199 
1200  for (const auto &clip: clipsToDelete)
1201  {
1202  auto myIt = FindClip(mClips, clip);
1203  if (myIt != mClips.end())
1204  mClips.erase(myIt); // deletes the clip!
1205  else
1206  wxASSERT(false);
1207  }
1208 
1209  for (auto &clip: clipsToAdd)
1210  mClips.push_back(std::move(clip)); // transfer ownership
1211 }
1212 
1213 void WaveTrack::SyncLockAdjust(double oldT1, double newT1)
1214 {
1215  if (newT1 > oldT1) {
1216  // Insert space within the track
1217 
1218  // JKC: This is a rare case where using >= rather than > on a float matters.
1219  // GetEndTime() looks through the clips and may give us EXACTLY the same
1220  // value as T1, when T1 was set to be at the end of one of those clips.
1221  if (oldT1 >= GetEndTime())
1222  return;
1223 
1224  // If track is empty at oldT1 insert whitespace; otherwise, silence
1225  if (IsEmpty(oldT1, oldT1))
1226  {
1227  // Check if clips can move
1228  bool clipsCanMove = true;
1229  gPrefs->Read(wxT("/GUI/EditClipCanMove"), &clipsCanMove);
1230  if (clipsCanMove) {
1231  auto tmp = Cut (oldT1, GetEndTime() + 1.0/GetRate());
1232 
1233  Paste(newT1, tmp.get());
1234  }
1235  return;
1236  }
1237  else {
1238  // AWD: Could just use InsertSilence() on its own here, but it doesn't
1239  // follow EditClipCanMove rules (Paste() does it right)
1240  auto tmp = std::make_shared<WaveTrack>(
1242 
1243  tmp->InsertSilence(0.0, newT1 - oldT1);
1244  tmp->Flush();
1245  Paste(oldT1, tmp.get());
1246  }
1247  }
1248  else if (newT1 < oldT1) {
1249  Clear(newT1, oldT1);
1250  }
1251 }
1252 
1253 void WaveTrack::PasteWaveTrack(double t0, const WaveTrack* other)
1254 {
1255  //
1256  // Pasting is a bit complicated, because with the existence of multiclip mode,
1257  // we must guess the behaviour the user wants.
1258  //
1259  // Currently, two modes are implemented:
1260  //
1261  // - If a single clip should be pasted, and it should be pasted inside another
1262  // clip, no NEW clips are generated. The audio is simply inserted.
1263  // This resembles the old (pre-multiclip support) behaviour. However, if
1264  // the clip is pasted outside of any clip, a NEW clip is generated. This is
1265  // the only behaviour which is different to what was done before, but it
1266  // shouldn't confuse users too much.
1267  //
1268  // - If multiple clips should be pasted, or a single clip that does not fill
1269  // the duration of the pasted track, these are always pasted as single
1270  // clips, and the current clip is split, when necessary. This may seem
1271  // strange at first, but it probably is better than trying to auto-merge
1272  // anything. The user can still merge the clips by hand (which should be a
1273  // simple command reachable by a hotkey or single mouse click).
1274  //
1275 
1276  if (other->GetNumClips() == 0)
1277  return;
1278 
1279  //wxPrintf("paste: we have at least one clip\n");
1280 
1281  bool singleClipMode = (other->GetNumClips() == 1 &&
1282  other->GetStartTime() == 0.0);
1283 
1284  const double insertDuration = other->GetEndTime();
1285  if (insertDuration != 0 && insertDuration < 1.0 / mRate)
1286  // PRL: I added this check to avoid violations of preconditions in other WaveClip and Sequence
1287  // methods, but allow the value 0 so I don't subvert the purpose of commit
1288  // 739422ba70ceb4be0bb1829b6feb0c5401de641e which causes append-recording always to make
1289  // a new clip.
1290  return;
1291 
1292  //wxPrintf("Check if we need to make room for the pasted data\n");
1293 
1294  auto pastingFromTempTrack = !other->GetOwner();
1295  bool editClipCanMove = GetEditClipsCanMove();
1296 
1297  // Make room for the pasted data
1298  if (editClipCanMove) {
1299  if (!singleClipMode) {
1300  // We need to insert multiple clips, so split the current clip and
1301  // move everything to the right, then try to paste again
1302  if (!IsEmpty(t0, GetEndTime())) {
1303  auto tmp = Cut(t0, GetEndTime() + 1.0 / mRate);
1304  Paste(t0 + insertDuration, tmp.get());
1305  }
1306  }
1307  else {
1308  // We only need to insert one single clip, so just move all clips
1309  // to the right of the paste point out of the way
1310  for (const auto& clip : mClips)
1311  {
1312  if (clip->GetPlayStartTime() > t0 - (1.0 / mRate))
1313  clip->Offset(insertDuration);
1314  }
1315  }
1316  }
1317 
1318  if (singleClipMode)
1319  {
1320  // Single clip mode
1321  // wxPrintf("paste: checking for single clip mode!\n");
1322 
1323  WaveClip* insideClip = nullptr;
1324 
1325  for (const auto& clip : mClips)
1326  {
1327  if (editClipCanMove)
1328  {
1329  if (clip->WithinPlayRegion(t0))
1330  {
1331  //wxPrintf("t0=%.6f: inside clip is %.6f ... %.6f\n",
1332  // t0, clip->GetStartTime(), clip->GetEndTime());
1333  insideClip = clip.get();
1334  break;
1335  }
1336  }
1337  else
1338  {
1339  // If clips are immovable we also allow prepending to clips
1340  if (clip->WithinPlayRegion(t0) ||
1341  TimeToLongSamples(t0) == clip->GetPlayStartSample())
1342  {
1343  insideClip = clip.get();
1344  break;
1345  }
1346  }
1347  }
1348 
1349  if (insideClip)
1350  {
1351  // Exhibit traditional behaviour
1352  //wxPrintf("paste: traditional behaviour\n");
1353  if (!editClipCanMove)
1354  {
1355  // We did not move other clips out of the way already, so
1356  // check if we can paste without having to move other clips
1357  for (const auto& clip : mClips)
1358  {
1359  if (clip->GetPlayStartTime() > insideClip->GetPlayStartTime() &&
1360  insideClip->GetPlayEndTime() + insertDuration >
1361  clip->GetPlayStartTime())
1362  // Strong-guarantee in case of this path
1363  // not that it matters.
1366  XO("There is not enough room available to paste the selection"),
1367  XO("Warning"),
1368  "Error:_Insufficient_space_in_track"
1369  };
1370  }
1371  }
1372  insideClip->Paste(t0, other->GetClipByIndex(0));
1373  return;
1374  }
1375  // Just fall through and exhibit NEW behaviour
1376  }
1377 
1378  // Insert NEW clips
1379  //wxPrintf("paste: multi clip mode!\n");
1380 
1381  if (!editClipCanMove && !IsEmpty(t0, t0 + insertDuration - 1.0 / mRate))
1382  // Strong-guarantee in case of this path
1383  // not that it matters.
1386  XO("There is not enough room available to paste the selection"),
1387  XO("Warning"),
1388  "Error:_Insufficient_space_in_track"
1389  };
1390 
1391  for (const auto& clip : other->mClips)
1392  {
1393  // AWD Oct. 2009: Don't actually paste in placeholder clips
1394  if (!clip->GetIsPlaceholder())
1395  {
1396  auto newClip =
1397  std::make_unique<WaveClip>(*clip, mpFactory, true);
1398  newClip->Resample(mRate);
1399  newClip->Offset(t0);
1400  newClip->MarkChanged();
1401  if (pastingFromTempTrack)
1402  //Clips from the tracks which aren't bound to any TrackList are
1403  //considered to be new entities, thus named using "new" name template
1404  newClip->SetName(MakeNewClipName());
1405  else
1406  newClip->SetName(MakeClipCopyName(clip->GetName()));
1407  mClips.push_back(std::move(newClip)); // transfer ownership
1408  }
1409  }
1410 }
1411 
1413 void WaveTrack::Paste(double t0, const Track *src)
1414 {
1415  if (auto other = dynamic_cast<const WaveTrack*>(src))
1416  PasteWaveTrack(t0, other);
1417  else
1418  // THROW_INCONSISTENCY_EXCEPTION; // ?
1419  (void)0;// Empty if intentional.
1420 }
1421 
1422 void WaveTrack::Silence(double t0, double t1)
1423 {
1424  if (t1 < t0)
1426 
1427  auto start = TimeToLongSamples(t0);
1428  auto end = TimeToLongSamples(t1);
1429 
1430  for (const auto &clip : mClips)
1431  {
1432  auto clipStart = clip->GetPlayStartSample();
1433  auto clipEnd = clip->GetPlayEndSample();
1434 
1435  if (clipEnd > start && clipStart < end)
1436  {
1437  auto offset = std::max(start - clipStart, sampleCount(0));
1438  // Clip sample region and Get/Put sample region overlap
1439  auto length = std::min(end, clipEnd) - (clipStart + offset);
1440 
1441  clip->SetSilence(offset, length);
1442  }
1443  }
1444 }
1445 
1447 void WaveTrack::InsertSilence(double t, double len)
1448 {
1449  // Nothing to do, if length is zero.
1450  // Fixes Bug 1626
1451  if( len == 0 )
1452  return;
1453  if (len <= 0)
1455 
1456  if (mClips.empty())
1457  {
1458  // Special case if there is no clip yet
1459  auto clip = std::make_unique<WaveClip>(mpFactory, mFormat, mRate, this->GetWaveColorIndex());
1460  clip->InsertSilence(0, len);
1461  // use No-fail-guarantee
1462  mClips.push_back( std::move( clip ) );
1463  return;
1464  }
1465  else {
1466  // Assume at most one clip contains t
1467  const auto end = mClips.end();
1468  const auto it = std::find_if( mClips.begin(), end,
1469  [&](const WaveClipHolder &clip) { return clip->WithinPlayRegion(t); } );
1470 
1471  // use Strong-guarantee
1472  if (it != end)
1473  it->get()->InsertSilence(t, len);
1474 
1475  // use No-fail-guarantee
1476  for (const auto &clip : mClips)
1477  {
1478  if (clip->BeforePlayStartTime(t))
1479  clip->Offset(len);
1480  }
1481  }
1482 }
1483 
1484 //Performs the opposite of Join
1485 //Analyses selected region for possible Joined clips and disjoins them
1487 void WaveTrack::Disjoin(double t0, double t1)
1488 {
1490  const size_t maxAtOnce = 1048576;
1491  Floats buffer{ maxAtOnce };
1492  Regions regions;
1493 
1494  wxBusyCursor busy;
1495 
1496  for (const auto &clip : mClips)
1497  {
1498  double startTime = clip->GetPlayStartTime();
1499  double endTime = clip->GetPlayEndTime();
1500 
1501  if( endTime < t0 || startTime > t1 )
1502  continue;
1503 
1504  if( t0 > startTime )
1505  startTime = t0;
1506  if( t1 < endTime )
1507  endTime = t1;
1508 
1509  //simply look for a sequence of zeroes and if the sequence
1510  //is greater than minimum number, split-DELETE the region
1511 
1512  sampleCount seqStart = -1;
1513  auto start = clip->TimeToSequenceSamples(startTime);
1514  auto end = clip->TimeToSequenceSamples(endTime);
1515 
1516  auto len = ( end - start );
1517  for( decltype(len) done = 0; done < len; done += maxAtOnce )
1518  {
1519  auto numSamples = limitSampleBufferSize( maxAtOnce, len - done );
1520 
1521  clip->GetSamples( ( samplePtr )buffer.get(), floatSample, start + done,
1522  numSamples );
1523  for( decltype(numSamples) i = 0; i < numSamples; i++ )
1524  {
1525  auto curSamplePos = start + done + i;
1526 
1527  //start a NEW sequence
1528  if( buffer[ i ] == 0.0 && seqStart == -1 )
1529  seqStart = curSamplePos;
1530  else if( buffer[ i ] != 0.0 || curSamplePos == end - 1 )
1531  {
1532  if( seqStart != -1 )
1533  {
1534  decltype(end) seqEnd;
1535 
1536  //consider the end case, where selection ends in zeroes
1537  if( curSamplePos == end - 1 && buffer[ i ] == 0.0 )
1538  seqEnd = end;
1539  else
1540  seqEnd = curSamplePos;
1541  if( seqEnd - seqStart + 1 > minSamples )
1542  {
1543  regions.push_back(Region(
1544  seqStart.as_double() / GetRate()
1545  + clip->GetPlayStartTime(),
1546  seqEnd.as_double() / GetRate()
1547  + clip->GetPlayStartTime()));
1548  }
1549  seqStart = -1;
1550  }
1551  }
1552  }
1553  }
1554  }
1555 
1556  for( unsigned int i = 0; i < regions.size(); i++ )
1557  {
1558  const Region &region = regions.at(i);
1559  SplitDelete(region.start, region.end );
1560  }
1561 }
1562 
1564 void WaveTrack::Join(double t0, double t1)
1565 {
1566  // Merge all WaveClips overlapping selection into one
1567 
1568  WaveClipPointers clipsToDelete;
1569  WaveClip* newClip{};
1570 
1571  for (const auto &clip: mClips)
1572  {
1573  if (clip->GetPlayStartTime() < t1-(1.0/mRate) &&
1574  clip->GetPlayEndTime()-(1.0/mRate) > t0) {
1575 
1576  // Put in sorted order
1577  auto it = clipsToDelete.begin(), end = clipsToDelete.end();
1578  for (; it != end; ++it)
1579  if ((*it)->GetPlayStartTime() > clip->GetPlayStartTime())
1580  break;
1581  //wxPrintf("Insert clip %.6f at position %d\n", clip->GetStartTime(), i);
1582  clipsToDelete.insert(it, clip.get());
1583  }
1584  }
1585 
1586  //if there are no clips to DELETE, nothing to do
1587  if( clipsToDelete.size() == 0 )
1588  return;
1589 
1590  auto t = clipsToDelete[0]->GetSequenceStartTime();
1591  //preserve left trim data if any
1592  newClip = CreateClip(t, clipsToDelete[0]->GetName());
1593 
1594  for (const auto &clip : clipsToDelete)
1595  {
1596  //wxPrintf("t=%.6f adding clip (offset %.6f, %.6f ... %.6f)\n",
1597  // t, clip->GetOffset(), clip->GetStartTime(), clip->GetEndTime());
1598 
1599  if (clip->GetPlayStartTime() - t > (1.0 / mRate)) {
1600  double addedSilence = (clip->GetPlayStartTime() - t);
1601  //wxPrintf("Adding %.6f seconds of silence\n");
1602  auto offset = clip->GetPlayStartTime();
1603  auto value = clip->GetEnvelope()->GetValue( offset );
1604  newClip->AppendSilence( addedSilence, value );
1605  t += addedSilence;
1606  }
1607 
1608  //wxPrintf("Pasting at %.6f\n", t);
1609  newClip->Paste(t, clip);
1610 
1611  t = newClip->GetPlayEndTime();
1612 
1613  auto it = FindClip(mClips, clip);
1614  mClips.erase(it); // deletes the clip
1615  }
1616 }
1617 
1622  size_t len, unsigned int stride /* = 1 */)
1623 {
1624  return RightmostOrNewClip()->Append(buffer, format, len, stride);
1625 }
1626 
1628 {
1629  for (const auto &clip : mClips)
1630  {
1631  const auto startSample = clip->GetPlayStartSample();
1632  const auto endSample = clip->GetPlayEndSample();
1633  if (s >= startSample && s < endSample)
1634  {
1635  auto blockStartOffset = clip->GetSequence()->GetBlockStart(clip->ToSequenceSamples(s));
1636  return std::max(startSample, clip->GetSequenceStartSample() + blockStartOffset);
1637  }
1638  }
1639 
1640  return -1;
1641 }
1642 
1644 {
1645  auto bestBlockSize = GetMaxBlockSize();
1646 
1647  for (const auto &clip : mClips)
1648  {
1649  auto startSample = clip->GetPlayStartSample();
1650  auto endSample = clip->GetPlayEndSample();
1651  if (s >= startSample && s < endSample)
1652  {
1653  bestBlockSize = clip->GetSequence()->GetBestBlockSize(s - clip->GetSequenceStartSample());
1654  break;
1655  }
1656  }
1657 
1658  return bestBlockSize;
1659 }
1660 
1662 {
1663  decltype(GetMaxBlockSize()) maxblocksize = 0;
1664  for (const auto &clip : mClips)
1665  {
1666  maxblocksize = std::max(maxblocksize, clip->GetSequence()->GetMaxBlockSize());
1667  }
1668 
1669  if (maxblocksize == 0)
1670  {
1671  // We really need the maximum block size, so create a
1672  // temporary sequence to get it.
1673  maxblocksize = Sequence{ mpFactory, mFormat }.GetMaxBlockSize();
1674  }
1675 
1676  wxASSERT(maxblocksize > 0);
1677 
1678  return maxblocksize;
1679 }
1680 
1682 {
1684 }
1685 
1692 {
1693  // After appending, presumably. Do this to the clip that gets appended.
1695 }
1696 
1697 namespace {
1698 bool IsValidChannel(const int nValue)
1699 {
1700  return (nValue >= Track::LeftChannel) && (nValue <= Track::MonoChannel);
1701 }
1702 }
1703 
1704 bool WaveTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
1705 {
1706  if (!wxStrcmp(tag, wxT("wavetrack"))) {
1707  double dblValue;
1708  long nValue;
1709  while(*attrs) {
1710  const wxChar *attr = *attrs++;
1711  const wxChar *value = *attrs++;
1712 
1713  if (!value)
1714  break;
1715 
1716  const wxString strValue = value;
1717  if (!wxStrcmp(attr, wxT("rate")))
1718  {
1719  // mRate is an int, but "rate" in the project file is a float.
1720  if (!XMLValueChecker::IsGoodString(strValue) ||
1721  !Internat::CompatibleToDouble(strValue, &dblValue) ||
1722  (dblValue < 1.0) || (dblValue > 1000000.0)) // allow a large range to be read
1723  return false;
1724  mRate = lrint(dblValue);
1725  }
1726  else if (!wxStrcmp(attr, wxT("offset")) &&
1727  XMLValueChecker::IsGoodString(strValue) &&
1728  Internat::CompatibleToDouble(strValue, &dblValue))
1729  {
1730  // Offset is only relevant for legacy project files. The value
1731  // is cached until the actual WaveClip containing the legacy
1732  // track is created.
1733  mLegacyProjectFileOffset = dblValue;
1734  }
1735  else if (this->PlayableTrack::HandleXMLAttribute(attr, value))
1736  {}
1737  else if (this->Track::HandleCommonXMLAttribute(attr, strValue))
1738  ;
1739  else if (!wxStrcmp(attr, wxT("gain")) &&
1740  XMLValueChecker::IsGoodString(strValue) &&
1741  Internat::CompatibleToDouble(strValue, &dblValue))
1742  mGain = dblValue;
1743  else if (!wxStrcmp(attr, wxT("pan")) &&
1744  XMLValueChecker::IsGoodString(strValue) &&
1745  Internat::CompatibleToDouble(strValue, &dblValue) &&
1746  (dblValue >= -1.0) && (dblValue <= 1.0))
1747  mPan = dblValue;
1748  else if (!wxStrcmp(attr, wxT("channel")))
1749  {
1750  if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&nValue) ||
1751  !IsValidChannel(nValue))
1752  return false;
1753  mChannel = static_cast<Track::ChannelType>( nValue );
1754  }
1755  else if (!wxStrcmp(attr, wxT("linked")) &&
1756  XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
1757  SetLinkType(ToLinkType(nValue));
1758  else if (!wxStrcmp(attr, wxT("colorindex")) &&
1759  XMLValueChecker::IsGoodString(strValue) &&
1760  strValue.ToLong(&nValue))
1761  // Don't use SetWaveColorIndex as it sets the clips too.
1762  mWaveColorIndex = nValue;
1763  else if (!wxStrcmp(attr, wxT("sampleformat")) &&
1764  XMLValueChecker::IsGoodInt(strValue) &&
1765  strValue.ToLong(&nValue) &&
1767  mFormat = static_cast<sampleFormat>(nValue);
1768  } // while
1769  return true;
1770  }
1771 
1772  return false;
1773 }
1774 
1775 void WaveTrack::HandleXMLEndTag(const wxChar * WXUNUSED(tag))
1776 {
1777  // In case we opened a pre-multiclip project, we need to
1778  // simulate closing the waveclip tag.
1779  NewestOrNewClip()->HandleXMLEndTag(wxT("waveclip"));
1780 }
1781 
1783 {
1784  //
1785  // This is legacy code (1.2 and previous) and is not called for NEW projects!
1786  //
1787  if (!wxStrcmp(tag, wxT("sequence")) || !wxStrcmp(tag, wxT("envelope")))
1788  {
1789  // This is a legacy project, so set the cached offset
1791 
1792  // Legacy project file tracks are imported as one single wave clip
1793  if (!wxStrcmp(tag, wxT("sequence")))
1794  return NewestOrNewClip()->GetSequence();
1795  else if (!wxStrcmp(tag, wxT("envelope")))
1796  return NewestOrNewClip()->GetEnvelope();
1797  }
1798 
1799  // JKC... for 1.1.0, one step better than what we had, but still badly broken.
1800  //If we see a waveblock at this level, we'd better generate a sequence.
1801  if( !wxStrcmp( tag, wxT("waveblock" )))
1802  {
1803  // This is a legacy project, so set the cached offset
1805  Sequence *pSeq = NewestOrNewClip()->GetSequence();
1806  return pSeq;
1807  }
1808 
1809  //
1810  // This is for the NEW file format (post-1.2)
1811  //
1812  if (!wxStrcmp(tag, wxT("waveclip")))
1813  return CreateClip();
1814  else
1815  return NULL;
1816 }
1817 
1818 void WaveTrack::WriteXML(XMLWriter &xmlFile) const
1819 // may throw
1820 {
1821  xmlFile.StartTag(wxT("wavetrack"));
1822  this->Track::WriteCommonXMLAttributes( xmlFile );
1823  xmlFile.WriteAttr(wxT("channel"), mChannel);
1824  xmlFile.WriteAttr(wxT("linked"), static_cast<int>(GetLinkType()));
1825  this->PlayableTrack::WriteXMLAttributes(xmlFile);
1826  xmlFile.WriteAttr(wxT("rate"), mRate);
1827  xmlFile.WriteAttr(wxT("gain"), (double)mGain);
1828  xmlFile.WriteAttr(wxT("pan"), (double)mPan);
1829  xmlFile.WriteAttr(wxT("colorindex"), mWaveColorIndex );
1830  xmlFile.WriteAttr(wxT("sampleformat"), static_cast<long>(mFormat) );
1831 
1832  for (const auto &clip : mClips)
1833  {
1834  clip->WriteXML(xmlFile);
1835  }
1836 
1837  xmlFile.EndTag(wxT("wavetrack"));
1838 }
1839 
1841 {
1842  for (const auto &clip : mClips)
1843  if (clip->GetSequence()->GetErrorOpening())
1844  return true;
1845 
1846  return false;
1847 }
1848 
1850 {
1851  for (const auto &clip : mClips)
1852  clip->CloseLock();
1853 
1854  return true;
1855 }
1856 
1857 AUDACITY_DLL_API sampleCount WaveTrack::TimeToLongSamples(double t0) const
1858 {
1859  return sampleCount( floor(t0 * mRate + 0.5) );
1860 }
1861 
1863 {
1864  return pos.as_double() / mRate;
1865 }
1866 
1868 {
1869  bool found = false;
1870  double best = 0.0;
1871 
1872  if (mClips.empty())
1873  return 0;
1874 
1875  for (const auto &clip : mClips)
1876  if (!found)
1877  {
1878  found = true;
1879  best = clip->GetPlayStartTime();
1880  }
1881  else if (clip->GetPlayStartTime() < best)
1882  best = clip->GetPlayStartTime();
1883 
1884  return best;
1885 }
1886 
1888 {
1889  bool found = false;
1890  double best = 0.0;
1891 
1892  if (mClips.empty())
1893  return 0;
1894 
1895  for (const auto &clip : mClips)
1896  if (!found)
1897  {
1898  found = true;
1899  best = clip->GetPlayEndTime();
1900  }
1901  else if (clip->GetPlayEndTime() > best)
1902  best = clip->GetPlayEndTime();
1903 
1904  return best;
1905 }
1906 
1907 //
1908 // Getting/setting samples. The sample counts here are
1909 // expressed relative to t=0.0 at the track's sample rate.
1910 //
1911 
1912 std::pair<float, float> WaveTrack::GetMinMax(
1913  double t0, double t1, bool mayThrow) const
1914 {
1915  std::pair<float, float> results {
1916  // we need these at extremes to make sure we find true min and max
1917  FLT_MAX, -FLT_MAX
1918  };
1919  bool clipFound = false;
1920 
1921  if (t0 > t1) {
1922  if (mayThrow)
1924  return results;
1925  }
1926 
1927  if (t0 == t1)
1928  return results;
1929 
1930  for (const auto &clip: mClips)
1931  {
1932  if (t1 >= clip->GetPlayStartTime() && t0 <= clip->GetPlayEndTime())
1933  {
1934  clipFound = true;
1935  auto clipResults = clip->GetMinMax(t0, t1, mayThrow);
1936  if (clipResults.first < results.first)
1937  results.first = clipResults.first;
1938  if (clipResults.second > results.second)
1939  results.second = clipResults.second;
1940  }
1941  }
1942 
1943  if(!clipFound)
1944  {
1945  results = { 0.f, 0.f }; // sensible defaults if no clips found
1946  }
1947 
1948  return results;
1949 }
1950 
1951 float WaveTrack::GetRMS(double t0, double t1, bool mayThrow) const
1952 {
1953  if (t0 > t1) {
1954  if (mayThrow)
1956  return 0.f;
1957  }
1958 
1959  if (t0 == t1)
1960  return 0.f;
1961 
1962  double sumsq = 0.0;
1963  sampleCount length = 0;
1964 
1965  for (const auto &clip: mClips)
1966  {
1967  // If t1 == clip->GetStartTime() or t0 == clip->GetEndTime(), then the clip
1968  // is not inside the selection, so we don't want it.
1969  // if (t1 >= clip->GetStartTime() && t0 <= clip->GetEndTime())
1970  if (t1 >= clip->GetPlayStartTime() && t0 <= clip->GetPlayEndTime())
1971  {
1972  auto clipStart = clip->TimeToSequenceSamples(wxMax(t0, clip->GetPlayStartTime()));
1973  auto clipEnd = clip->TimeToSequenceSamples(wxMin(t1, clip->GetPlayEndTime()));
1974 
1975  float cliprms = clip->GetRMS(t0, t1, mayThrow);
1976 
1977  sumsq += cliprms * cliprms * (clipEnd - clipStart).as_float();
1978  length += (clipEnd - clipStart);
1979  }
1980  }
1981  return length > 0 ? sqrt(sumsq / length.as_double()) : 0.0;
1982 }
1983 
1985  sampleCount start, size_t len, fillFormat fill,
1986  bool mayThrow, sampleCount * pNumWithinClips) const
1987 {
1988  // Simple optimization: When this buffer is completely contained within one clip,
1989  // don't clear anything (because we won't have to). Otherwise, just clear
1990  // everything to be on the safe side.
1991  bool doClear = true;
1992  bool result = true;
1993  sampleCount samplesCopied = 0;
1994  for (const auto &clip: mClips)
1995  {
1996  if (start >= clip->GetPlayStartSample() && start+len <= clip->GetPlayEndSample())
1997  {
1998  doClear = false;
1999  break;
2000  }
2001  }
2002  if (doClear)
2003  {
2004  // Usually we fill in empty space with zero
2005  if( fill == fillZero )
2006  ClearSamples(buffer, format, 0, len);
2007  // but we don't have to.
2008  else if( fill==fillTwo )
2009  {
2010  wxASSERT( format==floatSample );
2011  float * pBuffer = (float*)buffer;
2012  for(size_t i=0;i<len;i++)
2013  pBuffer[i]=2.0f;
2014  }
2015  else
2016  {
2017  wxFAIL_MSG(wxT("Invalid fill format"));
2018  }
2019  }
2020 
2021  // Iterate the clips. They are not necessarily sorted by time.
2022  for (const auto &clip: mClips)
2023  {
2024  auto clipStart = clip->GetPlayStartSample();
2025  auto clipEnd = clip->GetPlayEndSample();
2026 
2027  if (clipEnd > start && clipStart < start+len)
2028  {
2029  // Clip sample region and Get/Put sample region overlap
2030  auto samplesToCopy =
2031  std::min( start+len - clipStart, clip->GetPlaySamplesCount() );
2032  auto startDelta = clipStart - start;
2033  decltype(startDelta) inclipDelta = 0;
2034  if (startDelta < 0)
2035  {
2036  inclipDelta = -startDelta; // make positive value
2037  samplesToCopy -= inclipDelta;
2038  // samplesToCopy is now either len or
2039  // (clipEnd - clipStart) - (start - clipStart)
2040  // == clipEnd - start > 0
2041  // samplesToCopy is not more than len
2042  //
2043  startDelta = 0;
2044  // startDelta is zero
2045  }
2046  else {
2047  // startDelta is nonnegative and less than len
2048  // samplesToCopy is positive and not more than len
2049  }
2050 
2051  if (!clip->GetSamples(
2052  (samplePtr)(((char*)buffer) +
2053  startDelta.as_size_t() *
2054  SAMPLE_SIZE(format)),
2055  format, inclipDelta, samplesToCopy.as_size_t(), mayThrow ))
2056  result = false;
2057  else
2058  samplesCopied += samplesToCopy;
2059  }
2060  }
2061  if( pNumWithinClips )
2062  *pNumWithinClips = samplesCopied;
2063  return result;
2064 }
2065 
2068  sampleCount start, size_t len)
2069 {
2070  for (const auto &clip: mClips)
2071  {
2072  auto clipStart = clip->GetPlayStartSample();
2073  auto clipEnd = clip->GetPlayEndSample();
2074 
2075  if (clipEnd > start && clipStart < start+len)
2076  {
2077  // Clip sample region and Get/Put sample region overlap
2078  auto samplesToCopy =
2079  std::min( start+len - clipStart, clip->GetPlaySamplesCount() );
2080  auto startDelta = clipStart - start;
2081  decltype(startDelta) inclipDelta = 0;
2082  if (startDelta < 0)
2083  {
2084  inclipDelta = -startDelta; // make positive value
2085  samplesToCopy -= inclipDelta;
2086  // samplesToCopy is now either len or
2087  // (clipEnd - clipStart) - (start - clipStart)
2088  // == clipEnd - start > 0
2089  // samplesToCopy is not more than len
2090  //
2091  startDelta = 0;
2092  // startDelta is zero
2093  }
2094  else {
2095  // startDelta is nonnegative and less than len
2096  // samplesToCopy is positive and not more than len
2097  }
2098 
2099  clip->SetSamples(
2100  (constSamplePtr)(((const char*)buffer) +
2101  startDelta.as_size_t() *
2102  SAMPLE_SIZE(format)),
2103  format, inclipDelta, samplesToCopy.as_size_t() );
2104  clip->MarkChanged();
2105  }
2106  }
2107 }
2108 
2109 void WaveTrack::GetEnvelopeValues(double *buffer, size_t bufferLen,
2110  double t0) const
2111 {
2112  // The output buffer corresponds to an unbroken span of time which the callers expect
2113  // to be fully valid. As clips are processed below, the output buffer is updated with
2114  // envelope values from any portion of a clip, start, end, middle, or none at all.
2115  // Since this does not guarantee that the entire buffer is filled with values we need
2116  // to initialize the entire buffer to a default value.
2117  //
2118  // This does mean that, in the cases where a usable clip is located, the buffer value will
2119  // be set twice. Unfortunately, there is no easy way around this since the clips are not
2120  // stored in increasing time order. If they were, we could just track the time as the
2121  // buffer is filled.
2122  for (decltype(bufferLen) i = 0; i < bufferLen; i++)
2123  {
2124  buffer[i] = 1.0;
2125  }
2126 
2127  double startTime = t0;
2128  auto tstep = 1.0 / mRate;
2129  double endTime = t0 + tstep * bufferLen;
2130  for (const auto &clip: mClips)
2131  {
2132  // IF clip intersects startTime..endTime THEN...
2133  auto dClipStartTime = clip->GetPlayStartTime();
2134  auto dClipEndTime = clip->GetPlayEndTime();
2135  if ((dClipStartTime < endTime) && (dClipEndTime > startTime))
2136  {
2137  auto rbuf = buffer;
2138  auto rlen = bufferLen;
2139  auto rt0 = t0;
2140 
2141  if (rt0 < dClipStartTime)
2142  {
2143  // This is not more than the number of samples in
2144  // (endTime - startTime) which is bufferLen:
2145  auto nDiff = (sampleCount)floor((dClipStartTime - rt0) * mRate + 0.5);
2146  auto snDiff = nDiff.as_size_t();
2147  rbuf += snDiff;
2148  wxASSERT(snDiff <= rlen);
2149  rlen -= snDiff;
2150  rt0 = dClipStartTime;
2151  }
2152 
2153  if (rt0 + rlen*tstep > dClipEndTime)
2154  {
2155  auto nClipLen = clip->GetPlayEndSample() - clip->GetPlayStartSample();
2156 
2157  if (nClipLen <= 0) // Testing for bug 641, this problem is consistently '== 0', but doesn't hurt to check <.
2158  return;
2159 
2160  // This check prevents problem cited in http://bugzilla.audacityteam.org/show_bug.cgi?id=528#c11,
2161  // Gale's cross_fade_out project, which was already corrupted by bug 528.
2162  // This conditional prevents the previous write past the buffer end, in clip->GetEnvelope() call.
2163  // Never increase rlen here.
2164  // PRL bug 827: rewrote it again
2165  rlen = limitSampleBufferSize( rlen, nClipLen );
2166  rlen = std::min(rlen, size_t(floor(0.5 + (dClipEndTime - rt0) / tstep)));
2167  }
2168  // Samples are obtained for the purpose of rendering a wave track,
2169  // so quantize time
2170  clip->GetEnvelope()->GetValues(rbuf, rlen, rt0, tstep);
2171  }
2172  }
2173 }
2174 
2176 {
2177  for (const auto &clip: mClips)
2178  {
2179  auto start = clip->GetPlayStartSample();
2180  auto len = clip->GetPlaySamplesCount();
2181 
2182  if (sample >= start && sample < start + len)
2183  return clip.get();
2184  }
2185 
2186  return NULL;
2187 }
2188 
2189 // When the time is both the end of a clip and the start of the next clip, the
2190 // latter clip is returned.
2192 {
2193 
2194  const auto clips = SortedClipArray();
2195  auto p = std::find_if(clips.rbegin(), clips.rend(), [&] (WaveClip* const& clip) {
2196  return time >= clip->GetPlayStartTime() && time <= clip->GetPlayEndTime(); });
2197 
2198  // When two clips are immediately next to each other, the GetPlayEndTime() of the first clip
2199  // and the GetPlayStartTime() of the second clip may not be exactly equal due to rounding errors.
2200  // If "time" is the end time of the first of two such clips, and the end time is slightly
2201  // less than the start time of the second clip, then the first rather than the
2202  // second clip is found by the above code. So correct this.
2203  if (p != clips.rend() && p != clips.rbegin() &&
2204  time == (*p)->GetPlayEndTime() &&
2205  (*p)->SharesBoundaryWithNextClip(*(p-1))) {
2206  p--;
2207  }
2208 
2209  return p != clips.rend() ? *p : nullptr;
2210 }
2211 
2213 {
2214  WaveClip* clip = GetClipAtTime(time);
2215  if (clip)
2216  return clip->GetEnvelope();
2217  else
2218  return NULL;
2219 }
2220 
2222 {
2223  WaveClip* clip = GetClipAtTime(time);
2224  if (clip)
2225  return clip->GetSequence();
2226  else
2227  return NULL;
2228 }
2229 
2230 WaveClip* WaveTrack::CreateClip(double offset, const wxString& name)
2231 {
2232  auto clip = std::make_unique<WaveClip>(mpFactory, mFormat, mRate, GetWaveColorIndex());
2233  clip->SetName(name);
2234  clip->SetSequenceStartTime(offset);
2235  mClips.push_back(std::move(clip));
2236 
2237  return mClips.back().get();
2238 }
2239 
2241 {
2242  if (mClips.empty()) {
2243  return CreateClip(mOffset, MakeNewClipName());
2244  }
2245  else
2246  return mClips.back().get();
2247 }
2248 
2251 {
2252  if (mClips.empty()) {
2253  return CreateClip(mOffset, MakeNewClipName());
2254  }
2255  else
2256  {
2257  auto it = mClips.begin();
2258  WaveClip *rightmost = (*it++).get();
2259  double maxOffset = rightmost->GetPlayStartTime();
2260  for (auto end = mClips.end(); it != end; ++it)
2261  {
2262  WaveClip *clip = it->get();
2263  double offset = clip->GetPlayStartTime();
2264  if (maxOffset < offset)
2265  maxOffset = offset, rightmost = clip;
2266  }
2267  return rightmost;
2268  }
2269 }
2270 
2271 int WaveTrack::GetClipIndex(const WaveClip* clip) const
2272 {
2273  int result;
2274  FindClip(mClips, clip, &result);
2275  return result;
2276 }
2277 
2279 {
2280  if(index < (int)mClips.size())
2281  return mClips[index].get();
2282  else
2283  return nullptr;
2284 }
2285 
2286 const WaveClip* WaveTrack::GetClipByIndex(int index) const
2287 {
2288  return const_cast<WaveTrack&>(*this).GetClipByIndex(index);
2289 }
2290 
2292 {
2293  return mClips.size();
2294 }
2295 
2297  const std::vector<WaveClip*> &clips,
2298  double amount,
2299  double *allowedAmount /* = NULL */)
2300 {
2301  if (allowedAmount)
2302  *allowedAmount = amount;
2303 
2304  const auto &moving = [&](WaveClip *clip){
2305  // linear search might be improved, but expecting few moving clips
2306  // compared with the fixed clips
2307  return clips.end() != std::find( clips.begin(), clips.end(), clip );
2308  };
2309 
2310  for (const auto &c: mClips) {
2311  if ( moving( c.get() ) )
2312  continue;
2313  for (const auto clip : clips) {
2314  if (c->GetPlayStartTime() < clip->GetPlayEndTime() + amount &&
2315  c->GetPlayEndTime() > clip->GetPlayStartTime() + amount)
2316  {
2317  if (!allowedAmount)
2318  return false; // clips overlap
2319 
2320  if (amount > 0)
2321  {
2322  if (c->GetPlayStartTime() - clip->GetPlayEndTime() < *allowedAmount)
2323  *allowedAmount = c->GetPlayStartTime() - clip->GetPlayEndTime();
2324  if (*allowedAmount < 0)
2325  *allowedAmount = 0;
2326  } else
2327  {
2328  if (c->GetPlayEndTime() - clip->GetPlayStartTime() > *allowedAmount)
2329  *allowedAmount = c->GetPlayEndTime() - clip->GetPlayStartTime();
2330  if (*allowedAmount > 0)
2331  *allowedAmount = 0;
2332  }
2333  }
2334  }
2335  }
2336 
2337  if (allowedAmount)
2338  {
2339  if (*allowedAmount == amount)
2340  return true;
2341 
2342  // Check if the NEW calculated amount would not violate
2343  // any other constraint
2344  if (!CanOffsetClips(clips, *allowedAmount, nullptr)) {
2345  *allowedAmount = 0; // play safe and don't allow anything
2346  return false;
2347  }
2348  else
2349  return true;
2350  } else
2351  return true;
2352 }
2353 
2355  WaveClip* clip, double &slideBy, double &tolerance) const
2356 {
2357  for (const auto &c : mClips)
2358  {
2359  double d1 = c->GetPlayStartTime() - (clip->GetPlayEndTime()+slideBy);
2360  double d2 = (clip->GetPlayStartTime()+slideBy) - c->GetPlayEndTime();
2361  if ( (d1<0) && (d2<0) )
2362  {
2363  // clips overlap.
2364  // Try to rescue it.
2365  // The rescue logic is not perfect, and will typically
2366  // move the clip at most once.
2367  // We divide by 1000 rather than set to 0, to allow for
2368  // a second 'micro move' that is really about rounding error.
2369  if( -d1 < tolerance ){
2370  // right edge of clip overlaps slightly.
2371  // slide clip left a small amount.
2372  slideBy +=d1;
2373  tolerance /=1000;
2374  } else if( -d2 < tolerance ){
2375  // left edge of clip overlaps slightly.
2376  // slide clip right a small amount.
2377  slideBy -= d2;
2378  tolerance /=1000;
2379  }
2380  else
2381  return false; // clips overlap No tolerance left.
2382  }
2383  }
2384 
2385  return true;
2386 }
2387 
2389 void WaveTrack::Split( double t0, double t1 )
2390 {
2391  SplitAt( t0 );
2392  if( t0 != t1 )
2393  SplitAt( t1 );
2394 }
2395 
2397 void WaveTrack::SplitAt(double t)
2398 {
2399  for (const auto &c : mClips)
2400  {
2401  if (c->WithinPlayRegion(t))
2402  {
2404  auto newClip = std::make_unique<WaveClip>( *c, mpFactory, true );
2405  c->TrimRightTo(t);// put t on a sample
2406  newClip->TrimLeftTo(t);
2407 
2408  // This could invalidate the iterators for the loop! But we return
2409  // at once so it's okay
2410  mClips.push_back(std::move(newClip)); // transfer ownership
2411  return;
2412  }
2413  }
2414 }
2415 
2417 {
2418  auto clips = SortedClipArray();
2419 
2420  mDisplayLocationsCache.clear();
2421 
2422  // Count number of display locations
2423  int num = 0;
2424  {
2425  const WaveClip *prev = nullptr;
2426  for (const auto clip : clips)
2427  {
2428  //enough for estimation
2429  num += clip->NumCutLines();
2430 
2431  if (prev && fabs(prev->GetPlayEndTime() -
2432  clip->GetPlayStartTime()) < WAVETRACK_MERGE_POINT_TOLERANCE)
2433  ++num;
2434  prev = clip;
2435  }
2436  }
2437 
2438  if (num == 0)
2439  return;
2440 
2441  // Alloc necessary number of display locations
2442  mDisplayLocationsCache.reserve(num);
2443 
2444  // Add all display locations to cache
2445  int curpos = 0;
2446 
2447  const WaveClip *previousClip = nullptr;
2448  for (const auto clip: clips)
2449  {
2450  for (const auto &cc : clip->GetCutLines())
2451  {
2452  auto cutlinePosition = clip->GetSequenceStartTime() + cc->GetSequenceStartTime();
2453  if (clip->WithinPlayRegion(cutlinePosition))
2454  {
2455  // Add cut line expander point
2457  cutlinePosition,
2459  });
2460  }
2461  // If cutline is skipped, we still need to count it
2462  // so that curpos match num at the end
2463  curpos++;
2464  }
2465 
2466  if (previousClip)
2467  {
2468  if (fabs(previousClip->GetPlayEndTime() - clip->GetPlayStartTime())
2470  {
2471  // Add merge point
2473  previousClip->GetPlayEndTime(),
2475  GetClipIndex(previousClip),
2476  GetClipIndex(clip)
2477  });
2478  curpos++;
2479  }
2480  }
2481 
2482  previousClip = clip;
2483  }
2484 
2485  wxASSERT(curpos == num);
2486 }
2487 
2488 // Expand cut line (that is, re-insert audio, then DELETE audio saved in cut line)
2490 void WaveTrack::ExpandCutLine(double cutLinePosition, double* cutlineStart,
2491  double* cutlineEnd)
2492 {
2493  bool editClipCanMove = GetEditClipsCanMove();
2494 
2495  // Find clip which contains this cut line
2496  double start = 0, end = 0;
2497  auto pEnd = mClips.end();
2498  auto pClip = std::find_if( mClips.begin(), pEnd,
2499  [&](const WaveClipHolder &clip) {
2500  return clip->FindCutLine(cutLinePosition, &start, &end); } );
2501  if (pClip != pEnd)
2502  {
2503  auto &clip = *pClip;
2504  if (!editClipCanMove)
2505  {
2506  // We are not allowed to move the other clips, so see if there
2507  // is enough room to expand the cut line
2508  for (const auto &clip2: mClips)
2509  {
2510  if (clip2->GetPlayStartTime() > clip->GetPlayStartTime() &&
2511  clip->GetPlayEndTime() + end - start > clip2->GetPlayStartTime())
2512  // Strong-guarantee in case of this path
2515  XO("There is not enough room available to expand the cut line"),
2516  XO("Warning"),
2517  "Error:_Insufficient_space_in_track"
2518  };
2519  }
2520  }
2521 
2522  clip->ExpandCutLine(cutLinePosition);
2523 
2524  // Strong-guarantee provided that the following gives No-fail-guarantee
2525 
2526  if (cutlineStart)
2527  *cutlineStart = start;
2528  if (cutlineEnd)
2529  *cutlineEnd = end;
2530 
2531  // Move clips which are to the right of the cut line
2532  if (editClipCanMove)
2533  {
2534  for (const auto &clip2 : mClips)
2535  {
2536  if (clip2->GetPlayStartTime() > clip->GetPlayStartTime())
2537  clip2->Offset(end - start);
2538  }
2539  }
2540  }
2541 }
2542 
2543 bool WaveTrack::RemoveCutLine(double cutLinePosition)
2544 {
2545  for (const auto &clip : mClips)
2546  if (clip->RemoveCutLine(cutLinePosition))
2547  return true;
2548 
2549  return false;
2550 }
2551 
2553 void WaveTrack::MergeClips(int clipidx1, int clipidx2)
2554 {
2555  WaveClip* clip1 = GetClipByIndex(clipidx1);
2556  WaveClip* clip2 = GetClipByIndex(clipidx2);
2557 
2558  if (!clip1 || !clip2) // Could happen if one track of a linked pair had a split and the other didn't.
2559  return; // Don't throw, just do nothing.
2560 
2561  // Append data from second clip to first clip
2562  // use Strong-guarantee
2563  clip1->Paste(clip1->GetPlayEndTime(), clip2);
2564 
2565  // use No-fail-guarantee for the rest
2566  // Delete second clip
2567  auto it = FindClip(mClips, clip2);
2568  mClips.erase(it);
2569 }
2570 
2573 void WaveTrack::Resample(int rate, ProgressDialog *progress)
2574 {
2575  for (const auto &clip : mClips)
2576  clip->Resample(rate, progress);
2577 
2578  mRate = rate;
2579 }
2580 
2581 namespace {
2582  template < typename Cont1, typename Cont2 >
2583  Cont1 FillSortedClipArray(const Cont2& mClips)
2584  {
2585  Cont1 clips;
2586  for (const auto &clip : mClips)
2587  clips.push_back(clip.get());
2588  std::sort(clips.begin(), clips.end(),
2589  [](const WaveClip *a, const WaveClip *b)
2590  { return a->GetPlayStartTime() < b->GetPlayStartTime(); });
2591  return clips;
2592  }
2593 }
2594 
2596 {
2597  return FillSortedClipArray<WaveClipPointers>(mClips);
2598 }
2599 
2601 {
2602  return FillSortedClipArray<WaveClipConstPointers>(mClips);
2603 }
2604 
2607 {
2608  for (const auto &clip : mClips)
2609  clip->ClearWaveCache();
2610 }
2611 
2613 {
2614 }
2615 
2616 void WaveTrackCache::SetTrack(const std::shared_ptr<const WaveTrack> &pTrack)
2617 {
2618  if (mPTrack != pTrack) {
2619  if (pTrack) {
2620  mBufferSize = pTrack->GetMaxBlockSize();
2621  if (!mPTrack ||
2622  mPTrack->GetMaxBlockSize() != mBufferSize) {
2623  Free();
2624  mBuffers[0].data = Floats{ mBufferSize };
2625  mBuffers[1].data = Floats{ mBufferSize };
2626  }
2627  }
2628  else
2629  Free();
2630  mPTrack = pTrack;
2631  mNValidBuffers = 0;
2632  }
2633 }
2634 
2636  sampleCount start, size_t len, bool mayThrow)
2637 {
2638  constexpr auto format = floatSample;
2639  if (format == floatSample && len > 0) {
2640  const auto end = start + len;
2641 
2642  bool fillFirst = (mNValidBuffers < 1);
2643  bool fillSecond = (mNValidBuffers < 2);
2644 
2645  // Discard cached results that we no longer need
2646  if (mNValidBuffers > 0 &&
2647  (end <= mBuffers[0].start ||
2648  start >= mBuffers[mNValidBuffers - 1].end())) {
2649  // Complete miss
2650  fillFirst = true;
2651  fillSecond = true;
2652  }
2653  else if (mNValidBuffers == 2 &&
2654  start >= mBuffers[1].start &&
2655  end > mBuffers[1].end()) {
2656  // Request starts in the second buffer and extends past it.
2657  // Discard the first buffer.
2658  // (But don't deallocate the buffer space.)
2659  mBuffers[0] .swap ( mBuffers[1] );
2660  fillSecond = true;
2661  mNValidBuffers = 1;
2662  }
2663  else if (mNValidBuffers > 0 &&
2664  start < mBuffers[0].start &&
2665  0 <= mPTrack->GetBlockStart(start)) {
2666  // Request is not a total miss but starts before the cache,
2667  // and there is a clip to fetch from.
2668  // Not the access pattern for drawing spectrogram or playback,
2669  // but maybe scrubbing causes this.
2670  // Move the first buffer into second place, and later
2671  // refill the first.
2672  // (This case might be useful when marching backwards through
2673  // the track, as with scrubbing.)
2674  mBuffers[0] .swap ( mBuffers[1] );
2675  fillFirst = true;
2676  fillSecond = false;
2677  // Cache is not in a consistent state yet
2678  mNValidBuffers = 0;
2679  }
2680 
2681  // Refill buffers as needed
2682  if (fillFirst) {
2683  const auto start0 = mPTrack->GetBlockStart(start);
2684  if (start0 >= 0) {
2685  const auto len0 = mPTrack->GetBestBlockSize(start0);
2686  wxASSERT(len0 <= mBufferSize);
2687  if (!mPTrack->GetFloats(
2688  mBuffers[0].data.get(), start0, len0,
2689  fillZero, mayThrow))
2690  return nullptr;
2691  mBuffers[0].start = start0;
2692  mBuffers[0].len = len0;
2693  if (!fillSecond &&
2694  mBuffers[0].end() != mBuffers[1].start)
2695  fillSecond = true;
2696  // Keep the partially updated state consistent:
2697  mNValidBuffers = fillSecond ? 1 : 2;
2698  }
2699  else {
2700  // Request may fall between the clips of a track.
2701  // Invalidate all. WaveTrack::Get() will return zeroes.
2702  mNValidBuffers = 0;
2703  fillSecond = false;
2704  }
2705  }
2706  wxASSERT(!fillSecond || mNValidBuffers > 0);
2707  if (fillSecond) {
2708  mNValidBuffers = 1;
2709  const auto end0 = mBuffers[0].end();
2710  if (end > end0) {
2711  const auto start1 = mPTrack->GetBlockStart(end0);
2712  if (start1 == end0) {
2713  const auto len1 = mPTrack->GetBestBlockSize(start1);
2714  wxASSERT(len1 <= mBufferSize);
2715  if (!mPTrack->GetFloats(mBuffers[1].data.get(), start1, len1, fillZero, mayThrow))
2716  return nullptr;
2717  mBuffers[1].start = start1;
2718  mBuffers[1].len = len1;
2719  mNValidBuffers = 2;
2720  }
2721  }
2722  }
2723  wxASSERT(mNValidBuffers < 2 || mBuffers[0].end() == mBuffers[1].start);
2724 
2725  samplePtr buffer = nullptr; // will point into mOverlapBuffer
2726  auto remaining = len;
2727 
2728  // Possibly get an initial portion that is uncached
2729 
2730  // This may be negative
2731  const auto initLen =
2732  mNValidBuffers < 1 ? sampleCount( len )
2733  : std::min(sampleCount( len ), mBuffers[0].start - start);
2734 
2735  if (initLen > 0) {
2736  // This might be fetching zeroes between clips
2738  // initLen is not more than len:
2739  auto sinitLen = initLen.as_size_t();
2740  if (!mPTrack->GetFloats(
2741  // See comment below about casting
2742  reinterpret_cast<float *>(mOverlapBuffer.ptr()),
2743  start, sinitLen, fillZero, mayThrow))
2744  return nullptr;
2745  wxASSERT( sinitLen <= remaining );
2746  remaining -= sinitLen;
2747  start += initLen;
2748  buffer = mOverlapBuffer.ptr() + sinitLen * SAMPLE_SIZE(format);
2749  }
2750 
2751  // Now satisfy the request from the buffers
2752  for (int ii = 0; ii < mNValidBuffers && remaining > 0; ++ii) {
2753  const auto starti = start - mBuffers[ii].start;
2754  // Treatment of initLen above establishes this loop invariant,
2755  // and statements below preserve it:
2756  wxASSERT(starti >= 0);
2757 
2758  // This may be negative
2759  const auto leni =
2760  std::min( sampleCount( remaining ), mBuffers[ii].len - starti );
2761  if (initLen <= 0 && leni == len) {
2762  // All is contiguous already. We can completely avoid copying
2763  // leni is nonnegative, therefore start falls within mBuffers[ii],
2764  // so starti is bounded between 0 and buffer length
2765  return mBuffers[ii].data.get() + starti.as_size_t() ;
2766  }
2767  else if (leni > 0) {
2768  // leni is nonnegative, therefore start falls within mBuffers[ii]
2769  // But we can't satisfy all from one buffer, so copy
2770  if (!buffer) {
2772  buffer = mOverlapBuffer.ptr();
2773  }
2774  // leni is positive and not more than remaining
2775  const size_t size = sizeof(float) * leni.as_size_t();
2776  // starti is less than mBuffers[ii].len and nonnegative
2777  memcpy(buffer, mBuffers[ii].data.get() + starti.as_size_t(), size);
2778  wxASSERT( leni <= remaining );
2779  remaining -= leni.as_size_t();
2780  start += leni;
2781  buffer += size;
2782  }
2783  }
2784 
2785  if (remaining > 0) {
2786  // Very big request!
2787  // Fall back to direct fetch
2788  if (!buffer) {
2790  buffer = mOverlapBuffer.ptr();
2791  }
2792  // See comment below about casting
2793  if (!mPTrack->GetFloats( reinterpret_cast<float*>(buffer),
2794  start, remaining, fillZero, mayThrow))
2795  return 0;
2796  }
2797 
2798  // Overlap buffer was meant for the more general support of sample formats
2799  // besides float, which explains the cast
2800  return reinterpret_cast<const float*>(mOverlapBuffer.ptr());
2801  }
2802  else {
2803 #if 0
2804  // Cache works only for float format.
2806  if (mPTrack->Get(mOverlapBuffer.ptr(), format, start, len, fillZero, mayThrow))
2807  return mOverlapBuffer.ptr();
2808 #else
2809  // No longer handling other than float format. Therefore len is 0.
2810 #endif
2811  return nullptr;
2812  }
2813 }
2814 
2816 {
2817  mBuffers[0].Free();
2818  mBuffers[1].Free();
2819  mOverlapBuffer.Free();
2820  mNValidBuffers = 0;
2821 }
2822 
2824 {
2825  // The unspecified sequence is a post-order, but there is no
2826  // promise whether sister nodes are ordered in time.
2827  if ( !mStack.empty() ) {
2828  auto &pair = mStack.back();
2829  if ( ++pair.first == pair.second ) {
2830  mStack.pop_back();
2831  }
2832  else
2833  push( (*pair.first)->GetCutLines() );
2834  }
2835 
2836  return *this;
2837 }
2838 
2840 {
2841  auto pClips = &clips;
2842  while (!pClips->empty()) {
2843  auto first = pClips->begin();
2844  mStack.push_back( Pair( first, pClips->end() ) );
2845  pClips = &(*first)->GetCutLines();
2846  }
2847 }
2848 
2849 #include "SampleBlock.h"
2850 void VisitBlocks(TrackList &tracks, BlockVisitor visitor,
2851  SampleBlockIDSet *pIDs)
2852 {
2853  for (auto wt : tracks.Any< const WaveTrack >()) {
2854  // Scan all clips within current track
2855  for(const auto &clip : wt->GetAllClips()) {
2856  // Scan all sample blocks within current clip
2857  auto blocks = clip->GetSequenceBlockArray();
2858  for (const auto &block : *blocks) {
2859  auto &pBlock = block.sb;
2860  if ( pBlock ) {
2861  if ( pIDs && !pIDs->insert(pBlock->GetBlockID()).second )
2862  continue;
2863  if ( visitor )
2864  visitor( *pBlock );
2865  }
2866  }
2867  }
2868  }
2869 }
2870 
2871 void InspectBlocks(const TrackList &tracks, BlockInspector inspector,
2872  SampleBlockIDSet *pIDs)
2873 {
2874  VisitBlocks(
2875  const_cast<TrackList &>(tracks), std::move( inspector ), pIDs );
2876 }
2877 
2878 #include "Project.h"
2879 #include "SampleBlock.h"
2880 static auto TrackFactoryFactory = []( AudacityProject &project ) {
2881  return std::make_shared< WaveTrackFactory >(
2882  ProjectRate::Get( project ),
2883  SampleBlockFactory::New( project ) );
2884 };
2885 
2888 };
2889 
2891 {
2892  return project.AttachedObjects::Get< WaveTrackFactory >( key2 );
2893 }
2894 
2896 {
2897  return Get( const_cast< AudacityProject & >( project ) );
2898 }
2899 
2901 {
2902  auto result = TrackFactoryFactory( project );
2903  project.AttachedObjects::Assign( key2, result );
2904  return *result;
2905 }
2906 
2908 {
2909  project.AttachedObjects::Assign( key2, nullptr );
2910 }
XMLWriter
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
Definition: XMLWriter.h:23
size
size_t size
Definition: ffmpeg-2.3.6-single-header.h:412
WaveClip::Flush
void Flush()
Flush must be called after last Append.
Definition: WaveClip.cpp:1190
WaveTrack.h
WaveClip::Offset
void Offset(double delta) noexcept
Definition: WaveClip.cpp:1900
WaveTrack::SetOldChannelGain
void SetOldChannelGain(int channel, float gain)
Definition: WaveTrack.cpp:526
WaveformSettings::scaleType
ScaleType scaleType
Definition: WaveformSettings.h:67
GrowableSampleBuffer::Resize
GrowableSampleBuffer & Resize(size_t count, sampleFormat format)
Definition: SampleFormat.h:118
ClearSamples
void ClearSamples(samplePtr dst, sampleFormat format, size_t start, size_t len)
Definition: SampleFormat.cpp:77
WaveTrack::GetSequenceAtTime
Sequence * GetSequenceAtTime(double time)
Definition: WaveTrack.cpp:2221
WaveTrack::Flush
void Flush()
Flush must be called after last Append.
Definition: WaveTrack.cpp:1691
Track::mChannel
ChannelType mChannel
Definition: Track.h:407
WaveClipConstPointers
std::vector< const WaveClip * > WaveClipConstPointers
Definition: WaveTrack.h:42
Track::LinkType::Aligned
@ Aligned
anonymous_namespace{WaveTrack.cpp}::AreAligned
bool AreAligned(const WaveClipPointers &a, const WaveClipPointers &b)
Definition: WaveTrack.cpp:70
WaveTrackFactory::Get
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:2890
WaveTrack::SetSpectrumBounds
void SetSpectrumBounds(float min, float max) const
Definition: WaveTrack.cpp:376
SpectrogramSettings
Spectrogram settings, either for one track or as defaults.
Definition: SpectrogramSettings.h:27
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:69
Track::GetDefaultName
wxString GetDefaultName() const
Definition: Track.h:428
Track::mOffset
double mOffset
Definition: Track.h:408
Track::WriteCommonXMLAttributes
void WriteCommonXMLAttributes(XMLWriter &xmlFile, bool includeNameAndSelected=true) const
Definition: Track.cpp:1255
SpectrogramSettings.h
WaveClip::GetPlayStartSample
sampleCount GetPlayStartSample() const
Definition: WaveClip.cpp:1811
WaveTrack::GetNumClips
int GetNumClips() const
Definition: WaveTrack.cpp:2291
VisitBlocks
void VisitBlocks(TrackList &tracks, BlockVisitor visitor, SampleBlockIDSet *pIDs)
Definition: WaveTrack.cpp:2850
make_iterator_range
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:551
TimeWarper
Transforms one point in time to another point. For example, a time stretching effect might use one to...
Definition: TimeWarper.h:62
SampleBlockIDSet
std::unordered_set< SampleBlockID > SampleBlockIDSet
Definition: WaveTrack.h:693
WaveTrackCache::Buffer::swap
void swap(Buffer &other)
Definition: WaveTrack.h:675
GrowableSampleBuffer::Free
void Free()
Definition: SampleFormat.h:127
Track::GetLinkType
LinkType GetLinkType() const noexcept
Definition: Track.cpp:1312
WaveTrack::GetErrorOpening
bool GetErrorOpening() override
Definition: WaveTrack.cpp:1840
TrackView::Get
static TrackView & Get(Track &)
Definition: TrackView.cpp:63
WaveTrack::AllClipsIterator::Pair
std::pair< Iterator, Iterator > Pair
Definition: WaveTrack.h:414
XMLValueChecker::IsGoodInt
static bool IsGoodInt(const wxString &strInt)
Check that the supplied string can be converted to a long (32bit) integer.
Definition: XMLTagHandler.cpp:157
WaveTrackCache::mNValidBuffers
int mNValidBuffers
Definition: WaveTrack.h:687
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:70
WaveTrackCache::mBuffers
Buffer mBuffers[2]
Definition: WaveTrack.h:685
ClientData::Site::Find
Subclass * Find(const RegisteredFactory &key)
Get a (bare) pointer to an attachment, or null, down-cast it to Subclass *; will not create on demand...
Definition: ClientData.h:333
TrackView.h
WaveTrack::GetEnvelopeValues
void GetEnvelopeValues(double *buffer, size_t bufferLen, double t0) const
Definition: WaveTrack.cpp:2109
Track::GetEndTime
virtual double GetEndTime() const =0
WaveTrackCache::~WaveTrackCache
~WaveTrackCache()
Definition: WaveTrack.cpp:2612
WaveClip::GetEnvelope
Envelope * GetEnvelope()
Definition: WaveClip.h:277
GrowableSampleBuffer::ptr
samplePtr ptr() const
Definition: SampleFormat.h:98
WaveTrack::GetEndTime
double GetEndTime() const override
Get the time at which the last clip in the track ends, plus recorded stuff.
Definition: WaveTrack.cpp:1887
Track::GetName
wxString GetName() const
Definition: Track.h:426
WaveTrack::mWaveColorIndex
int mWaveColorIndex
Definition: WaveTrack.h:592
Project.h
WaveTrack::MakeNewClipName
wxString MakeNewClipName() const
Definition: WaveTrack.cpp:445
ProjectRate::Get
static ProjectRate & Get(AudacityProject &project)
Definition: ProjectRate.cpp:42
Track::ConstIntervals
std::vector< ConstInterval > ConstIntervals
Definition: Track.h:331
WaveTrackFactory::mRate
const ProjectRate & mRate
Definition: WaveTrack.h:733
InconsistencyException.h
MessageBoxException for violation of preconditions or assertions.
WaveClip::Paste
void Paste(double t0, const WaveClip *other)
Paste data from other clip, resampling it if not equal rate.
Definition: WaveClip.cpp:1314
WaveClip::SetSequenceStartTime
void SetSequenceStartTime(double startTime)
Definition: WaveClip.cpp:1873
TimeWarper.h
Contains declarations for TimeWarper, IdentityTimeWarper, ShiftTimeWarper, LinearTimeWarper,...
TrackControls::Get
static TrackControls & Get(Track &track)
Definition: TrackControls.cpp:25
fillFormat
fillFormat
Definition: SampleFormat.h:53
WaveTrack::mLastdBRange
int mLastdBRange
Definition: WaveTrack.h:606
XMLMethodRegistry::ObjectReaderEntry
Definition: XMLMethodRegistry.h:82
WaveTrack::SetLastdBRange
void SetLastdBRange() const
Definition: WaveTrack.cpp:315
PlayableTrack::Merge
void Merge(const Track &init) override
Definition: Track.cpp:318
WaveTrack::GetClipByIndex
WaveClip * GetClipByIndex(int index)
Definition: WaveTrack.cpp:2278
TrackList
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:1280
TracksPrefs.h
WaveTrack::ClearAndAddCutLine
void ClearAndAddCutLine(double t0, double t1)
Definition: WaveTrack.cpp:758
fillTwo
@ fillTwo
Definition: SampleFormat.h:55
WaveTrack::RightmostOrNewClip
WaveClip * RightmostOrNewClip()
Get access to the last (rightmost) clip, or create a clip, if there is not already one.
Definition: WaveTrack.cpp:2250
Envelope
Piecewise linear or piecewise exponential function from double to double.
Definition: Envelope.h:71
Track::SetLinkType
void SetLinkType(LinkType linkType)
Definition: Track.cpp:174
WaveTrack::mpSpectrumSettings
std::unique_ptr< SpectrogramSettings > mpSpectrumSettings
Definition: WaveTrack.h:629
WaveTrack::AllClipsIterator::mStack
Stack mStack
Definition: WaveTrack.h:417
Track::LinkConsistencyCheck
virtual bool LinkConsistencyCheck()
Definition: Track.cpp:397
WaveTrack::GetEnvelopeAtTime
Envelope * GetEnvelopeAtTime(double time)
Definition: WaveTrack.cpp:2212
WaveTrackLocation::locationMergePoint
@ locationMergePoint
Definition: WaveTrackLocation.h:18
GetEditClipsCanMove
bool GetEditClipsCanMove()
Definition: TracksBehaviorsPrefs.cpp:143
SAMPLE_SIZE
#define SAMPLE_SIZE(SampleFormat)
Definition: SampleFormat.h:44
XO
#define XO(s)
Definition: Internat.h:31
WaveTrack::GetMinMax
std::pair< float, float > GetMinMax(double t0, double t1, bool mayThrow=true) const
Definition: WaveTrack.cpp:1912
XC
#define XC(s, c)
Definition: Internat.h:37
Track::Duplicate
virtual Holder Duplicate() const
Definition: Track.cpp:112
Track::GetOwner
std::shared_ptr< TrackList > GetOwner() const
Definition: Track.h:379
WaveTrack::SetRate
void SetRate(double newRate)
Definition: WaveTrack.cpp:462
WaveTrack::WriteXML
void WriteXML(XMLWriter &xmlFile) const override
Definition: WaveTrack.cpp:1818
Region::start
double start
Definition: WaveTrack.h:56
WaveTrack::LinkConsistencyCheck
bool LinkConsistencyCheck() override
Definition: WaveTrack.cpp:278
WaveTrack::GetWaveColorIndex
int GetWaveColorIndex() const
Definition: WaveTrack.h:148
PlayableTrack::Init
void Init(const PlayableTrack &init)
Definition: Track.cpp:311
WaveTrack::mSpectrumMax
float mSpectrumMax
Definition: WaveTrack.h:603
WaveTrackFactory::Destroy
static void Destroy(AudacityProject &project)
Definition: WaveTrack.cpp:2907
WaveTrack::GetOffset
double GetOffset() const override
Definition: WaveTrack.cpp:237
WaveTrackLocation
Definition: WaveTrackLocation.h:14
WaveClipPointers
std::vector< WaveClip * > WaveClipPointers
Definition: WaveTrack.h:41
WaveTrack::GetRMS
float GetRMS(double t0, double t1, bool mayThrow=true) const
Definition: WaveTrack.cpp:1951
WaveTrackCache::Buffer::end
sampleCount end() const
Definition: WaveTrack.h:673
WaveTrack::GetSpectrogramSettings
const SpectrogramSettings & GetSpectrogramSettings() const
Definition: WaveTrack.cpp:763
Sequence
A WaveTrack contains WaveClip(s). A WaveClip contains a Sequence. A Sequence is primarily an interfac...
Definition: Sequence.h:61
WaveTrack::ClearAndPaste
void ClearAndPaste(double t0, double t1, const Track *src, bool preserve=true, bool merge=true, const TimeWarper *effectWarper=NULL)
Definition: WaveTrack.cpp:848
WaveTrack::mpWaveformSettings
std::unique_ptr< WaveformSettings > mpWaveformSettings
Definition: WaveTrack.h:630
WaveClipHolders
std::vector< WaveClipHolder > WaveClipHolders
Definition: WaveClip.h:124
Regions
std::vector< Region > Regions
Definition: WaveTrack.h:65
WaveTrack::Copy
Track::Holder Copy(double t0, double t1, bool forClipboard=true) const override
Definition: WaveTrack.cpp:680
InspectBlocks
void InspectBlocks(const TrackList &tracks, BlockInspector inspector, SampleBlockIDSet *pIDs)
Definition: WaveTrack.cpp:2871
Track::HandleCommonXMLAttribute
bool HandleCommonXMLAttribute(const wxChar *attr, const wxChar *value)
Definition: Track.cpp:1269
TracksPrefs::GetDefaultAudioTrackNamePreference
static wxString GetDefaultAudioTrackNamePreference()
Definition: TracksPrefs.cpp:422
fillZero
@ fillZero
Definition: SampleFormat.h:54
WaveTrackCache::GetFloats
const float * GetFloats(sampleCount start, size_t len, bool mayThrow)
Retrieve samples as floats from the track or from the memory cache.
Definition: WaveTrack.cpp:2635
TracksBehaviorsPrefs.h
ClientData::Site::RegisteredFactory
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:266
WaveTrack::EmptyCopy
Holder EmptyCopy(const SampleBlockFactoryPtr &pFactory={}) const
Definition: WaveTrack.cpp:671
XMLValueChecker::IsGoodString
static bool IsGoodString(const wxString &str)
Definition: XMLTagHandler.cpp:38
WaveTrack::ZeroLevelYCoordinate
int ZeroLevelYCoordinate(wxRect rect) const
Definition: WaveTrack.cpp:382
WaveTrack::GetSequenceSamplesCount
sampleCount GetSequenceSamplesCount() const
Definition: WaveTrack.cpp:551
WaveTrack::Reinit
void Reinit(const WaveTrack &orig)
Definition: WaveTrack.cpp:196
WaveTrack::RemoveAndReturnClip
std::shared_ptr< WaveClip > RemoveAndReturnClip(WaveClip *clip)
Definition: WaveTrack.cpp:1054
WaveTrack::SetWaveColorIndex
void SetWaveColorIndex(int colorIndex)
Definition: WaveTrack.cpp:534
WaveTrack::~WaveTrack
virtual ~WaveTrack()
Definition: WaveTrack.cpp:233
WaveTrack::GetClipAtSample
WaveClip * GetClipAtSample(sampleCount sample)
Definition: WaveTrack.cpp:2175
WaveTrack::SplitDelete
void SplitDelete(double t0, double t1)
Definition: WaveTrack.cpp:1012
WaveTrack::Get
bool Get(samplePtr buffer, sampleFormat format, sampleCount start, size_t len, fillFormat fill=fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const
Retrieve samples from a track in a specified format.
Definition: WaveTrack.cpp:1984
WaveTrack::Cut
Track::Holder Cut(double t0, double t1) override
Definition: WaveTrack.cpp:593
WaveTrack::mSpectrumMin
float mSpectrumMin
Definition: WaveTrack.h:602
WaveTrack::Merge
void Merge(const Track &orig) override
Definition: WaveTrack.cpp:217
WaveTrack::SortedClipArray
WaveClipPointers SortedClipArray()
Definition: WaveTrack.cpp:2595
WaveTrackFactory::mpFactory
SampleBlockFactoryPtr mpFactory
Definition: WaveTrack.h:734
key2
static const AudacityProject::AttachedObjects::RegisteredFactory key2
Definition: WaveTrack.cpp:2886
WaveformSettings.h
SampleBlock.h
WaveClip::GetSequenceEndTime
double GetSequenceEndTime() const
Definition: WaveClip.cpp:1879
WaveClip::GetSequence
Sequence * GetSequence()
Definition: WaveClip.h:285
WaveTrack::Set
void Set(constSamplePtr buffer, sampleFormat format, sampleCount start, size_t len)
Definition: WaveTrack.cpp:2067
floatSample
@ floatSample
Definition: SampleFormat.h:34
WaveTrack::NewestOrNewClip
WaveClip * NewestOrNewClip()
Get access to the most recently added clip, or create a clip, if there is not already one....
Definition: WaveTrack.cpp:2240
WaveTrack::GetIndependentSpectrogramSettings
SpectrogramSettings & GetIndependentSpectrogramSettings()
Definition: WaveTrack.cpp:779
WaveTrack::Holder
std::shared_ptr< WaveTrack > Holder
Definition: WaveTrack.h:96
BlockVisitor
std::function< void(SampleBlock &) > BlockVisitor
Definition: WaveTrack.h:695
WaveTrack::mLastScaleType
int mLastScaleType
Definition: WaveTrack.h:605
WaveTrack::SetSpectrogramSettings
void SetSpectrogramSettings(std::unique_ptr< SpectrogramSettings > &&pSettings)
Definition: WaveTrack.cpp:787
WaveClip
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:175
WaveTrack::SyncLockAdjust
void SyncLockAdjust(double oldT1, double newT1) override
Definition: WaveTrack.cpp:1213
WaveTrack::ConvertToSampleFormat
void ConvertToSampleFormat(sampleFormat format, const std::function< void(size_t)> &progressReport={})
Definition: WaveTrack.cpp:562
WaveTrack::Clear
void Clear(double t0, double t1) override
Definition: WaveTrack.cpp:752
WaveTrack::InsertSilence
void InsertSilence(double t, double len) override
Definition: WaveTrack.cpp:1447
Sequence::IsValidSampleFormat
static bool IsValidSampleFormat(const int nValue)
true if nValue is one of the sampleFormat enum values
Definition: Sequence.cpp:1958
ProgressDialog
ProgressDialog Class.
Definition: ProgressDialog.h:51
sampleCount::as_double
double as_double() const
Definition: SampleCount.h:45
WaveTrack::Split
void Split(double t0, double t1)
Definition: WaveTrack.cpp:2389
WaveTrack::Resample
void Resample(int rate, ProgressDialog *progress=NULL)
Definition: WaveTrack.cpp:2573
Sequence::GetFactory
const SampleBlockFactoryPtr & GetFactory()
Definition: Sequence.h:131
Track::Holder
std::shared_ptr< Track > Holder
Definition: Track.h:336
WaveTrack::IsEmpty
bool IsEmpty(double t0, double t1) const
Returns true if there are no WaveClips in the specified region.
Definition: WaveTrack.cpp:571
WaveTrack::LongSamplesToTime
double LongSamplesToTime(sampleCount pos) const
Convert correctly between a number of samples and an (absolute) time in seconds.
Definition: WaveTrack.cpp:1862
WaveTrack::GetIdealBlockSize
size_t GetIdealBlockSize()
Definition: WaveTrack.cpp:1681
Track::SetDefaultName
void SetDefaultName(const wxString &n)
Definition: Track.h:429
WaveTrack::FindClipByName
const WaveClip * FindClipByName(const wxString &name) const
Returns nullptr if clip with such name was not found.
Definition: WaveTrack.cpp:418
WaveTrack::RemoveCutLine
bool RemoveCutLine(double cutLinePosition)
Definition: WaveTrack.cpp:2543
WaveTrack::SplitCut
Track::Holder SplitCut(double t0, double t1)
Definition: WaveTrack.cpp:606
WaveTrackCache::Buffer::len
sampleCount len
Definition: WaveTrack.h:669
WaveTrack::GetSpectrumBounds
void GetSpectrumBounds(float *min, float *max) const
Definition: WaveTrack.cpp:332
Track::LinkType::Group
@ Group
WaveTrack::mRate
int mRate
Definition: WaveTrack.h:589
constSamplePtr
const char * constSamplePtr
Definition: SampleFormat.h:50
WaveTrack::GetPlaySamplesCount
sampleCount GetPlaySamplesCount() const
Definition: WaveTrack.cpp:541
WaveTrack::SetPanFromChannelType
virtual void SetPanFromChannelType() override
Definition: WaveTrack.cpp:270
WaveTrackCache::Buffer::Free
void Free()
Definition: WaveTrack.h:672
WaveTrackCache::mPTrack
std::shared_ptr< const WaveTrack > mPTrack
Definition: WaveTrack.h:683
WaveTrackCache::mOverlapBuffer
GrowableSampleBuffer mOverlapBuffer
Definition: WaveTrack.h:686
WaveTrack::CreateClip
WaveClip * CreateClip(double offset=.0, const wxString &name=wxEmptyString)
Definition: WaveTrack.cpp:2230
WaveTrackCache::mBufferSize
size_t mBufferSize
Definition: WaveTrack.h:684
WaveTrack::mGain
float mGain
Definition: WaveTrack.h:590
WaveTrack::CloseLock
bool CloseLock()
Definition: WaveTrack.cpp:1849
name
const TranslatableString name
Definition: Distortion.cpp:98
WaveTrack::Paste
void Paste(double t0, const Track *src) override
Definition: WaveTrack.cpp:1413
WaveTrack::mDisplayLocationsCache
std::vector< Location > mDisplayLocationsCache
Definition: WaveTrack.h:607
WaveTrack::WaveTrack
WaveTrack(const SampleBlockFactoryPtr &pFactory, sampleFormat format, double rate)
Definition: WaveTrack.cpp:127
Track::RightChannel
@ RightChannel
Definition: Track.h:277
format
int format
Definition: ExportPCM.cpp:56
WaveTrack::mpFactory
SampleBlockFactoryPtr mpFactory
Definition: WaveTrack.h:623
WaveTrack::mClips
WaveClipHolders mClips
Definition: WaveTrack.h:586
WaveTrack::SetGain
void SetGain(float newGain)
Definition: WaveTrack.cpp:479
TrackControls.h
THROW_INCONSISTENCY_EXCEPTION
#define THROW_INCONSISTENCY_EXCEPTION
Throw InconsistencyException, using C++ preprocessor to identify the source code location.
Definition: InconsistencyException.h:79
WaveTrack::SetDisplayBounds
void SetDisplayBounds(float min, float max) const
Definition: WaveTrack.cpp:326
WaveTrack::CanInsertClip
bool CanInsertClip(WaveClip *clip, double &slideBy, double &tolerance) const
Definition: WaveTrack.cpp:2354
anonymous_namespace{WaveTrack.cpp}::FillSortedClipArray
Cont1 FillSortedClipArray(const Cont2 &mClips)
Definition: WaveTrack.cpp:2583
Track::LinkType::None
@ None
WaveTrack::GetGain
float GetGain() const
Definition: WaveTrack.cpp:474
SampleBlockFactory::New
static SampleBlockFactoryPtr New(AudacityProject &project)
Definition: SampleBlock.cpp:31
WaveTrackFactory::Reset
static WaveTrackFactory & Reset(AudacityProject &project)
Definition: WaveTrack.cpp:2900
ProjectRate::GetRate
double GetRate() const
Definition: ProjectRate.cpp:68
SpectrogramSettings::ScaleType
int ScaleType
Definition: SpectrogramSettings.h:57
WaveClip::GetPlayEndTime
double GetPlayEndTime() const
Definition: WaveClip.cpp:1800
WaveTrack::GetWaveformSettings
const WaveformSettings & GetWaveformSettings() const
Definition: WaveTrack.cpp:811
WaveTrack::GetStartTime
double GetStartTime() const override
Get the time at which the first clip in the track starts.
Definition: WaveTrack.cpp:1867
WaveTrack::Init
void Init(const WaveTrack &orig)
Definition: WaveTrack.cpp:175
WaveTrack::SetLastScaleType
void SetLastScaleType() const
Definition: WaveTrack.cpp:310
WaveTrack::GetSampleFormat
sampleFormat GetSampleFormat() const
Definition: WaveTrack.h:154
WaveTrack::Append
bool Append(constSamplePtr buffer, sampleFormat format, size_t len, unsigned int stride=1)
Append the sample data to the WaveTrack. You must call Flush() after the last Append.
Definition: WaveTrack.cpp:1621
MakeIntervals
static Container MakeIntervals(const std::vector< WaveClipHolder > &clips)
Definition: WaveTrack.cpp:389
WaveClipHolder
std::shared_ptr< WaveClip > WaveClipHolder
Definition: WaveClip.h:123
SpectrogramSettings::stLinear
@ stLinear
Definition: SpectrogramSettings.h:59
WaveTrack::GetClipAtTime
WaveClip * GetClipAtTime(double time)
Definition: WaveTrack.cpp:2191
TimeWarper::Warp
virtual double Warp(double originalTime) const =0
Region::end
double end
Definition: WaveTrack.h:56
PlayableTrack
AudioTrack subclass that can also be audibly replayed by the program.
Definition: Track.h:854
WaveTrackCache::SetTrack
void SetTrack(const std::shared_ptr< const WaveTrack > &pTrack)
Definition: WaveTrack.cpp:2616
WaveTrackFactory
Used to create or clone a WaveTrack, with appropriate context from the project that will own the trac...
Definition: WaveTrack.h:713
XMLTagHandler
This class is an interface which should be implemented by classes which wish to be able to load and s...
Definition: XMLTagHandler.h:62
Track::Intervals
std::vector< Interval > Intervals
Definition: Track.h:329
WaveClip::Append
bool Append(constSamplePtr buffer, sampleFormat format, size_t len, unsigned int stride)
Definition: WaveClip.cpp:1129
Envelope.h
WaveTrack::mFormat
sampleFormat mFormat
Definition: WaveTrack.h:588
WaveTrack::MergeClips
void MergeClips(int clipidx1, int clipidx2)
Definition: WaveTrack.cpp:2553
sampleFormat
sampleFormat
Definition: SampleFormat.h:29
samplePtr
char * samplePtr
Definition: SampleFormat.h:49
BlockInspector
std::function< void(const SampleBlock &) > BlockInspector
Definition: WaveTrack.h:696
WaveformSettings::defaults
static WaveformSettings & defaults()
Definition: WaveformSettings.cpp:69
WaveTrack::GetMaxBlockSize
size_t GetMaxBlockSize() const
Definition: WaveTrack.cpp:1661
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
WaveTrack::UseSpectralPrefs
void UseSpectralPrefs(bool bUse=true)
Definition: WaveTrack.cpp:794
WaveTrack::HandleXMLEndTag
void HandleXMLEndTag(const wxChar *tag) override
Definition: WaveTrack.cpp:1775
WaveTrack::GetChannelIgnoringPan
virtual ChannelType GetChannelIgnoringPan() const
Definition: WaveTrack.cpp:254
WaveTrack::GetIntervals
ConstIntervals GetIntervals() const override
Report times on the track where important intervals begin and end, for UI to snap to.
Definition: WaveTrack.cpp:408
Track::TypeSwitch
R TypeSwitch(const Functions &...functions)
Use this function rather than testing track type explicitly and making down-casts.
Definition: Track.h:709
WaveTrack::GetOldChannelGain
float GetOldChannelGain(int channel) const
Definition: WaveTrack.cpp:521
WaveTrack::HandleClear
void HandleClear(double t0, double t1, bool addCutLines, bool split)
Definition: WaveTrack.cpp:1080
WaveTrack::HandleXMLChild
XMLTagHandler * HandleXMLChild(const wxChar *tag) override
Definition: WaveTrack.cpp:1782
WaveTrack::CanOffsetClips
bool CanOffsetClips(const std::vector< WaveClip * > &clips, double amount, double *allowedAmount=nullptr)
Decide whether the clips could be offset (and inserted) together without overlapping other clips.
Definition: WaveTrack.cpp:2296
WaveTrack::Join
void Join(double t0, double t1)
Definition: WaveTrack.cpp:1564
QualitySettings.h
WaveTrack::TimeToLongSamples
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: WaveTrack.cpp:1857
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:506
WaveTrack::AddClip
bool AddClip(const std::shared_ptr< WaveClip > &clip)
Append a clip to the track; which must have the same block factory as this track; return success.
Definition: WaveTrack.cpp:1067
Track::SetName
void SetName(const wxString &n)
Definition: Track.cpp:82
Track
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:239
anonymous_namespace{WaveTrack.cpp}::IsValidChannel
bool IsValidChannel(const int nValue)
Definition: WaveTrack.cpp:1698
Track::Notify
void Notify(int code=-1)
Definition: Track.cpp:286
WaveClip::NumCutLines
size_t NumCutLines() const
Definition: WaveClip.h:349
readerEntry
static ProjectFileIORegistry::ObjectReaderEntry readerEntry
Definition: WaveTrack.cpp:100
Track::ChannelType
ChannelType
Definition: Track.h:275
WaveTrack::SetPan
void SetPan(float newPan) override
Definition: WaveTrack.cpp:492
WaveTrack::ClearWaveCaches
void ClearWaveCaches()
Invalidates all clips' wavecaches. Careful, This may not be threadsafe.
Definition: WaveTrack.cpp:2606
WaveTrack::MakeClipCopyName
wxString MakeClipCopyName(const wxString &originalName) const
Definition: WaveTrack.cpp:433
sampleCount
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
QualitySettings::SampleFormatChoice
PROJECT_RATE_API sampleFormat SampleFormatChoice()
Definition: QualitySettings.cpp:38
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:92
WaveTrackCache::Free
void Free()
Definition: WaveTrack.cpp:2815
WaveTrack::AllClipsIterator
Definition: WaveTrack.h:379
WaveClip::GetSequenceStartTime
double GetSequenceStartTime() const noexcept
Definition: WaveClip.cpp:1867
WaveTrack::GetBlockStart
sampleCount GetBlockStart(sampleCount t) const
Definition: WaveTrack.cpp:1627
WaveformSettings::dBRange
int dBRange
Definition: WaveformSettings.h:68
Track::MonoChannel
@ MonoChannel
Definition: Track.h:278
WaveTrack::SetOffset
void SetOffset(double o) override
Definition: WaveTrack.cpp:243
WaveTrack::mOldGain
float mOldGain[2]
Definition: WaveTrack.h:593
WaveformSettings
Waveform settings, either for one track or as defaults.
Definition: WaveformSettings.h:19
WaveTrack::CopyNonconst
Track::Holder CopyNonconst(double t0, double t1)
Definition: WaveTrack.cpp:746
Sequence.h
ProjectRate.h
an object holding per-project preferred sample rate
WaveTrack::UpdateLocationsCache
void UpdateLocationsCache() const
Definition: WaveTrack.cpp:2416
WaveTrack::AllClipsIterator::push
void push(WaveClipHolders &clips)
Definition: WaveTrack.cpp:2839
WaveTrack::Silence
void Silence(double t0, double t1) override
Definition: WaveTrack.cpp:1422
WaveTrackLocation::locationCutLine
@ locationCutLine
Definition: WaveTrackLocation.h:17
Region
#define Region
Definition: VSTControlGTK.h:16
WaveTrack::PasteWaveTrack
void PasteWaveTrack(double t0, const WaveTrack *other)
Definition: WaveTrack.cpp:1253
WaveTrack::GetBestBlockSize
size_t GetBestBlockSize(sampleCount t) const
Definition: WaveTrack.cpp:1643
Track::SetChannel
void SetChannel(ChannelType c) noexcept
Definition: Track.cpp:198
Prefs.h
WaveTrack::Clone
Track::Holder Clone() const override
Definition: WaveTrack.cpp:428
WaveTrack::AllClipsIterator::operator++
AllClipsIterator & operator++()
Definition: WaveTrack.cpp:2823
WaveTrack::GetChannelGain
float GetChannelGain(int channel) const
Definition: WaveTrack.cpp:505
TrackFactoryFactory
static auto TrackFactoryFactory
Definition: WaveTrack.cpp:2880
TrackList::Any
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:1371
WaveTrack::GetPan
float GetPan() const
Definition: WaveTrack.cpp:487
PlayableTrack::HandleXMLAttribute
bool HandleXMLAttribute(const wxChar *attr, const wxChar *value)
Definition: Track.cpp:352
WaveTrack::mDisplayMax
float mDisplayMax
Definition: WaveTrack.h:601
WAVETRACK_MERGE_POINT_TOLERANCE
#define WAVETRACK_MERGE_POINT_TOLERANCE
Definition: WaveTrack.h:47
WaveTrack::HandleXMLTag
bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override
Definition: WaveTrack.cpp:1704
WaveTrack::GetDisplayBounds
void GetDisplayBounds(float *min, float *max) const
Definition: WaveTrack.cpp:320
SampleBlockFactoryPtr
std::shared_ptr< SampleBlockFactory > SampleBlockFactoryPtr
Definition: SampleBlock.h:25
WaveTrack::PasteInto
Track::Holder PasteInto(AudacityProject &) const override
Find or create the destination track for a paste, maybe in a different project.
Definition: WaveTrack.cpp:399
anonymous_namespace{WaveTrack.cpp}::FindClip
WaveClipHolders::iterator FindClip(WaveClipHolders &list, const WaveClip *clip, int *distance=nullptr)
Definition: WaveTrack.cpp:1038
PlayableTrack::WriteXMLAttributes
void WriteXMLAttributes(XMLWriter &xmlFile) const
Definition: Track.cpp:344
ExceptionType::BadUserAction
@ BadUserAction
Indicates that the user performed an action that is not allowed.
anonymous_namespace{WaveTrack.cpp}::ToLinkType
Track::LinkType ToLinkType(int value)
Definition: WaveTrack.cpp:89
Region
Structure to hold region of a wavetrack and a comparison function for sortability.
Definition: WaveTrack.h:52
settings
static Settings & settings()
Definition: TrackInfo.cpp:86
lrint
#define lrint(dbl)
Definition: float_cast.h:169
float_cast.h
WaveTrack::SplitAt
void SplitAt(double t)
Definition: WaveTrack.cpp:2397
Track::LinkType
LinkType
For two tracks describes the type of the linkage.
Definition: Track.h:243
SpectrogramSettings::stPeriod
@ stPeriod
Definition: SpectrogramSettings.h:64
WaveTrackCache::Buffer::data
Floats data
Definition: WaveTrack.h:667
limitSampleBufferSize
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: SampleCount.cpp:23
SimpleMessageBoxException
A MessageBoxException that shows a given, unvarying string.
Definition: AudacityException.h:95
Track::LeftChannel
@ LeftChannel
Definition: Track.h:276
WaveTrack::GetChannel
ChannelType GetChannel() const override
Definition: WaveTrack.cpp:258
WaveTrack::mLegacyProjectFileOffset
double mLegacyProjectFileOffset
Definition: WaveTrack.h:627
WaveClip::GetPlayStartTime
double GetPlayStartTime() const noexcept
Definition: WaveClip.cpp:1790
WaveTrack::mPan
float mPan
Definition: WaveTrack.h:591
WaveTrackFactory::NewWaveTrack
std::shared_ptr< WaveTrack > NewWaveTrack(sampleFormat format=(sampleFormat) 0, double rate=0)
Definition: WaveTrack.cpp:118
WaveTrack::Trim
void Trim(double t0, double t1)
Definition: WaveTrack.cpp:639
WaveTrack::Disjoin
void Disjoin(double t0, double t1)
Definition: WaveTrack.cpp:1487
ArrayOf< float >
WaveTrackCache::Buffer::start
sampleCount start
Definition: WaveTrack.h:668
WaveTrack::SetWaveformSettings
void SetWaveformSettings(std::unique_ptr< WaveformSettings > &&pSettings)
Definition: WaveTrack.cpp:825
WaveTrack::GetClipIndex
int GetClipIndex(const WaveClip *clip) const
Definition: WaveTrack.cpp:2271
WaveTrack::ExpandCutLine
void ExpandCutLine(double cutLinePosition, double *cutlineStart=NULL, double *cutlineEnd=NULL)
Definition: WaveTrack.cpp:2490
SpectrogramSettings::defaults
static SpectrogramSettings & defaults()
Definition: SpectrogramSettings.cpp:177
Internat::CompatibleToDouble
static bool CompatibleToDouble(const wxString &stringToConvert, double *result)
Convert a string to a number.
Definition: Internat.cpp:134
WaveTrack::mDisplayMin
float mDisplayMin
Definition: WaveTrack.h:600
WaveClip.h
WaveTrackFactory::DuplicateWaveTrack
std::shared_ptr< WaveTrack > DuplicateWaveTrack(const WaveTrack &orig)
Definition: WaveTrack.cpp:112
Sequence::GetIdealBlockSize
size_t GetIdealBlockSize() const
Definition: Sequence.cpp:81
WaveClip::HandleXMLEndTag
void HandleXMLEndTag(const wxChar *tag) override
Definition: WaveClip.cpp:1270
IdentityTimeWarper
No change to time at all.
Definition: TimeWarper.h:69
WaveTrack::GetRate
double GetRate() const
Definition: WaveTrack.cpp:457