1 /********************************************************************** 2 3 Audacity: A Digital Audio Editor 4 5 WaveTrack.h 6 7 Dominic Mazzoni 8 9 **********************************************************************/ 10 11 #ifndef __AUDACITY_WAVETRACK__ 12 #define __AUDACITY_WAVETRACK__ 13 14 #include "Track.h" 15 #include "SampleCount.h" 16 17 #include <vector> 18 #include <functional> 19 #include <wx/longlong.h> 20 21 #include "WaveTrackLocation.h" 22 23 class ProgressDialog; 24 25 class SampleBlockFactory; 26 using SampleBlockFactoryPtr = std::shared_ptr<SampleBlockFactory>; 27 28 class SpectrogramSettings; 29 class WaveformSettings; 30 class TimeWarper; 31 32 class Sequence; 33 class WaveClip; 34 35 // Array of pointers that assume ownership 36 using WaveClipHolder = std::shared_ptr< WaveClip >; 37 using WaveClipHolders = std::vector < WaveClipHolder >; 38 using WaveClipConstHolders = std::vector < std::shared_ptr< const WaveClip > >; 39 40 // Temporary arrays of mere pointers 41 using WaveClipPointers = std::vector < WaveClip* >; 42 using WaveClipConstPointers = std::vector < const WaveClip* >; 43 44 // 45 // Tolerance for merging wave tracks (in seconds) 46 // 47 #define WAVETRACK_MERGE_POINT_TOLERANCE 0.01 48 49 /// \brief Structure to hold region of a wavetrack and a comparison function 50 /// for sortability. 51 struct Region 52 { RegionRegion53 Region() : start(0), end(0) {} RegionRegion54 Region(double start_, double end_) : start(start_), end(end_) {} 55 56 double start, end; 57 58 //used for sorting 59 bool operator < (const Region &b) const 60 { 61 return this->start < b.start; 62 } 63 }; 64 65 using Regions = std::vector < Region >; 66 67 class Envelope; 68 69 class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { 70 public: 71 72 // 73 // Constructor / Destructor / Duplicator 74 // 75 76 WaveTrack( 77 const SampleBlockFactoryPtr &pFactory, sampleFormat format, double rate); 78 WaveTrack(const WaveTrack &orig); 79 80 // overwrite data excluding the sample sequence but including display 81 // settings 82 void Reinit(const WaveTrack &orig); 83 private: 84 void Init(const WaveTrack &orig); 85 86 Track::Holder Clone() const override; 87 88 friend class WaveTrackFactory; 89 90 wxString MakeClipCopyName(const wxString& originalName) const; 91 wxString MakeNewClipName() const; 92 public: 93 94 typedef WaveTrackLocation Location; 95 using Holder = std::shared_ptr<WaveTrack>; 96 97 virtual ~WaveTrack(); 98 99 double GetOffset() const override; 100 void SetOffset(double o) override; 101 virtual ChannelType GetChannelIgnoringPan() const; 102 ChannelType GetChannel() const override; 103 virtual void SetPanFromChannelType() override; 104 105 bool LinkConsistencyCheck() override; 106 107 /** @brief Get the time at which the first clip in the track starts 108 * 109 * @return time in seconds, or zero if there are no clips in the track 110 */ 111 double GetStartTime() const override; 112 113 /** @brief Get the time at which the last clip in the track ends, plus 114 * recorded stuff 115 * 116 * @return time in seconds, or zero if there are no clips in the track. 117 */ 118 double GetEndTime() const override; 119 120 // 121 // Identifying the type of track 122 // 123 124 // 125 // WaveTrack parameters 126 // 127 128 double GetRate() const; 129 void SetRate(double newRate); 130 131 // Multiplicative factor. Only converted to dB for display. 132 float GetGain() const; 133 void SetGain(float newGain); 134 135 // -1.0 (left) -> 1.0 (right) 136 float GetPan() const; 137 void SetPan(float newPan) override; 138 139 // Takes gain and pan into account 140 float GetChannelGain(int channel) const; 141 142 // Old gain is used in playback in linearly interpolating 143 // the gain. 144 float GetOldChannelGain(int channel) const; 145 void SetOldChannelGain(int channel, float gain); 146 GetWaveColorIndex()147 int GetWaveColorIndex() const { return mWaveColorIndex; }; 148 void SetWaveColorIndex(int colorIndex); 149 150 sampleCount GetPlaySamplesCount() const; 151 sampleCount GetSequenceSamplesCount() const; 152 GetSampleFormat()153 sampleFormat GetSampleFormat() const { return mFormat; } 154 void ConvertToSampleFormat(sampleFormat format, 155 const std::function<void(size_t)> & progressReport = {}); 156 157 const SpectrogramSettings &GetSpectrogramSettings() const; 158 SpectrogramSettings &GetSpectrogramSettings(); 159 SpectrogramSettings &GetIndependentSpectrogramSettings(); 160 void SetSpectrogramSettings(std::unique_ptr<SpectrogramSettings> &&pSettings); 161 162 const WaveformSettings &GetWaveformSettings() const; 163 WaveformSettings &GetWaveformSettings(); 164 void SetWaveformSettings(std::unique_ptr<WaveformSettings> &&pSettings); 165 void UseSpectralPrefs( bool bUse=true ); 166 // 167 // High-level editing 168 // 169 170 Track::Holder Cut(double t0, double t1) override; 171 172 // Make another track copying format, rate, color, etc. but containing no 173 // clips 174 // It is important to pass the correct factory (that for the project 175 // which will own the copy) in the unusual case that a track is copied from 176 // another project or the clipboard. For copies within one project, the 177 // default will do. 178 Holder EmptyCopy(const SampleBlockFactoryPtr &pFactory = {} ) const; 179 180 // If forClipboard is true, 181 // and there is no clip at the end time of the selection, then the result 182 // will contain a "placeholder" clip whose only purpose is to make 183 // GetEndTime() correct. This clip is not re-copied when pasting. 184 Track::Holder Copy(double t0, double t1, bool forClipboard = true) const override; 185 Track::Holder CopyNonconst(double t0, double t1) /* not override */; 186 187 void Clear(double t0, double t1) override; 188 void Paste(double t0, const Track *src) override; 189 // May assume precondition: t0 <= t1 190 void ClearAndPaste(double t0, double t1, 191 const Track *src, 192 bool preserve = true, 193 bool merge = true, 194 const TimeWarper *effectWarper = NULL) /* not override */; 195 196 void Silence(double t0, double t1) override; 197 void InsertSilence(double t, double len) override; 198 199 void SplitAt(double t) /* not override */; 200 void Split(double t0, double t1) /* not override */; 201 // Track::Holder CutAndAddCutLine(double t0, double t1) /* not override */; 202 // May assume precondition: t0 <= t1 203 void ClearAndAddCutLine(double t0, double t1) /* not override */; 204 205 Track::Holder SplitCut(double t0, double t1) /* not override */; 206 // May assume precondition: t0 <= t1 207 void SplitDelete(double t0, double t1) /* not override */; 208 void Join(double t0, double t1) /* not override */; 209 // May assume precondition: t0 <= t1 210 void Disjoin(double t0, double t1) /* not override */; 211 212 // May assume precondition: t0 <= t1 213 void Trim(double t0, double t1) /* not override */; 214 215 // May assume precondition: t0 <= t1 216 void HandleClear(double t0, double t1, bool addCutLines, bool split); 217 218 void SyncLockAdjust(double oldT1, double newT1) override; 219 220 /** @brief Returns true if there are no WaveClips in the specified region 221 * 222 * @return true if no clips in the track overlap the specified time range, 223 * false otherwise. 224 */ 225 bool IsEmpty(double t0, double t1) const; 226 227 /** @brief Append the sample data to the WaveTrack. You must call Flush() 228 * after the last Append. 229 * 230 * If there is an existing WaveClip in the WaveTrack then the data is 231 * appended to that clip. If there are no WaveClips in the track, then a NEW 232 * one is created. 233 * 234 * @return true if at least one complete block was created 235 */ 236 bool Append(constSamplePtr buffer, sampleFormat format, 237 size_t len, unsigned int stride=1); 238 /// Flush must be called after last Append 239 void Flush(); 240 241 ///Invalidates all clips' wavecaches. Careful, This may not be threadsafe. 242 void ClearWaveCaches(); 243 244 /// 245 /// MM: Now that each wave track can contain multiple clips, we don't 246 /// have a continuous space of samples anymore, but we simulate it, 247 /// because there are a lot of places (e.g. effects) using this interface. 248 /// This interface makes much sense for modifying samples, but note that 249 /// it is not time-accurate, because the "offset" is a double value and 250 /// therefore can lie inbetween samples. But as long as you use the 251 /// same value for "start" in both calls to "Set" and "Get" it is 252 /// guaranteed that the same samples are affected. 253 /// 254 255 //! Retrieve samples from a track in floating-point format, regardless of the storage format 256 /*! 257 @param buffer receives the samples 258 @param start starting sample, relative to absolute time zero (not to the track's offset value) 259 @param len how many samples to get. buffer is assumed sufficiently large 260 @param fill how to assign values for sample positions between clips 261 @param mayThrow if false, fill buffer with zeros when there is failure to retrieve samples; else throw 262 @param[out] pNumWithinClips Report how many samples were copied from within clips, rather 263 than filled according to fillFormat; but these were not necessarily one contiguous range. 264 */ 265 bool GetFloats(float *buffer, sampleCount start, size_t len, 266 fillFormat fill = fillZero, bool mayThrow = true, 267 sampleCount * pNumWithinClips = nullptr) const 268 { 269 //! Cast the pointer to pass it to Get() which handles multiple destination formats 270 return Get(reinterpret_cast<samplePtr>(buffer), 271 floatSample, start, len, fill, mayThrow, pNumWithinClips); 272 } 273 274 //! Retrieve samples from a track in a specified format 275 /*! 276 @copydetails WaveTrack::GetFloats() 277 @param format sample format of the destination buffer 278 */ 279 bool Get(samplePtr buffer, sampleFormat format, 280 sampleCount start, size_t len, 281 fillFormat fill = fillZero, 282 bool mayThrow = true, 283 // Report how many samples were copied from within clips, rather than 284 // filled according to fillFormat; but these were not necessarily one 285 // contiguous range. 286 sampleCount * pNumWithinClips = nullptr) const; 287 288 void Set(constSamplePtr buffer, sampleFormat format, 289 sampleCount start, size_t len); 290 291 // Fetch envelope values corresponding to uniformly separated sample times 292 // starting at the given time. 293 void GetEnvelopeValues(double *buffer, size_t bufferLen, 294 double t0) const; 295 296 // May assume precondition: t0 <= t1 297 std::pair<float, float> GetMinMax( 298 double t0, double t1, bool mayThrow = true) const; 299 // May assume precondition: t0 <= t1 300 float GetRMS(double t0, double t1, bool mayThrow = true) const; 301 302 // 303 // MM: We now have more than one sequence and envelope per track, so 304 // instead of GetSequence() and GetEnvelope() we have the following 305 // function which give the sequence and envelope which contains the given 306 // time. 307 // 308 Sequence* GetSequenceAtTime(double time); 309 Envelope* GetEnvelopeAtTime(double time); 310 311 WaveClip* GetClipAtSample(sampleCount sample); 312 WaveClip* GetClipAtTime(double time); 313 314 // 315 // Getting information about the track's internal block sizes 316 // and alignment for efficiency 317 // 318 319 // This returns a possibly large or negative value 320 sampleCount GetBlockStart(sampleCount t) const; 321 322 // These return a nonnegative number of samples meant to size a memory buffer 323 size_t GetBestBlockSize(sampleCount t) const; 324 size_t GetMaxBlockSize() const; 325 size_t GetIdealBlockSize(); 326 327 // 328 // XMLTagHandler callback methods for loading and saving 329 // 330 331 bool HandleXMLTag(const std::string_view& tag, const AttributesList& attrs) override; 332 void HandleXMLEndTag(const std::string_view& tag) override; 333 XMLTagHandler *HandleXMLChild(const std::string_view& tag) override; 334 void WriteXML(XMLWriter &xmlFile) const override; 335 336 // Returns true if an error occurred while reading from XML 337 bool GetErrorOpening() override; 338 339 // 340 // Lock and unlock the track: you must lock the track before 341 // doing a copy and paste between projects. 342 // 343 344 bool CloseLock(); //should be called when the project closes. 345 // not balanced by unlocking calls. 346 347 /** @brief Convert correctly between an (absolute) time in seconds and a number of samples. 348 * 349 * This method will not give the correct results if used on a relative time (difference of two 350 * times). Each absolute time must be converted and the numbers of samples differenced: 351 * sampleCount start = track->TimeToLongSamples(t0); 352 * sampleCount end = track->TimeToLongSamples(t1); 353 * sampleCount len = (sampleCount)(end - start); 354 * NOT the likes of: 355 * sampleCount len = track->TimeToLongSamples(t1 - t0); 356 * See also WaveTrack::TimeToLongSamples(). 357 * @param t0 The time (floating point seconds) to convert 358 * @return The number of samples from the start of the track which lie before the given time. 359 */ 360 sampleCount TimeToLongSamples(double t0) const; 361 /** @brief Convert correctly between a number of samples and an (absolute) time in seconds. 362 * 363 * @param pos The time number of samples from the start of the track to convert. 364 * @return The time in seconds. 365 */ 366 double LongSamplesToTime(sampleCount pos) const; 367 368 // Get access to the (visible) clips in the tracks, in unspecified order 369 // (not necessarily sequenced in time). GetClips()370 WaveClipHolders &GetClips() { return mClips; } GetClips()371 const WaveClipConstHolders &GetClips() const 372 { return reinterpret_cast< const WaveClipConstHolders& >( mClips ); } 373 374 // Get mutative access to all clips (in some unspecified sequence), 375 // including those hidden in cutlines. 376 class AllClipsIterator 377 : public ValueIterator< WaveClip * > 378 { 379 public: 380 // Constructs an "end" iterator AllClipsIterator()381 AllClipsIterator () {} 382 383 // Construct a "begin" iterator AllClipsIterator(WaveTrack & track)384 explicit AllClipsIterator( WaveTrack &track ) 385 { 386 push( track.mClips ); 387 } 388 389 WaveClip *operator * () const 390 { 391 if (mStack.empty()) 392 return nullptr; 393 else 394 return mStack.back().first->get(); 395 } 396 397 AllClipsIterator &operator ++ (); 398 399 // Define == well enough to serve for loop termination test 400 friend bool operator == ( 401 const AllClipsIterator &a, const AllClipsIterator &b) 402 { return a.mStack.empty() == b.mStack.empty(); } 403 404 friend bool operator != ( 405 const AllClipsIterator &a, const AllClipsIterator &b) 406 { return !( a == b ); } 407 408 private: 409 410 void push( WaveClipHolders &clips ); 411 412 using Iterator = WaveClipHolders::iterator; 413 using Pair = std::pair< Iterator, Iterator >; 414 using Stack = std::vector< Pair >; 415 416 Stack mStack; 417 }; 418 419 // Get const access to all clips (in some unspecified sequence), 420 // including those hidden in cutlines. 421 class AllClipsConstIterator 422 : public ValueIterator< const WaveClip * > 423 { 424 public: 425 // Constructs an "end" iterator AllClipsConstIterator()426 AllClipsConstIterator () {} 427 428 // Construct a "begin" iterator AllClipsConstIterator(const WaveTrack & track)429 explicit AllClipsConstIterator( const WaveTrack &track ) 430 : mIter{ const_cast< WaveTrack& >( track ) } 431 {} 432 433 const WaveClip *operator * () const 434 { return *mIter; } 435 436 AllClipsConstIterator &operator ++ () 437 { ++mIter; return *this; } 438 439 // Define == well enough to serve for loop termination test 440 friend bool operator == ( 441 const AllClipsConstIterator &a, const AllClipsConstIterator &b) 442 { return a.mIter == b.mIter; } 443 444 friend bool operator != ( 445 const AllClipsConstIterator &a, const AllClipsConstIterator &b) 446 { return !( a == b ); } 447 448 private: 449 AllClipsIterator mIter; 450 }; 451 GetAllClips()452 IteratorRange< AllClipsIterator > GetAllClips() 453 { 454 return { AllClipsIterator{ *this }, AllClipsIterator{ } }; 455 } 456 GetAllClips()457 IteratorRange< AllClipsConstIterator > GetAllClips() const 458 { 459 return { AllClipsConstIterator{ *this }, AllClipsConstIterator{ } }; 460 } 461 462 // Create NEW clip and add it to this track. Returns a pointer 463 // to the newly created clip. Optionally initial offset and 464 // clip name may be provided 465 WaveClip* CreateClip(double offset = .0, const wxString& name = wxEmptyString); 466 467 /** @brief Get access to the most recently added clip, or create a clip, 468 * if there is not already one. THIS IS NOT NECESSARILY RIGHTMOST. 469 * 470 * @return a pointer to the most recently added WaveClip 471 */ 472 WaveClip* NewestOrNewClip(); 473 474 /** @brief Get access to the last (rightmost) clip, or create a clip, 475 * if there is not already one. 476 * 477 * @return a pointer to a WaveClip at the end of the track 478 */ 479 WaveClip* RightmostOrNewClip(); 480 481 // Get the linear index of a given clip (-1 if the clip is not found) 482 int GetClipIndex(const WaveClip* clip) const; 483 484 // Get the nth clip in this WaveTrack (will return NULL if not found). 485 // Use this only in special cases (like getting the linked clip), because 486 // it is much slower than GetClipIterator(). 487 WaveClip *GetClipByIndex(int index); 488 const WaveClip* GetClipByIndex(int index) const; 489 490 // Get number of clips in this WaveTrack 491 int GetNumClips() const; 492 493 // Add all wave clips to the given array 'clips' and sort the array by 494 // clip start time. The array is emptied prior to adding the clips. 495 WaveClipPointers SortedClipArray(); 496 WaveClipConstPointers SortedClipArray() const; 497 498 //! Decide whether the clips could be offset (and inserted) together without overlapping other clips 499 /*! 500 @return true if possible to offset by `(allowedAmount ? *allowedAmount : amount)` 501 */ 502 bool CanOffsetClips( 503 const std::vector<WaveClip*> &clips, //!< not necessarily in this track 504 double amount, //!< signed 505 double *allowedAmount = nullptr /*!< 506 [out] if null, test exact amount only; else, largest (in magnitude) possible offset with same sign */ 507 ); 508 509 // Before moving a clip into a track (or inserting a clip), use this 510 // function to see if the times are valid (i.e. don't overlap with 511 // existing clips). 512 bool CanInsertClip(WaveClip* clip, double &slideBy, double &tolerance) const; 513 514 // Remove the clip from the track and return a SMART pointer to it. 515 // You assume responsibility for its memory! 516 std::shared_ptr<WaveClip> RemoveAndReturnClip(WaveClip* clip); 517 518 //! Append a clip to the track; which must have the same block factory as this track; return success 519 bool AddClip(const std::shared_ptr<WaveClip> &clip); 520 521 // Merge two clips, that is append data from clip2 to clip1, 522 // then remove clip2 from track. 523 // clipidx1 and clipidx2 are indices into the clip list. 524 void MergeClips(int clipidx1, int clipidx2); 525 526 // Cache special locations (e.g. cut lines) for later speedy access 527 void UpdateLocationsCache() const; 528 529 // Get cached locations GetCachedLocations()530 const std::vector<Location> &GetCachedLocations() const { return mDisplayLocationsCache; } 531 532 // Expand cut line (that is, re-insert audio, then DELETE audio saved in cut line) 533 void ExpandCutLine(double cutLinePosition, double* cutlineStart = NULL, double* cutlineEnd = NULL); 534 535 // Remove cut line, without expanding the audio in it 536 bool RemoveCutLine(double cutLinePosition); 537 538 // This track has been merged into a stereo track. Copy shared parameters 539 // from the NEW partner. 540 void Merge(const Track &orig) override; 541 542 // Resample track (i.e. all clips in the track) 543 void Resample(int rate, ProgressDialog *progress = NULL); 544 GetLastScaleType()545 int GetLastScaleType() const { return mLastScaleType; } 546 void SetLastScaleType() const; 547 GetLastdBRange()548 int GetLastdBRange() const { return mLastdBRange; } 549 void SetLastdBRange() const; 550 551 void GetDisplayBounds(float *min, float *max) const; 552 void SetDisplayBounds(float min, float max) const; 553 void GetSpectrumBounds(float *min, float *max) const; 554 void SetSpectrumBounds(float min, float max) const; 555 556 // For display purposes, calculate the y coordinate where the midline of 557 // the wave should be drawn, if display minimum and maximum map to the 558 // bottom and top. Maybe that is out of bounds. 559 int ZeroLevelYCoordinate(wxRect rect) const; 560 561 class IntervalData final : public Track::IntervalData { 562 public: IntervalData(const std::shared_ptr<WaveClip> & pClip)563 explicit IntervalData( const std::shared_ptr<WaveClip> &pClip ) 564 : pClip{ pClip } 565 {} GetClip()566 std::shared_ptr<const WaveClip> GetClip() const { return pClip; } GetClip()567 std::shared_ptr<WaveClip> &GetClip() { return pClip; } 568 private: 569 std::shared_ptr<WaveClip> pClip; 570 }; 571 572 Track::Holder PasteInto( AudacityProject & ) const override; 573 574 ConstIntervals GetIntervals() const override; 575 Intervals GetIntervals() override; 576 577 //! Returns nullptr if clip with such name was not found 578 const WaveClip* FindClipByName(const wxString& name) const; 579 protected: 580 // 581 // Protected variables 582 // 583 584 WaveClipHolders mClips; 585 586 sampleFormat mFormat; 587 int mRate; 588 float mGain; 589 float mPan; 590 int mWaveColorIndex; 591 float mOldGain[2]; 592 593 594 // 595 // Data that should be part of GUIWaveTrack 596 // and will be taken out of the WaveTrack class: 597 // 598 mutable float mDisplayMin; 599 mutable float mDisplayMax; 600 mutable float mSpectrumMin; 601 mutable float mSpectrumMax; 602 603 mutable int mLastScaleType; // last scale type choice 604 mutable int mLastdBRange; 605 mutable std::vector <Location> mDisplayLocationsCache; 606 607 // 608 // Protected methods 609 // 610 611 private: 612 613 void PasteWaveTrack(double t0, const WaveTrack* other); 614 GetKind()615 TrackKind GetKind() const override { return TrackKind::Wave; } 616 617 // 618 // Private variables 619 // 620 621 SampleBlockFactoryPtr mpFactory; 622 623 wxCriticalSection mFlushCriticalSection; 624 wxCriticalSection mAppendCriticalSection; 625 double mLegacyProjectFileOffset; 626 627 std::unique_ptr<SpectrogramSettings> mpSpectrumSettings; 628 std::unique_ptr<WaveformSettings> mpWaveformSettings; 629 }; 630 631 //! A short-lived object, during whose lifetime, the contents of the WaveTrack are assumed not to change. 632 /*! It can replace repeated calls to WaveTrack::Get() (each of which opens and closes at least one block). 633 */ 634 class AUDACITY_DLL_API WaveTrackCache { 635 public: WaveTrackCache()636 WaveTrackCache() 637 : mBufferSize(0) 638 , mOverlapBuffer() 639 , mNValidBuffers(0) 640 { 641 } 642 WaveTrackCache(const std::shared_ptr<const WaveTrack> & pTrack)643 explicit WaveTrackCache(const std::shared_ptr<const WaveTrack> &pTrack) 644 : mBufferSize(0) 645 , mOverlapBuffer() 646 , mNValidBuffers(0) 647 { 648 SetTrack(pTrack); 649 } 650 ~WaveTrackCache(); 651 GetTrack()652 const std::shared_ptr<const WaveTrack>& GetTrack() const { return mPTrack; } 653 void SetTrack(const std::shared_ptr<const WaveTrack> &pTrack); 654 655 //! Retrieve samples as floats from the track or from the memory cache 656 /*! Uses fillZero always 657 @return null on failure; this object owns the memory; may be invalidated if GetFloats() is called again 658 */ 659 const float *GetFloats(sampleCount start, size_t len, bool mayThrow); 660 661 private: 662 void Free(); 663 664 struct Buffer { 665 Floats data; 666 sampleCount start; 667 sampleCount len; 668 BufferBuffer669 Buffer() : start(0), len(0) {} FreeBuffer670 void Free() { data.reset(); start = 0; len = 0; } endBuffer671 sampleCount end() const { return start + len; } 672 swapBuffer673 void swap ( Buffer &other ) 674 { 675 data .swap ( other.data ); 676 std::swap( start, other.start ); 677 std::swap( len, other.len ); 678 } 679 }; 680 681 std::shared_ptr<const WaveTrack> mPTrack; 682 size_t mBufferSize; 683 Buffer mBuffers[2]; 684 GrowableSampleBuffer mOverlapBuffer; 685 int mNValidBuffers; 686 }; 687 688 #include <unordered_set> 689 class SampleBlock; 690 using SampleBlockID = long long; 691 using SampleBlockIDSet = std::unordered_set<SampleBlockID>; 692 class TrackList; 693 using BlockVisitor = std::function< void(SampleBlock&) >; 694 using BlockInspector = std::function< void(const SampleBlock&) >; 695 696 // Function to visit all sample blocks from a list of tracks. 697 // If a set is supplied, then only visit once each unique block ID not already 698 // in that set, and accumulate those into the set as a side-effect. 699 // The visitor function may be null. 700 void VisitBlocks(TrackList &tracks, BlockVisitor visitor, 701 SampleBlockIDSet *pIDs = nullptr); 702 703 // Non-mutating version of the above 704 void InspectBlocks(const TrackList &tracks, BlockInspector inspector, 705 SampleBlockIDSet *pIDs = nullptr); 706 707 class ProjectRate; 708 709 class AUDACITY_DLL_API WaveTrackFactory final 710 : public ClientData::Base 711 { 712 public: 713 static WaveTrackFactory &Get( AudacityProject &project ); 714 static const WaveTrackFactory &Get( const AudacityProject &project ); 715 static WaveTrackFactory &Reset( AudacityProject &project ); 716 static void Destroy( AudacityProject &project ); 717 WaveTrackFactory(const ProjectRate & rate,const SampleBlockFactoryPtr & pFactory)718 WaveTrackFactory( 719 const ProjectRate& rate, 720 const SampleBlockFactoryPtr &pFactory) 721 : mRate{ rate } 722 , mpFactory(pFactory) 723 { 724 } 725 WaveTrackFactory( const WaveTrackFactory & ) PROHIBITED; 726 WaveTrackFactory &operator=( const WaveTrackFactory & ) PROHIBITED; 727 GetSampleBlockFactory()728 const SampleBlockFactoryPtr &GetSampleBlockFactory() const 729 { return mpFactory; } 730 731 private: 732 const ProjectRate &mRate; 733 SampleBlockFactoryPtr mpFactory; 734 public: 735 std::shared_ptr<WaveTrack> DuplicateWaveTrack(const WaveTrack &orig); 736 std::shared_ptr<WaveTrack> NewWaveTrack( 737 sampleFormat format = (sampleFormat)0, 738 double rate = 0); 739 }; 740 741 #endif // __AUDACITY_WAVETRACK__ 742