Audacity 3.2.0
Snap.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 Snap.cpp
6
7 Dominic Mazzoni
8
9**********************************************************************/
10
11
12#include "Snap.h"
13
14#include <algorithm>
15#include <cstdlib>
16
17#include "Project.h"
19#include "ProjectRate.h"
20#include "ProjectSettings.h"
21#include "Track.h"
22#include "ViewInfo.h"
23
24inline bool operator < (SnapPoint s1, SnapPoint s2)
25{
26 return s1.t < s2.t;
27}
28
30 SnapPointArray candidates,
31 const ZoomInfo &zoomInfo,
32 bool noTimeSnap,
33 int pixelTolerance)
34: mProject{ &project }
35, mZoomInfo{ &zoomInfo }
36, mPixelTolerance{ pixelTolerance }
37, mNoTimeSnap{ noTimeSnap }
38, mCandidates{ move( candidates ) }
39, mSnapPoints{}
40, mConverter{ NumericConverter::TIME }
41{
42 Reinit();
43}
44
45namespace {
47 SnapPointArray candidates, const TrackList &tracks )
48{
49 for ( const auto track : tracks.Any() ) {
50 auto intervals = track->GetIntervals();
51 for (const auto &interval : intervals) {
52 candidates.emplace_back( interval.Start(), track );
53 if ( interval.Start() != interval.End() )
54 candidates.emplace_back( interval.End(), track );
55 }
56 }
57 return move(candidates);
58}
59}
60
62 const TrackList &tracks,
63 const ZoomInfo &zoomInfo,
64 SnapPointArray candidates,
65 bool noTimeSnap,
66 int pixelTolerance)
67 : SnapManager{ project,
68 // Add candidates to given ones by default rules,
69 // then delegate to other ctor
70 FindCandidates( move(candidates), tracks ),
71 zoomInfo, noTimeSnap, pixelTolerance }
72{
73}
74
76{
77}
78
80{
81 const auto &formats = ProjectNumericFormats::Get(*mProject);
82 const auto &settings = ProjectSettings::Get( *mProject );
83 int snapTo = settings.GetSnapTo();
84 auto rate = ProjectRate::Get(*mProject).GetRate();
85 auto format = formats.GetSelectionFormat();
86
87 // No need to reinit if these are still the same
88 if (snapTo == mSnapTo && rate == mRate && format == mFormat)
89 {
90 return;
91 }
92
93 // Save NEW settings
94 mSnapTo = snapTo;
95 mRate = rate;
97
98 mSnapPoints.clear();
99
100 // Grab time-snapping prefs (unless otherwise requested)
101 mSnapToTime = false;
102
103 // Look up the format string
104 if (mSnapTo != SNAP_OFF && !mNoTimeSnap)
105 {
106 mSnapToTime = true;
109 }
110
111 // Add a SnapPoint at t=0
112 mSnapPoints.push_back(SnapPoint{});
113
114 // Adjust and filter the candidate points
115 for (const auto &candidate : mCandidates)
116 CondListAdd( candidate.t, candidate.track );
117
118 // Sort all by time
119 std::sort(mSnapPoints.begin(), mSnapPoints.end());
120}
121
122// Adds to mSnapPoints, filtering by TimeConverter
123void SnapManager::CondListAdd(double t, const Track *track)
124{
125 if (mSnapToTime)
126 {
128 }
129
130 if (!mSnapToTime || mConverter.GetValue() == t)
131 {
132 mSnapPoints.push_back(SnapPoint{ t, track });
133 }
134}
135
136// Return the time of the SnapPoint at a given index
137double SnapManager::Get(size_t index)
138{
139 return mSnapPoints[index].t;
140}
141
142// Returns the difference in time between t and the point at a given index
143wxInt64 SnapManager::PixelDiff(double t, size_t index)
144{
145 return std::abs(mZoomInfo->TimeToPosition(t, 0) -
146 mZoomInfo->TimeToPosition(Get(index), 0));
147}
148
149// Find the index where this SnapPoint should go in
150// sorted order, between i0 (inclusive) and i1 (exclusive).
151size_t SnapManager::Find(double t, size_t i0, size_t i1)
152{
153 if (i1 <= i0 + 1)
154 {
155 return i0;
156 }
157
158 size_t half = (i0 + i1) / 2;
159
160 if (t < Get(half))
161 {
162 return Find(t, i0, half);
163 }
164
165 return Find(t, half, i1);
166}
167
168// Find the SnapPoint nearest to time t
169size_t SnapManager::Find(double t)
170{
171 size_t cnt = mSnapPoints.size();
172 size_t index = Find(t, 0, cnt);
173
174 // At this point, either index is the closest, or the next one
175 // to the right is. Keep moving to the right until we get a
176 // different value
177 size_t next = index + 1;
178 while (next + 1 < cnt && Get(next) == Get(index))
179 {
180 next++;
181 }
182
183 // Now return whichever one is closer to time t
184 if (next < cnt && PixelDiff(t, next) < PixelDiff(t, index))
185 {
186 return next;
187 }
188
189 return index;
190}
191
192// Helper: performs snap-to-points for Snap(). Returns true if a snap happened.
194 double t,
195 bool rightEdge,
196 double *outT)
197{
198 *outT = t;
199
200 size_t cnt = mSnapPoints.size();
201 if (cnt == 0)
202 {
203 return false;
204 }
205
206 // Find the nearest SnapPoint
207 size_t index = Find(t);
208
209 // If it's too far away, just give up now
210 if (PixelDiff(t, index) >= mPixelTolerance)
211 {
212 return false;
213 }
214
215 // Otherwise, search left and right for all of the points
216 // within the allowed range.
217 size_t left = index;
218 size_t right = index;
219 size_t i;
220
221 while (left > 0 && PixelDiff(t, left - 1) < mPixelTolerance)
222 {
223 left--;
224 }
225
226 while (right < cnt - 1 && PixelDiff(t, right + 1) < mPixelTolerance)
227 {
228 right++;
229 }
230
231 if (left == index && right == index)
232 {
233 // Awesome, there's only one point that matches!
234 *outT = Get(index);
235 return true;
236 }
237
238 size_t indexInThisTrack = 0;
239 size_t countInThisTrack = 0;
240 for (i = left; i <= right; ++i)
241 {
242 if (mSnapPoints[i].track == currentTrack)
243 {
244 indexInThisTrack = i;
245 countInThisTrack++;
246 }
247 }
248
249 if (countInThisTrack == 1)
250 {
251 // Cool, only one of the points is in the same track, so
252 // we'll use that one.
253 *outT = Get(indexInThisTrack);
254 return true;
255 }
256
257 if (Get(right) - Get(left) < mEpsilon)
258 {
259 // OK, they're basically the same point
260 if (rightEdge)
261 {
262 *outT = Get(right); // Return rightmost
263 }
264 else {
265 *outT = Get(left); // Return leftmost
266 }
267 return true;
268 }
269
270 // None of the points matched, bummer.
271 return false;
272}
273
275(Track *currentTrack, double t, bool rightEdge)
276{
277
278 SnapResults results;
279 // Check to see if we need to reinitialize
280 Reinit();
281
282 results.timeSnappedTime = results.outTime = t;
283 results.outCoord = mZoomInfo->TimeToPosition(t);
284
285 // First snap to points in mSnapPoints
286 results.snappedPoint =
287 SnapToPoints(currentTrack, t, rightEdge, &results.outTime);
288
289 if (mSnapToTime) {
290 // Find where it would snap time to the grid
292 t,
294 );
297 }
298
299 results.snappedTime = false;
300 if (mSnapToTime)
301 {
302 if (results.snappedPoint)
303 {
304 // Since mSnapPoints only contains points on the grid, we're done
305 results.snappedTime = true;
306 }
307 else
308 {
309 results.outTime = results.timeSnappedTime;
310 results.snappedTime = true;
311 }
312 }
313
314 if (results.Snapped())
315 results.outCoord = mZoomInfo->TimeToPosition(results.outTime);
316
317 return results;
318}
319
321{
322 static const TranslatableStrings result{
323 XO("Off") ,
324 XO("Nearest") ,
325 XO("Prior") ,
326 };
327 return result;
328}
329
330#include "AColor.h"
331
332void SnapManager::Draw( wxDC *dc, wxInt64 snap0, wxInt64 snap1 )
333{
335 if ( snap0 >= 0 ) {
336 AColor::Line(*dc, (int)snap0, 0, (int)snap0, 30000);
337 }
338 if ( snap1 >= 0 ) {
339 AColor::Line(*dc, (int)snap1, 0, (int)snap1, 30000);
340 }
341}
int format
Definition: ExportPCM.cpp:53
XO("Cut/Copy/Paste")
an object holding per-project preferred sample rate
@ SNAP_NEAREST
@ SNAP_OFF
bool operator<(SnapPoint s1, SnapPoint s2)
Definition: Snap.cpp:24
std::vector< SnapPoint > SnapPointArray
Definition: Snap.h:43
declares abstract base class Track, TrackList, and iterators over TrackList
static Settings & settings()
Definition: TrackInfo.cpp:87
std::vector< TranslatableString > TranslatableStrings
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:187
static void SnapGuidePen(wxDC *dc)
Definition: AColor.cpp:488
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
NumericConverter provides the advanced formatting control used in the selection bar of Audacity.
virtual void ControlsToValue()
virtual void ValueToControls()
void SetSampleRate(double sampleRate)
void SetValue(double newValue)
bool SetFormatName(const NumericFormatSymbol &formatName)
static ProjectNumericFormats & Get(AudacityProject &project)
static ProjectRate & Get(AudacityProject &project)
Definition: ProjectRate.cpp:28
double GetRate() const
Definition: ProjectRate.cpp:53
static ProjectSettings & Get(AudacityProject &project)
int GetSnapTo() const
size_t Find(double t, size_t i0, size_t i1)
Definition: Snap.cpp:151
bool SnapToPoints(Track *currentTrack, double t, bool rightEdge, double *outT)
Definition: Snap.cpp:193
~SnapManager()
Definition: Snap.cpp:75
NumericConverter mConverter
Definition: Snap.h:112
static void Draw(wxDC *dc, wxInt64 snap0, wxInt64 snap1)
Definition: Snap.cpp:332
double mEpsilon
Two time points closer than this are considered the same.
Definition: Snap.h:107
double mRate
Definition: Snap.h:116
wxInt64 PixelDiff(double t, size_t index)
Definition: Snap.cpp:143
double Get(size_t index)
Definition: Snap.cpp:137
NumericFormatSymbol mFormat
Definition: Snap.h:117
int mSnapTo
Definition: Snap.h:115
void CondListAdd(double t, const Track *track)
Definition: Snap.cpp:123
const AudacityProject * mProject
Definition: Snap.h:101
SnapResults Snap(Track *currentTrack, double t, bool rightEdge)
Definition: Snap.cpp:275
SnapManager(const AudacityProject &project, SnapPointArray candidates, const ZoomInfo &zoomInfo, bool noTimeSnap=false, int pixelTolerance=kPixelTolerance)
Construct only for specified candidate points.
Definition: Snap.cpp:29
void Reinit()
Definition: Snap.cpp:79
bool mSnapToTime
Definition: Snap.h:113
SnapPointArray mCandidates
Definition: Snap.h:108
SnapPointArray mSnapPoints
Definition: Snap.h:109
bool mNoTimeSnap
Definition: Snap.h:104
static const TranslatableStrings & GetSnapLabels()
Definition: Snap.cpp:320
int mPixelTolerance
Definition: Snap.h:103
const ZoomInfo * mZoomInfo
Definition: Snap.h:102
Definition: Snap.h:31
double t
Definition: Snap.h:39
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:226
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:1339
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:1440
int64 TimeToPosition(double time, int64 origin=0, bool ignoreFisheye=false) const
STM: Converts a project time to screen x position.
Definition: ZoomInfo.cpp:45
SnapPointArray FindCandidates(SnapPointArray candidates, const TrackList &tracks)
Definition: Snap.cpp:46
bool snappedTime
Definition: Snap.h:50
double outTime
Definition: Snap.h:47
double timeSnappedTime
Definition: Snap.h:46
wxInt64 outCoord
Definition: Snap.h:48
bool Snapped() const
Definition: Snap.h:52
bool snappedPoint
Definition: Snap.h:49