1
0
mirror of https://github.com/cookiengineer/audacity synced 2026-01-02 06:08:44 +01:00

Move TrackShifter subclasses each to its own new source file...

... These do not require header files; they are tiny proto-plugins that work
by registration of AttachedVirtualFunction overrides at startup.

Dependency may go from them to TrackView subclasses but not back; so in
principle a reduced Audacity without time-shift could be linked that still uses
the TrackView subclasses.

But other work to make the hit test for the Time Shift tool registrable would
have to precede that.
This commit is contained in:
Paul Licameli
2020-09-20 14:17:27 -04:00
committed by James Crook
parent 4abd38b9a0
commit 2b542bf734
7 changed files with 486 additions and 462 deletions

View File

@@ -1303,172 +1303,3 @@ void WaveTrackView::Draw(
CommonTrackView::Draw( context, rect, iPass );
}
class WaveTrackShifter final : public TrackShifter {
public:
WaveTrackShifter( WaveTrack &track )
: mpTrack{ track.SharedPointer<WaveTrack>() }
{
InitIntervals();
}
~WaveTrackShifter() override {}
Track &GetTrack() const override { return *mpTrack; }
HitTestResult HitTest(
double time, const ViewInfo &viewInfo, HitTestParams* ) override
{
auto pClip = mpTrack->GetClipAtTime( time );
if (!pClip)
return HitTestResult::Miss;
auto t0 = viewInfo.selectedRegion.t0();
auto t1 = viewInfo.selectedRegion.t1();
if ( mpTrack->IsSelected() && time >= t0 && time < t1 ) {
// Unfix maybe many intervals (at least one because of test above)
SelectInterval({t0, t1});
return HitTestResult::Selection;
}
// Select just one interval
UnfixIntervals( [&](const auto &interval){
return
static_cast<WaveTrack::IntervalData*>(interval.Extra())
->GetClip().get() == pClip;
} );
return HitTestResult::Intervals;
}
void SelectInterval( const TrackInterval &interval ) override
{
UnfixIntervals( [&](auto &myInterval){
// Use a slightly different test from CommonSelectInterval, rounding times
// to exact samples according to the clip's rate
auto data =
static_cast<WaveTrack::IntervalData*>( myInterval.Extra() );
auto clip = data->GetClip().get();
return !(clip->IsClipStartAfterClip(interval.Start()) ||
clip->BeforeClip(interval.End()));
});
}
bool SyncLocks() override { return true; }
bool MayMigrateTo(Track &other) override
{
return TrackShifter::CommonMayMigrateTo(other);
}
double HintOffsetLarger(double desiredOffset) override
{
// set it to a sample point, and minimum of 1 sample point
bool positive = (desiredOffset > 0);
if (!positive)
desiredOffset *= -1;
double nSamples = rint(mpTrack->GetRate() * desiredOffset);
nSamples = std::max(nSamples, 1.0);
desiredOffset = nSamples / mpTrack->GetRate();
if (!positive)
desiredOffset *= -1;
return desiredOffset;
}
double QuantizeOffset( double desiredOffset ) override
{
const auto rate = mpTrack->GetRate();
// set it to a sample point
return rint(desiredOffset * rate) / rate;
}
double AdjustOffsetSmaller(double desiredOffset) override
{
std::vector< WaveClip * > movingClips;
for ( auto &interval : MovingIntervals() ) {
auto data =
static_cast<WaveTrack::IntervalData*>( interval.Extra() );
movingClips.push_back(data->GetClip().get());
}
double newAmount = 0;
(void) mpTrack->CanOffsetClips(movingClips, desiredOffset, &newAmount);
return newAmount;
}
Intervals Detach() override
{
for ( auto &interval: mMoving ) {
auto pData = static_cast<WaveTrack::IntervalData*>( interval.Extra() );
auto pClip = pData->GetClip().get();
// interval will still hold the clip, so ignore the return:
(void) mpTrack->RemoveAndReturnClip(pClip);
mMigrated.erase(pClip);
}
return std::move( mMoving );
}
bool AdjustFit(
const Track &otherTrack, const Intervals &intervals,
double &desiredOffset, double tolerance) override
{
bool ok = true;
auto pOtherWaveTrack = static_cast<const WaveTrack*>(&otherTrack);
for ( auto &interval: intervals ) {
auto pData =
static_cast<WaveTrack::IntervalData*>( interval.Extra() );
auto pClip = pData->GetClip().get();
ok = pOtherWaveTrack->CanInsertClip(
pClip, desiredOffset, tolerance );
if( !ok )
break;
}
return ok;
}
bool Attach( Intervals intervals ) override
{
for (auto &interval : intervals) {
auto pData = static_cast<WaveTrack::IntervalData*>( interval.Extra() );
auto pClip = pData->GetClip();
if ( !mpTrack->AddClip( pClip ) )
return false;
mMigrated.insert( pClip.get() );
mMoving.emplace_back( std::move( interval ) );
}
return true;
}
bool FinishMigration() override
{
auto rate = mpTrack->GetRate();
for (auto pClip : mMigrated) {
// Now that user has dropped the clip into a different track,
// make sure the sample rate matches the destination track.
pClip->Resample(rate);
pClip->MarkChanged();
}
return true;
}
void DoHorizontalOffset( double offset ) override
{
for ( auto &interval : MovingIntervals() ) {
auto data =
static_cast<WaveTrack::IntervalData*>( interval.Extra() );
data->GetClip()->Offset( offset );
}
}
private:
std::shared_ptr<WaveTrack> mpTrack;
// Clips that may require resampling
std::unordered_set<WaveClip *> mMigrated;
};
using MakeWaveTrackShifter = MakeTrackShifter::Override<WaveTrack>;
template<> template<> auto MakeWaveTrackShifter::Implementation() -> Function {
return [](WaveTrack &track, AudacityProject&) {
return std::make_unique<WaveTrackShifter>(track);
};
}
static MakeWaveTrackShifter registerMakeWaveTrackShifter;