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:
parent
d3ab8b7f76
commit
633b2e28bc
@ -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
|
||||
|
@ -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.
|
||||
auto &capturedTrack = state.mCapturedTrack;
|
||||
auto sameType = [&]( auto pTrack ){
|
||||
return capturedTrack->SameKindAs( *pTrack );
|
||||
};
|
||||
if (!sameType(&track))
|
||||
return false;
|
||||
|
||||
// All tracks of the same kind as the captured track
|
||||
auto range = trackList.Any() + sameType;
|
||||
|
||||
Track *const pSrcTrack = trackClip.track;
|
||||
auto pDstTrack = NthAudioTrack(trackList,
|
||||
diff + TrackPosition(trackList, pSrcTrack));
|
||||
if (!pDstTrack)
|
||||
// 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;
|
||||
|
||||
if (TrackList::Channels(pSrcTrack).size() !=
|
||||
TrackList::Channels(pDstTrack).size())
|
||||
if ( !pShifter->MayMigrateTo(*pOther) )
|
||||
// Rejected for other reason
|
||||
return false;
|
||||
|
||||
auto pDstChannel = NthChannel(
|
||||
*pDstTrack, ChannelPosition(pSrcTrack));
|
||||
|
||||
if (!pDstChannel) {
|
||||
wxASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
trackClip.dstTrack = pDstChannel;
|
||||
correspondence[ pTrack ] = pOther;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user