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