1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-16 08:09:32 +02:00

All tracks allocated with make_shared, no more make_unique...

... so that we can use Track::SharedPointer without undefined behavior even on
tracks that don't yet belong to any TrackList.

Also fix the return type of function template TrackList::Add and remove some
casts.
This commit is contained in:
Paul Licameli 2018-11-18 23:07:05 -05:00
parent 6f89c48873
commit a0aa69a248
18 changed files with 60 additions and 109 deletions

View File

@ -99,7 +99,7 @@ int LabelTrack::mFontHeight=-1;
LabelTrack::Holder TrackFactory::NewLabelTrack() LabelTrack::Holder TrackFactory::NewLabelTrack()
{ {
return std::make_unique<LabelTrack>(mDirManager); return std::make_shared<LabelTrack>(mDirManager);
} }
LabelTrack::LabelTrack(const std::shared_ptr<DirManager> &projDirManager): LabelTrack::LabelTrack(const std::shared_ptr<DirManager> &projDirManager):
@ -1142,7 +1142,7 @@ double LabelTrack::GetEndTime() const
Track::Holder LabelTrack::Duplicate() const Track::Holder LabelTrack::Duplicate() const
{ {
return std::make_unique<LabelTrack>( *this ); return std::make_shared<LabelTrack>( *this );
} }
void LabelTrack::SetSelected(bool s) void LabelTrack::SetSelected(bool s)
@ -2489,7 +2489,7 @@ Track::Holder LabelTrack::SplitCut(double t0, double t1)
Track::Holder LabelTrack::Copy(double t0, double t1, bool) const Track::Holder LabelTrack::Copy(double t0, double t1, bool) const
{ {
auto tmp = std::make_unique<LabelTrack>(GetDirManager()); auto tmp = std::make_shared<LabelTrack>(GetDirManager());
const auto lt = static_cast<LabelTrack*>(tmp.get()); const auto lt = static_cast<LabelTrack*>(tmp.get());
for (auto &labelStruct: mLabels) { for (auto &labelStruct: mLabels) {
@ -2534,8 +2534,7 @@ Track::Holder LabelTrack::Copy(double t0, double t1, bool) const
} }
lt->mClipLen = (t1 - t0); lt->mClipLen = (t1 - t0);
// This std::move is needed to "upcast" the pointer type return tmp;
return std::move(tmp);
} }

View File

@ -161,7 +161,7 @@ class AUDACITY_DLL_API LabelTrack final : public Track
double GetStartTime() const override; double GetStartTime() const override;
double GetEndTime() const override; double GetEndTime() const override;
using Holder = std::unique_ptr<LabelTrack>; using Holder = std::shared_ptr<LabelTrack>;
Track::Holder Duplicate() const override; Track::Holder Duplicate() const override;
void SetSelected(bool s) override; void SetSelected(bool s) override;

View File

