Audacity 3.2.0
ClipParameters.cpp
Go to the documentation of this file.
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/**********************************************************************
3
4Audacity: A Digital Audio Editor
5
6ClipParameters.cpp
7
8Matthieu Hodgkinson split from class WaveChannelView.cpp
9
10**********************************************************************/
11#include "ClipParameters.h"
12#include "ClipInterface.h"
13#include "ZoomInfo.h"
14
15namespace
16{
17// Returns an offset in seconds to be applied to the right clip
18// boundary so that it does not overlap the last sample
19double CalculateAdjustmentForZoomLevel(double avgPixPerSecond, bool showSamples)
20{
21 constexpr double pixelsOffset { 2 }; // The desired offset in pixels
22 if (showSamples)
23 // adjustment so that the last circular point doesn't appear
24 // to be hanging off the end
25 return pixelsOffset /
26 avgPixPerSecond; // pixels / ( pixels / second ) = seconds
27 return .0;
28}
29
30double GetPixelsPerSecond(const wxRect& viewRect, const ZoomInfo& zoomInfo)
31{
32 const auto h = zoomInfo.PositionToTime(0, 0, true);
33 const auto trackRectT1 = zoomInfo.PositionToTime(viewRect.width, 0, true);
34 return viewRect.width / (trackRectT1 - h);
35}
36
38 int sampleRate, double stretchRatio, double pixelsPerSecond)
39{
40 const auto secondsPerSample = stretchRatio / sampleRate;
41 const auto pixelsPerSample = pixelsPerSecond * secondsPerSample;
42 return pixelsPerSample > 0.5;
43}
44
46{
47 return 0.99 * clip.GetStretchRatio() / clip.GetRate();
48}
49} // namespace
50
52 const ClipTimes& clip, const wxRect& rect, const ZoomInfo& zoomInfo)
53 : trackRectT0 { zoomInfo.PositionToTime(0, 0, true) }
54 , averagePixelsPerSecond { GetPixelsPerSecond(rect, zoomInfo) }
55 , showIndividualSamples { ShowIndividualSamples(
56 clip.GetRate(), clip.GetStretchRatio(), averagePixelsPerSecond) }
57{
58 const auto trackRectT1 = zoomInfo.PositionToTime(rect.width, 0, true);
59 const auto stretchRatio = clip.GetStretchRatio();
60 const auto playStartTime = clip.GetPlayStartTime();
61
62 const double clipLength = clip.GetPlayEndTime() - clip.GetPlayStartTime();
63
64 // Hidden duration because too far left.
65 const auto tpre = trackRectT0 - playStartTime;
66 const auto tpost = trackRectT1 - playStartTime;
67
68 const auto blank = GetBlankSpaceBeforePlayEndTime(clip);
69
70 // Calculate actual selection bounds so that t0 > 0 and t1 < the
71 // end of the track
72 t0 = std::max(tpre, .0);
73 t1 = std::min(tpost, clipLength - blank) +
76
77 // Make sure t1 (the right bound) is greater than 0
78 if (t1 < 0.0)
79 {
80 t1 = 0.0;
81 }
82
83 // Make sure t1 is greater than t0
84 if (t0 > t1)
85 {
86 t0 = t1;
87 }
88
89 // The variable "hiddenMid" will be the rectangle containing the
90 // actual waveform, as opposed to any blank area before
91 // or after the track, as it would appear without the fisheye.
92 hiddenMid = rect;
93
94 // If the left edge of the track is to the right of the left
95 // edge of the display, then there's some unused area to the
96 // left of the track. Reduce the "hiddenMid"
98 if (tpre < 0)
99 {
100 // Fix Bug #1296 caused by premature conversion to (int).
101 wxInt64 time64 = zoomInfo.TimeToPosition(playStartTime, 0, true);
102 if (time64 < 0)
103 time64 = 0;
104 hiddenLeftOffset = (time64 < rect.width) ? (int)time64 : rect.width;
105
108 }
109
110 // If the right edge of the track is to the left of the right
111 // edge of the display, then there's some unused area to the right
112 // of the track. Reduce the "hiddenMid" rect by the
113 // size of the blank area.
114 if (tpost > t1)
115 {
116 wxInt64 time64 = zoomInfo.TimeToPosition(playStartTime + t1, 0, true);
117 if (time64 < 0)
118 time64 = 0;
119 const int hiddenRightOffset =
120 (time64 < rect.width) ? (int)time64 : rect.width;
121
122 hiddenMid.width = std::max(0, hiddenRightOffset - hiddenLeftOffset);
123 }
124 // The variable "mid" will be the rectangle containing the
125 // actual waveform, as distorted by the fisheye,
126 // as opposed to any blank area before or after the track.
127 mid = rect;
128
129 // If the left edge of the track is to the right of the left
130 // edge of the display, then there's some unused area to the
131 // left of the track. Reduce the "mid"
132 leftOffset = 0;
133 if (tpre < 0)
134 {
135 wxInt64 time64 = zoomInfo.TimeToPosition(playStartTime, 0, false);
136 if (time64 < 0)
137 time64 = 0;
138 leftOffset = (time64 < rect.width) ? (int)time64 : rect.width;
139
140 mid.x += leftOffset;
141 mid.width -= leftOffset;
142 }
143
144 // If the right edge of the track is to the left of the right
145 // edge of the display, then there's some unused area to the right
146 // of the track. Reduce the "mid" rect by the
147 // size of the blank area.
148 if (tpost > t1)
149 {
150 wxInt64 time64 = zoomInfo.TimeToPosition(playStartTime + t1, 0, false);
151 if (time64 < 0)
152 time64 = 0;
153 const int distortedRightOffset =
154 (time64 < rect.width) ? (int)time64 : rect.width;
155
156 mid.width = std::max(0, distortedRightOffset - leftOffset);
157 }
158}
159
161 const ClipTimes& clip, const ZoomInfo& zoomInfo, const wxRect& viewRect,
162 bool* outShowSamples)
163{
164 const auto pixelsPerSecond = GetPixelsPerSecond(viewRect, zoomInfo);
166 clip.GetRate(), clip.GetStretchRatio(), pixelsPerSecond);
167 const auto clipEndingAdjustment =
169 if (outShowSamples != nullptr)
170 *outShowSamples = showIndividualSamples;
171 constexpr auto edgeLeft =
173 constexpr auto edgeRight =
174 static_cast<ZoomInfo::int64>(std::numeric_limits<int>::max());
175 const auto left = std::clamp(
176 zoomInfo.TimeToPosition(clip.GetPlayStartTime(), viewRect.x, true),
177 edgeLeft, edgeRight);
178 const auto right = std::clamp(
179 zoomInfo.TimeToPosition(
181 clipEndingAdjustment,
182 viewRect.x, true),
183 edgeLeft, edgeRight);
184 if (right >= left)
185 {
186 // after clamping we can expect that left and right
187 // are small enough to be put into int
188 return wxRect(
189 static_cast<int>(left), viewRect.y,
190 std::max(1, static_cast<int>(right - left)), viewRect.height);
191 }
192 return wxRect();
193}
int min(int a, int b)
virtual double GetPlayEndTime() const =0
virtual int GetRate() const =0
virtual double GetStretchRatio() const =0
virtual double GetPlayStartTime() const =0
double PositionToTime(int64 position, int64 origin=0, bool ignoreFisheye=false) const
Definition: ZoomInfo.cpp:34
int64 TimeToPosition(double time, int64 origin=0, bool ignoreFisheye=false) const
STM: Converts a project time to screen x position.
Definition: ZoomInfo.cpp:44
std::int64_t int64
Definition: ZoomInfo.h:41
bool ShowIndividualSamples(int sampleRate, double stretchRatio, double pixelsPerSecond)
double GetBlankSpaceBeforePlayEndTime(const ClipTimes &clip)
double CalculateAdjustmentForZoomLevel(double avgPixPerSecond, bool showSamples)
double GetPixelsPerSecond(const wxRect &viewRect, const ZoomInfo &zoomInfo)
double GetRate(const Track &track)
Definition: TimeTrack.cpp:182
const double trackRectT0
ClipParameters(const ClipTimes &clip, const wxRect &rect, const ZoomInfo &zoomInfo)
static wxRect GetClipRect(const ClipTimes &clip, const ZoomInfo &zoomInfo, const wxRect &viewRect, bool *outShowSamples=nullptr)
const double averagePixelsPerSecond
const bool showIndividualSamples