Audacity 3.2.0
WaveTrackShifter.cpp
Go to the documentation of this file.
1
6#include "../../../ui/TimeShiftHandle.h"
7#include "ViewInfo.h"
8#include "WaveClip.h"
9#include "WaveTrack.h"
10#include "WaveChannelView.h"
11
12#include <cassert>
13#include <unordered_set>
14
15class WaveTrackShifter final : public TrackShifter {
16public:
18 : mpTrack{ track.SharedPointer<WaveTrack>() }
19 {
21 }
22 ~WaveTrackShifter() override {}
23 Track &GetTrack() const override {
24 return *mpTrack;
25 }
26
28 double time, const ViewInfo &viewInfo, HitTestParams* params) override
29 {
30 const auto pClip = [&]() -> std::shared_ptr<WaveClip> {
31 for (auto clip : mpTrack->Intervals())
32 if ((
33 // y coordinates in this HitTest come from the third argument
34 // The channel of the interval is used only for times
36 *clip, viewInfo, params->rect, { params->xx, params->yy })
37 ) || (
38 // WithinPlayRegion misses first sample, which breaks moving
39 // "selected" clip. Probable WithinPlayRegion should be fixed
40 // instead?
41 clip->GetPlayStartTime() <= time &&
42 time < clip->GetPlayEndTime()
43 ))
44 return clip;
45 return {};
46 }();
47
48 if (!pClip)
50
51 auto t0 = viewInfo.selectedRegion.t0();
52 auto t1 = viewInfo.selectedRegion.t1();
53 if (mpTrack->IsSelected() && time >= t0 && time < t1) {
54 // Unfix maybe many intervals (at least one because of test above)
55 SelectInterval({ t0, t1 });
57 }
58
59 // Select just one interval
60 UnfixIntervals([&](const auto &interval){
61 return &interval == pClip.get();
62 });
63
65 }
66
67 void SelectInterval(TimeInterval interval) override
68 {
69 UnfixIntervals([&](auto &myInterval){
70 // Use a slightly different test from CommonSelectInterval, rounding times
71 // to exact samples according to the clip's rate
72 auto &clip = static_cast<const WaveTrack::Interval&>(myInterval);
73 const auto c0 = mpTrack->TimeToLongSamples(clip.GetPlayStartTime());
74 const auto c1 = mpTrack->TimeToLongSamples(clip.GetPlayEndTime());
75 return
76 mpTrack->TimeToLongSamples(interval.Start()) < c1 &&
77 mpTrack->TimeToLongSamples(interval.End()) > c0;
78 });
79 }
80
81 bool SyncLocks() override { return true; }
82
83 bool MayMigrateTo(Track &other) override
84 {
86 }
87
88 double HintOffsetLarger(double desiredOffset) override
89 {
90 // set it to a sample point, and minimum of 1 sample point
91 bool positive = (desiredOffset > 0);
92 if (!positive)
93 desiredOffset *= -1;
94 double nSamples = rint(mpTrack->GetRate() * desiredOffset);
95 nSamples = std::max(nSamples, 1.0);
96 desiredOffset = nSamples / mpTrack->GetRate();
97 if (!positive)
98 desiredOffset *= -1;
99 return desiredOffset;
100 }
101
102 double QuantizeOffset( double desiredOffset ) override
103 {
104 const auto rate = mpTrack->GetRate();
105 // set it to a sample point
106 return rint(desiredOffset * rate) / rate;
107 }
108
109 double AdjustOffsetSmaller(double desiredOffset) override
110 {
111 std::vector<WaveTrack::Interval *> movingClips;
112 for (auto &interval : MovingIntervals()) {
113 auto &data = static_cast<WaveTrack::Interval&>(*interval);
114 movingClips.push_back(&data);
115 }
116 double newAmount = 0;
117 mpTrack->CanOffsetClips(movingClips, desiredOffset, &newAmount);
118 return newAmount;
119 }
120
121 Intervals Detach() override
122 {
123 for (auto &interval: mMoving) {
124 auto pClip = std::static_pointer_cast<WaveTrack::Interval>(interval);
125 mpTrack->RemoveInterval(pClip);
126 mMigrated.erase(
127 std::remove(mMigrated.begin(), mMigrated.end(), pClip),
128 mMigrated.end());
129 }
130 return std::move(mMoving);
131 }
132
134 const Track &otherTrack, const Intervals &intervals,
135 double &desiredOffset, double tolerance) override
136 {
137 bool ok = true;
138 auto pOtherWaveTrack = static_cast<const WaveTrack*>(&otherTrack);
139 for (auto &interval: intervals) {
140 auto &data = static_cast<WaveTrack::Interval&>(*interval);
141 if (!(ok = pOtherWaveTrack->CanInsertClip(data, desiredOffset, tolerance)))
142 break;
143 }
144 return ok;
145 }
146
147 bool Attach(Intervals intervals, double offset) override
148 {
149 for (auto interval : intervals) {
150 auto data = std::static_pointer_cast<WaveTrack::Interval>(interval);
151 mpTrack->InsertInterval(data, false);
152 mMigrated.push_back(data);
153 if (offset != .0)
154 data->ShiftBy(offset);
155 mMoving.emplace_back(std::move(interval));
156 }
157 return true;
158 }
159
160 bool FinishMigration() override
161 {
162 auto rate = mpTrack->GetRate();
163 for (auto pClip : mMigrated) {
164 // Now that user has dropped the clip into a different track,
165 // make sure the sample rate matches the destination track.
166 pClip->Resample(rate);
167 }
168 return true;
169 }
170
171 void DoHorizontalOffset(double offset) override
172 {
173 for (auto &interval : MovingIntervals()) {
174 auto &clip = static_cast<WaveTrack::Interval&>(*interval);
175 clip.ShiftBy(offset);
176 }
177 }
178
179
180 // Ensure that t0 is still within the clip which it was in before the move.
181 // This corrects for any rounding errors.
182 double AdjustT0(double t0) const override
183 {
184 if (MovingIntervals().empty())
185 return t0;
186 else {
187 auto &clip =
188 static_cast<WaveTrack::Interval&>(*MovingIntervals()[0]);
189 t0 = std::clamp(t0, clip.GetPlayStartTime(), clip.GetPlayEndTime());
190 }
191 return t0;
192 }
193
194private:
195 const std::shared_ptr<WaveTrack> mpTrack;
196
197 // Clips that may require resampling
198 std::vector<WaveTrack::IntervalHolder> mMigrated;
199};
200
203 return [](WaveTrack &track, AudacityProject&) {
204 return std::make_unique<WaveTrackShifter>(track);
205 };
206}
EffectDistortionSettings params
DEFINE_ATTACHED_VIRTUAL_OVERRIDE(MakeWaveTrackShifter)
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
double t1() const
Definition: ViewInfo.h:36
double t0() const
Definition: ViewInfo.h:35
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:110
Abstract base class for policies to manipulate a track type for Time Shift.
void InitIntervals()
Derived class constructor can initialize all intervals reported by the track as fixed,...
const Intervals & MovingIntervals() const
Return special intervals of the track that may move.
void UnfixIntervals(std::function< bool(const ChannelGroupInterval &)> pred)
Change intervals satisfying a predicate from fixed to moving.
bool CommonMayMigrateTo(Track &otherTrack)
HitTestResult
Possibilities for HitTest on the clicked track.
@ Selection
Shift chosen intervals of this track; may shift other tracks' intervals.
@ Intervals
Shift intervals only of selected track and sister channels.
@ Miss
Don't shift anything.
Intervals mMoving
std::vector< std::shared_ptr< ChannelGroupInterval > > Intervals
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:216
static bool HitTest(const ClipTimes &clip, const ZoomInfo &zoomInfo, const wxRect &rect, const wxPoint &pos)
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:238
void ShiftBy(double delta) noexcept
Definition: WaveClip.cpp:1898
A Track that contains audio waveform data.
Definition: WaveTrack.h:203
Intervals Detach() override
Remove all moving intervals from the track, if possible.
bool Attach(Intervals intervals, double offset) override
Put moving intervals into the track, which may have migrated from another.
double AdjustT0(double t0) const override
const std::shared_ptr< WaveTrack > mpTrack
bool SyncLocks() override
Whether unfixing of an interval should propagate to all overlapping intervals in the sync lock group.
bool FinishMigration() override
When dragging is done, do (once) the final steps of migration (which may be expensive)
~WaveTrackShifter() override
double AdjustOffsetSmaller(double desiredOffset) override
Given amount to shift by horizontally, maybe adjust it toward zero to meet placement constraints.
bool MayMigrateTo(Track &other) override
bool AdjustFit(const Track &otherTrack, const Intervals &intervals, double &desiredOffset, double tolerance) override
void DoHorizontalOffset(double offset) override
std::vector< WaveTrack::IntervalHolder > mMigrated
Track & GetTrack() const override
There is always an associated track.
void SelectInterval(TimeInterval interval) override
Notifies the shifter that a region is selected, so it may update its fixed and moving intervals.
WaveTrackShifter(WaveTrack &track)
double HintOffsetLarger(double desiredOffset) override
Given amount to shift by horizontally, maybe adjust it from zero to suggest minimum distance.
double QuantizeOffset(double desiredOffset) override
Given amount to shift by horizontally, do any preferred rounding, before placement constraint checks.
HitTestResult HitTest(double time, const ViewInfo &viewInfo, HitTestParams *params) override
Decide how shift behaves, based on the track that is clicked in.
__finl float __vecc rint(float a)
For defining overrides of the method.
Optional, more complete information for hit testing.
A simple time interval.