@ -49,7 +49,8 @@ class WaveTrackCache;
void MixAndRender(TrackList * tracks, TrackFactory *factory, void MixAndRender(TrackList * tracks, TrackFactory *factory,
double rate, sampleFormat format, double rate, sampleFormat format,
double startTime, double endTime, double startTime, double endTime,
std::unique_ptr<WaveTrack> &uLeft, std::unique_ptr<WaveTrack> &uRight); std::shared_ptr<WaveTrack> &uLeft,
std::shared_ptr<WaveTrack> &uRight);
void MixBuffers(unsigned numChannels, int *channelFlags, float *gains, void MixBuffers(unsigned numChannels, int *channelFlags, float *gains,
samplePtr src, samplePtr src,

View File

@ -104,7 +104,7 @@ SONFNS(AutoSave)
NoteTrack::Holder TrackFactory::NewNoteTrack() NoteTrack::Holder TrackFactory::NewNoteTrack()
{ {
return std::make_unique<NoteTrack>(mDirManager); return std::make_shared<NoteTrack>(mDirManager);
} }
NoteTrack::NoteTrack(const std::shared_ptr<DirManager> &projDirManager) NoteTrack::NoteTrack(const std::shared_ptr<DirManager> &projDirManager)
@ -155,7 +155,7 @@ Alg_seq &NoteTrack::GetSeq() const
Track::Holder NoteTrack::Duplicate() const Track::Holder NoteTrack::Duplicate() const
{ {
auto duplicate = std::make_unique<NoteTrack>(mDirManager); auto duplicate = std::make_shared<NoteTrack>(mDirManager);
duplicate->Init(*this); duplicate->Init(*this);
// The duplicate begins life in serialized state. Often the duplicate is // The duplicate begins life in serialized state. Often the duplicate is
// pushed on the Undo stack. Then we want to un-serialize it (or a further // pushed on the Undo stack. Then we want to un-serialize it (or a further
@ -190,8 +190,7 @@ Track::Holder NoteTrack::Duplicate() const
#ifdef EXPERIMENTAL_MIDI_OUT #ifdef EXPERIMENTAL_MIDI_OUT
duplicate->SetVelocity(GetVelocity()); duplicate->SetVelocity(GetVelocity());
#endif #endif
// This std::move is needed to "upcast" the pointer type return duplicate;
return std::move(duplicate);
} }
@ -463,7 +462,7 @@ Track::Holder NoteTrack::Cut(double t0, double t1)
//( std::min( t1, GetEndTime() ) ) - ( std::max( t0, GetStartTime() ) ) //( std::min( t1, GetEndTime() ) ) - ( std::max( t0, GetStartTime() ) )
//); //);
auto newTrack = std::make_unique<NoteTrack>(mDirManager); auto newTrack = std::make_shared<NoteTrack>(mDirManager);
newTrack->Init(*this); newTrack->Init(*this);
@ -480,8 +479,7 @@ Track::Holder NoteTrack::Cut(double t0, double t1)
//(mBottomNote, mDirManager, //(mBottomNote, mDirManager,
// mSerializationBuffer, mSerializationLength, mVisibleChannels) // mSerializationBuffer, mSerializationLength, mVisibleChannels)
// This std::move is needed to "upcast" the pointer type return newTrack;
return std::move(newTrack);
} }
Track::Holder NoteTrack::Copy(double t0, double t1, bool) const Track::Holder NoteTrack::Copy(double t0, double t1, bool) const
@ -491,7 +489,7 @@ Track::Holder NoteTrack::Copy(double t0, double t1, bool) const
double len = t1-t0; double len = t1-t0;
auto newTrack = std::make_unique<NoteTrack>(mDirManager); auto newTrack = std::make_shared<NoteTrack>(mDirManager);
newTrack->Init(*this); newTrack->Init(*this);
@ -504,8 +502,7 @@ Track::Holder NoteTrack::Copy(double t0, double t1, bool) const
// (mBottomNote, mDirManager, mSerializationBuffer, // (mBottomNote, mDirManager, mSerializationBuffer,
// mSerializationLength, mVisibleChannels) // mSerializationLength, mVisibleChannels)
// This std::move is needed to "upcast" the pointer type return newTrack;
return std::move(newTrack);
} }
bool NoteTrack::Trim(double t0, double t1) bool NoteTrack::Trim(double t0, double t1)

View File

@ -75,7 +75,7 @@ class AUDACITY_DLL_API NoteTrack final
const AudacityProject *pProject, int currentTool, bool bMultiTool) const AudacityProject *pProject, int currentTool, bool bMultiTool)
override; override;
using Holder = std::unique_ptr<NoteTrack>; using Holder = std::shared_ptr<NoteTrack>;
Track::Holder Duplicate() const override; Track::Holder Duplicate() const override;
double GetOffset() const override; double GetOffset() const override;

View File

@ -33,9 +33,9 @@
#define TIMETRACK_MIN 0.01 #define TIMETRACK_MIN 0.01
#define TIMETRACK_MAX 10.0 #define TIMETRACK_MAX 10.0
std::unique_ptr<TimeTrack> TrackFactory::NewTimeTrack() std::shared_ptr<TimeTrack> TrackFactory::NewTimeTrack()
{ {
return std::make_unique<TimeTrack>(mDirManager, mZoomInfo); return std::make_shared<TimeTrack>(mDirManager, mZoomInfo);
} }
TimeTrack::TimeTrack(const std::shared_ptr<DirManager> &projDirManager, const ZoomInfo *zoomInfo): TimeTrack::TimeTrack(const std::shared_ptr<DirManager> &projDirManager, const ZoomInfo *zoomInfo):
@ -108,8 +108,7 @@ Track::Holder TimeTrack::Cut( double t0, double t1 )
Track::Holder TimeTrack::Copy( double t0, double t1, bool ) const Track::Holder TimeTrack::Copy( double t0, double t1, bool ) const
{ {
auto result = std::make_unique<TimeTrack>( *this, &t0, &t1 ); return std::make_shared<TimeTrack>( *this, &t0, &t1 );
return Track::Holder{ std::move( result ) };
} }
void TimeTrack::Clear(double t0, double t1) void TimeTrack::Clear(double t0, double t1)
@ -143,7 +142,7 @@ void TimeTrack::InsertSilence(double t, double len)
Track::Holder TimeTrack::Duplicate() const Track::Holder TimeTrack::Duplicate() const
{ {
return std::make_unique<TimeTrack>(*this); return std::make_shared<TimeTrack>(*this);
} }
bool TimeTrack::GetInterpolateLog() const bool TimeTrack::GetInterpolateLog() const

