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