Audacity 3.2.0
Functions | Variables
anonymous_namespace{DynamicRangeProcessorHistoryPanel.cpp} Namespace Reference

Functions

bool MayUsePenGradients ()
 
int GetActualCompressionLineWidth ()
 
double GetDisplayPixel (float elapsedSincePacket, int panelWidth)
 
void InsertCrossings (std::vector< wxPoint2DDouble > &A, std::vector< wxPoint2DDouble > &B)
 
void FillUpTo (std::vector< wxPoint2DDouble > lines, const wxColor &color, wxGraphicsContext &gc, const wxRect &rect)
 
void DrawLegend (size_t height, wxPaintDC &dc, wxGraphicsContext &gc)
 

Variables

constexpr auto timerId = 7000
 
constexpr auto timerPeriodMs = 1000 / 200
 

Detailed Description


Audacity: A Digital Audio Editor

DynamicRangeProcessorHistoryPanel.cpp

Matthieu Hodgkinson

Function Documentation

◆ DrawLegend()

void anonymous_namespace{DynamicRangeProcessorHistoryPanel.cpp}::DrawLegend ( size_t  height,
wxPaintDC &  dc,
wxGraphicsContext &  gc 
)

Definition at line 206 of file DynamicRangeProcessorHistoryPanel.cpp.