View File

@ -728,35 +728,10 @@ Track *TrackList::FindById( TrackId id )
return it->get(); return it->get();
} }
template<typename TrackKind> Track *TrackList::DoAddToHead(const std::shared_ptr<Track> &t)
Track *TrackList::Add(std::unique_ptr<TrackKind> &&t)
{ {
Track *pTrack; Track *pTrack = t.get();
push_back(ListOfTracks::value_type(pTrack = t.release())); push_front(ListOfTracks::value_type(t));
auto n = getPrev( getEnd() );
pTrack->SetOwner(mSelf, n);
pTrack->SetId( TrackId{ ++sCounter } );
RecalcPositions(n);
AdditionEvent(n);
return back().get();
}
// Make instantiations for the linker to find
template Track *TrackList::Add<TimeTrack>(std::unique_ptr<TimeTrack> &&);
#if defined(USE_MIDI)
template Track *TrackList::Add<NoteTrack>(std::unique_ptr<NoteTrack> &&);
#endif
template Track *TrackList::Add<WaveTrack>(std::unique_ptr<WaveTrack> &&);
template Track *TrackList::Add<LabelTrack>(std::unique_ptr<LabelTrack> &&);
template Track *TrackList::Add<Track>(std::unique_ptr<Track> &&);
template<typename TrackKind>
Track *TrackList::AddToHead(std::unique_ptr<TrackKind> &&t)
{
Track *pTrack;
push_front(ListOfTracks::value_type(pTrack = t.release()));
auto n = getBegin(); auto n = getBegin();
pTrack->SetOwner(mSelf, n); pTrack->SetOwner(mSelf, n);
pTrack->SetId( TrackId{ ++sCounter } ); pTrack->SetId( TrackId{ ++sCounter } );
@ -765,11 +740,7 @@ Track *TrackList::AddToHead(std::unique_ptr<TrackKind> &&t)
return front().get(); return front().get();
} }
// Make instantiations for the linker to find Track *TrackList::DoAdd(const std::shared_ptr<Track> &t)
template Track *TrackList::AddToHead<TimeTrack>(std::unique_ptr<TimeTrack> &&);
template<typename TrackKind>
Track *TrackList::Add(std::shared_ptr<TrackKind> &&t)
{ {
push_back(t); push_back(t);
@ -782,10 +753,6 @@ Track *TrackList::Add(std::shared_ptr<TrackKind> &&t)
return back().get(); return back().get();
} }
// Make instantiations for the linker to find
template Track *TrackList::Add<Track>(std::shared_ptr<Track> &&);
template Track *TrackList::Add<WaveTrack>(std::shared_ptr<WaveTrack> &&);
void TrackList::GroupChannels( void TrackList::GroupChannels(
Track &track, size_t groupSize, bool resetChannels ) Track &track, size_t groupSize, bool resetChannels )
{ {
@ -1234,8 +1201,7 @@ TrackList::RegisterPendingChangedTrack( Updater updater, Track *src )
{ {
std::shared_ptr<Track> pTrack; std::shared_ptr<Track> pTrack;
if (src) if (src)
// convert from unique_ptr to shared_ptr pTrack = src->Duplicate();
pTrack.reset( src->Duplicate().release() );
if (pTrack) { if (pTrack) {
mUpdaters.push_back( updater ); mUpdaters.push_back( updater );

View File

@ -367,7 +367,7 @@ private:
void Init(const Track &orig); void Init(const Track &orig);
using Holder = std::unique_ptr<Track>; using Holder = std::shared_ptr<Track>;
virtual Holder Duplicate() const = 0; virtual Holder Duplicate() const = 0;
// Called when this track is merged to stereo with another, and should // Called when this track is merged to stereo with another, and should
@ -1330,6 +1330,9 @@ class TrackList final : public wxEvtHandler, public ListOfTracks
} }
private: private:
Track *DoAddToHead(const std::shared_ptr<Track> &t);
Track *DoAdd(const std::shared_ptr<Track> &t);
template< typename TrackType, typename InTrackType > template< typename TrackType, typename InTrackType >
static TrackIterRange< TrackType > static TrackIterRange< TrackType >
Channels_( TrackIter< InTrackType > iter1 ) Channels_( TrackIter< InTrackType > iter1 )
@ -1369,15 +1372,12 @@ public:
/// Add a Track, giving it a fresh id /// Add a Track, giving it a fresh id
template<typename TrackKind> template<typename TrackKind>
Track *Add(std::unique_ptr<TrackKind> &&t); TrackKind *AddToHead( const std::shared_ptr< TrackKind > &t )
{ return static_cast< TrackKind* >( DoAddToHead( t ) ); }
/// Add a Track, giving it a fresh id
template<typename TrackKind> template<typename TrackKind>
Track *AddToHead(std::unique_ptr<TrackKind> &&t); TrackKind *Add( const std::shared_ptr< TrackKind > &t )
{ return static_cast< TrackKind* >( DoAdd( t ) ); }
/// Add a Track, giving it a fresh id
template<typename TrackKind>
Track *Add(std::shared_ptr<TrackKind> &&t);
/** \brief Define a group of channels starting at the given track /** \brief Define a group of channels starting at the given track
* *
@ -1632,13 +1632,13 @@ class AUDACITY_DLL_API TrackFactory
public: public:
// These methods are defined in WaveTrack.cpp, NoteTrack.cpp, // These methods are defined in WaveTrack.cpp, NoteTrack.cpp,
// LabelTrack.cpp, and TimeTrack.cpp respectively // LabelTrack.cpp, and TimeTrack.cpp respectively
std::unique_ptr<WaveTrack> DuplicateWaveTrack(const WaveTrack &orig); std::shared_ptr<WaveTrack> DuplicateWaveTrack(const WaveTrack &orig);
std::unique_ptr<WaveTrack> NewWaveTrack(sampleFormat format = (sampleFormat)0, std::shared_ptr<WaveTrack> NewWaveTrack(sampleFormat format = (sampleFormat)0,
double rate = 0); double rate = 0);
std::unique_ptr<LabelTrack> NewLabelTrack(); std::shared_ptr<LabelTrack> NewLabelTrack();
std::unique_ptr<TimeTrack> NewTimeTrack(); std::shared_ptr<TimeTrack> NewTimeTrack();
#if defined(USE_MIDI) #if defined(USE_MIDI)
std::unique_ptr<NoteTrack> NewNoteTrack(); std::shared_ptr<NoteTrack> NewNoteTrack();
#endif #endif
}; };

View File

@ -70,15 +70,13 @@ using std::max;
WaveTrack::Holder TrackFactory::DuplicateWaveTrack(const WaveTrack &orig) WaveTrack::Holder TrackFactory::DuplicateWaveTrack(const WaveTrack &orig)
{ {
return std::unique_ptr<WaveTrack> return std::static_pointer_cast<WaveTrack>( orig.Duplicate() );
{ static_cast<WaveTrack*>(orig.Duplicate().release()) };
} }
WaveTrack::Holder TrackFactory::NewWaveTrack(sampleFormat format, double rate) WaveTrack::Holder TrackFactory::NewWaveTrack(sampleFormat format, double rate)
{ {
return std::unique_ptr<WaveTrack> return std::make_shared<WaveTrack> ( mDirManager, format, rate );
{ safenew WaveTrack(mDirManager, format, rate) };
} }
WaveTrack::WaveTrack(const std::shared_ptr<DirManager> &projDirManager, sampleFormat format, double rate) : WaveTrack::WaveTrack(const std::shared_ptr<DirManager> &projDirManager, sampleFormat format, double rate) :
@ -395,7 +393,7 @@ int WaveTrack::ZeroLevelYCoordinate(wxRect rect) const
Track::Holder WaveTrack::Duplicate() const Track::Holder WaveTrack::Duplicate() const
{ {
return Track::Holder{ safenew WaveTrack{ *this } }; return std::make_shared<WaveTrack>( *this );
} }
double WaveTrack::GetRate() const double WaveTrack::GetRate() const
@ -629,9 +627,8 @@ Track::Holder WaveTrack::Copy(double t0, double t1, bool forClipboard) const
if (t1 < t0) if (t1 < t0)
THROW_INCONSISTENCY_EXCEPTION; THROW_INCONSISTENCY_EXCEPTION;
WaveTrack *newTrack; auto result = std::make_shared<WaveTrack>( mDirManager );
Track::Holder result WaveTrack *newTrack = result.get();
{ newTrack = safenew WaveTrack{ mDirManager } };
newTrack->Init(*this); newTrack->Init(*this);

View File

@ -58,28 +58,24 @@ using Regions = std::vector < Region >;
class Envelope; class Envelope;
class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { class AUDACITY_DLL_API WaveTrack final : public PlayableTrack {
public:
private:
// //
// Constructor / Destructor / Duplicator // Constructor / Destructor / Duplicator
// //
// Private since only factories are allowed to construct WaveTracks
//
WaveTrack(const std::shared_ptr<DirManager> &projDirManager, WaveTrack(const std::shared_ptr<DirManager> &projDirManager,
sampleFormat format = (sampleFormat)0, sampleFormat format = (sampleFormat)0,
double rate = 0); double rate = 0);
WaveTrack(const WaveTrack &orig); WaveTrack(const WaveTrack &orig);
void Init(const WaveTrack &orig);
public:
// overwrite data excluding the sample sequence but including display // overwrite data excluding the sample sequence but including display
// settings // settings
void Reinit(const WaveTrack &orig); void Reinit(const WaveTrack &orig);
private: private:
void Init(const WaveTrack &orig);
Track::Holder Duplicate() const override; Track::Holder Duplicate() const override;
friend class TrackFactory; friend class TrackFactory;
@ -87,7 +83,7 @@ private:
public: public:
typedef WaveTrackLocation Location; typedef WaveTrackLocation Location;
using Holder = std::unique_ptr<WaveTrack>; using Holder = std::shared_ptr<WaveTrack>;
virtual ~WaveTrack(); virtual ~WaveTrack();

View File

@ -1207,7 +1207,7 @@ bool Effect::DoEffect(wxWindow *parent,
// We don't yet know the effect type for code in the Nyquist Prompt, so // We don't yet know the effect type for code in the Nyquist Prompt, so
// assume it requires a track and handle errors when the effect runs. // assume it requires a track and handle errors when the effect runs.
if ((GetType() == EffectTypeGenerate || GetPath() == NYQUIST_PROMPT_ID) && (mNumTracks == 0)) { if ((GetType() == EffectTypeGenerate || GetPath() == NYQUIST_PROMPT_ID) && (mNumTracks == 0)) {
newTrack = static_cast<WaveTrack*>(mTracks->Add(mFactory->NewWaveTrack())); newTrack = mTracks->Add(mFactory->NewWaveTrack());
newTrack->SetSelected(true); newTrack->SetSelected(true);
} }
@ -1553,7 +1553,7 @@ bool Effect::ProcessTrack(int count,
auto chans = std::min<unsigned>(mNumAudioOut, mNumChannels); auto chans = std::min<unsigned>(mNumAudioOut, mNumChannels);
std::unique_ptr<WaveTrack> genLeft, genRight; std::shared_ptr<WaveTrack> genLeft, genRight;
decltype(len) genLength = 0; decltype(len) genLength = 0;
bool isGenerator = GetType() == EffectTypeGenerate; bool isGenerator = GetType() == EffectTypeGenerate;
@ -2073,11 +2073,11 @@ void Effect::CopyInputTracks(bool allSyncLockSelected)
} }
} }
Track *Effect::AddToOutputTracks(std::unique_ptr<Track> &&t) Track *Effect::AddToOutputTracks(const std::shared_ptr<Track> &t)
{ {
mIMap.push_back(NULL); mIMap.push_back(NULL);
mOMap.push_back(t.get()); mOMap.push_back(t.get());
return mOutputTracks->Add(std::move(t)); return mOutputTracks->Add(t);
} }
Effect::AddedAnalysisTrack::AddedAnalysisTrack(Effect *pEffect, const wxString &name) Effect::AddedAnalysisTrack::AddedAnalysisTrack(Effect *pEffect, const wxString &name)

View File

@ -443,7 +443,7 @@ protected:
void ReplaceProcessedTracks(const bool bGoodResult); void ReplaceProcessedTracks(const bool bGoodResult);
// Use this to append a NEW output track. // Use this to append a NEW output track.
Track *AddToOutputTracks(std::unique_ptr<Track> &&t); Track *AddToOutputTracks(const std::shared_ptr<Track> &t);
// //
// protected data // protected data

View File

@ -59,8 +59,8 @@ public:
// Not required by callbacks, but makes for easier cleanup // Not required by callbacks, but makes for easier cleanup
std::unique_ptr<Resampler> resampler; std::unique_ptr<Resampler> resampler;
std::unique_ptr<SBSMSQuality> quality; std::unique_ptr<SBSMSQuality> quality;
std::unique_ptr<WaveTrack> outputLeftTrack; std::shared_ptr<WaveTrack> outputLeftTrack;
std::unique_ptr<WaveTrack> outputRightTrack; std::shared_ptr<WaveTrack> outputRightTrack;
std::exception_ptr mpException {}; std::exception_ptr mpException {};
}; };

View File

@ -1419,7 +1419,7 @@ bool NyquistEffect::ProcessOne()
return false; return false;
} }
std::unique_ptr<WaveTrack> outputTrack[2]; std::shared_ptr<WaveTrack> outputTrack[2];
double rate = mCurTrack[0]->GetRate(); double rate = mCurTrack[0]->GetRate();
for (int i = 0; i < outChannels; i++) { for (int i = 0; i < outChannels; i++) {

View File

@ -23,7 +23,7 @@ class wxWindow;
// Newly constructed WaveTracks that are not yet owned by a TrackList // Newly constructed WaveTracks that are not yet owned by a TrackList
// are held in unique_ptr not shared_ptr // are held in unique_ptr not shared_ptr
using NewChannelGroup = std::vector< std::unique_ptr<WaveTrack> >; using NewChannelGroup = std::vector< std::shared_ptr<WaveTrack> >;
using TrackHolders = std::vector< NewChannelGroup >; using TrackHolders = std::vector< NewChannelGroup >;

View File

@ -41,10 +41,8 @@ int DoAddLabel(
auto lt = * iter.Filter< LabelTrack >(); auto lt = * iter.Filter< LabelTrack >();
// If none found, start a NEW label track and use it // If none found, start a NEW label track and use it
if (!lt) { if (!lt)
lt = static_cast<LabelTrack*> lt = tracks->Add(trackFactory->NewLabelTrack());
(tracks->Add(trackFactory->NewLabelTrack()));
}
// LLL: Commented as it seemed a little forceful to remove users // LLL: Commented as it seemed a little forceful to remove users
// selection when adding the label. This does not happen if // selection when adding the label. This does not happen if
@ -158,7 +156,7 @@ void EditByLabel(
} }
} }
using EditDestFunction = std::unique_ptr<Track> (WaveTrack::*)(double, double); using EditDestFunction = std::shared_ptr<Track> (WaveTrack::*)(double, double);
//Executes the edit function on all selected wave tracks with //Executes the edit function on all selected wave tracks with
//regions specified by selected labels //regions specified by selected labels

View File

@ -1168,9 +1168,7 @@ bool ControlToolBar::DoRecord(AudacityProject &project,
Track *first {}; Track *first {};
for (int c = 0; c < recordingChannels; c++) { for (int c = 0; c < recordingChannels; c++) {
std::shared_ptr<WaveTrack> newTrack{ auto newTrack = p->GetTrackFactory()->NewWaveTrack();
p->GetTrackFactory()->NewWaveTrack().release()
};
if (!first) if (!first)
first = newTrack.get(); first = newTrack.get();

View File

@ -156,7 +156,7 @@ class TranscriptionToolBar final : public ToolBar {
int mBackgroundWidth; int mBackgroundWidth;
int mBackgroundHeight; int mBackgroundHeight;
std::unique_ptr<TimeTrack> mTimeTrack; std::shared_ptr<TimeTrack> mTimeTrack;
public: public: