1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-04-30 15:49:41 +02:00

Different procedure, same results, to find corresponding tracks...

... for shifting of clips among tracks

But this (temporarily) breaks the behavior of dragging back to the original
clip without first releasing the mouse
This commit is contained in:
Paul Licameli 2020-09-16 08:10:13 -04:00
parent d3ab8b7f76
commit 633b2e28bc
3 changed files with 97 additions and 65 deletions

View File

@ -1344,6 +1344,11 @@ public:
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

View File

@ -164,46 +164,6 @@ namespace
viewInfo.selectedRegion.t1() );
}
WaveTrack *NthChannel(WaveTrack &leader, int nn)
{
if (nn < 0)
return nullptr;
return *TrackList::Channels( &leader ).begin().advance(nn);
}
int ChannelPosition(const Track *pChannel)
{
return static_cast<int>(
TrackList::Channels( pChannel )
.EndingAfter( pChannel ).size()
) - 1;
}
// Don't count right channels.
WaveTrack *NthAudioTrack(TrackList &list, int nn)
{
if (nn >= 0) {
for ( auto pTrack : list.Leaders< WaveTrack >() )
if (nn -- == 0)
return pTrack;
}
return NULL;
}
// Don't count right channels.
int TrackPosition(TrackList &list, const Track *pFindTrack)
{
pFindTrack = *list.FindLeader(pFindTrack);
int nn = 0;
for ( auto pTrack : list.Leaders< const WaveTrack >() ) {
if (pTrack == pFindTrack)
return nn;
++nn;
}
return -1;
}
WaveClip *FindClipAtTime(WaveTrack *pTrack, double time)
{
if (pTrack) {
@ -279,6 +239,42 @@ double TrackShifter::HintOffsetLarger(double desiredOffset)
return desiredOffset;
}
bool TrackShifter::MayMigrateTo(Track &)
{
return false;
}
bool TrackShifter::CommonMayMigrateTo(Track &otherTrack)
{
auto &track = GetTrack();
// Both tracks need to be owned to decide this
auto pMyList = track.GetOwner().get();
auto pOtherList = otherTrack.GetOwner().get();
if (pMyList && pOtherList) {
// Can migrate to another track of the same kind...
if ( otherTrack.SameKindAs( track ) ) {
// ... with the same number of channels ...
auto myChannels = TrackList::Channels( &track );
auto otherChannels = TrackList::Channels( &otherTrack );
if (myChannels.size() == otherChannels.size()) {
// ... and where this track and the other have corresponding
// positions
return myChannels.size() == 1 ||
std::distance(myChannels.first, pMyList->Find(&track)) ==
std::distance(otherChannels.first, pOtherList->Find(&otherTrack));
}
}
}
return false;
}
void TrackShifter::InitIntervals()
{
mMoving.clear();
@ -724,41 +720,62 @@ namespace {
}
}
using Correspondence = std::unordered_map< Track*, Track* >;
bool FindCorrespondence(
Correspondence &correspondence,
TrackList &trackList, Track &track,
ClipMoveState &state)
{
Track &capturedTrack = *state.mCapturedTrack;
const int diff =
TrackPosition(trackList, &track) -
TrackPosition(trackList, &capturedTrack);
for ( auto &trackClip : state.capturedClipArray ) {
if (trackClip.clip) {
// Move all clips up or down by an equal count of audio tracks.
// Can only move between tracks with equal numbers of channels,
// and among corresponding channels.
Track *const pSrcTrack = trackClip.track;
auto pDstTrack = NthAudioTrack(trackList,
diff + TrackPosition(trackList, pSrcTrack));
if (!pDstTrack)
auto &capturedTrack = state.mCapturedTrack;
auto sameType = [&]( auto pTrack ){
return capturedTrack->SameKindAs( *pTrack );
};
if (!sameType(&track))
return false;
if (TrackList::Channels(pSrcTrack).size() !=
TrackList::Channels(pDstTrack).size())
// All tracks of the same kind as the captured track
auto range = trackList.Any() + sameType;
// Find how far this track would shift down among those (signed)
const auto myPosition =
std::distance( range.first, trackList.Find( capturedTrack.get() ) );
const auto otherPosition =
std::distance( range.first, trackList.Find( &track ) );
auto diff = otherPosition - myPosition;
// Point to destination track
auto iter = range.first.advance( diff > 0 ? diff : 0 );
for (auto pTrack : range) {
auto &pShifter = state.shifters[pTrack];
if ( !pShifter->MovingIntervals().empty() ) {
// One of the interesting tracks
auto pOther = *iter;
if ( diff < 0 || !pOther )
// No corresponding track
return false;
auto pDstChannel = NthChannel(
*pDstTrack, ChannelPosition(pSrcTrack));
if (!pDstChannel) {
wxASSERT(false);
if ( !pShifter->MayMigrateTo(*pOther) )
// Rejected for other reason
return false;
correspondence[ pTrack ] = pOther;
}
trackClip.dstTrack = pDstChannel;
}
if ( diff < 0 )
++diff; // Still consuming initial tracks
else
++iter; // Safe to increment TrackIter even at end of range
}
// Record the correspondence in TrackClip
for ( auto &trackClip: state.capturedClipArray )
if ( trackClip.clip )
trackClip.dstTrack =
dynamic_cast<WaveTrack*>(correspondence[ trackClip.track ]);
return true;
}
@ -841,7 +858,8 @@ bool TimeShiftHandle::DoSlideVertical
ClipMoveState &state, TrackList &trackList,
Track &dstTrack, double &desiredSlideAmount )
{
if (!FindCorrespondence( trackList, dstTrack, state ))
Correspondence correspondence;
if (!FindCorrespondence( correspondence, trackList, dstTrack, state ))
return false;
// Having passed that test, remove clips temporarily from their

View File

@ -75,10 +75,19 @@ public:
*/
virtual double HintOffsetLarger( double desiredOffset );
//! Whether intervals may migrate to the other track, not yet checking all placement constraints */
/*! Default implementation returns false */
virtual bool MayMigrateTo( Track &otherTrack );
protected:
/*! Unfix any of the intervals that intersect the given one; may be useful to override `SelectInterval()` */
void CommonSelectInterval( const TrackInterval &interval );
/*! May be useful to override `MayMigrateTo()`, if certain other needed overrides are given.
Returns true, iff: tracks have same type, and corresponding positions in their channel groups,
which have same size */
bool CommonMayMigrateTo( Track &otherTrack );
//! Derived class constructor can initialize all intervals reported by the track as fixed, none moving
/*! This can't be called by the base class constructor, when GetTrack() isn't yet callable */
void InitIntervals();