207{
208 using namespace DynamicRangeProcessorPanel;
209
210 constexpr auto legendWidth = 16;
211 constexpr auto legendHeight = 16;
212 constexpr auto legendSpacing = 8;
213 constexpr auto legendX = 5;
214 const auto legendY = height - 5 - legendHeight;
215 const auto legendTextX = legendX + legendWidth + 5;
216 const auto legendTextHeight = dc.GetTextExtent("X").GetHeight();
217 const auto legendTextYOffset = (legendHeight - legendTextHeight) / 2;
218 const auto legendTextY = legendY + legendTextYOffset;
219
220 struct LegendInfo
221 {
222 const wxColor color;
223 const TranslatableString text;
224 };
225
226 std::vector<LegendInfo> legends = {
227 { inputColor, XO("Input") },
228 { outputColor, XO("Output") },
229 };
230
231 int legendTextXOffset = 0;
232 dc.SetTextForeground(*wxBLACK);
233 dc.SetFont(
234 { 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL });
235 for (const auto& legend : legends)
236 {
237 // First fill with background color so that transparent foreground colors
238 // yield the same result as on the graph.
239 gc.SetPen(*wxTRANSPARENT_PEN);
240 gc.SetBrush(backgroundColor);
241 gc.DrawRectangle(
242 legendX + legendTextXOffset, legendY, legendWidth, legendHeight);
243
244 gc.SetBrush(wxColor { legend.color.GetRGB() });
245 gc.DrawRectangle(
246 legendX + legendTextXOffset, legendY, legendWidth, legendHeight);
247
248 gc.SetPen(lineColor);
249 gc.SetBrush(*wxTRANSPARENT_BRUSH);
250 gc.DrawRectangle(
251 legendX + legendTextXOffset, legendY, legendWidth, legendHeight);
252
253 dc.DrawText(
254 legend.text.Translation(), legendTextX + legendTextXOffset,
255 legendTextY);
256 const auto legendTextWidth =
257 dc.GetTextExtent(legend.text.Translation()).GetWidth();
258 legendTextXOffset += legendWidth + 5 + legendTextWidth + legendSpacing;
259 }
260
261 const auto lineY = legendY + legendHeight / 2.;
262 constexpr auto lineWidth = 24;
263
264 // Actual compression
265 const auto actualX = legendX + legendTextXOffset + legendSpacing;
266 const std::array<wxPoint2DDouble, 2> actualLine {
267 wxPoint2DDouble(actualX, lineY),
268 wxPoint2DDouble(actualX + lineWidth, lineY)
269 };
270
272 gc.DrawLines(2, actualLine.data());
273
274 if (MayUsePenGradients())
275 {
276 wxGraphicsPenInfo penInfo;
277 wxGraphicsGradientStops stops { actualCompressionColor,
279 stops.Add(attackColor.GetRGB(), 1 / 4.);
280 stops.Add(actualCompressionColor, 2 / 4.);
281 stops.Add(releaseColor.GetRGB(), 3 / 4.);
282 penInfo.LinearGradient(actualX, 0, actualX + lineWidth, 0, stops)
284 gc.SetPen(gc.CreatePen(penInfo));
285 }
286 else
287 gc.SetPen(actualCompressionColor);
288
289 gc.DrawLines(2, actualLine.data());
290 const auto actualText = XO("Actual Compression");
291 const auto actualTextX = actualX + lineWidth + legendSpacing;
292 dc.DrawText(actualText.Translation(), actualTextX, legendTextY);
293
294 // Target compression
296 const auto targetX =
297 actualTextX + dc.GetTextExtent(actualText.Translation()).GetWidth() + 10;
298 gc.StrokeLine(targetX, lineY, targetX + lineWidth, lineY);
299 const auto compressionText = XO("Target Compression");
300 dc.DrawText(
301 compressionText.Translation(), targetX + lineWidth + 5, legendTextY);
302}
XO("Cut/Copy/Paste")
Holds a msgid for the translation catalog; may also bind format arguments.

References DynamicRangeProcessorPanel::actualCompressionColor, DynamicRangeProcessorPanel::attackColor, DynamicRangeProcessorPanel::backgroundColor, GetActualCompressionLineWidth(), DynamicRangeProcessorPanel::inputColor, DynamicRangeProcessorPanel::lineColor, MayUsePenGradients(), DynamicRangeProcessorPanel::outputColor, DynamicRangeProcessorPanel::releaseColor, DynamicRangeProcessorPanel::targetCompressionColor, DynamicRangeProcessorPanel::targetCompressionLineWidth, and XO().

Referenced by DynamicRangeProcessorHistoryPanel::OnPaint().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ FillUpTo()

void anonymous_namespace{DynamicRangeProcessorHistoryPanel.cpp}::FillUpTo ( std::vector< wxPoint2DDouble >  lines,
const wxColor &  color,
wxGraphicsContext &  gc,
const wxRect &  rect 
)

Fills the area between the lines and the bottom of the panel with the given color.

Definition at line 188 of file DynamicRangeProcessorHistoryPanel.cpp.

191{
192 const auto height = rect.GetHeight();
193 const auto left = std::max<double>(rect.GetX(), lines.front().m_x);
194 const auto right = std::min<double>(rect.GetWidth(), lines.back().m_x);
195 auto area = gc.CreatePath();
196 area.MoveToPoint(right, height);
197 area.AddLineToPoint(left, height);
198 std::for_each(lines.begin(), lines.end(), [&area](const auto& p) {
199 area.AddLineToPoint(p);
200 });
201 area.CloseSubpath();
202 gc.SetBrush(color);
203 gc.FillPath(area);
204}

Referenced by DynamicRangeProcessorHistoryPanel::OnPaint().

Here is the caller graph for this function:

◆ GetActualCompressionLineWidth()

int anonymous_namespace{DynamicRangeProcessorHistoryPanel.cpp}::GetActualCompressionLineWidth ( )

Definition at line 44 of file DynamicRangeProcessorHistoryPanel.cpp.

45{
46 using namespace DynamicRangeProcessorPanel;
48}

References MayUsePenGradients(), and DynamicRangeProcessorPanel::targetCompressionLineWidth.

Referenced by DrawLegend(), and DynamicRangeProcessorHistoryPanel::OnPaint().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetDisplayPixel()

double anonymous_namespace{DynamicRangeProcessorHistoryPanel.cpp}::GetDisplayPixel ( float  elapsedSincePacket,
int  panelWidth 
)

Definition at line 118 of file DynamicRangeProcessorHistoryPanel.cpp.

119{
120 const auto secondsPerPixel =
122 // A display delay to avoid the display to tremble near time zero because the
123 // data hasn't arrived yet.
124 // This is a trade-off between visual comfort and timely update. It was set
125 // empirically, but with a relatively large audio playback delay. Maybe it
126 // will be found to lag on lower-latency playbacks. Best would probably be to
127 // make it playback-delay dependent.
128 constexpr auto displayDelay = 0.2f;
129 return panelWidth - 1 -
130 (elapsedSincePacket - displayDelay) / secondsPerPixel;
131}

References DynamicRangeProcessorHistory::maxTimeSeconds.

◆ InsertCrossings()

void anonymous_namespace{DynamicRangeProcessorHistoryPanel.cpp}::InsertCrossings ( std::vector< wxPoint2DDouble > &  A,
std::vector< wxPoint2DDouble > &  B 
)

Wherever A and B cross, evaluates the exact x and y crossing position and adds a point to A and B.

Precondition
A.size() == B.size()
Postcondition
A.size() == B.size()

Definition at line 139 of file DynamicRangeProcessorHistoryPanel.cpp.

141{
142 assert(A.size() == B.size());
143 if (A.size() != B.size())
144 return;
145 std::optional<bool> aWasBelow;
146 auto x0 = 0.;
147 auto y0_a = 0.;
148 auto y0_b = 0.;
149 auto it = A.begin();
150 auto jt = B.begin();
151 while (it != A.end())
152 {
153 const auto x2 = it->m_x;
154 const auto y2_a = it->m_y;
155 const auto y2_b = jt->m_y;
156 const auto aIsBelow = y2_a < y2_b;
157 if (aWasBelow.has_value() && *aWasBelow != aIsBelow)
158 {
159 // clang-format off
160 // We have a crossing of y2_a and y2_b between x0 and x2.
161 // y_a(x) = y0_a + (x - x0) / (x2 - x0) * (y2_a - y0_a)
162 // and likewise for y_b.
163 // Let y_a(x1) = y_b(x1) and solve for x1:
164 // x1 = x0 + (x2 - x0) * (y0_b - y0_a) / ((a_n - y0_a) - (b_n - y0_b))
165 // clang-format on
166 const auto x1 =
167 x0 + (x2 - x0) * (y0_a - y0_b) / (y2_b - y2_a + y0_a - y0_b);
168 const auto y = y0_a + (x1 - x0) / (x2 - x0) * (y2_a - y0_a);
169 if (std::isfinite(x1) && std::isfinite(y))
170 {
171 it = A.emplace(it, x1, y)++;
172 jt = B.emplace(jt, x1, y)++;
173 };
174 }
175 x0 = x2;
176 y0_a = y2_a;
177 y0_b = y2_b;
178 aWasBelow = aIsBelow;
179 ++it;
180 ++jt;
181 }
182}
#define A(N)
Definition: ToChars.cpp:62

References A.

Referenced by DynamicRangeProcessorHistoryPanel::OnPaint().

Here is the caller graph for this function:

◆ MayUsePenGradients()

bool anonymous_namespace{DynamicRangeProcessorHistoryPanel.cpp}::MayUsePenGradients ( )

Definition at line 37 of file DynamicRangeProcessorHistoryPanel.cpp.

38{
39 // MacOS doesn't cope well with pen gradients. (Freezes in debug and is
40 // transperent in release.)
41 return wxPlatformInfo::Get().GetOperatingSystemId() & wxOS_WINDOWS;
42}
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:202

References BasicUI::Get().

Referenced by DrawLegend(), GetActualCompressionLineWidth(), and DynamicRangeProcessorHistoryPanel::OnPaint().

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ timerId

constexpr auto anonymous_namespace{DynamicRangeProcessorHistoryPanel.cpp}::timerId = 7000
constexpr

Definition at line 31 of file DynamicRangeProcessorHistoryPanel.cpp.

◆ timerPeriodMs

constexpr auto anonymous_namespace{DynamicRangeProcessorHistoryPanel.cpp}::timerPeriodMs = 1000 / 200
constexpr